vbase.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       vbase.cc
00003 ///             vformat support routines in base class
00004 ///
00005 
00006 /*
00007     Copyright (C) 2006-2012, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #include "vbase.h"
00023 //#include "trace.h"
00024 #include "vformat.h"            // comes from opensync, but not a public header yet
00025 #include "tzwrapper.h"
00026 #include "r_contact.h"          // for CategoryList
00027 #include <stdio.h>
00028 #include <stdarg.h>
00029 #include <stdint.h>
00030 #include <string.h>
00031 #include <glib.h>
00032 #include <sstream>
00033 
00034 using namespace std;
00035 
00036 namespace Barry { namespace Sync {
00037 
00038 //////////////////////////////////////////////////////////////////////////////
00039 // vTimeConverter
00040 
00041 std::string vTimeConverter::unix2vtime(const time_t *timestamp)
00042 {
00043         struct tm split;
00044         if( !gmtime_r(timestamp, &split) ) {
00045                 ostringstream oss;
00046                 oss << "gmtime_r() failed on time_t of ";
00047                 if( timestamp )
00048                         oss << *timestamp;
00049                 else
00050                         oss << "(null pointer)";
00051                 throw Barry::ConvertError(oss.str());
00052         }
00053 
00054         return tm_to_iso(&split, true);
00055 }
00056 
00057 time_t vTimeConverter::vtime2unix(const char *vtime)
00058 {
00059         return TzWrapper::iso_mktime(vtime);
00060 }
00061 
00062 //
00063 // The following implementation is taken from opensync's
00064 // opensync_time.c implementation with the following copyright
00065 // notices at the top as of July 2010:
00066 //
00067 //  * Copyright (C) 2004-2005  Armin Bauer <armin.bauer@opensync.org>
00068 //  * Copyright (C) 2006-2008 Daniel Gollub <gollub@b1-systems.de>
00069 //  * Copyright (C) 2007 Chris Frey <cdfrey@netdirect.ca>
00070 //
00071 // License: LGPL 2.1 or later
00072 //
00073 int vTimeConverter::alarmduration2sec(const char *alarm)
00074 {
00075         int i, secs, digits = 0;
00076         int is_digit = 0;
00077         int sign = 1;   // when ical stamp doesn't start with '-' => seconds after event
00078         int days = 0, weeks = 0, hours = 0, minutes = 0, seconds = 0;
00079         int len = strlen(alarm);
00080 
00081         for (i=0; i < len; i++) {
00082 
00083                 switch (alarm[i]) {
00084                 case '-':
00085                         sign = -1; // seconds before event - change the sign
00086                 case 'P':
00087                 case 'T':
00088                         is_digit = 0;
00089                         break;
00090                 case 'W':
00091                         is_digit = 0;
00092                         weeks = digits;
00093                         break;
00094                 case 'D':
00095                         is_digit = 0;
00096                         days = digits;
00097                         break;
00098                 case 'H':
00099                         is_digit = 0;
00100                         hours = digits;
00101                         break;
00102                 case 'M':
00103                         is_digit = 0;
00104                         minutes = digits;
00105                         break;
00106                 case 'S':
00107                         is_digit = 0;
00108                         seconds = digits;
00109                         break;
00110                 case '0':
00111                 case '1':
00112                 case '2':
00113                 case '3':
00114                 case '4':
00115                 case '5':
00116                 case '6':
00117                 case '7':
00118                 case '8':
00119                 case '9':
00120                         if (is_digit)
00121                                 break;
00122 
00123                         if (sscanf((char*)(alarm+i),"%d",&digits) == EOF)
00124                                 return -1;
00125 
00126                         is_digit = 1;
00127                         break;
00128                 }
00129         }
00130 
00131         secs = (weeks * 7 * 24 * 3600) + (days * 24 * 3600) + (hours * 3600) + (minutes * 60) + seconds;
00132 
00133         secs = secs * sign;     // change sign if the alarm is in seconds before event (leading '-')
00134 
00135         return secs;
00136 
00137 }
00138 
00139 
00140 //////////////////////////////////////////////////////////////////////////////
00141 // vAttr
00142 
00143 std::string vAttr::GetName()
00144 {
00145         std::string ret;
00146 
00147         if( !m_attr )
00148                 return ret;
00149 
00150         const char *name = b_vformat_attribute_get_name(m_attr);
00151         if( name )
00152                 ret = name;
00153         return ret;
00154 }
00155 
00156 std::string vAttr::GetValue(int nth)
00157 {
00158         std::string ret;
00159         const char *value = 0;
00160 
00161         if( m_attr ) {
00162                 if( b_vformat_attribute_is_single_valued(m_attr) ) {
00163                         if( nth == 0 )
00164                                 value = b_vformat_attribute_get_value(m_attr);
00165                 }
00166                 else {
00167                         value = b_vformat_attribute_get_nth_value(m_attr, nth);
00168                 }
00169         }
00170 
00171         if( value )
00172                 ret = value;
00173 
00174         return ret;
00175 }
00176 
00177 std::string vAttr::GetDecodedValue()
00178 {
00179         std::string ret;
00180         GString *value = NULL;
00181 
00182         if( m_attr ) {
00183                 if( b_vformat_attribute_is_single_valued(m_attr) ) {
00184                         value = b_vformat_attribute_get_value_decoded(m_attr);
00185                 }
00186         }
00187 
00188         if( value )
00189                 ret.assign(value->str, value->len);
00190 
00191         return ret;
00192 }
00193 
00194 std::string vAttr::GetParam(const char *name, int nth)
00195 {
00196         std::string ret;
00197 
00198         if( !m_attr )
00199                 return ret;
00200 
00201         b_VFormatParam *param = b_vformat_attribute_find_param(m_attr, name, 0);
00202         if( !param )
00203                 return ret;
00204 
00205         const char *value = b_vformat_attribute_param_get_nth_value(param, nth);
00206         if( value )
00207                 ret = value;
00208 
00209         return ret;
00210 }
00211 
00212 /// Does an exhaustive search through the attribute, searching for all
00213 /// param values that exist for the given name, and returns all values
00214 /// in a comma delimited string.
00215 std::string vAttr::GetAllParams(const char *name)
00216 {
00217         std::string ret;
00218 
00219         if( !m_attr )
00220                 return ret;
00221 
00222         b_VFormatParam *param = 0;
00223         for( int level = 0;
00224              (param = b_vformat_attribute_find_param(m_attr, name, level));
00225              level++ )
00226         {
00227                 const char *value = 0;
00228                 for( int nth = 0;
00229                      (value = b_vformat_attribute_param_get_nth_value(param, nth));
00230                      nth++ )
00231                 {
00232                         if( ret.size() )
00233                                 ret += ",";
00234                         ret += value;
00235                 }
00236         }
00237 
00238         return ret;
00239 }
00240 
00241 
00242 //////////////////////////////////////////////////////////////////////////////
00243 // vCalendar
00244 
00245 vBase::vBase()
00246         : m_format(b_vformat_new())
00247 {
00248 }
00249 
00250 vBase::vBase(b_VFormat *format)
00251         : m_format(format)
00252 {
00253         if( !format )
00254                 throw Barry::Error("Cannot construct vBase with null format");
00255 }
00256 
00257 vBase::~vBase()
00258 {
00259         if( m_format ) {
00260                 b_vformat_free(m_format);
00261                 m_format = 0;
00262         }
00263 }
00264 
00265 void vBase::SetFormat(b_VFormat *format)
00266 {
00267         if( !format )
00268                 throw Barry::Error("Cannot set vBase with null format");
00269 
00270         if( m_format ) {
00271                 b_vformat_free(m_format);
00272                 m_format = 0;
00273         }
00274         m_format = format;
00275 }
00276 
00277 void vBase::Clear()
00278 {
00279         if( m_format ) {
00280                 b_vformat_free(m_format);
00281                 m_format = b_vformat_new();
00282         }
00283 }
00284 
00285 vAttrPtr vBase::NewAttr(const char *name)
00286 {
00287 //      Trace trace("vBase::NewAttr");
00288 
00289 //      trace.logf("creating valueless attr: %s", name);
00290 
00291         vAttrPtr attr(b_vformat_attribute_new(NULL, name));
00292         if( !attr.Get() )
00293                 throw Barry::ConvertError("resource error allocating vformat attribute");
00294         return attr;
00295 }
00296 
00297 vAttrPtr vBase::NewAttr(const char *name, const char *value)
00298 {
00299 //      Trace trace("vBase::NewAttr");
00300 
00301 /*
00302 some vCard values are positional (like name), so blank should be allowed...
00303 
00304         if( strlen(value) == 0 ) {
00305                 trace.logf("attribute '%s' contains no data, skipping", name);
00306                 return vAttrPtr();
00307         }
00308 */
00309 
00310 //      trace.logf("creating attr: %s, %s", name, value);
00311 
00312         vAttrPtr attr(b_vformat_attribute_new(NULL, name));
00313         if( !attr.Get() )
00314                 throw ConvertError("resource error allocating vformat attribute");
00315 
00316         b_vformat_attribute_add_value(attr.Get(), value);
00317         return attr;
00318 }
00319 
00320 void vBase::AddAttr(vAttrPtr attr)
00321 {
00322 //      Trace trace("vBase::AddAttr");
00323 
00324         if( !attr.Get() ) {
00325 //              trace.log("attribute contains no data, skipping");
00326                 return;
00327         }
00328 
00329         b_vformat_add_attribute(m_format, attr.Extract());
00330 }
00331 
00332 void vBase::AddValue(vAttrPtr &attr, const char *value)
00333 {
00334 //      Trace trace("vBase::AddValue");
00335         if( !attr.Get() ) {
00336 //              trace.log("attribute pointer contains no data, skipping");
00337                 return;
00338         }
00339 /*
00340         if( strlen(value) == 0 ) {
00341                 trace.log("attribute value is empty, skipping");
00342                 return;
00343         }
00344 */
00345         b_vformat_attribute_add_value(attr.Get(), value);
00346 }
00347 
00348 void vBase::AddEncodedValue(vAttrPtr &attr, b_VFormatEncoding encoding, const char *value, int len)
00349 {
00350 //      Trace trace("vBase::AddValue");
00351         if( !attr.Get() ) {
00352 //              trace.log("attribute pointer contains no data, skipping");
00353                 return;
00354         }
00355 
00356         attr.Get()->encoding = encoding;
00357         attr.Get()->encoding_set = TRUE;
00358 
00359         b_vformat_attribute_add_value_decoded(attr.Get(), value, len);
00360 }
00361 
00362 void vBase::AddParam(vAttrPtr &attr, const char *name, const char *value)
00363 {
00364 //      Trace trace("vBase::AddParam");
00365 
00366         if( !attr.Get() ) {
00367 //              trace.log("attribute pointer contains no data, skipping");
00368                 return;
00369         }
00370 /*
00371         if( strlen(value) == 0 ) {
00372                 trace.log("parameter value is empty, skipping");
00373                 return;
00374         }
00375 */
00376 
00377         b_VFormatParam *pParam = b_vformat_attribute_param_new(name);
00378         b_vformat_attribute_param_add_value(pParam, value);
00379         b_vformat_attribute_add_param(attr.Get(), pParam);
00380 }
00381 
00382 void vBase::AddCategories(const Barry::CategoryList &categories)
00383 {
00384         if( !categories.size() )
00385                 return;
00386 
00387         vAttrPtr cat = NewAttr("CATEGORIES");           // RFC 2426, 3.6.1
00388         Barry::CategoryList::const_iterator i = categories.begin();
00389         for( ; i < categories.end(); ++i ) {
00390                 AddValue(cat, i->c_str());
00391         }
00392         AddAttr(cat);
00393 }
00394 
00395 std::string vBase::GetAttr(const char *attrname, const char *block)
00396 {
00397 //      Trace trace("vBase::GetAttr");
00398 //      trace.logf("getting attr: %s", attrname);
00399 
00400         std::string ret;
00401         const char *value = 0;
00402 
00403         bool needs_freeing = false;
00404 
00405         b_VFormatAttribute *attr = b_vformat_find_attribute(m_format, attrname, 0, block);
00406         if( attr ) {
00407                 if( b_vformat_attribute_is_single_valued(attr) ) {
00408                         value = b_vformat_attribute_get_value(attr);
00409                         needs_freeing = true;
00410                 }
00411                 else {
00412                         // FIXME, this is hardcoded
00413                         value = b_vformat_attribute_get_nth_value(attr, 0);
00414                 }
00415         }
00416 
00417         if( value )
00418                 ret = value;
00419 
00420         if( needs_freeing )
00421                 g_free((char *)value);
00422 
00423 //      trace.logf("attr value: %s", ret.c_str());
00424         return ret;
00425 }
00426 
00427 std::vector<std::string> vBase::GetValueVector(const char *attrname, const char *block)
00428 {
00429 //      Trace trace("vBase::GetValueVector");
00430 //      trace.logf("getting value vector for: %s", attrname);
00431 
00432         std::vector<std::string> ret;
00433         const char *value = 0;
00434         bool needs_freeing = false;
00435 
00436         b_VFormatAttribute *attr = b_vformat_find_attribute(m_format, attrname, 0, block);
00437         if( attr ) {
00438                 if( b_vformat_attribute_is_single_valued(attr) ) {
00439                         value = b_vformat_attribute_get_value(attr);
00440                         needs_freeing = true;
00441                 } else {
00442                         // nasty, but avoids tweaking vformat.
00443                         int idx = 0;
00444                         do {
00445                                 value = b_vformat_attribute_get_nth_value(attr, idx++);
00446                                 if( value ) {
00447                                         ret.push_back(value);
00448                                 }
00449                         } while( value );
00450                 }
00451         }
00452 
00453         if( needs_freeing )
00454                 g_free((char *)value);
00455 
00456         return ret;
00457 }
00458 
00459 vAttr vBase::GetAttrObj(const char *attrname, int nth, const char *block)
00460 {
00461 //      Trace trace("vBase::GetAttrObj");
00462 //      trace.logf("getting attr: %s", attrname);
00463 
00464         return vAttr(b_vformat_find_attribute(m_format, attrname, nth, block));
00465 }
00466 
00467 std::vector<std::string> vBase::Tokenize(const std::string& str, const char delim)
00468 {
00469         std::vector<std::string> tokens;
00470         std::string::size_type delimPos = 0, tokenPos = 0, pos = 0;
00471 
00472         if( str.length() < 1 ) {
00473                 return tokens;
00474         }
00475 
00476         while( 1 ) {
00477                 delimPos = str.find_first_of(delim, pos);
00478                 tokenPos = str.find_first_not_of(delim, pos);
00479 
00480                 if( std::string::npos != delimPos ) {
00481                         if( std::string::npos != tokenPos ) {
00482                                 if( tokenPos < delimPos ) {
00483                                         tokens.push_back(str.substr(pos, delimPos-pos));
00484                                 } else {
00485                                         tokens.push_back("");
00486                                 }
00487                         } else {
00488                                 tokens.push_back("");
00489                         }
00490                         pos = delimPos + 1;
00491                 } else {
00492                         if( std::string::npos != tokenPos ){
00493                                 tokens.push_back(str.substr(pos));
00494                         } else {
00495                                 tokens.push_back("");
00496                         }
00497                         break;
00498                 }
00499         }
00500         return tokens;
00501 }
00502 
00503 std::string vBase::ToStringList(const std::vector<std::string> &list, const char delim)
00504 {
00505         std::string str;
00506         for( unsigned int idx = 0; idx < list.size(); idx++ ) {
00507                 if( idx ) {
00508                         str += delim;
00509                 }
00510                 str += list[idx];
00511         }
00512         return str;
00513 }
00514 
00515 }} // namespace Barry::Sync
00516