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