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::Clear()
00227 {
00228 RecType = GetDefaultRecType();
00229 RecordId = 0;
00230
00231 MessageStatus = Unknown;
00232 DeliveryStatus = NoReport;
00233
00234 IsNew = NewConversation = Saved = Deleted = Opened = false;
00235
00236 Timestamp = ServiceCenterTimestamp = 0;
00237
00238 DataCodingScheme = SevenBit;
00239
00240 ErrorId = 0;
00241
00242 Addresses.clear();
00243 Body.clear();
00244
00245 Unknowns.clear();
00246 }
00247
00248 void Sms::Dump(std::ostream &os) const
00249 {
00250
00251 os << "SMS record: 0x" << setbase(16) << RecordId
00252 << " (" << (unsigned int)RecType << ")\n";
00253 time_t t = GetTime();
00254 os << "\tTimestamp: " << ctime(&t);
00255
00256 if (MessageStatus == Received) {
00257 t = GetServiceCenterTime();
00258 os << "\tService Center Timestamp: " << ctime(&t);
00259 }
00260
00261 if (ErrorId)
00262 os << "\tSend Error: 0x" << setbase(16) << ErrorId << "\n";
00263
00264 switch (MessageStatus)
00265 {
00266 case Received:
00267 os << "\tReceived From:\n";
00268 break;
00269 case Sent:
00270 os << "\tSent to:\n";
00271 break;
00272 case Draft:
00273 os << "\tDraft for:\n";
00274 break;
00275 case Unknown:
00276 os << "\tUnknown status for:\n";
00277 break;
00278 }
00279
00280 os << "\t";
00281 for (std::vector<std::string>::const_iterator i = Addresses.begin(); i < Addresses.end(); ++i) {
00282 if (i != Addresses.begin())
00283 os << ", ";
00284 os << *i;
00285 }
00286 os << "\n";
00287
00288 if (IsNew || Opened || Saved || Deleted || NewConversation) {
00289 os << "\t";
00290 if (IsNew)
00291 os << "New ";
00292 if (Opened)
00293 os << "Opened ";
00294 if (Saved)
00295 os << "Saved ";
00296 if (Deleted)
00297 os << "Deleted ";
00298 os << "Message" << (NewConversation ? " that starts a new conversation" : "") << "\n";
00299 }
00300 os << "\tContent: " << Body << "\n";
00301 os << "\n";
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 std::string Sms::ConvertGsmToUtf8(const std::string &s)
00313 {
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 static const std::string GsmTable[0x80] = {
00326
00327 "\x40", "\xc2\xa3", "\x24", "\xc2\xa5", "\xc3\xa8", "\xc3\xa9", "\xc3\xb9", "\xc3\xac",
00328 "\xc3\xb2", "\xc3\x87", "\x0a", "\xc3\x98", "\xc3\xb8", "\x0d", "\xc3\x85", "\xc3\xa5",
00329 "\xce\x94", "\x5f", "\xce\xa6", "\xce\x93", "\xce\x9b", "\xce\xa9", "\xce\xa0", "\xce\xa8",
00330 "\xce\xa3", "\xce\x98", "\xce\x9e", "\x20", "\xc3\x86", "\xc3\xa6", "\xc3\x9f", "\xc3\x89",
00331 "\x20", "\x21", "\x22", "\x23", "\xc2\xa4", "\x25", "\x26", "\x27",
00332 "\x28", "\x29", "\x2a", "\x2b", "\x2c", "\x2d", "\x2e", "\x2f",
00333 "\x30", "\x31", "\x32", "\x33", "\x34", "\x35", "\x36", "\x37",
00334 "\x38", "\x39", "\x3a", "\x3b", "\x3c", "\x3d", "\x3e", "\x3f",
00335 "\xc2\xa1", "\x41", "\x42", "\x43", "\x44", "\x45", "\x46", "\x47",
00336 "\x48", "\x49", "\x4a", "\x4b", "\x4c", "\x4d", "\x4e", "\x4f",
00337 "\x50", "\x51", "\x52", "\x53", "\x54", "\x55", "\x56", "\x57",
00338 "\x58", "\x59", "\x5a", "\xc3\x84", "\xc3\x96", "\xc3\x91", "\xc3\x9c", "\xc2\xa7",
00339 "\xc2\xbf", "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67",
00340 "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f",
00341 "\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77",
00342 "\x78", "\x79", "\x7a", "\xc3\xa4", "\xc3\xb6", "\xc3\xb1", "\xc3\xbc", "\xc3\xa0"
00343 };
00344
00345
00346
00347
00348
00349
00350 static const std::string GsmExtensionTable[0x80] = {
00351
00352 "", "", "", "", "", "", "", "",
00353 "", "", "\x0c", "", "", "", "", "",
00354 "", "", "", "", "\x5e", "", "", "",
00355 "", "", "", " ", "", "", "", "",
00356 "", "", "", "", "", "", "", "",
00357 "\x7b", "\x7d", "", "", "", "", "", "\x5c",
00358 "", "", "", "", "", "", "", "",
00359 "", "", "", "", "\x5b", "\x7e", "\x5d", "",
00360 "\x7c", "", "", "", "", "", "", "",
00361 "", "", "", "", "", "", "", "",
00362 "", "", "", "", "", "", "", "",
00363 "", "", "", "", "", "", "", "",
00364 "", "", "", "", "", "\xe2\x82\xac", "", "",
00365 "", "", "", "", "", "", "", "",
00366 "", "", "", "", "", "", "", "",
00367 "", "", "", "", "", "", "", ""
00368 };
00369 std::string ret;
00370 unsigned len = s.length();
00371 for (unsigned i = 0; i < len; ++i) {
00372 unsigned char c = (unsigned char) s[i];
00373 if (c > 0x7f)
00374 continue;
00375 else if (c == 0x1b) {
00376 if (i < len - 1) {
00377 c = (unsigned char) s[++i];
00378 if (c <= 0x7f)
00379 ret += GsmExtensionTable[c];
00380 }
00381 }
00382 else
00383 ret += GsmTable[c];
00384 }
00385 return ret;
00386 }
00387
00388 }
00389