--- smsdaemon/SmsPdu.cpp 2008/06/12 11:05:18 61 +++ smsdaemon/SmsPdu.cpp 2008/12/18 06:53:29 196 @@ -8,174 +8,424 @@ #include #include -#include +#include +#include "Logger.h" +#include "Util.h" -#include "util.h" +#include "Exceptions.h" +#include +#include +#include using namespace std; - namespace SmsPdu { -vector BcdEncode(string input) -{ - char buf[2] = " "; - vector result; - unsigned char current; - for (unsigned int i=0; i vec) -{ - ostringstream os; - for (unsigned int i=0; i vec) { - os.width(2); - os.fill('0'); - os << hex << uppercase << static_cast(vec.at(i)); + ostringstream os; + + for (unsigned int i=0; i(vec.at(i)); + } + + + return os.str(); } + vector HexDecodeString(string str) + { + vector vec; + for (unsigned int i=0; i vec) -{ - string result; + std::string Decode8to7bit(vector input, int shift_start) + { + string result; - return result; -} + int shift = shift_start; + for (unsigned int i=0; i0) ? input.at(i-1) : 0; -vector Encode7to8bit(std::string str) -{ - vector buf; + current <<= shift; + + prev >>= (8-shift); + + unsigned char byte = current | prev; + byte &= 0x7F; - int shift = 0; - for (unsigned int i=0; i> 1); + + shift = (shift+1) % 7; + + } + + return result; + } + + + + + vector Encode7to8bit(std::string str, int shift_start) { - unsigned char current = str.at(i) & 0x7F; - unsigned char next = ( (i+1) buf; + + int shift = shift_start; + for (unsigned int i=0; i>= shift; - next <<= (7-shift); + current >>= shift; + next <<= (7-shift); - unsigned char byte = current | next; - buf.push_back(byte); + unsigned char byte = current | next; + buf.push_back(byte); - if (shift == 6) - i++; + if (shift == 6) + i++; - shift = (shift+1) % 7; + shift = (shift+1) % 7; + } + + return buf; } - return buf; -} + vector CreateSmsPdu(string to, string message, bool allowMultipart) + { + bool multipart = allowMultipart && message.length() > 160; -vector CreateSmsPdu(string to, string message, bool allowMultipart) -{ - bool multipart = allowMultipart && message.length() > 160; + const unsigned char UDHI = multipart ? 0x40 : 0; - const unsigned char UDHI = multipart ? 0x40 : 0; + unsigned char csms_ref = rand() % 128; - srand(time(0)); - unsigned char csms_ref = rand() % 128; + int part_count; - int part_count; + const int PDU_LEN = 153; - const int PDU_LEN = 153; + if (multipart) + { + if (message.length() > 800) + { + Logger::logMessage("Trying to send multipart sms > 800 bytes !!!"); + message = message.substr(0,800); + } + + part_count = message.length() / PDU_LEN; + if (message.length() % PDU_LEN) + part_count++; + } + else + { + part_count = 1; + } - if (multipart) + vector result; + for (int partnr = 0; partnr < part_count; ++partnr) + { + vector pdu; + + pdu.push_back(0x00); // use SMSC from phone + 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 + + + vector phone = HexDecodeString( EncodePhonenr(to )); + pdu.insert( pdu.end(), phone.begin(), phone.end()); + + pdu.push_back(0x00); // Protocol identifier + pdu.push_back(0x00); // Data coding scheme + + int shift_start = 0; + string message_part; + if (multipart) + { + message_part = message.substr(0, PDU_LEN); + message.erase(0, PDU_LEN-1); + + pdu.push_back( message_part.length()+ 7 ); //UserDataLength + pdu.push_back( 0x06 ); // UDH Len + pdu.push_back( 0x00 ); // UDH Element Identifier + pdu.push_back( 0x03 ); // UDH element length + pdu.push_back( csms_ref ); // csms_ref reference + pdu.push_back( part_count ); + pdu.push_back( partnr+1 ); + pdu.push_back( 0x00); + //shift_start = 6; + } + else + { + if (message.length() > 160) + { + message_part = message.substr(0,160); //truncate to 160 + Logger::logMessage("Truncated message"); + } + else + { + message_part = message; + } + + pdu.push_back( message_part.length() ); //UserDataLength + } + + vector userData = Encode7to8bit(message_part, shift_start); + + pdu.insert( pdu.end(), userData.begin(), userData.end()); + + PduInfo info; + info.len = pdu.size()-1; + info.pdu = HexformatVector(pdu); + result.push_back(info); + + } + return result; + } + + typedef vector::iterator char_it; + + string DecodeRawPhonenr(char_it start, char_it end) { - part_count = message.length() / PDU_LEN; - if (message.length() % PDU_LEN) - part_count++; + ostringstream os; + + for (char_it it = start; it != end; ++it) + { + os.width(2); + os.fill('0'); + os << hex << (int)(*it); + } + return DecodePhonenr(os.str()); } - else + + string DecodeTimestamp(char_it start, char_it end) { - part_count = 1; + string stamp = DecodeRawPhonenr(start,end); + + ostringstream os; + + os << stamp.substr(0,2) << "/"; //year + os << stamp.substr(2,2) << "/"; //month + os << stamp.substr(4,2) << ","; //day + os << stamp.substr(6,2) << ":"; //hour + os << stamp.substr(8,2) << ":"; //minute + os << stamp.substr(10,2) ; //second + + int timezone = strtol(stamp.substr(12,2).c_str(), 0, 16); + + + if (timezone > 127) + os << "-"; + else + os << "+"; + + os.width(2); + os.fill('0'); + os << (timezone & 0x7F); + + return os.str(); } - vector result; - for (int partnr = 0; partnr < part_count; ++partnr) + + std::list partlist; + typedef std::list::iterator iterator; + + SMS ConcatenateParts(SmsPart& part) { - vector pdu; + SMS sms; + if (part.group == -1) + { + sms.SetMessage(part.message); + sms.SetSender(part.sender); + } + else + { + partlist.push_back(part); + + vector vec; + for (iterator it=partlist.begin(); it!=partlist.end(); ++it) + { + SmsPart& current = *it; + if (current.sender == part.sender && current.group == part.group) + vec.push_back(current); + } + + if (vec.size() == (unsigned)part.count) //we have all parts + { + sort(vec.begin(), vec.end()); + string message; + for (unsigned i=0; i phone = BcdEncode(to); - pdu.insert( pdu.end(), phone.begin(), phone.end()); + return sms; + } - pdu.push_back(0x00); // Protocol identifier - pdu.push_back(0x00); // Data coding scheme - string message_part; - if (multipart) + SMS ParseSmsPdu(std::string pdu_str) + { + SmsPart part = ParseSmsPduWorker(pdu_str); + + return ConcatenateParts(part); + + } + + void ParseUdh(vector& udh, SmsPart& part) + { + if (udh.size() == 0) { - message_part = message.substr(0, PDU_LEN); - message.erase(0, PDU_LEN); + Logger::logMessage("ParseUdh(): empty udh"); + return; + } - pdu.push_back( message_part.length()+ 6 ); //UserDataLength - pdu.push_back( 0x05 ); // UDH Len - pdu.push_back( 0x00 ); // UDH Element Identifier - pdu.push_back( 0x03 ); // UDH element length - pdu.push_back( csms_ref ); // csms_ref reference - pdu.push_back( part_count ); - pdu.push_back( partnr+1 ); + if (udh[0] != 0) + { + Logger::logMessage("unknown UDH type"); + return; + } + if (udh.size() < 5) + { + Logger::logMessage("UDH to short to be multipart"); + return; } - else + + part.group = udh[2]; + part.count = udh[3]; + part.id = udh[4]; + } + + + SmsPart ParseSmsPduWorker(std::string pdu_str) + { + + vector pdu = HexDecodeString(pdu_str); + + vector::iterator it = pdu.begin(); + + it += (*it++); // Skip smsc info + + unsigned char deliver_first_octet = (*it++); + + bool UDHI = (deliver_first_octet & 0x40) > 0; + + unsigned char sender_len = (*it++); + if ( (sender_len % 2) == 1) + sender_len++; + + ++it; //ignore Type-Of-Address + + string sender = DecodeRawPhonenr( it, it+(sender_len/2) ); + + it += (sender_len/2); + ++it; //protocol identifier + ++it; //Data encoding + + string timestamp = DecodeTimestamp(it, it+7); + it += 7; + + + unsigned char data_len = (*it++); + + + SmsPart part; + part.group = -1; + + int shift_start = 0; + + if (UDHI) { - message_part = message.substr(0,160); //truncate to 160 + int udh_len = (*it++); + + vector udh; + for (int i=0; i userData = Encode7to8bit(message_part); - pdu.insert( pdu.end(), userData.begin(), userData.end()); + vector user_data; + user_data.insert(user_data.end(), it, it+data_len); + + string message = Decode8to7bit(user_data, shift_start).substr(0,data_len); - PduInfo info; - info.len = pdu.size()-1; - info.pdu = HexformatVector(pdu); - result.push_back(info); + message = Util::str_trim(message); + + part.message = message; + part.sender = sender; + + return part; } - return result; -} }