record.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       record.cc
00003 ///             Misc. Blackberry database record helper classes and functions.
00004 ///             Helps translate data from data packets to useful structures,
00005 ///             and back.
00006 ///
00007 
00008 /*
00009     Copyright (C) 2005-2011, Net Direct Inc. (http://www.netdirect.ca/)
00010 
00011     This program is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU General Public License as published by
00013     the Free Software Foundation; either version 2 of the License, or
00014     (at your option) any later version.
00015 
00016     This program is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00019 
00020     See the GNU General Public License in the COPYING file at the
00021     root directory of this project for more details.
00022 */
00023 
00024 #include "record.h"
00025 #include "record-internal.h"
00026 #include "protocol.h"
00027 #include "protostructs.h"
00028 #include "data.h"
00029 #include "time.h"
00030 #include "error.h"
00031 #include "endian.h"
00032 #include <sstream>
00033 #include <iomanip>
00034 #include <time.h>
00035 #include <string.h>
00036 #include <stdio.h>                      // for sscanf()
00037 #include <stdexcept>
00038 
00039 #define __DEBUG_MODE__
00040 #include "debug.h"
00041 
00042 using namespace std;
00043 using namespace Barry::Protocol;
00044 
00045 namespace Barry {
00046 
00047 BXEXPORT std::ostream& operator<< (std::ostream &os, const Cr2LfWrapper &str)
00048 {
00049         for(    std::string::const_iterator i = str.m_str.begin();
00050                 i != str.m_str.end() && *i;
00051                 i++)
00052         {
00053                 if( *i == '\r' )
00054                         os << '\n';
00055                 else
00056                         os << *i;
00057         }
00058         return os;
00059 }
00060 
00061 //////////////////////////////////////////////////////////////////////////////
00062 // Field builder helper functions
00063 
00064 void BuildField1900(Data &data, size_t &size, uint8_t type, time_t t)
00065 {
00066         size_t timesize = COMMON_FIELD_MIN1900_SIZE;
00067         size_t fieldsize = COMMON_FIELD_HEADER_SIZE + timesize;
00068         unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00069         CommonField *field = (CommonField *) pd;
00070 
00071         field->size = htobs(timesize);
00072         field->type = type;
00073         field->u.min1900 = time2min(t);
00074 
00075         size += fieldsize;
00076 }
00077 
00078 void BuildField(Data &data, size_t &size, uint8_t type, char c)
00079 {
00080         BuildField(data, size, type, (uint8_t)c);
00081 }
00082 
00083 void BuildField(Data &data, size_t &size, uint8_t type, uint8_t c)
00084 {
00085         size_t strsize = 1;
00086         size_t fieldsize = COMMON_FIELD_HEADER_SIZE + strsize;
00087         unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00088         CommonField *field = (CommonField *) pd;
00089 
00090         field->size = htobs(strsize);
00091         field->type = type;
00092         memcpy(field->u.raw, &c, strsize);
00093 
00094         size += fieldsize;
00095 }
00096 
00097 void BuildField(Data &data, size_t &size, uint8_t type, uint16_t value)
00098 {
00099         size_t strsize = 2;
00100         size_t fieldsize = COMMON_FIELD_HEADER_SIZE + strsize;
00101         unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00102         CommonField *field = (CommonField *) pd;
00103 
00104         field->size = htobs(strsize);
00105         field->type = type;
00106 
00107         uint16_t store = htobs(value);
00108         memcpy(field->u.raw, &store, strsize);
00109 
00110         size += fieldsize;
00111 }
00112 
00113 void BuildField(Data &data, size_t &size, uint8_t type, uint32_t value)
00114 {
00115         size_t strsize = 4;
00116         size_t fieldsize = COMMON_FIELD_HEADER_SIZE + strsize;
00117         unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00118         CommonField *field = (CommonField *) pd;
00119 
00120         field->size = htobl(strsize);
00121         field->type = type;
00122 
00123         uint32_t store = htobl(value);
00124         memcpy(field->u.raw, &store, strsize);
00125 
00126         size += fieldsize;
00127 }
00128 
00129 void BuildField(Data &data, size_t &size, uint8_t type, uint64_t value)
00130 {
00131         size_t strsize = 8;
00132         size_t fieldsize = COMMON_FIELD_HEADER_SIZE + strsize;
00133         unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00134         CommonField *field = (CommonField *) pd;
00135 
00136         field->size = htobl(strsize);
00137         field->type = type;
00138 
00139         uint64_t store = htobll(value);
00140         memcpy(field->u.raw, &store, strsize);
00141 
00142         size += fieldsize;
00143 }
00144 
00145 void BuildField(Data &data, size_t &size, uint8_t type, const std::string &str)
00146 {
00147         // include null terminator
00148         BuildField(data, size, type, str.c_str(), str.size() + 1);
00149 }
00150 
00151 void BuildField(Data &data, size_t &size, uint8_t type,
00152                 const void *buf, size_t bufsize)
00153 {
00154         // include null terminator
00155         size_t fieldsize = COMMON_FIELD_HEADER_SIZE + bufsize;
00156         unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00157         CommonField *field = (CommonField *) pd;
00158 
00159         field->size = htobs(bufsize);
00160         field->type = type;
00161         memcpy(field->u.raw, buf, bufsize);
00162 
00163         size += fieldsize;
00164 }
00165 
00166 void BuildField(Data &data, size_t &size, const Barry::UnknownField &field)
00167 {
00168         BuildField(data, size, field.type,
00169                 field.data.raw_data.data(), field.data.raw_data.size());
00170 }
00171 
00172 void BuildField(Data &data, size_t &size, uint8_t type, const Barry::Protocol::GroupLink &link)
00173 {
00174         size_t linksize = sizeof(Barry::Protocol::GroupLink);
00175         size_t fieldsize = COMMON_FIELD_HEADER_SIZE + linksize;
00176         unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00177         CommonField *field = (CommonField *) pd;
00178 
00179         field->size = htobs(linksize);
00180         field->type = type;
00181         field->u.link = link;
00182 
00183         size += fieldsize;
00184 }
00185 
00186 std::string ParseFieldString(const Barry::Protocol::CommonField *field)
00187 {
00188         // make no assumptions here, and pass the full size in as
00189         // the maxlen, even though 99% of the time, it will be a null...
00190         // this function can be used by non-null terminated strings as well
00191         return ParseFieldString(field->u.raw, btohs(field->size));
00192 }
00193 
00194 std::string ParseFieldString(const void *data, uint16_t maxlen)
00195 {
00196         const char *str = (const char *)data;
00197 
00198         // find last non-null character, since some fields
00199         // can have multiple null terminators
00200         while( maxlen && str[maxlen-1] == 0 )
00201                 maxlen--;
00202 
00203         return std::string(str, maxlen);
00204 }
00205 
00206 
00207 ///////////////////////////////////////////////////////////////////////////////
00208 // UnknownField
00209 
00210 std::ostream& operator<< (std::ostream &os, const std::vector<UnknownField> &unknowns)
00211 {
00212         std::vector<UnknownField>::const_iterator
00213                 ub = unknowns.begin(), ue = unknowns.end();
00214         if( ub != ue )
00215                 os << "    Unknowns:\n";
00216         for( ; ub != ue; ub++ ) {
00217                 os << "        Type: 0x" << setbase(16)
00218                    << (unsigned int) ub->type
00219                    << " Data:\n" << Data(ub->data.data(), ub->data.size());
00220         }
00221         return os;
00222 }
00223 
00224 
00225 ///////////////////////////////////////////////////////////////////////////////
00226 // EmailAddress class
00227 
00228 std::ostream& operator<<(std::ostream &os, const EmailAddress &msga) {
00229         os << msga.Name << " <" << msga.Email << ">";
00230         return os;
00231 }
00232 
00233 std::ostream& operator<<(std::ostream &os, const EmailAddressList &elist) {
00234         for( EmailAddressList::const_iterator i = elist.begin(); i != elist.end(); ++i ) {
00235                 if( i != elist.begin() )
00236                         os << ", ";
00237                 os << *i;
00238         }
00239         return os;
00240 }
00241 
00242 
00243 ///////////////////////////////////////////////////////////////////////////////
00244 // PostalAddress class
00245 
00246 //
00247 // GetLabel
00248 //
00249 /// Format a mailing address into a single string, handling missing fields.
00250 ///
00251 std::string PostalAddress::GetLabel() const
00252 {
00253         std::string address = Address1;
00254         if( Address2.size() ) {
00255                 if( address.size() )
00256                         address += "\n";
00257                 address += Address2;
00258         }
00259         if( Address3.size() ) {
00260                 if( address.size() )
00261                         address += "\n";
00262                 address += Address3;
00263         }
00264         if( address.size() )
00265                 address += "\n";
00266         if( City.size() )
00267                 address += City + " ";
00268         if( Province.size() )
00269                 address += Province + " ";
00270         if( Country.size() )
00271                 address += Country;
00272         if( address.size() )
00273                 address += "\n";
00274         if( PostalCode.size() )
00275                 address += PostalCode;
00276 
00277         return address;
00278 }
00279 
00280 void PostalAddress::Clear()
00281 {
00282         Address1.clear();
00283         Address2.clear();
00284         Address3.clear();
00285         City.clear();
00286         Province.clear();
00287         PostalCode.clear();
00288         Country.clear();
00289 }
00290 
00291 std::ostream& operator<<(std::ostream &os, const PostalAddress &post) {
00292         os << post.GetLabel();
00293         return os;
00294 }
00295 
00296 
00297 
00298 ///////////////////////////////////////////////////////////////////////////////
00299 // Date class
00300 
00301 Date::Date(const struct tm *timep)
00302 {
00303         FromTm(timep);
00304 }
00305 
00306 void Date::Clear()
00307 {
00308         Month = Day = Year = 0;
00309 }
00310 
00311 void Date::ToTm(struct tm *timep) const
00312 {
00313         memset(timep, 0, sizeof(tm));
00314         timep->tm_year = Year - 1900;
00315         timep->tm_mon = Month;
00316         timep->tm_mday = Day;
00317 }
00318 
00319 std::string Date::ToYYYYMMDD() const
00320 {
00321         std::ostringstream oss;
00322         // setfill and setw not sticky.
00323         oss     << setw(4) << setfill('0') << dec << Year
00324                 << setw(2) << setfill('0') << dec << (Month + 1)
00325                 << setw(2) << setfill('0') << dec << Day;
00326         return oss.str();
00327 }
00328 
00329 //
00330 // ToBBString
00331 //
00332 /// The Blackberry stores Birthday and Anniversary date fields
00333 /// with the format: DD/MM/YYYY
00334 ///
00335 std::string Date::ToBBString() const
00336 {
00337         std::ostringstream oss;
00338         // setw() ain't 'sticky'!
00339         oss     << setw(2) << setfill('0') << dec << Day << '/'
00340                 << setw(2) << setfill('0') << dec << (Month + 1) << '/'
00341                 << setw(2) << setfill('0') << dec << Year;
00342         return oss.str();
00343 }
00344 
00345 bool Date::FromTm(const struct tm *timep)
00346 {
00347         if( !timep )
00348                 throw std::logic_error("NULL time pointer passed to Date::FromTm");
00349 
00350         Year = timep->tm_year + 1900;
00351         Month = timep->tm_mon;
00352         Day = timep->tm_mday;
00353         return true;
00354 }
00355 
00356 bool Date::FromBBString(const std::string &str)
00357 {
00358         int m, d, y;
00359         if( 3 == sscanf(str.c_str(), "%d/%d/%d", &d, &m, &y) ) {
00360                 Year = y;
00361                 Month = m - 1;
00362                 Day = d;
00363                 return true;
00364         }
00365         return false;
00366 }
00367 
00368 bool Date::FromYYYYMMDD(const std::string &str)
00369 {
00370         int m, d, y;
00371         if( 3 == sscanf(str.c_str(), "%4d%2d%2d", &y, &m, &d) ) {
00372                 Year = y;
00373                 Month = m - 1;
00374                 Day = d;
00375                 return true;
00376         }
00377         return false;
00378 }
00379 
00380 std::ostream& operator<<(std::ostream &os, const Date &date)
00381 {
00382         os      << setw(4) << setfill('0') << dec << date.Year << '/'
00383                 << setw(2) << setfill('0') << dec << (date.Month + 1) << '/'
00384                 << setw(2) << setfill('0') << dec << date.Day;
00385         return os;
00386 }
00387 
00388 
00389 ///////////////////////////////////////////////////////////////////////////////
00390 // CategoryList class
00391 
00392 /// Parses the given comma delimited category string into
00393 /// this CategoryList object, appending each token to the vector.
00394 /// Will clear vector beforehand.
00395 void CategoryList::CategoryStr2List(const std::string &str)
00396 {
00397         // start fresh
00398         clear();
00399 
00400         if( !str.size() )
00401                 return;
00402 
00403         // parse the comma-delimited string to a list, stripping away
00404         // any white space around each category name
00405         string::size_type start = 0, end = 0, delim = str.find(',', start);
00406         while( start != string::npos ) {
00407                 if( delim == string::npos )
00408                         end = str.size() - 1;
00409                 else
00410                         end = delim - 1;
00411 
00412                 // strip surrounding whitespace
00413                 while( str[start] == ' ' )
00414                         start++;
00415                 while( end && str[end] == ' ' )
00416                         end--;
00417 
00418                 if( start <= end ) {
00419                         string token = str.substr(start, end-start+1);
00420                         push_back(token);
00421                 }
00422 
00423                 // next
00424                 start = delim;
00425                 if( start != string::npos )
00426                         start++;
00427                 delim = str.find(',', start);
00428         }
00429 }
00430 
00431 /// Turns the current vectory into a comma delimited category
00432 /// string suitable for use in Calendar, Task, and Memo protocol values.
00433 void CategoryList::CategoryList2Str(std::string &str) const
00434 {
00435         str.clear();
00436 
00437         Barry::CategoryList::const_iterator i = begin();
00438         for( ; i != end(); ++i ) {
00439                 if( str.size() )
00440                         str += ", ";
00441                 str += *i;
00442         }
00443 }
00444 
00445 
00446 } // namespace Barry
00447 
00448 
00449 #ifdef __TEST_MODE__
00450 
00451 #include <iostream>
00452 
00453 int main(int argc, char *argv[])
00454 {
00455         if( argc < 2 ) {
00456                 cerr << "Usage: test <datafile>" << endl;
00457                 return 1;
00458         }
00459 
00460         std::vector<Data> array;
00461         if( !LoadDataArray(argv[1], array) ) {
00462                 cerr << "Unable to load file: " << argv[1] << endl;
00463                 return 1;
00464         }
00465 
00466         cout << "Loaded " << array.size() << " items" << endl;
00467 
00468         for( std::vector<Data>::iterator b = array.begin(), e = array.end();
00469                 b != e; b++ )
00470         {
00471                 Data &d = *b;
00472 //              cout << d << endl;
00473                 if( d.GetSize() > 13 && d.GetData()[6] == 0x4f ) {
00474                         Barry::Contact contact;
00475                         size_t size = 13;
00476                         contact.ParseFields(d, size);
00477                         cout << contact << endl;
00478                         contact.DumpLdif(cout, "ou=People,dc=example,dc=com");
00479                 }
00480                 else if( d.GetSize() > 13 && d.GetData()[6] == 0x44 ) {
00481                         Barry::Calendar cal;
00482                         size_t size = 13;
00483                         cal.ParseFields(d, size);
00484                         cout << cal << endl;
00485                 }
00486         }
00487 }
00488 
00489 #endif
00490 

Generated on Tue Mar 1 17:50:16 2011 for Barry by  doxygen 1.5.6