#include "PDU.h"
#include "buffer.h"
#include <string.h>
#include <stdlib.h>
#include <limits.h>
static tm* createTime(const char *source);
bool PDU::PDU_to_text(char *dest, const char *source)
{
Buffer buffer(MAX_TEXT);
int length;
try {
length = Buffer::getChar(source);
}
catch (int) { return true; }
source += 2;
if (buffer.copyHexData(source)) return true;
for (int i = 0; i < length; i++) {
if (buffer.read((unsigned char&) dest[i], (short)7))
return true;
switch (dest[i]) {
case 0: dest[i] = '@'; break;
case 2: dest[i] = '$'; break;
case 17: dest[i] = '_'; break;
}
}
dest[length] = 0;
return false;
}
bool PDU::text_to_PDU(char *dest, const char *source)
{
char simbol;
size_t len = strlen(source);
Buffer buffer(MAX_PDU);
// inserts simbols amount
Buffer::getHex(dest, (unsigned char) len);
dest += 2;
for (unsigned i = 0; i < len; i++) {
simbol = source[i];
switch (simbol) {
case '@': simbol = 0; break;
case '$': simbol = 2; break;
case '_': simbol = 17; break;
case 13 : simbol = ' '; break; // carriage return invisible
}
if (simbol & 0x80) // >= 128
simbol = '.'; // unknown simbol
buffer.insert(simbol, 7);
}
if (buffer.toString(dest, MAX_PDU)) return true;
return false;
}
int PDU::phone_to_hex(char *dest, const char *source)
{
if (source[0] == '+') source++;
int len = (int) strlen(source);
int len2 = (len%2)? len - 1: len; // characters to swap
int ret = (len != len2)? len + 5: len + 4; // full length
Buffer::getHex(dest, len);
dest += 2;
strcpy(dest, "81");
dest += 2;
swap(dest, source, len2);
if (len != len2) {
dest[len2] = 'F';
dest[len] = source[len2];
}
return ret;
}
// convert PDU hex form to phone number
bool PDU::hex_to_phone(char *dest, const char *source)
{
dest[0] = '+';
dest++;
if (swap(dest, source, 10)) return true;
dest[10] = source[11];
dest[11] = 0;
return false;
}
int PDU::create_PDU_SMS(char *dest, const char *number, const char *message)
{
int phone_len;
strcpy(dest, "001100");
dest += 6;
phone_len = phone_to_hex(dest, number);
dest += phone_len;
strcpy(dest, "0000AA");
dest += 6;
if (text_to_PDU(dest, message)) return -1;
size_t pdu_len;
size_t m_len = strlen(message) * 7;
pdu_len = m_len / 8;
if (m_len % 8)
pdu_len++;
return (int) pdu_len + 14;
}
int PDU::create_PDU_SMS(char *dest, SMS &sms)
{
if (!sms.getNumber() || !sms.getText())
return -3;
return create_PDU_SMS(dest, sms.getNumber(), sms.getText());
}
// decode PDU sms and store information about SMS
int PDU::decode_PDU_SMS(SMS &sms, const char *source)
{
char buf[MAX_SMS];
char date_time[20];
tm *p_time;
if (!memcmp(source, "0791", 4)) {
source += 4;
if (hex_to_phone(buf, source)) return -2;
sms.setCenterNumber(buf);
source += 12;
}
else if (!memcmp(source, "00", 2))
source += 2;
else
return -1;
if (memcmp(source, "11", 2))
source += 2;
else
source += 4;
if (memcmp(source, "0B91", 4)) return -3;
source += 4;
if (hex_to_phone(buf, source)) return -4;
sms.setNumber(buf);
source += 16;
/* Read Date and time here */
if (memcmp(source, "FF", 2) && memcmp(source, "AA", 2)) {
memcpy(buf, source, 12);
swap(date_time, buf, 12);
p_time = createTime(date_time);
if (p_time)
sms.setDateTime(p_time);
source += 14;
} else source += 2;
if (PDU_to_text(buf, source)) return -5;
sms.setText(buf);
sms.length = (unsigned) strlen(buf);
return false;
}
// swap bytes in array. abcdef = badcfe
bool PDU::swap(char *dest, const char *source, size_t len)
{
if ((int)len == -1) len = strlen(source);
if (len %2) return true;
len--;
for (unsigned i = 1; i <= len; i += 2) {
dest[i-1] = source[i];
dest[i] = source[i-1];
}
return false;
}
static tm* createTime(const char *source)
{
tm *date_time;
char pduDate[7];
char pduTime[7];
unsigned buf;
memcpy(pduDate, source, 6);
pduDate[6] = 0;
source += 6;
memcpy(pduTime, source, 6);
pduTime[6] = 0;
buf = atoi(pduDate);
if ((int) buf == LONG_MIN || buf == LONG_MAX) return 0;
time_t rawtime;
time ( &rawtime );
date_time = localtime( &rawtime );
date_time->tm_mday = buf % 100;
buf /= 100;
date_time->tm_mon = (buf % 100) - 1;
buf /= 100;
date_time->tm_year = buf + 100;
buf = atoi(pduTime);
if ((int)buf == LONG_MIN || buf == LONG_MAX) {
delete date_time;
return 0;
}
date_time->tm_sec = buf % 100;
buf /= 100;
date_time->tm_min = buf % 100;
buf /= 100;
date_time->tm_hour = buf;
mktime(date_time);
return date_time;
}