Hi Chris,
I've fixed the parser and I think it's now OK. Nice update of IConverter
class.
Right, it's endian issue, since the message encoded in UCS-2 is in big
endian, but iconv takes little endian as default. As you suggested, I
tried desperately to add a BOM, but didn't work. Several hours later I
realized a more directly "UCS-2BE" should work instead of "UCS-2". And
it did. No preprocess anymore. :-)
Chris Frey wrote:
I'm curious about the preprocess function... it looks like it's just a
big / little endian issue... I'm surprised that the iconv libraries can't
handle that... maybe we're specifying the encoding incorrectly?
Looking at http://en.wikipedia.org/wiki/UTF-16, under "Byte order encoding
schemes" it looks like we should just prepend a Byte Order Mark (BOM)
and then let iconv handle it.
Yeah, implemented.
If there are functions to get time_t, there should be corresponding functions
to set it via time_t as well.
I see it and made it this time. But I want to know how to change the
GIT_COMMITER_IDENT and GIT_AUTHOR_IDENT variables? They look pretty
ugly, not displaying my email correctly. Anyway, attached the patch file.
See http://www.netdirect.ca/software/packages/barry/patches.php for
docs on how to submit patches. With git, you can create a fork on
repo.or.cz and push your changes there, or even just push to the mob
branch, or create your changes on a git branch of your own, and
then do:
git diff master mybranch
If you've taken the time to make the patches in small chunks, and have
a series of them to submit, use git-format-patch:
git format-patch master
and post the resulting 000*.patch files to the mailing list.
Feel free to ask any questions on how to work with git and Barry. I'm a git
fan, and am always looking for ways to make things easier for contributors
and myself, when dealing with patches.
I myself don't have Boost enabled when compiling, hence didn't notice
this problem. Now it should work. (But not tested...)
When you have that figured out, please resubmit your patch, and include
your s11n-boost.h changes needed to get everything to compile. They were
missing and it didn't fully compile here.
Happy hacking,
Ryan
>From f377e0e60c83ae51c3b2d111a5816cb58f12da9f Mon Sep 17 00:00:00 2001
From: Ryan Li <r...@ryan-laptop.(none)>
Date: Thu, 9 Apr 2009 20:07:14 +0800
Subject: [PATCH] Sms Class updated UCS-2 support, variable names standardized(along with ones in
s11n-boost.h ), time-related functions implemented, and various trivial fixes.
---
src/r_sms.cc | 231 +++++++++++++++++++++++++++++++++++-------------------
src/r_sms.h | 21 +++--
src/s11n-boost.h | 8 +-
3 files changed, 168 insertions(+), 92 deletions(-)
diff --git a/src/r_sms.cc b/src/r_sms.cc
index a054a90..69aa3ce 100644
--- a/src/r_sms.cc
+++ b/src/r_sms.cc
@@ -37,18 +37,58 @@ using namespace Barry::Protocol;
namespace Barry {
///////////////////////////////////////////////////////////////////////////////
-// SMS Class
+// Sms Class
// SMS Field Codes
#define SMSFC_METADATA 0x01
-#define SMSFC_PHONE_NUMBER 0x02
-#define SMSFC_CONTENT 0x04
-#define SMSFC_END 0xffff
+#define SMSFC_ADDRESS 0x02
+#define SMSFC_BODY 0x04
+
+// SMS Field Sizes and Header Sizes
+#define SMS_METADATA_SIZE 0x40
+#define SMS_ADDRESS_HEADER_SIZE 0x04
+
+// SMS Field Indices
+#define SMS_FLAGS 0x01
+#define SMS_NEW 0x02
+#define SMS_STATUS 0x05
+#define SMS_ERRORID 0x09
+#define SMS_TIMESTAMP 0x0d
+#define SMS_SERVICE_CENTER_TIMESTAMP 0x15
+#define SMS_DCS 0x1d
+
+// SMS Flags and Field Values
+#define SMS_FLG_NEW_CONVERSATION 0x20
+#define SMS_FLG_SAVED 0x10
+#define SMS_FLG_DELETED 0x08
+#define SMS_FLG_OPENED 0x01
+#define SMS_STA_RECEIVED 0x000007ff
+#define SMS_STA_DRAFT 0x7fffffff
+#define SMS_DCS_7BIT 0x00
+#define SMS_DCS_8BIT 0x01
+#define SMS_DCS_UCS2 0x02
+
+#define MILLISECONDS_IN_A_SECOND 1000
+
+time_t Sms::GetTime() const
+{
+ return (time_t)(Timestamp / MILLISECONDS_IN_A_SECOND);
+}
+
+time_t Sms::GetServiceCenterTime() const
+{
+ return (time_t)(ServiceCenterTimestamp / MILLISECONDS_IN_A_SECOND);
+}
+
+void Sms::SetTime(const time_t timestamp, const unsigned milliseconds)
+{
+ Timestamp = (uint64_t)timestamp * MILLISECONDS_IN_A_SECOND + milliseconds;
+}
-static FieldLink<Sms> SMSFieldLinks[] = {
- {SMSFC_CONTENT, "Content", 0, 0, &Sms::Content, 0, 0, 0, 0, true},
- {SMSFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false},
-};
+void Sms::SetServiceCenterTime(const time_t timestamp, const unsigned milliseconds)
+{
+ ServiceCenterTimestamp = (uint64_t)timestamp * MILLISECONDS_IN_A_SECOND + milliseconds;
+}
Sms::Sms()
{
@@ -67,66 +107,91 @@ const unsigned char* Sms::ParseField(const unsigned char *begin,
// advance and check size
begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
- if (begin > end) // if begin==end, we are ok
+ if (begin > end) // if begin==end, we are ok
return begin;
- if (!btohs(field->size)) // if field has no size, something's up
+ if (!btohs(field->size)) // if field has no size, something's up
return begin;
- // cycle through the type table
- for(FieldLink<Sms> *b = SMSFieldLinks;
- b->type != SMSFC_END;
- b++)
- {
- if (b->type == field->type) {
- if (b->strMember) {
- std::string &s = this->*(b->strMember);
- s = ParseFieldString(field);
- if (b->iconvNeeded && ic)
- s = ic->FromBB(s);
- return begin; // done!
- }
- }
- }
-
- // handle special cases
switch (field->type)
{
case SMSFC_METADATA:
{
- if( btohs(field->size) < 30 )
- break; // not enough data
-
- const unsigned char *str = (const unsigned char *)field->u.raw;
- NewConversation = str[1] & 0x20;
- Saved = str[1] & 0x10;
- Deleted = str[1] & 0x08;
- Opened = str[1] & 0x01;
- IsNew = str[2];
- if (*((uint32_t *) (str + 5)) == 0x000007ff)
- MessageStatus = Received;
- else if (*((uint32_t *) (str + 5)) == 0x7fffffff)
- MessageStatus = Draft;
- else
- MessageStatus = Sent; //consider all others as sent.
-
- ErrorId = *((uint32_t *) (str + 9));
+ if (btohs(field->size) != SMS_METADATA_SIZE)
+ break; // size not match
+
+ const unsigned char *metadata = (const unsigned char *)field->u.raw;
+
+ NewConversation = metadata[SMS_FLAGS] & SMS_FLG_NEW_CONVERSATION;
+ Saved = metadata[SMS_FLAGS] & SMS_FLG_SAVED;
+ Deleted = metadata[SMS_FLAGS] & SMS_FLG_DELETED;
+ Opened = metadata[SMS_FLAGS] & SMS_FLG_OPENED;
+
+ IsNew = metadata[SMS_NEW];
+
+ uint32_t status = *((uint32_t *) (metadata + SMS_STATUS));
+ switch (status)
+ {
+ case SMS_STA_RECEIVED:
+ MessageStatus = Received;
+ break;
+ case SMS_STA_DRAFT:
+ MessageStatus = Draft;
+ break;
+ default:
+ MessageStatus = Sent; // consider all others as sent
+ }
- Timestamp = *((uint64_t *) (str + 13));
+ ErrorId = *((uint32_t *) (metadata + SMS_ERRORID));
+
+ Timestamp = *((uint64_t *) (metadata + SMS_TIMESTAMP));
+
+ ServiceCenterTimestamp = *((uint64_t *) (metadata + SMS_SERVICE_CENTER_TIMESTAMP));
+
+ switch (metadata[SMS_DCS])
+ {
+ case SMS_DCS_7BIT:
+ DataCodingScheme = SevenBit;
+ break;
+ case SMS_DCS_8BIT:
+ DataCodingScheme = EightBit;
+ break;
+ case SMS_DCS_UCS2:
+ DataCodingScheme = UCS2;
+ break;
+ default:
+ DataCodingScheme = SevenBit; // consider all unknowns as 7bit
+ }
- SentTimestamp += *((uint64_t *) (str + 21));
+ return begin;
+ }
- Encoding = (EncodingType)str[29];
+ case SMSFC_ADDRESS:
+ {
+ uint16_t length = btohs(field->size);
+ if (length < SMS_ADDRESS_HEADER_SIZE + 1) // trailing '\0'
+ break; // too short
+ length -= SMS_ADDRESS_HEADER_SIZE;
+ const char *address = (const char *)field->u.raw + SMS_ADDRESS_HEADER_SIZE;
+ Addresses.push_back(std::string(address, length));
return begin;
}
- case SMSFC_PHONE_NUMBER:
- const char *str = (const char *)field->u.raw;
- uint16_t len = btohs(field->size);
- if( len >= 4 )
- PhoneNumbers.push_back(std::string(str + 4, len - 4));
+ case SMSFC_BODY:
+ {
+ const char *body_begin = (const char *)field->u.raw;
+ Body = std::string(body_begin, body_begin + btohs(field->size));
+ if (DataCodingScheme == UCS2)
+ {
+ if (ic)
+ {
+ IConvHandle ucs2("UCS-2BE", *ic);
+ Body = ic->Convert(ucs2, Body);
+ }
+ }
return begin;
+ }
}
// if still not handled, add to the Unknowns list
@@ -155,15 +220,15 @@ void Sms::Clear()
{
MessageStatus = Unknown;
DeliveryStatus = NoReport;
- Encoding = SevenBit;
+ DataCodingScheme = SevenBit;
IsNew = NewConversation = Saved = Deleted = Opened = false;
- Timestamp = SentTimestamp = 0;
+ Timestamp = ServiceCenterTimestamp = 0;
ErrorId = 0;
- PhoneNumbers.clear();
- Content.clear();
+ Addresses.clear();
+ Body.clear();
Unknowns.clear();
}
@@ -173,52 +238,58 @@ void Sms::Dump(std::ostream &os) const
os << "SMS record: 0x" << setbase(16) << RecordId
<< " (" << (unsigned int)RecType << ")\n";
- time_t t = Timestamp / 1000;
- os << " Time: " << ctime(&t);
+ time_t t = GetTime();
+ os << "\tTimestamp: " << ctime(&t);
if (MessageStatus == Received)
{
- t = SentTimestamp / 1000;
- os << " Sent at: " << ctime(&t);
- // FIXME - since the ISP may use a time zone other than UTC, this time probably has an offset.
+ t = GetServiceCenterTime();
+ os << "\tService Center Timestamp: " << ctime(&t);
}
if (ErrorId)
- os << " Send Error: 0x" << setbase(16) << ErrorId << "\n";
+ os << "\tSend Error: 0x" << setbase(16) << ErrorId << "\n";
switch (MessageStatus)
{
case Received:
- os << " Received From:\n";
+ os << "\tReceived From:\n";
break;
case Sent:
- os << " Sent to:\n";
+ os << "\tSent to:\n";
break;
case Draft:
- os << " Draft for:\n";
+ os << "\tDraft for:\n";
break;
case Unknown:
- os << " Unknown status for:\n";
+ os << "\tUnknown status for:\n";
break;
}
- for (std::vector<std::string>::const_iterator Iterator = PhoneNumbers.begin(); Iterator < PhoneNumbers.end(); ++Iterator)
- os << " " << *Iterator << "\n";
-
- os << " ";
- if (IsNew)
- os << "New ";
- if (Opened)
- os << "Opened ";
- if (Saved)
- os << "Saved ";
- if (Deleted)
- os << "Deleted ";
+ os << "\t";
+ for (std::vector<std::string>::const_iterator Iterator = Addresses.begin(); Iterator < Addresses.end(); ++Iterator)
+ {
+ if (Iterator != Addresses.begin())
+ os << ", ";
+ os << *Iterator;
+ }
+ os << "\n";
+
if (IsNew || Opened || Saved || Deleted || NewConversation)
+ {
+ os << "\t";
+ if (IsNew)
+ os << "New ";
+ if (Opened)
+ os << "Opened ";
+ if (Saved)
+ os << "Saved ";
+ if (Deleted)
+ os << "Deleted ";
os << "Message" << (NewConversation ? " that starts a new conversation" : "") << "\n";
- os << " Content: " << Content << "\n";
+ }
+ os << "\tContent: " << Body << "\n";
os << "\n";
}
} // namespace Barry
-
diff --git a/src/r_sms.h b/src/r_sms.h
index f144547..7ed0f9b 100644
--- a/src/r_sms.h
+++ b/src/r_sms.h
@@ -57,7 +57,7 @@ public:
Failed,
Succedded
};
- DeliveryType DeliveryStatus;
+ DeliveryType DeliveryStatus; // not implemented yet
bool IsNew;
bool NewConversation;
@@ -65,21 +65,21 @@ public:
bool Deleted;
bool Opened;
- uint64_t Timestamp;
- uint64_t SentTimestamp;
+ uint64_t Timestamp; // milliseconds from Jan 1, 1970
+ uint64_t ServiceCenterTimestamp; // not applicable for non-incoming messages
- enum EncodingType
+ enum DataCodingSchemeType
{
SevenBit = 0,
- VCard,
+ EightBit,
UCS2
};
- EncodingType Encoding;
+ DataCodingSchemeType DataCodingScheme;
uint32_t ErrorId;
- std::vector<std::string> PhoneNumbers;
- std::string Content;
+ std::vector<std::string> Addresses;
+ std::string Body;
UnknownsType Unknowns;
@@ -87,6 +87,11 @@ public:
Sms();
~Sms();
+ time_t GetTime() const;
+ time_t GetServiceCenterTime() const;
+ void SetTime(const time_t timestamp, unsigned int milliseconds = 0);
+ void SetServiceCenterTime(const time_t timestamp, unsigned int milliseconds = 0);
+
const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0);
uint8_t GetRecType() const { return RecType; }
uint32_t GetUniqueId() const { return RecordId; }
diff --git a/src/s11n-boost.h b/src/s11n-boost.h
index 59c46a5..b52ca33 100644
--- a/src/s11n-boost.h
+++ b/src/s11n-boost.h
@@ -358,13 +358,13 @@ void serialize(ArchiveT &ar, Barry::Sms &m, const unsigned int ver)
ar & make_nvp("Opened", m.Opened);
ar & make_nvp("Timestamp", m.Timestamp);
- ar & make_nvp("SentTimestamp", m.SentTimestamp);
+ ar & make_nvp("ServiceCenterTimestamp", m.ServiceCenterTimestamp);
- ar & make_nvp("Encoding", m.Encoding);
+ ar & make_nvp("DataCodingScheme", m.DataCodingScheme);
ar & make_nvp("ErrorId", m.ErrorId);
- ar & make_nvp("PhoneNumbers", m.PhoneNumbers);
- ar & make_nvp("Content", m.Content);
+ ar & make_nvp("Addresses", m.Addresses);
+ ar & make_nvp("Body", m.Body);
if( ver < BARRY_POD_MAP_VERSION ) {
ar & make_nvp("Unknowns", m.Unknowns);
--
1.5.6.3
------------------------------------------------------------------------------
This SF.net email is sponsored by:
High Quality Requirements in a Collaborative Environment.
Download a free trial of Rational Requirements Composer Now!
http://p.sf.net/sfu/www-ibm-com
_______________________________________________
Barry-devel mailing list
Barry-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/barry-devel