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