3 /// Misc. Blackberry database record helper classes and functions.
4 /// Helps translate data from data packets to useful structures,
9 Copyright (C) 2005-2010, Net Direct Inc. (http://www.netdirect.ca/)
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 See the GNU General Public License in the COPYING file at the
21 root directory of this project for more details.
25 #include "record-internal.h"
27 #include "protostructs.h"
36 #include <stdio.h> // for sscanf()
39 #define __DEBUG_MODE__
43 using namespace Barry::Protocol
;
47 BXEXPORT
std::ostream
& operator<< (std::ostream
&os
, const Cr2LfWrapper
&str
)
49 for( std::string::const_iterator i
= str
.m_str
.begin();
50 i
!= str
.m_str
.end() && *i
;
61 //////////////////////////////////////////////////////////////////////////////
62 // Field builder helper functions
64 void BuildField1900(Data
&data
, size_t &size
, uint8_t type
, time_t t
)
66 size_t timesize
= COMMON_FIELD_MIN1900_SIZE
;
67 size_t fieldsize
= COMMON_FIELD_HEADER_SIZE
+ timesize
;
68 unsigned char *pd
= data
.GetBuffer(size
+ fieldsize
) + size
;
69 CommonField
*field
= (CommonField
*) pd
;
71 field
->size
= htobs(timesize
);
73 field
->u
.min1900
= time2min(t
);
78 void BuildField(Data
&data
, size_t &size
, uint8_t type
, char c
)
80 BuildField(data
, size
, type
, (uint8_t)c
);
83 void BuildField(Data
&data
, size_t &size
, uint8_t type
, uint8_t c
)
86 size_t fieldsize
= COMMON_FIELD_HEADER_SIZE
+ strsize
;
87 unsigned char *pd
= data
.GetBuffer(size
+ fieldsize
) + size
;
88 CommonField
*field
= (CommonField
*) pd
;
90 field
->size
= htobs(strsize
);
92 memcpy(field
->u
.raw
, &c
, strsize
);
97 void BuildField(Data
&data
, size_t &size
, uint8_t type
, uint16_t value
)
100 size_t fieldsize
= COMMON_FIELD_HEADER_SIZE
+ strsize
;
101 unsigned char *pd
= data
.GetBuffer(size
+ fieldsize
) + size
;
102 CommonField
*field
= (CommonField
*) pd
;
104 field
->size
= htobs(strsize
);
107 uint16_t store
= htobs(value
);
108 memcpy(field
->u
.raw
, &store
, strsize
);
113 void BuildField(Data
&data
, size_t &size
, uint8_t type
, uint32_t value
)
116 size_t fieldsize
= COMMON_FIELD_HEADER_SIZE
+ strsize
;
117 unsigned char *pd
= data
.GetBuffer(size
+ fieldsize
) + size
;
118 CommonField
*field
= (CommonField
*) pd
;
120 field
->size
= htobl(strsize
);
123 uint32_t store
= htobl(value
);
124 memcpy(field
->u
.raw
, &store
, strsize
);
129 void BuildField(Data
&data
, size_t &size
, uint8_t type
, uint64_t value
)
132 size_t fieldsize
= COMMON_FIELD_HEADER_SIZE
+ strsize
;
133 unsigned char *pd
= data
.GetBuffer(size
+ fieldsize
) + size
;
134 CommonField
*field
= (CommonField
*) pd
;
136 field
->size
= htobl(strsize
);
139 uint64_t store
= htobll(value
);
140 memcpy(field
->u
.raw
, &store
, strsize
);
145 void BuildField(Data
&data
, size_t &size
, uint8_t type
, const std::string
&str
)
147 // include null terminator
148 BuildField(data
, size
, type
, str
.c_str(), str
.size() + 1);
151 void BuildField(Data
&data
, size_t &size
, uint8_t type
,
152 const void *buf
, size_t bufsize
)
154 // include null terminator
155 size_t fieldsize
= COMMON_FIELD_HEADER_SIZE
+ bufsize
;
156 unsigned char *pd
= data
.GetBuffer(size
+ fieldsize
) + size
;
157 CommonField
*field
= (CommonField
*) pd
;
159 field
->size
= htobs(bufsize
);
161 memcpy(field
->u
.raw
, buf
, bufsize
);
166 void BuildField(Data
&data
, size_t &size
, const Barry::UnknownField
&field
)
168 BuildField(data
, size
, field
.type
,
169 field
.data
.raw_data
.data(), field
.data
.raw_data
.size());
172 void BuildField(Data
&data
, size_t &size
, uint8_t type
, const Barry::Protocol::GroupLink
&link
)
174 size_t linksize
= sizeof(Barry::Protocol::GroupLink
);
175 size_t fieldsize
= COMMON_FIELD_HEADER_SIZE
+ linksize
;
176 unsigned char *pd
= data
.GetBuffer(size
+ fieldsize
) + size
;
177 CommonField
*field
= (CommonField
*) pd
;
179 field
->size
= htobs(linksize
);
181 field
->u
.link
= link
;
186 std::string
ParseFieldString(const Barry::Protocol::CommonField
*field
)
188 // make no assumptions here, and pass the full size in as
189 // the maxlen, even though 99% of the time, it will be a null...
190 // this function can be used by non-null terminated strings as well
191 return ParseFieldString(field
->u
.raw
, btohs(field
->size
));
194 std::string
ParseFieldString(const void *data
, uint16_t maxlen
)
196 const char *str
= (const char *)data
;
198 // find last non-null character, since some fields
199 // can have multiple null terminators
200 while( maxlen
&& str
[maxlen
-1] == 0 )
203 return std::string(str
, maxlen
);
207 ///////////////////////////////////////////////////////////////////////////////
210 std::ostream
& operator<< (std::ostream
&os
, const std::vector
<UnknownField
> &unknowns
)
212 std::vector
<UnknownField
>::const_iterator
213 ub
= unknowns
.begin(), ue
= unknowns
.end();
215 os
<< " Unknowns:\n";
216 for( ; ub
!= ue
; ub
++ ) {
217 os
<< " Type: 0x" << setbase(16)
218 << (unsigned int) ub
->type
219 << " Data:\n" << Data(ub
->data
.data(), ub
->data
.size());
225 ///////////////////////////////////////////////////////////////////////////////
226 // EmailAddress class
228 std::ostream
& operator<<(std::ostream
&os
, const EmailAddress
&msga
) {
229 os
<< msga
.Name
<< " <" << msga
.Email
<< ">";
233 std::ostream
& operator<<(std::ostream
&os
, const EmailAddressList
&elist
) {
234 for( EmailAddressList::const_iterator i
= elist
.begin(); i
!= elist
.end(); ++i
) {
235 if( i
!= elist
.begin() )
243 ///////////////////////////////////////////////////////////////////////////////
244 // PostalAddress class
249 /// Format a mailing address into a single string, handling missing fields.
251 std::string
PostalAddress::GetLabel() const
253 std::string address
= Address1
;
254 if( Address2
.size() ) {
259 if( Address3
.size() ) {
267 address
+= City
+ " ";
268 if( Province
.size() )
269 address
+= Province
+ " ";
274 if( PostalCode
.size() )
275 address
+= PostalCode
;
280 void PostalAddress::Clear()
291 std::ostream
& operator<<(std::ostream
&os
, const PostalAddress
&post
) {
292 os
<< post
.GetLabel();
298 ///////////////////////////////////////////////////////////////////////////////
301 Date::Date(const struct tm
*timep
)
308 Month
= Day
= Year
= 0;
311 void Date::ToTm(struct tm
*timep
) const
313 memset(timep
, 0, sizeof(tm
));
314 timep
->tm_year
= Year
- 1900;
315 timep
->tm_mon
= Month
;
316 timep
->tm_mday
= Day
;
319 std::string
Date::ToYYYYMMDD() const
321 std::ostringstream oss
;
322 // setfill and setw not sticky.
323 oss
<< setw(4) << setfill('0') << Year
324 << setw(2) << setfill('0') << (Month
+ 1)
325 << setw(2) << setfill('0') << Day
;
332 /// The Blackberry stores Birthday and Anniversary date fields
333 /// with the format: DD/MM/YYYY
335 std::string
Date::ToBBString() const
337 std::ostringstream oss
;
338 // setw() ain't 'sticky'!
339 oss
<< setw(2) << setfill('0') << Day
<< '/'
340 << setw(2) << setfill('0') << (Month
+ 1) << '/'
341 << setw(2) << setfill('0') << Year
;
345 bool Date::FromTm(const struct tm
*timep
)
348 throw std::logic_error("NULL time pointer passed to Date::FromTm");
350 Year
= timep
->tm_year
+ 1900;
351 Month
= timep
->tm_mon
;
352 Day
= timep
->tm_mday
;
356 bool Date::FromBBString(const std::string
&str
)
359 if( 3 == sscanf(str
.c_str(), "%d/%d/%d", &d
, &m
, &y
) ) {
368 bool Date::FromYYYYMMDD(const std::string
&str
)
371 if( 3 == sscanf(str
.c_str(), "%4d%2d%2d", &y
, &m
, &d
) ) {
380 std::ostream
& operator<<(std::ostream
&os
, const Date
&date
)
382 os
<< setw(4) << dec
<< date
.Year
<< '/'
383 << setw(2) << dec
<< (date
.Month
+ 1) << '/'
384 << setw(2) << dec
<< date
.Day
;
389 ///////////////////////////////////////////////////////////////////////////////
390 // CategoryList class
392 /// Parses the given comma delimited category string into
393 /// this CategoryList object, appending each token to the vector.
394 /// Will clear vector beforehand.
395 void CategoryList::CategoryStr2List(const std::string
&str
)
403 // parse the comma-delimited string to a list, stripping away
404 // any white space around each category name
405 string::size_type start
= 0, end
= 0, delim
= str
.find(',', start
);
406 while( start
!= string::npos
) {
407 if( delim
== string::npos
)
408 end
= str
.size() - 1;
412 // strip surrounding whitespace
413 while( str
[start
] == ' ' )
415 while( end
&& str
[end
] == ' ' )
419 string token
= str
.substr(start
, end
-start
+1);
425 if( start
!= string::npos
)
427 delim
= str
.find(',', start
);
431 /// Turns the current vectory into a comma delimited category
432 /// string suitable for use in Calendar, Task, and Memo protocol values.
433 void CategoryList::CategoryList2Str(std::string
&str
) const
437 Barry::CategoryList::const_iterator i
= begin();
438 for( ; i
!= end(); ++i
) {
453 int main(int argc
, char *argv
[])
456 cerr
<< "Usage: test <datafile>" << endl
;
460 std::vector
<Data
> array
;
461 if( !LoadDataArray(argv
[1], array
) ) {
462 cerr
<< "Unable to load file: " << argv
[1] << endl
;
466 cout
<< "Loaded " << array
.size() << " items" << endl
;
468 for( std::vector
<Data
>::iterator b
= array
.begin(), e
= array
.end();
472 // cout << d << endl;
473 if( d
.GetSize() > 13 && d
.GetData()[6] == 0x4f ) {
474 Barry::Contact contact
;
476 contact
.ParseFields(d
, size
);
477 cout
<< contact
<< endl
;
478 contact
.DumpLdif(cout
, "ou=People,dc=example,dc=com");
480 else if( d
.GetSize() > 13 && d
.GetData()[6] == 0x44 ) {
483 cal
.ParseFields(d
, size
);