--- smsdaemon/SmsPdu.cpp 2008/06/11 19:42:24 59 +++ smsdaemon/SmsPdu.cpp 2008/06/13 10:10:06 75 @@ -2,114 +2,330 @@ */ +#include "SmsPdu.h" + #include #include +#include +#include - - +#include "common.h" #include "util.h" 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.at(i)); + } + + + return os.str(); + } + + vector HexDecodeString(string str) { - buf[0] = input.at(i); - unsigned char tmp = atoi(buf); + vector vec; + for (unsigned int i=0; i input, int shift_start) + { + string result; + + int shift = shift_start; + for (unsigned int i=0; i0) ? input.at(i-1) : 0; + + current <<= shift; + + prev >>= (8-shift); + + unsigned char byte = current | prev; + byte &= 0x7F; + + result.append(1, byte); + + if (shift == 6) + result.append(1, input.at(i) >> 1); + + shift = (shift+1) % 7; + + } + + return result; + } + + + + + vector Encode7to8bit(std::string str, int shift_start) + { + vector buf; + + int shift = shift_start; + for (unsigned int i=0; i>= shift; + next <<= (7-shift); + + unsigned char byte = current | next; + buf.push_back(byte); + + if (shift == 6) + i++; + + shift = (shift+1) % 7; + + } + + return buf; + } + + vector CreateSmsPdu(string to, string message, bool allowMultipart) + { + bool multipart = allowMultipart && message.length() > 160; + + const unsigned char UDHI = multipart ? 0x40 : 0; + + srand(time(0)); + unsigned char csms_ref = rand() % 128; + + int part_count; + + const int PDU_LEN = 153; + + if (multipart) + { + if (message.length() > 800) + { + Common::instance()->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 { - current |= (tmp<<4); - result.push_back(current); + part_count = 1; + } + + 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); + + 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 + Common::instance()->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; } - return result; -} + typedef vector::iterator char_it; -string HexformatVector(vector vec) -{ - ostringstream os; + string DecodeRawPhonenr(char_it start, char_it end) + { + ostringstream os; - for (unsigned int i=0; i 127) + os << "-"; + else + os << "+"; + os.width(2); os.fill('0'); - os << hex << uppercase << static_cast(vec.at(i)); + os << (timezone & 0x7F); + + return os.str(); } - return os.str(); -} + SMS ParseSmsPdu(std::string pdu_str) + { + SMS result; -vector Encode7to8bit(std::string str) -{ - vector buf; + vector pdu = HexDecodeString(pdu_str); - int shift = 0; - for (unsigned int i=0; i::iterator it = pdu.begin(); - current >>= shift; - next <<= (7-shift); + it += (*it++); // Skip smsc info - unsigned char byte = current | next; - buf.push_back(byte); + unsigned char deliver_first_octet = (*it++); - if (shift == 6) - i++; + bool UDHI = (deliver_first_octet & 0x40) > 0; - shift = (shift+1) % 7; + unsigned char sender_len = (*it++); + if ( (sender_len % 2) == 1) + sender_len++; - } + ++it; //ignore Type-Of-Address - return buf; -} + result.sender = DecodeRawPhonenr( it, it+(sender_len/2) ); -string CreateSmsPdu(string to, string message, int& len) -{ - message = message.substr(0,160); //truncate to 160 + it += (sender_len/2); + ++it; //protocol identifier + ++it; //Data encoding - vector pdu; + result.timestamp = DecodeTimestamp(it, it+7); + it += 7; - pdu.push_back(0x00); // use SMSC from phone - pdu.push_back(0x01); // 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 - vector phone = BcdEncode(to); - pdu.insert( pdu.end(), phone.begin(), phone.end()); + unsigned char data_len = (*it++); - pdu.push_back(0x00); // Protocol identifier - pdu.push_back(0x00); // Data coding scheme - pdu.push_back( message.length() ); //UserDataLength + int shift_start = 0; + if (UDHI) + { + int udh_len = (*it++); + it += udh_len; //just ignore the User Data Header + data_len -= udh_len; - vector userData = Encode7to8bit(message); - pdu.insert( pdu.end(), userData.begin(), userData.end()); + shift_start = udh_len+1; //make the 8to7bit decode start with the right shift level + } - len = pdu.size()-1; - return HexformatVector(pdu); -} + + vector user_data; + user_data.insert(user_data.end(), it, it+data_len); + + result.message = Decode8to7bit(user_data, shift_start); + + + return result; + } }