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

Diff of /smsdaemon/SmsPdu.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 63 by torben, Thu Jun 12 12:43:29 2008 UTC revision 178 by torben, Fri Dec 12 12:13:05 2008 UTC
# Line 10  Line 10 
10  #include <time.h>  #include <time.h>
11  #include <stdlib.h>  #include <stdlib.h>
12    
13  #include "common.h"  #include "Logger.h"
14  #include "util.h"  #include "Util.h"
15    
16    #include "Exceptions.h"
17    #include <list>
18    #include <vector>
19    #include <algorithm>
20    
 using namespace std;  
21    
22    using namespace std;
23    
24  namespace SmsPdu  namespace SmsPdu
25  {  {
26    
27    
 vector<unsigned char> BcdEncode(string input)  
 {  
         char buf[2] = " ";  
         vector<unsigned char> result;  
28    
29          unsigned char current;          string SwitchChars(string input)
         for (unsigned int i=0; i<input.length(); ++i)  
30          {          {
31                  buf[0] = input.at(i);                  for (unsigned int i=1; i<input.length(); i+=2)
32                  unsigned char tmp = atoi(buf);          {
33                            char tmp = input[i];
34                  if ( (i%2) == 0)                          input[i] = input[i-1];
35                  {                          input[i-1] = tmp;
                         current = tmp;  
                 }  
                 else  
                 {  
                         current |= (tmp<<4);  
                         result.push_back(current);  
36                  }                  }
37                    return input;
38          }          }
39    
40          if ((input.length() % 2) == 1)          string EncodePhonenr(string input)
41          {          {
42                  current |= 0xF0;                  if ( input.at(0) == '+' )
43                  result.push_back(current);                          input.erase(0,1);
44    
45                    if ( (input.length() % 2) == 1)
46                            input.append("F");
47                    return SwitchChars(input);
48          }          }
49    
50          return result;          string DecodePhonenr(string input)
51  }          {
52                    input = SwitchChars(input);
53                    int last = input.length() -1;
54    
55  string HexformatVector(vector<unsigned char> vec)                  if (input.at(last) == 'F')
56  {                          input.erase(last,1);
57          ostringstream os;                  return input;
58            }
59    
60          for (unsigned int i=0; i<vec.size(); ++i)  
61    
62    
63            string HexformatVector(vector<unsigned char> vec)
64          {          {
65                  os.width(2);                  ostringstream os;
                 os.fill('0');  
                 os << hex << uppercase << static_cast<unsigned int>(vec.at(i));  
         }  
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    
         return os.str();  
 }  
74    
75  std::string Encode8to7bit(vector<unsigned char> vec)                  return os.str();
76  {          }
         string result;  
77    
78          return result;          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  vector<unsigned char> Encode7to8bit(std::string str)                  return vec;
85  {          }
         vector<unsigned char> buf;  
86    
87          int shift = 0;          std::string Decode8to7bit(vector<unsigned char> input, int shift_start)
         for (unsigned int i=0; i<str.size(); ++i)  
88          {          {
89                  unsigned char current = str.at(i) & 0x7F;                  string result;
                 unsigned char next = ( (i+1)<str.size()) ? str.at(i+1) : 0;  
                 next &= 0x7F;  
90    
91                  current >>= shift;                  int shift = shift_start;
92                  next <<= (7-shift);                  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                  unsigned char byte = current | next;                          current <<= shift;
                 buf.push_back(byte);  
98    
99                  if (shift == 6)                          prev >>= (8-shift);
                         i++;  
100    
101                  shift = (shift+1) % 7;                          unsigned char byte = current | prev;
102                            byte &= 0x7F;
103    
104          }                          result.append(1, byte);
105    
106          return buf;                          if (shift == 6)
107  }                                  result.append(1, input.at(i) >> 1);
108    
109  vector<PduInfo> CreateSmsPdu(string to, string message, bool allowMultipart)                          shift = (shift+1) % 7;
 {  
         bool multipart = allowMultipart && message.length() > 160;  
110    
111          const unsigned char UDHI = multipart ? 0x40 : 0;                  }
112    
113          srand(time(0));                  return result;
114          unsigned char csms_ref = rand() % 128;          }
115    
         int part_count;  
116    
         const int PDU_LEN = 153;  
117    
118          if (multipart)  
119          {          vector<unsigned char> Encode7to8bit(std::string str, int shift_start)
                 part_count = message.length() / PDU_LEN;  
                 if (message.length() % PDU_LEN)  
                         part_count++;  
         }  
         else  
120          {          {
121                  part_count = 1;                  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> result;          vector<PduInfo> CreateSmsPdu(string to, string message, bool allowMultipart)
         for (int partnr = 0; partnr < part_count; ++partnr)  
147          {          {
148                  vector<unsigned char> pdu;                  bool multipart = allowMultipart && message.length() > 160;
149    
150                    const unsigned char UDHI = multipart ? 0x40 : 0;
151    
152                  pdu.push_back(0x00); // use SMSC from phone                  unsigned char csms_ref = rand() % 128;
                 pdu.push_back( 0x01|UDHI ); // first octet -- no timeout  
                 pdu.push_back(0x00); // TP-MR message reference  
                 pdu.push_back(to.length() ); //length of phone nr  
                 pdu.push_back(0x91); // type of address (international nr  + ISDN/telephone range) - else try 0x81  
153    
154                  vector<unsigned char> phone = BcdEncode(to);                  int part_count;
                 pdu.insert( pdu.end(), phone.begin(), phone.end());  
155    
156                  pdu.push_back(0x00); // Protocol identifier                  const int PDU_LEN = 153;
                 pdu.push_back(0x00); // Data coding scheme  
157    
                 string message_part;  
158                  if (multipart)                  if (multipart)
159                  {                  {
160                          message_part = message.substr(0, PDU_LEN);                          if (message.length() > 800)
161                          message.erase(0, PDU_LEN);                          {
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                          pdu.push_back( message_part.length()+ 7 );  //UserDataLength                          PduInfo info;
230                          pdu.push_back( 0x06 ); // UDH Len                          info.len = pdu.size()-1;
231                          pdu.push_back( 0x00 ); // UDH Element Identifier                          info.pdu = HexformatVector(pdu);
232                          pdu.push_back( 0x03 ); // UDH element length                          result.push_back(info);
                         pdu.push_back( csms_ref ); // csms_ref reference  
                         pdu.push_back( part_count );  
                         pdu.push_back( partnr+1 );  
                         pdu.push_back( 0x00);  
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                  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                          if (message.length() > 160)                          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                                  message_part = message.substr(0,160); //truncate to 160                                  sort(vec.begin(), vec.end());
308                                  Common::instance()->logMessage("Truncated message");                                  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                          else
318                          {                          {
319                                  message_part = message;                                  throw smsnotfoundexception(); // need more parts
320                          }                          }
321    
                         pdu.push_back( message_part.length() ); //UserDataLength  
322                  }                  }
323    
324                  vector<unsigned char> userData = Encode7to8bit(message_part);                  return sms;
325            }
326    
327    
328                  pdu.insert( pdu.end(), userData.begin(), userData.end());          SMS ParseSmsPdu(std::string pdu_str)
329            {
330                    SmsPart part = ParseSmsPduWorker(pdu_str);
331    
332                  PduInfo info;                  return ConcatenateParts(part);
                 info.len = pdu.size()-1;  
                 info.pdu = HexformatVector(pdu);  
                 result.push_back(info);  
333    
334          }          }
335          return result;  
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  }  }
431    

Legend:
Removed from v.63  
changed lines
  Added in v.178

  ViewVC Help
Powered by ViewVC 1.1.20