00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "r_sms.h"
00024 #include "record-internal.h"
00025 #include "protostructs.h"
00026 #include "data.h"
00027 #include "time.h"
00028 #include "debug.h"
00029 #include "iconv.h"
00030 #include "strnlen.h"
00031 #include <ostream>
00032 #include <iomanip>
00033 #include <string.h>
00034
00035 using namespace std;
00036 using namespace Barry::Protocol;
00037
00038 namespace Barry {
00039
00040
00041
00042
00043
00044 #define SMSFC_METADATA 0x01
00045 #define SMSFC_ADDRESS 0x02
00046 #define SMSFC_BODY 0x04
00047
00048
00049 #define SMS_ADDRESS_HEADER_SIZE 0x04
00050
00051 #define MILLISECONDS_IN_A_SECOND 1000
00052
00053 time_t Sms::GetTime() const
00054 {
00055 return (time_t)(Timestamp / MILLISECONDS_IN_A_SECOND);
00056 }
00057
00058 time_t Sms::GetServiceCenterTime() const
00059 {
00060 return (time_t)(ServiceCenterTimestamp / MILLISECONDS_IN_A_SECOND);
00061 }
00062
00063 void Sms::SetTime(const time_t timestamp, const unsigned milliseconds)
00064 {
00065 Timestamp = (uint64_t)timestamp * MILLISECONDS_IN_A_SECOND + milliseconds;
00066 }
00067
00068 void Sms::SetServiceCenterTime(const time_t timestamp, const unsigned milliseconds)
00069 {
00070 ServiceCenterTimestamp = (uint64_t)timestamp * MILLISECONDS_IN_A_SECOND + milliseconds;
00071 }
00072
00073 Sms::Sms()
00074 {
00075 Clear();
00076 }
00077
00078 Sms::~Sms()
00079 {
00080 }
00081
00082 const unsigned char* Sms::ParseField(const unsigned char *begin,
00083 const unsigned char *end,
00084 const IConverter *ic)
00085 {
00086 const CommonField *field = (const CommonField *)begin;
00087
00088
00089 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00090 if (begin > end)
00091 return begin;
00092
00093 if (!btohs(field->size))
00094 return begin;
00095
00096 switch (field->type)
00097 {
00098 case SMSFC_METADATA:
00099 {
00100 if (btohs(field->size) < SMS_METADATA_SIZE)
00101 break;
00102
00103 const SMSMetaData &metadata = field->u.sms_metadata;
00104 NewConversation = metadata.flags & SMS_FLG_NEW_CONVERSATION;
00105 Saved = metadata.flags & SMS_FLG_SAVED;
00106 Deleted = metadata.flags & SMS_FLG_DELETED;
00107 Opened = metadata.flags & SMS_FLG_OPENED;
00108
00109 IsNew = metadata.new_flag;
00110
00111 uint32_t status = btohl(metadata.status);
00112
00113 switch (status)
00114 {
00115 case SMS_STA_RECEIVED:
00116 MessageStatus = Received;
00117 break;
00118 case SMS_STA_DRAFT:
00119 MessageStatus = Draft;
00120 break;
00121 default:
00122 MessageStatus = Sent;
00123 }
00124
00125 ErrorId = btohl(metadata.error_id);
00126
00127 Timestamp = btohll(metadata.timestamp);
00128 ServiceCenterTimestamp = btohll(metadata.service_center_timestamp);
00129
00130 switch (metadata.dcs)
00131 {
00132 case SMS_DCS_7BIT:
00133 DataCodingScheme = SevenBit;
00134 break;
00135 case SMS_DCS_8BIT:
00136 DataCodingScheme = EightBit;
00137 break;
00138 case SMS_DCS_UCS2:
00139 DataCodingScheme = UCS2;
00140 break;
00141 default:
00142 DataCodingScheme = SevenBit;
00143 }
00144
00145 return begin;
00146 }
00147
00148 case SMSFC_ADDRESS:
00149 {
00150 uint16_t length = btohs(field->size);
00151 if (length < SMS_ADDRESS_HEADER_SIZE + 1)
00152 break;
00153
00154 length -= SMS_ADDRESS_HEADER_SIZE;
00155 const char *address = (const char *)field->u.raw + SMS_ADDRESS_HEADER_SIZE;
00156 Addresses.push_back(std::string(address, strnlen(address, length)));
00157 return begin;
00158 }
00159
00160 case SMSFC_BODY:
00161 {
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 const char *str = (const char *)field->u.raw;
00174 uint16_t maxlen = btohs(field->size);
00175 if (DataCodingScheme != UCS2) {
00176 for (uint16_t i = 0; i < maxlen; ++i) {
00177 if (str[i])
00178 Body += str[i];
00179 }
00180 }
00181 else {
00182 for (uint16_t i = 0; maxlen && i < (maxlen-1); i += 2) {
00183 if (str[i] || str[i + 1])
00184 Body += std::string(str + i, 2);
00185 }
00186 }
00187 if (ic) {
00188 if (DataCodingScheme == SevenBit) {
00189
00190 IConvHandle utf8("UTF-8", *ic);
00191 Body = ic->Convert(utf8, ConvertGsmToUtf8(Body));
00192 }
00193 else if (DataCodingScheme == EightBit)
00194 Body = ic->FromBB(Body);
00195 else {
00196 IConvHandle ucs2("UCS-2BE", *ic);
00197 Body = ic->Convert(ucs2, Body);
00198 }
00199 }
00200 return begin;
00201 }
00202 }
00203
00204
00205 UnknownField uf;
00206 uf.type = field->type;
00207 uf.data.assign((const char*)field->u.raw, btohs(field->size));
00208 Unknowns.push_back(uf);
00209
00210
00211 return begin;
00212 }
00213
00214 void Sms::ParseHeader(const Data &data, size_t &offset)
00215 {
00216
00217 }
00218
00219 void Sms::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00220 {
00221 const unsigned char *finish = ParseCommonFields(*this,
00222 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00223 offset += finish - (data.GetData() + offset);
00224 }
00225
00226 void Sms::BuildHeader(Data &data, size_t &offset) const
00227 {
00228
00229 }
00230
00231 void Sms::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00232 {
00233
00234 }
00235
00236 void Sms::Clear()
00237 {
00238 RecType = GetDefaultRecType();
00239 RecordId = 0;
00240
00241 MessageStatus = Unknown;
00242 DeliveryStatus = NoReport;
00243
00244 IsNew = NewConversation = Saved = Deleted = Opened = false;
00245
00246 Timestamp = ServiceCenterTimestamp = 0;
00247
00248 DataCodingScheme = SevenBit;
00249
00250 ErrorId = 0;
00251
00252 Addresses.clear();
00253 Body.clear();
00254
00255 Unknowns.clear();
00256 }
00257
00258 std::string Sms::GetDescription() const
00259 {
00260 if( Addresses.size() )
00261 return Addresses[0];
00262 else
00263 return "Unknown destination";
00264 }
00265
00266 void Sms::Dump(std::ostream &os) const
00267 {
00268
00269 os << "SMS record: 0x" << setbase(16) << RecordId
00270 << " (" << (unsigned int)RecType << ")\n";
00271 time_t t = GetTime();
00272 os << "\tTimestamp: " << ctime(&t);
00273
00274 if (MessageStatus == Received) {
00275 t = GetServiceCenterTime();
00276 os << "\tService Center Timestamp: " << ctime(&t);
00277 }
00278
00279 if (ErrorId)
00280 os << "\tSend Error: 0x" << setbase(16) << ErrorId << "\n";
00281
00282 switch (MessageStatus)
00283 {
00284 case Received:
00285 os << "\tReceived From:\n";
00286 break;
00287 case Sent:
00288 os << "\tSent to:\n";
00289 break;
00290 case Draft:
00291 os << "\tDraft for:\n";
00292 break;
00293 case Unknown:
00294 os << "\tUnknown status for:\n";
00295 break;
00296 }
00297
00298 os << "\t";
00299 for (std::vector<std::string>::const_iterator i = Addresses.begin(); i < Addresses.end(); ++i) {
00300 if (i != Addresses.begin())
00301 os << ", ";
00302 os << *i;
00303 }
00304 os << "\n";
00305
00306 if (IsNew || Opened || Saved || Deleted || NewConversation) {
00307 os << "\t";
00308 if (IsNew)
00309 os << "New ";
00310 if (Opened)
00311 os << "Opened ";
00312 if (Saved)
00313 os << "Saved ";
00314 if (Deleted)
00315 os << "Deleted ";
00316 os << "Message" << (NewConversation ? " that starts a new conversation" : "") << "\n";
00317 }
00318 os << "\tContent: " << Body << "\n";
00319 os << "\n";
00320 }
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 std::string Sms::ConvertGsmToUtf8(const std::string &s)
00331 {
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 static const std::string GsmTable[0x80] = {
00344
00345 "\x40", "\xc2\xa3", "\x24", "\xc2\xa5", "\xc3\xa8", "\xc3\xa9", "\xc3\xb9", "\xc3\xac",
00346 "\xc3\xb2", "\xc3\x87", "\x0a", "\xc3\x98", "\xc3\xb8", "\x0d", "\xc3\x85", "\xc3\xa5",
00347 "\xce\x94", "\x5f", "\xce\xa6", "\xce\x93", "\xce\x9b", "\xce\xa9", "\xce\xa0", "\xce\xa8",
00348 "\xce\xa3", "\xce\x98", "\xce\x9e", "\x20", "\xc3\x86", "\xc3\xa6", "\xc3\x9f", "\xc3\x89",
00349 "\x20", "\x21", "\x22", "\x23", "\xc2\xa4", "\x25", "\x26", "\x27",
00350 "\x28", "\x29", "\x2a", "\x2b", "\x2c", "\x2d", "\x2e", "\x2f",
00351 "\x30", "\x31", "\x32", "\x33", "\x34", "\x35", "\x36", "\x37",
00352 "\x38", "\x39", "\x3a", "\x3b", "\x3c", "\x3d", "\x3e", "\x3f",
00353 "\xc2\xa1", "\x41", "\x42", "\x43", "\x44", "\x45", "\x46", "\x47",
00354 "\x48", "\x49", "\x4a", "\x4b", "\x4c", "\x4d", "\x4e", "\x4f",
00355 "\x50", "\x51", "\x52", "\x53", "\x54", "\x55", "\x56", "\x57",
00356 "\x58", "\x59", "\x5a", "\xc3\x84", "\xc3\x96", "\xc3\x91", "\xc3\x9c", "\xc2\xa7",
00357 "\xc2\xbf", "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67",
00358 "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f",
00359 "\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77",
00360 "\x78", "\x79", "\x7a", "\xc3\xa4", "\xc3\xb6", "\xc3\xb1", "\xc3\xbc", "\xc3\xa0"
00361 };
00362
00363
00364
00365
00366
00367
00368 static const std::string GsmExtensionTable[0x80] = {
00369
00370 "", "", "", "", "", "", "", "",
00371 "", "", "\x0c", "", "", "", "", "",
00372 "", "", "", "", "\x5e", "", "", "",
00373 "", "", "", " ", "", "", "", "",
00374 "", "", "", "", "", "", "", "",
00375 "\x7b", "\x7d", "", "", "", "", "", "\x5c",
00376 "", "", "", "", "", "", "", "",
00377 "", "", "", "", "\x5b", "\x7e", "\x5d", "",
00378 "\x7c", "", "", "", "", "", "", "",
00379 "", "", "", "", "", "", "", "",
00380 "", "", "", "", "", "", "", "",
00381 "", "", "", "", "", "", "", "",
00382 "", "", "", "", "", "\xe2\x82\xac", "", "",
00383 "", "", "", "", "", "", "", "",
00384 "", "", "", "", "", "", "", "",
00385 "", "", "", "", "", "", "", ""
00386 };
00387 std::string ret;
00388 unsigned len = s.length();
00389 for (unsigned i = 0; i < len; ++i) {
00390 unsigned char c = (unsigned char) s[i];
00391 if (c > 0x7f)
00392 continue;
00393 else if (c == 0x1b) {
00394 if (i < len - 1) {
00395 c = (unsigned char) s[++i];
00396 if (c <= 0x7f)
00397 ret += GsmExtensionTable[c];
00398 }
00399 }
00400 else
00401 ret += GsmTable[c];
00402 }
00403 return ret;
00404 }
00405
00406 }
00407