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