vevent.cc

00001 //
00002 // \file        vevent.cc
00003 //              Conversion routines for vevents (VCALENDAR, etc)
00004 //
00005 
00006 /*
00007     Copyright (C) 2006-2010, Net Direct Inc. (http://www.netdirect.ca/)
00008     Copyright (C) 2010, Nicolas VIVIEN
00009     Copyright (C) 2009, Dr J A Gow <J.A.Gow@wellfrazzled.com>
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 "vevent.h"
00025 //#include "trace.h"
00026 #include <stdint.h>
00027 #include <glib.h>
00028 #include <strings.h>
00029 #include <stdlib.h>
00030 #include <sstream>
00031 #include <string>
00032 
00033 using namespace std;
00034 
00035 namespace Barry { namespace Sync {
00036 
00037 //////////////////////////////////////////////////////////////////////////////
00038 // vCalendar
00039 
00040 vCalendar::vCalendar(vTimeConverter &vtc)
00041         : m_vtc(vtc)
00042         , m_gCalData(0)
00043 {
00044 }
00045 
00046 vCalendar::~vCalendar()
00047 {
00048         if( m_gCalData ) {
00049                 g_free(m_gCalData);
00050         }
00051 }
00052 
00053 const char *vCalendar::WeekDays[] = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" };
00054 
00055 unsigned short vCalendar::GetWeekDayIndex(const char *dayname)
00056 {
00057         for( int i = 0; i < 7; i++ ) {
00058                 if( strcasecmp(dayname, WeekDays[i]) == 0 )
00059                         return i;
00060         }
00061         return 0;
00062 }
00063 
00064 unsigned short vCalendar::GetMonthWeekNumFromBYDAY(const std::string& ByDay)
00065 {
00066         return atoi(ByDay.substr(0,ByDay.length()-2).c_str());
00067 }
00068 
00069 unsigned short vCalendar::GetWeekDayIndexFromBYDAY(const std::string& ByDay)
00070 {
00071         return GetWeekDayIndex(ByDay.substr(ByDay.length()-2).c_str());
00072 }
00073 
00074 
00075 bool vCalendar::HasMultipleVEvents() const
00076 {
00077         int count = 0;
00078         b_VFormat *format = const_cast<b_VFormat*>(Format());
00079         GList *attrs = format ? b_vformat_get_attributes(format) : 0;
00080         for( ; attrs; attrs = attrs->next ) {
00081                 b_VFormatAttribute *attr = (b_VFormatAttribute*) attrs->data;
00082                 if( strcasecmp(b_vformat_attribute_get_name(attr), "BEGIN") == 0 &&
00083                     strcasecmp(b_vformat_attribute_get_nth_value(attr, 0), "VEVENT") == 0 )
00084                 {
00085                         count++;
00086                 }
00087         }
00088         return count > 1;
00089 }
00090 
00091 void vCalendar::RecurToVCal()
00092 {
00093         using namespace Barry;
00094         using namespace std;
00095         Barry::Calendar &cal = m_BarryCal;
00096 
00097         if( !cal.Recurring )
00098                 return;
00099 
00100         vAttrPtr attr = NewAttr("RRULE");
00101 
00102         switch( cal.RecurringType )
00103         {
00104         case Calendar::Day:             // eg. every day
00105                 AddValue(attr,"FREQ=DAILY");
00106                 break;
00107 
00108         case Calendar::MonthByDate:     // eg. every month on the 12th
00109                                         // see: DayOfMonth
00110                 AddValue(attr,"FREQ=MONTHLY");
00111                 {
00112                         ostringstream oss;
00113                         oss << "BYMONTHDAY=" << cal.DayOfMonth;
00114                         AddValue(attr, oss.str().c_str());
00115                 }
00116                 break;
00117 
00118         case Calendar::MonthByDay:      // eg. every month on 3rd Wed
00119                                         // see: DayOfWeek and WeekOfMonth
00120                 AddValue(attr, "FREQ=MONTHLY");
00121                 if( cal.DayOfWeek <= 6 ) {      // DayOfWeek is unsigned
00122                         ostringstream oss;
00123                         oss << "BYDAY=" << cal.WeekOfMonth << WeekDays[cal.DayOfWeek];
00124                         AddValue(attr, oss.str().c_str());
00125                 }
00126                 break;
00127 
00128         case Calendar::YearByDate:      // eg. every year on March 5
00129                                         // see: DayOfMonth and MonthOfYear
00130                 AddValue(attr, "FREQ=YEARLY");
00131                 {
00132                         ostringstream oss;
00133                         oss << "BYMONTH=" << cal.MonthOfYear;
00134                         AddValue(attr, oss.str().c_str());
00135                 }
00136                 {
00137                         ostringstream oss;
00138                         oss << "BYMONTHDAY=" << cal.DayOfMonth;
00139                         AddValue(attr, oss.str().c_str());
00140                 }
00141                 break;
00142 
00143         case Calendar::YearByDay:       // eg. every year on 3rd Wed of Jan
00144                                         // see: DayOfWeek, WeekOfMonth, and
00145                                         //      MonthOfYear
00146                 AddValue(attr, "FREQ=YEARLY");
00147                 if( cal.DayOfWeek <= 6 ) {      // DayOfWeek is unsigned
00148                         ostringstream oss;
00149                         oss << "BYDAY=" << cal.WeekOfMonth << WeekDays[cal.DayOfWeek];
00150                         AddValue(attr, oss.str().c_str());
00151 
00152                         oss.str("");
00153                         oss << "BYMONTH=" << cal.MonthOfYear;
00154                         AddValue(attr, oss.str().c_str());
00155                 }
00156                 break;
00157 
00158         case Calendar::Week:            // eg. every week on Mon and Fri
00159                                         // see: WeekDays
00160                 AddValue(attr, "FREQ=WEEKLY");
00161                 {
00162                         ostringstream oss;
00163                         oss << "BYDAY=";
00164                         for( int i = 0, bm = 1, cnt = 0; i < 7; i++, bm <<= 1 ) {
00165                                 if( cal.WeekDays & bm ) {
00166                                         if( cnt )
00167                                                 oss << ",";
00168                                         oss << WeekDays[i];
00169                                         cnt++;
00170                                 }
00171                         }
00172                         AddValue(attr, oss.str().c_str());
00173                 }
00174                 break;
00175 
00176         default:
00177                 throw ConvertError("Unknown RecurringType in Barry Calendar object");
00178         }
00179 
00180         // add some common parameters
00181         if( cal.Interval > 1 ) {
00182                 ostringstream oss;
00183                 oss << "INTERVAL=" << cal.Interval;
00184                 AddValue(attr, oss.str().c_str());
00185         }
00186         if( !cal.Perpetual ) {
00187                 ostringstream oss;
00188                 oss << "UNTIL=" << m_vtc.unix2vtime(&cal.RecurringEndTime);
00189                 AddValue(attr, oss.str().c_str());
00190         }
00191 
00192         AddAttr(attr);
00193 
00194 /*
00195         bool AllDayEvent;
00196 
00197         ///
00198         /// Recurring data
00199         ///
00200         /// Note: interval can be used on all of these recurring types to
00201         ///       make it happen "every other time" or more, etc.
00202         ///
00203 
00204         bool Recurring;
00205         RecurringCodeType RecurringType;
00206         unsigned short Interval;        // must be >= 1
00207         time_t RecurringEndTime;        // only pertains if Recurring is true
00208                                         // sets the date and time when
00209                                         // recurrence of this appointment
00210                                         // should no longer occur
00211                                         // If a perpetual appointment, this
00212                                         // is 0xFFFFFFFF in the low level data
00213                                         // Instead, set the following flag.
00214         bool Perpetual;                 // if true, this will always recur
00215         unsigned short TimeZoneCode;    // the time zone originally used
00216                                         // for the recurrence data...
00217                                         // seems to have little use, but
00218                                         // set to your current time zone
00219                                         // as a good default
00220 
00221         unsigned short                  // recurring details, depending on type
00222                 DayOfWeek,              // 0-6
00223                 WeekOfMonth,            // 1-5
00224                 DayOfMonth,             // 1-31
00225                 MonthOfYear;            // 1-12
00226         unsigned char WeekDays;         // bitmask, bit 0 = sunday
00227 
00228                 #define CAL_WD_SUN      0x01
00229                 #define CAL_WD_MON      0x02
00230                 #define CAL_WD_TUE      0x04
00231                 #define CAL_WD_WED      0x08
00232                 #define CAL_WD_THU      0x10
00233                 #define CAL_WD_FRI      0x20
00234                 #define CAL_WD_SAT      0x40
00235 
00236 */
00237 
00238 }
00239 
00240 void vCalendar::RecurToBarryCal(vAttr& rrule, time_t starttime)
00241 {
00242         using namespace Barry;
00243         using namespace std;
00244         Barry::Calendar &cal = m_BarryCal;
00245 //      Trace trace("vCalendar::RecurToBarryCal");
00246         std::map<std::string,unsigned char> pmap;
00247         pmap["SU"] = CAL_WD_SUN;
00248         pmap["MO"] = CAL_WD_MON;
00249         pmap["TU"] = CAL_WD_TUE;
00250         pmap["WE"] = CAL_WD_WED;
00251         pmap["TH"] = CAL_WD_THU;
00252         pmap["FR"] = CAL_WD_FRI;
00253         pmap["SA"] = CAL_WD_SAT;
00254 
00255 
00256         int i=0;
00257         unsigned int count=0;
00258         string val;
00259         std::map<std::string,std::string> args;
00260         do {
00261                 val=rrule.GetValue(i++);
00262                 if(val.length()==0) {
00263                         break;
00264                 }
00265                 string n=val.substr(0,val.find("="));
00266                 string v=val.substr(val.find("=")+1);
00267                 args[n]=v;
00268 //              trace.logf("RecurToBarryCal: |%s|%s|",n.c_str(),v.c_str());
00269         } while(1);
00270 
00271         // now process the interval.
00272         cal.Recurring=TRUE;
00273 
00274         if(args.find(string("INTERVAL"))!=args.end()) {
00275                 cal.Interval = atoi(args["INTERVAL"].c_str());
00276         }
00277         if(args.find(string("UNTIL"))!=args.end()) {
00278                 cal.Perpetual = FALSE;
00279                 cal.RecurringEndTime=m_vtc.vtime2unix(args["UNTIL"].c_str());
00280                 if( cal.RecurringEndTime == (time_t)-1 ) {
00281 //                      trace.logf("osync_time_vtime2unix() failed: UNTIL = %s, zoneoffset = %d", args["UNTIL"].c_str(), zoneoffset);
00282                 }
00283         } else {
00284                 // if we do not also have COUNT, then we must be forerver
00285                 if(args.find(string("COUNT"))==args.end()) {
00286                         cal.Perpetual=TRUE;
00287                 } else {
00288                         // we do have COUNT. This means we won't have UNTIL.
00289                         // So we need to process the RecurringEndTime from
00290                         // the current start date. Set the count level to
00291                         // something other than zero to indicate we need
00292                         // to process it as the exact end date will
00293                         // depend upon the frequency.
00294                         count=atoi(args["COUNT"].c_str());
00295                         if( count == 0 ) {
00296                                 throw std::runtime_error("Invalid COUNT in recurring rule: " + args["COUNT"]);
00297                         }
00298                 }
00299         }
00300 
00301         // we need these if COUNT is true, or if we are a yearly job.
00302 
00303         // TO-DO: we must process COUNT in terms of an end date if we have it.
00304 
00305         // Now deal with the freq
00306 
00307         if(args.find(string("FREQ"))==args.end()) {
00308 //              trace.logf("RecurToBarryCal: No frequency specified!");
00309                 return;
00310         }
00311 
00312         if(args["FREQ"]==string("DAILY")) {
00313                 cal.RecurringType=Calendar::Day;
00314 
00315         } else if(args["FREQ"]==string("WEEKLY")) {
00316                 cal.RecurringType=Calendar::Week;
00317                 // we must have a dayofweek entry
00318                 if(args.find(string("BYDAY"))!=args.end()) {
00319                         std::vector<std::string> v=Tokenize(args["BYDAY"]);
00320                         // iterate along our vector and convert
00321                         for(unsigned int idx=0;idx<v.size();idx++) {
00322                                 cal.WeekDays|=pmap[v[idx]];
00323                         }
00324                 } else {
00325                         // handle error here
00326 //                      trace.logf("RecurToBarryCal: no BYDAY on weekly event");
00327                 }
00328                 if(count) {
00329                         // need to process end date. This is easy
00330                         // for weeks, as a number of weeks can be
00331                         // reduced to seconds simply.
00332                         cal.RecurringEndTime=starttime +((count-1)*60*60*24*7);
00333                 }
00334         } else if(args["FREQ"]=="MONTHLY") {
00335                 if(args.find(string("BYMONTHDAY"))!=args.end()) {
00336                         cal.RecurringType=Calendar::MonthByDate;
00337                         cal.DayOfMonth=atoi(args["BYMONTHDAY"].c_str());
00338                 } else {
00339                         if(args.find(string("BYDAY"))!=args.end()) {
00340                                 cal.RecurringType=Calendar::MonthByDay;
00341                                 cal.WeekOfMonth=GetMonthWeekNumFromBYDAY(args["BYDAY"]);
00342                                 cal.DayOfWeek=GetWeekDayIndexFromBYDAY(args["BYDAY"]);
00343                         } else {
00344 //                              trace.logf("RecurToBarryCal: No qualifier on MONTHLY freq");
00345                         }
00346                 }
00347                 if(count) {
00348                         // Nasty. We need to convert to struct tm,
00349                         // do some modulo-12 addition then back
00350                         // to time_t
00351                         struct tm datestruct;
00352                         localtime_r(&starttime,&datestruct);
00353                         // now do some modulo-12 on the month and year
00354                         // We could end up with an illegal date if
00355                         // the day of month is >28 and the resulting
00356                         // month falls on a February. We don't need
00357                         // to worry about day of week as mktime()
00358                         // clobbers it.
00359                         datestruct.tm_year += (datestruct.tm_mon+count)/12;
00360                         datestruct.tm_mon = (datestruct.tm_mon+count)%12;
00361                         if(datestruct.tm_mday>28 && datestruct.tm_mon==1) {
00362                                 // force it to 1st Mar
00363                                 // TODO Potential bug on leap years
00364                                 datestruct.tm_mon=2;
00365                                 datestruct.tm_mday=1;
00366                         }
00367                         if(datestruct.tm_mday==31 && (datestruct.tm_mon==8 ||
00368                                                       datestruct.tm_mon==3 ||
00369                                                       datestruct.tm_mon==5 ||
00370                                                                                   datestruct.tm_mon==10)) {
00371                                 datestruct.tm_mon+=1;
00372                                 datestruct.tm_mday=1;
00373                         }
00374                         cal.RecurringEndTime=mktime(&datestruct);
00375                 }
00376         } else if(args["FREQ"]=="YEARLY") {
00377                 if(args.find(string("BYMONTH"))!=args.end()) {
00378                         cal.MonthOfYear=atoi(args["BYMONTH"].c_str());
00379                         if(args.find(string("BYMONTHDAY"))!=args.end()) {
00380                                 cal.RecurringType=Calendar::YearByDate;
00381                                 cal.DayOfMonth=atoi(args["BYMONTHDAY"].c_str());
00382                         } else {
00383                                 if(args.find(string("BYDAY"))!=args.end()) {
00384                                         cal.RecurringType=Calendar::YearByDay;
00385                                         cal.WeekOfMonth=GetMonthWeekNumFromBYDAY(args["BYDAY"]);
00386                                         cal.DayOfWeek=GetWeekDayIndexFromBYDAY(args["BYDAY"]);
00387                                 } else {
00388 //                                      trace.logf("RecurToBarryCal: No qualifier on YEARLY freq");
00389                                 }
00390                         }
00391                 } else {
00392                         // otherwise use the start date and translate
00393                         // to a BYMONTHDAY.
00394                         // cal.StartTime has already been processed
00395                         // when we get here we need month of year,
00396                         // and day of month.
00397                         struct tm datestruct;
00398                         localtime_r(&starttime,&datestruct);
00399                         cal.RecurringType=Calendar::YearByDate;
00400                         cal.MonthOfYear=datestruct.tm_mon;
00401                         cal.DayOfMonth=datestruct.tm_mday;
00402                 }
00403                 if(count) {
00404                         // convert to struct tm, then simply add to the year.
00405                         struct tm datestruct;
00406                         localtime_r(&starttime,&datestruct);
00407                         datestruct.tm_year += count;
00408                         cal.RecurringEndTime=mktime(&datestruct);
00409                 }
00410         }
00411 
00412 //      unsigned char WeekDays;         // bitmask, bit 0 = sunday
00413 //
00414 //              #define CAL_WD_SUN      0x01
00415 //              #define CAL_WD_MON      0x02
00416 //              #define CAL_WD_TUE      0x04
00417 //              #define CAL_WD_WED      0x08
00418 //              #define CAL_WD_THU      0x10
00419 //              #define CAL_WD_FRI      0x20
00420 //              #define CAL_WD_SAT      0x40
00421 }
00422 
00423 // Main conversion routine for converting from Barry::Calendar to
00424 // a vCalendar string of data.
00425 const std::string& vCalendar::ToVCal(const Barry::Calendar &cal)
00426 {
00427 //      Trace trace("vCalendar::ToVCal");
00428         std::ostringstream oss;
00429         cal.Dump(oss);
00430 //      trace.logf("ToVCal, initial Barry record: %s", oss.str().c_str());
00431 
00432         // start fresh
00433         Clear();
00434         SetFormat( b_vformat_new() );
00435         if( !Format() )
00436                 throw ConvertError("resource error allocating vformat");
00437 
00438         // store the Barry object we're working with
00439         m_BarryCal = cal;
00440 
00441         // begin building vCalendar data
00442         AddAttr(NewAttr("PRODID", "-//OpenSync//NONSGML Barry Calendar Record//EN"));
00443         AddAttr(NewAttr("BEGIN", "VEVENT"));
00444         AddAttr(NewAttr("SEQUENCE", "0"));
00445         AddAttr(NewAttr("SUMMARY", cal.Subject.c_str()));
00446         AddAttr(NewAttr("DESCRIPTION", cal.Notes.c_str()));
00447         AddAttr(NewAttr("LOCATION", cal.Location.c_str()));
00448 
00449         string start(m_vtc.unix2vtime(&cal.StartTime));
00450         string end(m_vtc.unix2vtime(&cal.EndTime));
00451         string notify(m_vtc.unix2vtime(&cal.NotificationTime));
00452 
00453         AddAttr(NewAttr("DTSTART", start.c_str()));
00454         AddAttr(NewAttr("DTEND", end.c_str()));
00455         // FIXME - add a truly globally unique "UID" string?
00456 
00457 
00458         AddAttr(NewAttr("BEGIN", "VALARM"));
00459         AddAttr(NewAttr("ACTION", "AUDIO"));
00460 
00461         // notify must be UTC, when specified in DATE-TIME
00462         vAttrPtr trigger = NewAttr("TRIGGER", notify.c_str());
00463         AddParam(trigger, "VALUE", "DATE-TIME");
00464         AddAttr(trigger);
00465 
00466         AddAttr(NewAttr("END", "VALARM"));
00467 
00468 
00469         if( cal.Recurring ) {
00470                 RecurToVCal();
00471         }
00472 
00473         AddAttr(NewAttr("END", "VEVENT"));
00474 
00475         // generate the raw VCALENDAR data
00476         m_gCalData = b_vformat_to_string(Format(), VFORMAT_EVENT_20);
00477         m_vCalData = m_gCalData;
00478 
00479 //      trace.logf("ToVCal, resulting vcal data: %s", m_vCalData.c_str());
00480         return m_vCalData;
00481 }
00482 
00483 // Main conversion routine for converting from vCalendar data string
00484 // to a Barry::Calendar object.
00485 const Barry::Calendar& vCalendar::ToBarry(const char *vcal, uint32_t RecordId)
00486 {
00487         using namespace std;
00488 
00489 //      Trace trace("vCalendar::ToBarry");
00490 //      trace.logf("ToBarry, working on vcal data: %s", vcal);
00491 
00492         // we only handle vCalendar data with one vevent block
00493         if( HasMultipleVEvents() )
00494                 throw ConvertError("vCalendar data contains more than one VEVENT block, unsupported");
00495 
00496         // start fresh
00497         Clear();
00498 
00499         // store the vCalendar raw data
00500         m_vCalData = vcal;
00501 
00502         // create format parser structures
00503         SetFormat( b_vformat_new_from_string(vcal) );
00504         if( !Format() )
00505                 throw ConvertError("resource error allocating vformat");
00506 
00507         string start = GetAttr("DTSTART", "/vevent");
00508 //      trace.logf("DTSTART attr retrieved: %s", start.c_str());
00509         string end = GetAttr("DTEND", "/vevent");
00510 //      trace.logf("DTEND attr retrieved: %s", end.c_str());
00511         string subject = GetAttr("SUMMARY", "/vevent");
00512 //      trace.logf("SUMMARY attr retrieved: %s", subject.c_str());
00513         if( subject.size() == 0 ) {
00514                 subject = "<blank subject>";
00515 //              trace.logf("ERROR: bad data, blank SUMMARY: %s", vcal);
00516         }
00517         vAttr trigger_obj = GetAttrObj("TRIGGER", 0, "/valarm");
00518 
00519         string location = GetAttr("LOCATION", "/vevent");
00520 //      trace.logf("LOCATION attr retrieved: %s", location.c_str());
00521 
00522         string notes = GetAttr("DESCRIPTION", "/vevent");
00523 //      trace.logf("DESCRIPTION attr retrieved: %s", notes.c_str());
00524 
00525         vAttr rrule = GetAttrObj("RRULE",0,"/vevent");
00526 
00527 
00528         //
00529         // Now, run checks and convert into Barry object
00530         //
00531 
00532 
00533         // FIXME - we are assuming that any non-UTC timestamps
00534         // in the vcalendar record will be in the current timezone...
00535         // This is wrong!  fix this later.
00536         //
00537         // Also, we currently ignore any time zone
00538         // parameters that might be in the vcalendar format... this
00539         // must be fixed.
00540         //
00541         Barry::Calendar &rec = m_BarryCal;
00542         rec.SetIds(Barry::Calendar::GetDefaultRecType(), RecordId);
00543 
00544         if( !start.size() )
00545                 throw ConvertError("Blank DTSTART");
00546         rec.StartTime = m_vtc.vtime2unix(start.c_str());
00547 
00548         if( !end.size() ) {
00549                 // DTEND is actually optional!  According to the
00550                 // RFC, a DTSTART with no DTEND should be treated
00551                 // like a "special day" like an anniversary, which occupies
00552                 // no time.
00553                 //
00554                 // Since the Blackberry doesn't really map well to this
00555                 // case, we'll set the end time to 1 day past start.
00556                 //
00557                 rec.EndTime = rec.StartTime + 24 * 60 * 60;
00558         }
00559         else {
00560                 rec.EndTime = m_vtc.vtime2unix(end.c_str());
00561         }
00562 
00563         rec.Subject = subject;
00564         rec.Location = location;
00565         rec.Notes = notes;
00566 
00567         if(rrule.Get()) {
00568                 RecurToBarryCal(rrule, rec.StartTime);
00569         }
00570 
00571         // convert trigger time into notification time
00572         // assume no notification, by default
00573         rec.NotificationTime = 0;
00574         if( trigger_obj.Get() ) {
00575                 string trigger_type = trigger_obj.GetParam("VALUE");
00576                 string trigger = trigger_obj.GetValue();
00577 
00578                 if( trigger.size() == 0 ) {
00579 //                      trace.logf("ERROR: no TRIGGER found in calendar entry, assuming notification time as 15 minutes before start.");
00580                 }
00581                 else if( trigger_type == "DATE-TIME" ) {
00582                         rec.NotificationTime = m_vtc.vtime2unix(trigger.c_str());
00583                 }
00584                 else if( trigger_type == "DURATION" || trigger_type.size() == 0 ) {
00585                         // default is DURATION (RFC 4.8.6.3)
00586                         string related = trigger_obj.GetParam("RELATED");
00587 
00588                         // default to relative to start time
00589                         time_t *relative = &rec.StartTime;
00590                         if( related == "END" )
00591                                 relative = &rec.EndTime;
00592 
00593                         rec.NotificationTime = *relative + m_vtc.alarmduration2sec(trigger.c_str());
00594                 }
00595                 else {
00596                         throw ConvertError("Unknown TRIGGER VALUE");
00597                 }
00598         }
00599         else {
00600 //              trace.logf("ERROR: no TRIGGER found in calendar entry, assuming notification time as 15 minutes before start.");
00601         }
00602 
00603         std::ostringstream oss;
00604         m_BarryCal.Dump(oss);
00605 //      trace.logf("ToBarry, resulting Barry record: %s", oss.str().c_str());
00606         return m_BarryCal;
00607 }
00608 
00609 // Transfers ownership of m_gCalData to the caller.
00610 char* vCalendar::ExtractVCal()
00611 {
00612         char *ret = m_gCalData;
00613         m_gCalData = 0;
00614         return ret;
00615 }
00616 
00617 void vCalendar::Clear()
00618 {
00619         vBase::Clear();
00620         m_vCalData.clear();
00621         m_BarryCal.Clear();
00622 
00623         if( m_gCalData ) {
00624                 g_free(m_gCalData);
00625                 m_gCalData = 0;
00626         }
00627 }
00628 
00629 }} // namespace Barry::Sync
00630 
Generated by  doxygen 1.6.2-20100208