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

Diff of /smsdaemon/SmsPdu.cpp

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

revision 68 by torben, Thu Jun 12 18:54:24 2008 UTC revision 177 by torben, Fri Dec 12 10:58:11 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    
17  using namespace std;  using namespace std;
18    
   
19  namespace SmsPdu  namespace SmsPdu
20  {  {
21    
22    
23    
24  string SwitchChars(string input)          string SwitchChars(string input)
 {  
         for (unsigned int i=1; i<input.length(); i+=2)  
25          {          {
26                  char tmp = input[i];                  for (unsigned int i=1; i<input.length(); i+=2)
27                  input[i] = input[i-1];          {
28                  input[i-1] = tmp;                          char tmp = input[i];
29                            input[i] = input[i-1];
30                            input[i-1] = tmp;
31                    }
32                    return input;
33          }          }
         return input;  
 }  
34    
35  string EncodePhonenr(string input)          string EncodePhonenr(string input)
36  {          {
37          if ( (input.length() % 2) == 1)                  if ( input.at(0) == '+' )
38                  input.append("F");                          input.erase(0,1);
         return SwitchChars(input);  
 }  
39    
40  string DecodePhonenr(string input)                  if ( (input.length() % 2) == 1)
41  {                          input.append("F");
42          input = SwitchChars(input);                  return SwitchChars(input);
43          int last = input.length() -1;          }
44    
45          if (input.at(last) == 'F')          string DecodePhonenr(string input)
46                  input.erase(last,1);          {
47          return input;                  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    
 string HexformatVector(vector<unsigned char> vec)  
 {  
         ostringstream os;  
57    
58          for (unsigned int i=0; i<vec.size(); ++i)          string HexformatVector(vector<unsigned char> vec)
59          {          {
60                  os.width(2);                  ostringstream os;
                 os.fill('0');  
                 os << hex << uppercase << static_cast<unsigned int>(vec.at(i));  
         }  
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    
         return os.str();  
 }  
69    
70  std::string Decode8to7bit(vector<unsigned char> input)                  return os.str();
71  {          }
         string result;  
72    
73          int shift = 0;          vector<unsigned char> HexDecodeString(string str)
         for (unsigned int i=0; i<input.size(); ++i)  
74          {          {
75                  unsigned char current = input.at(i);                  vector<unsigned char> vec;
76                  unsigned char prev = (i>0) ? input.at(i-1) : 0;                  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                  current <<= shift;                  return vec;
80            }
81    
82                  prev >>= (8-shift);          std::string Decode8to7bit(vector<unsigned char> input, int shift_start)
83            {
84                    string result;
85    
86                  unsigned char byte = current | prev;                  int shift = shift_start;
87                  byte &= 0x7F;                  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                  result.append(1, byte);                          current <<= shift;
93    
94                  if (shift == 6)                          prev >>= (8-shift);
                         result.append(1, input.at(i) >> 1);  
95    
96                  shift = (shift+1) % 7;                          unsigned char byte = current | prev;
97                            byte &= 0x7F;
98    
99          }                          result.append(1, byte);
100    
101          return result;                          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    
 vector<unsigned char> Encode7to8bit(std::string str)  
 {  
         vector<unsigned char> buf;  
112    
113          int shift = 0;  
114          for (unsigned int i=0; i<str.size(); ++i)          vector<unsigned char> Encode7to8bit(std::string str, int shift_start)
115          {          {
116                  unsigned char current = str.at(i) & 0x7F;                  vector<unsigned char> buf;
117                  unsigned char next = ( (i+1)<str.size()) ? str.at(i+1) : 0;  
118                  next &= 0x7F;                  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                  current >>= shift;                          unsigned char byte = current | next;
129                  next <<= (7-shift);                          buf.push_back(byte);
130    
131                  unsigned char byte = current | next;                          if (shift == 6)
132                  buf.push_back(byte);                                  i++;
133    
134                  if (shift == 6)                          shift = (shift+1) % 7;
                         i++;  
135    
136                  shift = (shift+1) % 7;                  }
137    
138                    return buf;
139          }          }
140    
141          return buf;          vector<PduInfo> CreateSmsPdu(string to, string message, bool allowMultipart)
142  }          {
143                    bool multipart = allowMultipart && message.length() > 160;
144    
145  vector<PduInfo> CreateSmsPdu(string to, string message, bool allowMultipart)                  const unsigned char UDHI = multipart ? 0x40 : 0;
 {  
         bool multipart = allowMultipart && message.length() > 160;  
146    
147          const unsigned char UDHI = multipart ? 0x40 : 0;                  unsigned char csms_ref = rand() % 128;
148    
149          srand(time(0));                  int part_count;
         unsigned char csms_ref = rand() % 128;  
150    
151          int part_count;                  const int PDU_LEN = 153;
152    
153          const int PDU_LEN = 153;                  if (multipart)
154                    {
155                            if (message.length() > 800)
156                            {
157                                    Logger::logMessage("Trying to send multipart sms > 800 bytes !!!");
158                                    message = message.substr(0,800);
159                            }
160    
161          if (multipart)                          part_count = message.length() / PDU_LEN;
162          {                          if (message.length() % PDU_LEN)
163                  if (message.length() > 800)                                  part_count++;
164                    }
165                    else
166                  {                  {
167                          Common::instance()->logMessage("Trying to send multipart sms > 800 bytes !!!");                          part_count = 1;
                         message = message.substr(0,800);  
168                  }                  }
169    
170                  part_count = message.length() / PDU_LEN;                  vector<PduInfo> result;
171                  if (message.length() % PDU_LEN)                  for (int partnr = 0; partnr < part_count; ++partnr)
172                          part_count++;                  {
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                            vector<unsigned char> phone = HexDecodeString( 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                            int shift_start = 0;
189                            string message_part;
190                            if (multipart)
191                            {
192                                    message_part = message.substr(0, PDU_LEN);
193                                    message.erase(0, PDU_LEN-1);
194    
195                                    pdu.push_back( message_part.length()+ 7 );  //UserDataLength
196                                    pdu.push_back( 0x06 ); // UDH Len
197                                    pdu.push_back( 0x00 ); // UDH Element Identifier
198                                    pdu.push_back( 0x03 ); // UDH element length
199                                    pdu.push_back( csms_ref ); // csms_ref reference
200                                    pdu.push_back( part_count );
201                                    pdu.push_back( partnr+1 );
202                                    pdu.push_back( 0x00);
203                                    //shift_start = 6;
204                            }
205                            else
206                            {
207                                    if (message.length() > 160)
208                                    {
209                                            message_part = message.substr(0,160); //truncate to 160
210                                            Logger::logMessage("Truncated message");
211                                    }
212                                    else
213                                    {
214                                            message_part = message;
215                                    }
216    
217                                    pdu.push_back( message_part.length() ); //UserDataLength
218                            }
219    
220                            vector<unsigned char> userData = Encode7to8bit(message_part, shift_start);
221    
222                            pdu.insert( pdu.end(), userData.begin(), userData.end());
223    
224                            PduInfo info;
225                            info.len = pdu.size()-1;
226                            info.pdu = HexformatVector(pdu);
227                            result.push_back(info);
228    
229                    }
230                    return result;
231          }          }
232          else  
233            typedef vector<unsigned char>::iterator char_it;
234    
235            string DecodeRawPhonenr(char_it start, char_it end)
236          {          {
237                  part_count = 1;                  ostringstream os;
238    
239                    for (char_it it = start; it != end; ++it)
240                    {
241                            os.width(2);
242                            os.fill('0');
243                            os << hex << (int)(*it);
244                    }
245                    return DecodePhonenr(os.str());
246          }          }
247    
248          vector<PduInfo> result;          string DecodeTimestamp(char_it start, char_it end)
         for (int partnr = 0; partnr < part_count; ++partnr)  
249          {          {
250                  vector<unsigned char> pdu;                  string stamp = DecodeRawPhonenr(start,end);
251    
252                  pdu.push_back(0x00); // use SMSC from phone                  ostringstream os;
                 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(0x81); // type of address (international nr  + ISDN/telephone range) - else try 0x81  
253    
254                                    os << stamp.substr(0,2) << "/"; //year
255                  string phone = EncodePhonenr(to);                  os << stamp.substr(2,2) << "/"; //month
256                  pdu.insert( pdu.end(), phone.begin(), phone.end());                  os << stamp.substr(4,2) << ","; //day
257                    os << stamp.substr(6,2) << ":"; //hour
258                    os << stamp.substr(8,2) << ":"; //minute
259                    os << stamp.substr(10,2) ; //second
260    
261                  pdu.push_back(0x00); // Protocol identifier                  int timezone = strtol(stamp.substr(12,2).c_str(), 0, 16);
                 pdu.push_back(0x00); // Data coding scheme  
262    
                 string message_part;  
                 if (multipart)  
                 {  
                         message_part = message.substr(0, PDU_LEN);  
                         message.erase(0, PDU_LEN);  
263    
264                          pdu.push_back( message_part.length()+ 7 );  //UserDataLength                  if (timezone > 127)
265                          pdu.push_back( 0x06 ); // UDH Len                          os << "-";
266                          pdu.push_back( 0x00 ); // UDH Element Identifier                  else
267                          pdu.push_back( 0x03 ); // UDH element length                          os << "+";
268                          pdu.push_back( csms_ref ); // csms_ref reference  
269                          pdu.push_back( part_count );                  os.width(2);
270                          pdu.push_back( partnr+1 );                  os.fill('0');
271                          pdu.push_back( 0x00);                  os << (timezone & 0x7F);
272    
273                    return os.str();
274            }
275    
276    
277    
278            SMS ParseSmsPdu(std::string pdu_str)
279            {
280                    SmsPart part = ParseSmsPduWorker(pdu_str);
281    
282    
283                    SMS sms;
284                    sms.SetMessage(part.message);
285                    sms.SetSender(part.sender);
286                    return sms;
287            }
288    
289            void ParseUdh(vector<unsigned char>& udh, SmsPart& part)
290            {
291                    if (udh.size() == 0)
292                    {
293                            Logger::logMessage("ParseUdh(): empty udh");
294                            return;
295                  }                  }
296                  else          
297                    if (udh[0] != 0)
298                  {                  {
299                          if (message.length() > 160)                          Logger::logMessage("unknown UDH type");
300                          {                          return;
301                                  message_part = message.substr(0,160); //truncate to 160                  }
302                                  Common::instance()->logMessage("Truncated message");  
303                          }                  if (udh.size() < 5)
304                          else                  {
305                            Logger::logMessage("UDH to short to be multipart");
306                            return;
307                    }
308                    
309                    part.group = udh[2];
310                    part.count = udh[3];
311                    part.id = udh[4];
312            }
313    
314    
315            SmsPart ParseSmsPduWorker(std::string pdu_str)
316            {
317    
318                    vector<unsigned char> pdu = HexDecodeString(pdu_str);
319    
320                    vector<unsigned char>::iterator it = pdu.begin();
321    
322                    it += (*it++); // Skip smsc info
323    
324                    unsigned char deliver_first_octet = (*it++);
325    
326                    bool UDHI = (deliver_first_octet & 0x40) > 0;
327    
328                    unsigned char sender_len = (*it++);
329                    if ( (sender_len % 2) == 1)
330                            sender_len++;
331    
332                    ++it; //ignore Type-Of-Address
333    
334                    string sender = DecodeRawPhonenr( it, it+(sender_len/2) );
335    
336                    it += (sender_len/2);
337                    ++it; //protocol identifier
338                    ++it; //Data encoding
339    
340                    string timestamp = DecodeTimestamp(it, it+7);
341                    it += 7;
342    
343    
344                    unsigned char data_len = (*it++);
345    
346    
347                    SmsPart part;
348                    part.group = -1;
349    
350                    int shift_start = 0;
351    
352                    if (UDHI)
353                    {
354                            int udh_len = (*it++);
355    
356                            vector<unsigned char> udh;
357                            for (int i=0; i<udh_len; i++)
358                          {                          {
359                                  message_part = message;                                  udh.push_back (*it++);
360                          }                          }
361                            ParseUdh(udh,part);
362    
363                          pdu.push_back( message_part.length() ); //UserDataLength                          data_len -= udh_len;
364    
365                            shift_start = udh_len+1; //make the 8to7bit decode start with the right shift level
366                  }                  }
367    
                 vector<unsigned char> userData = Encode7to8bit(message_part);  
368    
369                  pdu.insert( pdu.end(), userData.begin(), userData.end());                  vector<unsigned char> user_data;
370                    user_data.insert(user_data.end(), it, it+data_len);
371                    
372                    string message = Decode8to7bit(user_data, shift_start).substr(0,data_len);
373    
374                  PduInfo info;                  message = Util::str_trim(message);
                 info.len = pdu.size()-1;  
                 info.pdu = HexformatVector(pdu);  
                 result.push_back(info);  
375    
376                    
377                    part.message = message;
378                    part.sender = sender;
379    
380                    return part;
381          }          }
         return result;  
 }  
382    
383  }  }
384    

Legend:
Removed from v.68  
changed lines
  Added in v.177

  ViewVC Help
Powered by ViewVC 1.1.20