diff --git a/kcal/vcalformat.cpp b/kcal/vcalformat.cpp index 31aa30264..8d73fc1eb 100644 --- a/kcal/vcalformat.cpp +++ b/kcal/vcalformat.cpp @@ -1,1674 +1,1674 @@ /* This file is part of the kcal library. Copyright (c) 1998 Preston Brown Copyright (c) 2001 Cornelius Schumacher This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @file This file is part of the API for handling calendar data and defines the VCalFormat base class. This class implements the vCalendar format. It provides methods for loading/saving/converting vCalendar format data into the internal representation as Calendar and Incidences. @brief vCalendar format implementation. @author Preston Brown \ @author Cornelius Schumacher \ */ #include "vcalformat.h" #include "calendar.h" #include "versit/vcc.h" #include "versit/vobject.h" #include #include #include #include #include #include #include #include using namespace KCal; /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class KCal::VCalFormat::Private { public: Calendar *mCalendar; Event::List mEventsRelate; // Events with relations Todo::List mTodosRelate; // To-dos with relations }; //@endcond VCalFormat::VCalFormat() : d( new KCal::VCalFormat::Private ) { } VCalFormat::~VCalFormat() { delete d; } bool VCalFormat::load( Calendar *calendar, const QString &fileName ) { d->mCalendar = calendar; clearException(); kDebug() << fileName; VObject *vcal = 0; // this is not necessarily only 1 vcal. Could be many vcals, or include // a vcard... vcal = Parse_MIME_FromFileName( const_cast( QFile::encodeName( fileName ).data() ) ); if ( !vcal ) { setException( new ErrorFormat( ErrorFormat::CalVersionUnknown ) ); return false; } // any other top-level calendar stuff should be added/initialized here // put all vobjects into their proper places populate( vcal ); // clean up from vcal API stuff cleanVObjects( vcal ); cleanStrTbl(); return true; } bool VCalFormat::save( Calendar *calendar, const QString &fileName ) { d->mCalendar = calendar; QString tmpStr; VObject *vcal, *vo; kDebug() << fileName; vcal = newVObject( VCCalProp ); // addPropValue(vcal,VCLocationProp, "0.0"); addPropValue( vcal, VCProdIdProp, productId().toLatin1() ); addPropValue( vcal, VCVersionProp, _VCAL_VERSION ); // TODO STUFF Todo::List todoList = d->mCalendar->rawTodos(); Todo::List::ConstIterator it; for ( it = todoList.constBegin(); it != todoList.constEnd(); ++it ) { vo = eventToVTodo( *it ); addVObjectProp( vcal, vo ); } // EVENT STUFF Event::List events = d->mCalendar->rawEvents(); Event::List::ConstIterator it2; for ( it2 = events.constBegin(); it2 != events.constEnd(); ++it2 ) { vo = eventToVEvent( *it2 ); addVObjectProp( vcal, vo ); } writeVObjectToFile( QFile::encodeName( fileName ).data(), vcal ); cleanVObjects( vcal ); cleanStrTbl(); if ( QFile::exists( fileName ) ) { return true; } else { return false; // error } return false; } bool VCalFormat::fromString( Calendar *calendar, const QString &text ) { return fromRawString( calendar, text.toUtf8() ); } bool VCalFormat::fromRawString( Calendar *calendar, const QByteArray &string ) { d->mCalendar = calendar; if ( !string.size() ) { return false; } VObject *vcal = Parse_MIME( string.data(), string.size() ); if ( !vcal ) { return false; } VObjectIterator i; VObject *curvo; initPropIterator( &i, vcal ); // we only take the first object. TODO: parse all incidences. do { curvo = nextVObject( &i ); } while ( strcmp( vObjectName( curvo ), VCEventProp ) && strcmp( vObjectName( curvo ), VCTodoProp ) ); if ( strcmp( vObjectName( curvo ), VCEventProp ) == 0 ) { Event *event = VEventToEvent( curvo ); calendar->addEvent( event ); } else { kDebug() << "Unknown object type."; deleteVObject( vcal ); return false; } deleteVObject( vcal ); return true; } QString VCalFormat::toString( Calendar *calendar ) { // TODO: Factor out VCalFormat::asString() d->mCalendar = calendar; VObject *vcal = newVObject( VCCalProp ); addPropValue( vcal, VCProdIdProp, CalFormat::productId().toLatin1() ); addPropValue( vcal, VCVersionProp, _VCAL_VERSION ); // TODO: Use all data. Event::List events = calendar->events(); if( events.isEmpty() ) { cleanVObject ( vcal ); return QString(); } Event *event = events.first(); if ( !event ) { cleanVObject ( vcal ); return QString(); } VObject *vevent = eventToVEvent( event ); addVObjectProp( vcal, vevent ); char *buf = writeMemVObject( 0, 0, vcal ); QString result( buf ); cleanVObject( vcal ); return result; } VObject *VCalFormat::eventToVTodo( const Todo *anEvent ) { VObject *vtodo; QString tmpStr; vtodo = newVObject( VCTodoProp ); // due date if ( anEvent->hasDueDate() ) { tmpStr = kDateTimeToISO( anEvent->dtDue(), !anEvent->allDay() ); addPropValue( vtodo, VCDueProp, tmpStr.toLocal8Bit() ); } // start date if ( anEvent->hasStartDate() ) { tmpStr = kDateTimeToISO( anEvent->dtStart(), !anEvent->allDay() ); addPropValue( vtodo, VCDTstartProp, tmpStr.toLocal8Bit() ); } // creation date tmpStr = kDateTimeToISO( anEvent->created() ); addPropValue( vtodo, VCDCreatedProp, tmpStr.toLocal8Bit() ); // unique id addPropValue( vtodo, VCUniqueStringProp, anEvent->uid().toLocal8Bit() ); // revision tmpStr.sprintf( "%i", anEvent->revision() ); addPropValue( vtodo, VCSequenceProp, tmpStr.toLocal8Bit() ); // last modification date tmpStr = kDateTimeToISO( anEvent->lastModified() ); addPropValue( vtodo, VCLastModifiedProp, tmpStr.toLocal8Bit() ); // organizer stuff // @TODO: How about the common name? if ( !anEvent->organizer().email().isEmpty() ) { tmpStr = "MAILTO:" + anEvent->organizer().email(); addPropValue( vtodo, ICOrganizerProp, tmpStr.toLocal8Bit() ); } // attendees if ( anEvent->attendeeCount() > 0 ) { Attendee::List::ConstIterator it; Attendee *curAttendee; for ( it = anEvent->attendees().begin(); it != anEvent->attendees().end(); ++it ) { curAttendee = *it; if ( !curAttendee->email().isEmpty() && !curAttendee->name().isEmpty() ) { tmpStr = "MAILTO:" + curAttendee->name() + " <" + curAttendee->email() + '>'; } else if ( curAttendee->name().isEmpty() ) { tmpStr = "MAILTO: " + curAttendee->email(); } else if ( curAttendee->email().isEmpty() ) { tmpStr = "MAILTO: " + curAttendee->name(); } else if ( curAttendee->name().isEmpty() && curAttendee->email().isEmpty() ) { kDebug() << "warning! this Event has an attendee w/o name or email!"; } VObject *aProp = addPropValue( vtodo, VCAttendeeProp, tmpStr.toLocal8Bit() ); addPropValue( aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE" ); addPropValue( aProp, VCStatusProp, writeStatus( curAttendee->status() ) ); } } // description BL: if ( !anEvent->description().isEmpty() ) { VObject *d = addPropValue( vtodo, VCDescriptionProp, anEvent->description().toLocal8Bit() ); if ( anEvent->description().indexOf( '\n' ) != -1 ) { addPropValue( d, VCEncodingProp, VCQuotedPrintableProp ); } } // summary if ( !anEvent->summary().isEmpty() ) { addPropValue( vtodo, VCSummaryProp, anEvent->summary().toLocal8Bit() ); } // location if ( !anEvent->location().isEmpty() ) { addPropValue( vtodo, VCLocationProp, anEvent->location().toLocal8Bit() ); } // completed status // backward compatibility, KOrganizer used to interpret only these two values addPropValue( vtodo, VCStatusProp, anEvent->isCompleted() ? "COMPLETED" : "NEEDS_ACTION" ); // completion date if ( anEvent->hasCompletedDate() ) { tmpStr = kDateTimeToISO( anEvent->completed() ); addPropValue( vtodo, VCCompletedProp, tmpStr.toLocal8Bit() ); } // priority tmpStr.sprintf( "%i", anEvent->priority() ); addPropValue( vtodo, VCPriorityProp, tmpStr.toLocal8Bit() ); // related event if ( anEvent->relatedTo() ) { addPropValue( vtodo, VCRelatedToProp, anEvent->relatedTo()->uid().toLocal8Bit() ); } // categories const QStringList tmpStrList = anEvent->categories(); tmpStr = ""; QString catStr; QStringList::const_iterator its; for ( its = tmpStrList.constBegin(); its != tmpStrList.constEnd(); ++its ) { catStr = *its; if ( catStr[0] == ' ' ) { tmpStr += catStr.mid( 1 ); } else { tmpStr += catStr; } // this must be a ';' character as the vCalendar specification requires! // vcc.y has been hacked to translate the ';' to a ',' when the vcal is // read in. tmpStr += ';'; } if ( !tmpStr.isEmpty() ) { tmpStr.truncate( tmpStr.length() - 1 ); addPropValue( vtodo, VCCategoriesProp, tmpStr.toLocal8Bit() ); } // alarm stuff Alarm::List::ConstIterator it; for ( it = anEvent->alarms().begin(); it != anEvent->alarms().end(); ++it ) { Alarm *alarm = *it; if ( alarm->enabled() ) { VObject *a = addProp( vtodo, VCDAlarmProp ); tmpStr = kDateTimeToISO( alarm->time() ); addPropValue( a, VCRunTimeProp, tmpStr.toLocal8Bit() ); addPropValue( a, VCRepeatCountProp, "1" ); addPropValue( a, VCDisplayStringProp, "beep!" ); if ( alarm->type() == Alarm::Audio ) { a = addProp( vtodo, VCAAlarmProp ); addPropValue( a, VCRunTimeProp, tmpStr.toLocal8Bit() ); addPropValue( a, VCRepeatCountProp, "1" ); addPropValue( a, VCAudioContentProp, QFile::encodeName( alarm->audioFile() ) ); } else if ( alarm->type() == Alarm::Procedure ) { a = addProp( vtodo, VCPAlarmProp ); addPropValue( a, VCRunTimeProp, tmpStr.toLocal8Bit() ); addPropValue( a, VCRepeatCountProp, "1" ); addPropValue( a, VCProcedureNameProp, QFile::encodeName( alarm->programFile() ) ); } } } QString pilotId = anEvent->nonKDECustomProperty( KPilotIdProp ); if ( !pilotId.isEmpty() ) { // pilot sync stuff addPropValue( vtodo, KPilotIdProp, pilotId.toLocal8Bit() ); addPropValue( vtodo, KPilotStatusProp, anEvent->nonKDECustomProperty( KPilotStatusProp ).toLocal8Bit() ); } return vtodo; } VObject *VCalFormat::eventToVEvent( const Event *anEvent ) { VObject *vevent; QString tmpStr; vevent = newVObject( VCEventProp ); // start and end time tmpStr = kDateTimeToISO( anEvent->dtStart(), !anEvent->allDay() ); addPropValue( vevent, VCDTstartProp, tmpStr.toLocal8Bit() ); // events that have time associated but take up no time should // not have both DTSTART and DTEND. if ( anEvent->dtStart() != anEvent->dtEnd() ) { tmpStr = kDateTimeToISO( anEvent->dtEnd(), !anEvent->allDay() ); addPropValue( vevent, VCDTendProp, tmpStr.toLocal8Bit() ); } // creation date tmpStr = kDateTimeToISO( anEvent->created() ); addPropValue( vevent, VCDCreatedProp, tmpStr.toLocal8Bit() ); // unique id addPropValue( vevent, VCUniqueStringProp, anEvent->uid().toLocal8Bit() ); // revision tmpStr.sprintf( "%i", anEvent->revision() ); addPropValue( vevent, VCSequenceProp, tmpStr.toLocal8Bit() ); // last modification date tmpStr = kDateTimeToISO( anEvent->lastModified() ); addPropValue( vevent, VCLastModifiedProp, tmpStr.toLocal8Bit() ); // attendee and organizer stuff // TODO: What to do with the common name? if ( !anEvent->organizer().email().isEmpty() ) { tmpStr = "MAILTO:" + anEvent->organizer().email(); addPropValue( vevent, ICOrganizerProp, tmpStr.toLocal8Bit() ); } // TODO: Put this functionality into Attendee class if ( anEvent->attendeeCount() > 0 ) { Attendee::List::ConstIterator it; for ( it = anEvent->attendees().constBegin(); it != anEvent->attendees().constEnd(); ++it ) { Attendee *curAttendee = *it; if ( !curAttendee->email().isEmpty() && !curAttendee->name().isEmpty() ) { tmpStr = "MAILTO:" + curAttendee->name() + " <" + curAttendee->email() + '>'; } else if ( curAttendee->name().isEmpty() ) { tmpStr = "MAILTO: " + curAttendee->email(); } else if ( curAttendee->email().isEmpty() ) { tmpStr = "MAILTO: " + curAttendee->name(); } else if ( curAttendee->name().isEmpty() && curAttendee->email().isEmpty() ) { kDebug() << "warning! this Event has an attendee w/o name or email!"; } VObject *aProp = addPropValue( vevent, VCAttendeeProp, tmpStr.toLocal8Bit() ); addPropValue( aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE" ); addPropValue( aProp, VCStatusProp, writeStatus( curAttendee->status() ) ); } } // recurrence rule stuff const Recurrence *recur = anEvent->recurrence(); if ( recur->recurs() ) { bool validRecur = true; QString tmpStr2; switch ( recur->recurrenceType() ) { case Recurrence::rDaily: tmpStr.sprintf( "D%i ", recur->frequency() ); break; case Recurrence::rWeekly: tmpStr.sprintf( "W%i ", recur->frequency() ); for ( int i = 0; i < 7; ++i ) { QBitArray days ( recur->days() ); if ( days.testBit(i) ) { tmpStr += dayFromNum( i ); } } break; case Recurrence::rMonthlyPos: { tmpStr.sprintf( "MP%i ", recur->frequency() ); // write out all rMonthPos's QList tmpPositions = recur->monthPositions(); for ( QList::ConstIterator posit = tmpPositions.constBegin(); posit != tmpPositions.constEnd(); ++posit ) { int pos = (*posit).pos(); tmpStr2.sprintf( "%i", ( pos > 0 ) ? pos : (-pos) ); if ( pos < 0 ) { tmpStr2 += "- "; } else { tmpStr2 += "+ "; } tmpStr += tmpStr2; tmpStr += dayFromNum( (*posit).day() - 1 ); } break; } case Recurrence::rMonthlyDay: { tmpStr.sprintf( "MD%i ", recur->frequency() ); // write out all rMonthDays; const QList tmpDays = recur->monthDays(); for ( QList::ConstIterator tmpDay = tmpDays.constBegin(); tmpDay != tmpDays.constEnd(); ++tmpDay ) { tmpStr2.sprintf( "%i ", *tmpDay ); tmpStr += tmpStr2; } break; } case Recurrence::rYearlyMonth: { tmpStr.sprintf( "YM%i ", recur->frequency() ); // write out all the months;' // TODO: Any way to write out the day within the month??? const QList months = recur->yearMonths(); for ( QList::ConstIterator mit = months.constBegin(); mit != months.constEnd(); ++mit ) { tmpStr2.sprintf( "%i ", *mit ); tmpStr += tmpStr2; } break; } case Recurrence::rYearlyDay: { tmpStr.sprintf( "YD%i ", recur->frequency() ); // write out all the rYearNums; const QList tmpDays = recur->yearDays(); for ( QList::ConstIterator tmpDay = tmpDays.begin(); tmpDay != tmpDays.end(); ++tmpDay ) { tmpStr2.sprintf( "%i ", *tmpDay ); tmpStr += tmpStr2; } break; } default: // TODO: Write rYearlyPos and arbitrary rules! kDebug() << "ERROR, it should never get here in eventToVEvent!"; validRecur = false; break; } // switch if ( recur->duration() > 0 ) { tmpStr2.sprintf( "#%i", recur->duration() ); tmpStr += tmpStr2; } else if ( recur->duration() == -1 ) { tmpStr += "#0"; // defined as repeat forever } else { tmpStr += kDateTimeToISO( recur->endDateTime(), false ); } // Only write out the rrule if we have a valid recurrence (i.e. a known // type in thee switch above) if ( validRecur ) { addPropValue( vevent, VCRRuleProp, tmpStr.toLocal8Bit() ); } } // event repeats // exceptions to recurrence DateList dateList = recur->exDates(); DateList::ConstIterator it; QString tmpStr2; for ( it = dateList.constBegin(); it != dateList.constEnd(); ++it ) { tmpStr = qDateToISO(*it) + ';'; tmpStr2 += tmpStr; } if ( !tmpStr2.isEmpty() ) { tmpStr2.truncate( tmpStr2.length() - 1 ); - addPropValue( vevent, VCExDateProp, tmpStr2.toLocal8Bit() ); + addPropValue( vevent, VCExpDateProp, tmpStr2.toLocal8Bit() ); } // description if ( !anEvent->description().isEmpty() ) { VObject *d = addPropValue( vevent, VCDescriptionProp, anEvent->description().toLocal8Bit() ); if ( anEvent->description().indexOf( '\n' ) != -1 ) { addPropValue( d, VCEncodingProp, VCQuotedPrintableProp ); } } // summary if ( !anEvent->summary().isEmpty() ) { addPropValue( vevent, VCSummaryProp, anEvent->summary().toLocal8Bit() ); } // location if ( !anEvent->location().isEmpty() ) { addPropValue( vevent, VCLocationProp, anEvent->location().toLocal8Bit() ); } // status // TODO: define Event status // addPropValue( vevent, VCStatusProp, anEvent->statusStr().toLocal8Bit() ); // secrecy const char *text = 0; switch ( anEvent->secrecy() ) { case Incidence::SecrecyPublic: text = "PUBLIC"; break; case Incidence::SecrecyPrivate: text = "PRIVATE"; break; case Incidence::SecrecyConfidential: text = "CONFIDENTIAL"; break; } if ( text ) { addPropValue( vevent, VCClassProp, text ); } // categories QStringList tmpStrList = anEvent->categories(); tmpStr = ""; QString catStr; for ( QStringList::const_iterator it = tmpStrList.constBegin(); it != tmpStrList.constEnd(); ++it ) { catStr = *it; if ( catStr[0] == ' ' ) { tmpStr += catStr.mid( 1 ); } else { tmpStr += catStr; } // this must be a ';' character as the vCalendar specification requires! // vcc.y has been hacked to translate the ';' to a ',' when the vcal is // read in. tmpStr += ';'; } if ( !tmpStr.isEmpty() ) { tmpStr.truncate( tmpStr.length() - 1 ); addPropValue( vevent, VCCategoriesProp, tmpStr.toLocal8Bit() ); } // attachments // TODO: handle binary attachments! Attachment::List attachments = anEvent->attachments(); Attachment::List::ConstIterator atIt; for ( atIt = attachments.constBegin(); atIt != attachments.constEnd(); ++atIt ) { addPropValue( vevent, VCAttachProp, (*atIt)->uri().toLocal8Bit() ); } // resources tmpStrList = anEvent->resources(); tmpStr = tmpStrList.join( ";" ); if ( !tmpStr.isEmpty() ) { addPropValue( vevent, VCResourcesProp, tmpStr.toLocal8Bit() ); } // alarm stuff Alarm::List::ConstIterator it2; for ( it2 = anEvent->alarms().constBegin(); it2 != anEvent->alarms().constEnd(); ++it2 ) { Alarm *alarm = *it2; if ( alarm->enabled() ) { VObject *a = addProp( vevent, VCDAlarmProp ); tmpStr = kDateTimeToISO( alarm->time() ); addPropValue( a, VCRunTimeProp, tmpStr.toLocal8Bit() ); addPropValue( a, VCRepeatCountProp, "1" ); addPropValue( a, VCDisplayStringProp, "beep!" ); if ( alarm->type() == Alarm::Audio ) { a = addProp( vevent, VCAAlarmProp ); addPropValue( a, VCRunTimeProp, tmpStr.toLocal8Bit() ); addPropValue( a, VCRepeatCountProp, "1" ); addPropValue( a, VCAudioContentProp, QFile::encodeName( alarm->audioFile() ) ); } if ( alarm->type() == Alarm::Procedure ) { a = addProp( vevent, VCPAlarmProp ); addPropValue( a, VCRunTimeProp, tmpStr.toLocal8Bit() ); addPropValue( a, VCRepeatCountProp, "1" ); addPropValue( a, VCProcedureNameProp, QFile::encodeName( alarm->programFile() ) ); } } } // priority tmpStr.sprintf( "%i", anEvent->priority() ); addPropValue( vevent, VCPriorityProp, tmpStr.toLocal8Bit() ); // transparency tmpStr.sprintf( "%i", anEvent->transparency() ); addPropValue( vevent, VCTranspProp, tmpStr.toLocal8Bit() ); // related event if ( anEvent->relatedTo() ) { addPropValue( vevent, VCRelatedToProp, anEvent->relatedTo()->uid().toLocal8Bit() ); } QString pilotId = anEvent->nonKDECustomProperty( KPilotIdProp ); if ( !pilotId.isEmpty() ) { // pilot sync stuff addPropValue( vevent, KPilotIdProp, pilotId.toLocal8Bit() ); addPropValue( vevent, KPilotStatusProp, anEvent->nonKDECustomProperty( KPilotStatusProp ).toLocal8Bit() ); } return vevent; } Todo *VCalFormat::VTodoToEvent( VObject *vtodo ) { VObject *vo; VObjectIterator voi; char *s; Todo *anEvent = new Todo; // creation date if ( ( vo = isAPropertyOf( vtodo, VCDCreatedProp ) ) != 0 ) { anEvent->setCreated( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); } // unique id vo = isAPropertyOf( vtodo, VCUniqueStringProp ); // while the UID property is preferred, it is not required. We'll use the // default Event UID if none is given. if ( vo ) { anEvent->setUid( s = fakeCString( vObjectUStringZValue( vo ) ) ); deleteStr( s ); } // last modification date if ( ( vo = isAPropertyOf( vtodo, VCLastModifiedProp ) ) != 0 ) { anEvent->setLastModified( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); } else { anEvent->setLastModified( KDateTime::currentUtcDateTime() ); } // organizer // if our extension property for the event's ORGANIZER exists, add it. if ( ( vo = isAPropertyOf( vtodo, ICOrganizerProp ) ) != 0 ) { anEvent->setOrganizer( s = fakeCString( vObjectUStringZValue( vo ) ) ); deleteStr( s ); } else { anEvent->setOrganizer( d->mCalendar->owner() ); } // attendees. initPropIterator( &voi, vtodo ); while ( moreIteration( &voi ) ) { vo = nextVObject( &voi ); if ( strcmp( vObjectName( vo ), VCAttendeeProp ) == 0 ) { Attendee *a; VObject *vp; s = fakeCString( vObjectUStringZValue( vo ) ); QString tmpStr = QString::fromLocal8Bit( s ); deleteStr( s ); tmpStr = tmpStr.simplified(); int emailPos1, emailPos2; if ( ( emailPos1 = tmpStr.indexOf( '<' ) ) > 0 ) { // both email address and name emailPos2 = tmpStr.lastIndexOf( '>' ); a = new Attendee( tmpStr.left( emailPos1 - 1 ), tmpStr.mid( emailPos1 + 1, emailPos2 - ( emailPos1 + 1 ) ) ); } else if ( tmpStr.indexOf( '@' ) > 0 ) { // just an email address a = new Attendee( 0, tmpStr ); } else { // just a name // WTF??? Replacing the spaces of a name and using this as email? QString email = tmpStr.replace( ' ', '.' ); a = new Attendee( tmpStr, email ); } // is there an RSVP property? if ( ( vp = isAPropertyOf( vo, VCRSVPProp ) ) != 0 ) { a->setRSVP( vObjectStringZValue( vp ) ); } // is there a status property? if ( ( vp = isAPropertyOf( vo, VCStatusProp ) ) != 0 ) { a->setStatus( readStatus( vObjectStringZValue( vp ) ) ); } // add the attendee anEvent->addAttendee( a ); } } // description for todo if ( ( vo = isAPropertyOf( vtodo, VCDescriptionProp ) ) != 0 ) { s = fakeCString( vObjectUStringZValue( vo ) ); anEvent->setDescription( QString::fromLocal8Bit( s ), Qt::mightBeRichText( s ) ); deleteStr( s ); } // summary if ( ( vo = isAPropertyOf( vtodo, VCSummaryProp ) ) ) { s = fakeCString( vObjectUStringZValue( vo ) ); anEvent->setSummary( QString::fromLocal8Bit( s ), Qt::mightBeRichText( s ) ); deleteStr( s ); } // location if ( ( vo = isAPropertyOf( vtodo, VCLocationProp ) ) != 0 ) { s = fakeCString( vObjectUStringZValue( vo ) ); anEvent->setLocation( QString::fromLocal8Bit( s ), Qt::mightBeRichText( s ) ); deleteStr( s ); } // completed // was: status if ( ( vo = isAPropertyOf( vtodo, VCStatusProp ) ) != 0 ) { s = fakeCString( vObjectUStringZValue( vo ) ); if ( strcmp( s, "COMPLETED" ) == 0 ) { anEvent->setCompleted( true ); } else { anEvent->setCompleted( false ); } deleteStr( s ); } else { anEvent->setCompleted( false ); } // completion date if ( ( vo = isAPropertyOf( vtodo, VCCompletedProp ) ) != 0 ) { anEvent->setCompleted( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); } // priority if ( ( vo = isAPropertyOf( vtodo, VCPriorityProp ) ) ) { anEvent->setPriority( atoi( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); } // due date if ( ( vo = isAPropertyOf( vtodo, VCDueProp ) ) != 0 ) { anEvent->setDtDue( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); anEvent->setHasDueDate( true ); } else { anEvent->setHasDueDate( false ); } // start time if ( ( vo = isAPropertyOf( vtodo, VCDTstartProp ) ) != 0 ) { anEvent->setDtStart( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); anEvent->setHasStartDate( true ); } else { anEvent->setHasStartDate( false ); } // alarm stuff if ( ( vo = isAPropertyOf( vtodo, VCDAlarmProp ) ) ) { Alarm *alarm = anEvent->newAlarm(); VObject *a; if ( ( a = isAPropertyOf( vo, VCRunTimeProp ) ) ) { alarm->setTime( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( a ) ) ) ); deleteStr( s ); } alarm->setEnabled( true ); if ( ( vo = isAPropertyOf( vtodo, VCPAlarmProp ) ) ) { if ( ( a = isAPropertyOf( vo, VCProcedureNameProp ) ) ) { s = fakeCString( vObjectUStringZValue( a ) ); alarm->setProcedureAlarm( QFile::decodeName( s ) ); deleteStr( s ); } } if ( ( vo = isAPropertyOf( vtodo, VCAAlarmProp ) ) ) { if ( ( a = isAPropertyOf( vo, VCAudioContentProp ) ) ) { s = fakeCString( vObjectUStringZValue( a ) ); alarm->setAudioAlarm( QFile::decodeName( s ) ); deleteStr( s ); } } } // related todo if ( ( vo = isAPropertyOf( vtodo, VCRelatedToProp ) ) != 0 ) { anEvent->setRelatedToUid( s = fakeCString( vObjectUStringZValue( vo ) ) ); deleteStr( s ); d->mTodosRelate.append( anEvent ); } // categories if ( ( vo = isAPropertyOf( vtodo, VCCategoriesProp ) ) != 0 ) { s = fakeCString( vObjectUStringZValue( vo ) ); QString categories = QString::fromLocal8Bit( s ); deleteStr( s ); QStringList tmpStrList = categories.split( ';' ); anEvent->setCategories( tmpStrList ); } /* PILOT SYNC STUFF */ if ( ( vo = isAPropertyOf( vtodo, KPilotIdProp ) ) ) { anEvent->setNonKDECustomProperty( KPilotIdProp, QString::fromLocal8Bit( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); if ( ( vo = isAPropertyOf( vtodo, KPilotStatusProp ) ) ) { anEvent->setNonKDECustomProperty( KPilotStatusProp, QString::fromLocal8Bit( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); } else { anEvent->setNonKDECustomProperty( KPilotStatusProp, QString::number( SYNCMOD ) ); } } return anEvent; } Event *VCalFormat::VEventToEvent( VObject *vevent ) { VObject *vo; VObjectIterator voi; char *s; Event *anEvent = new Event; // creation date if ( ( vo = isAPropertyOf( vevent, VCDCreatedProp ) ) != 0 ) { anEvent->setCreated( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); } // unique id vo = isAPropertyOf( vevent, VCUniqueStringProp ); // while the UID property is preferred, it is not required. We'll use the // default Event UID if none is given. if ( vo ) { anEvent->setUid( s = fakeCString( vObjectUStringZValue( vo ) ) ); deleteStr( s ); } // revision // again NSCAL doesn't give us much to work with, so we improvise... if ( ( vo = isAPropertyOf( vevent, VCSequenceProp ) ) != 0 ) { anEvent->setRevision( atoi( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); } else { anEvent->setRevision( 0 ); } // last modification date if ( ( vo = isAPropertyOf( vevent, VCLastModifiedProp ) ) != 0 ) { anEvent->setLastModified( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); } else { anEvent->setLastModified( KDateTime::currentUtcDateTime() ); } // organizer // if our extension property for the event's ORGANIZER exists, add it. if ( ( vo = isAPropertyOf( vevent, ICOrganizerProp ) ) != 0 ) { // FIXME: Also use the full name, not just the email address anEvent->setOrganizer( s = fakeCString( vObjectUStringZValue( vo ) ) ); deleteStr( s ); } else { anEvent->setOrganizer( d->mCalendar->owner() ); } // deal with attendees. initPropIterator( &voi, vevent ); while ( moreIteration( &voi ) ) { vo = nextVObject( &voi ); if ( strcmp( vObjectName( vo ), VCAttendeeProp ) == 0 ) { Attendee *a; VObject *vp; s = fakeCString( vObjectUStringZValue( vo ) ); QString tmpStr = QString::fromLocal8Bit( s ); deleteStr( s ); tmpStr = tmpStr.simplified(); int emailPos1, emailPos2; if ( ( emailPos1 = tmpStr.indexOf( '<' ) ) > 0 ) { // both email address and name emailPos2 = tmpStr.lastIndexOf( '>' ); a = new Attendee( tmpStr.left( emailPos1 - 1 ), tmpStr.mid( emailPos1 + 1, emailPos2 - ( emailPos1 + 1 ) ) ); } else if ( tmpStr.indexOf( '@' ) > 0 ) { // just an email address a = new Attendee( 0, tmpStr ); } else { // just a name QString email = tmpStr.replace( ' ', '.' ); a = new Attendee( tmpStr, email ); } // is there an RSVP property? if ( ( vp = isAPropertyOf( vo, VCRSVPProp ) ) != 0 ) { a->setRSVP( vObjectStringZValue( vp ) ); } // is there a status property? if ( ( vp = isAPropertyOf( vo, VCStatusProp ) ) != 0 ) { a->setStatus( readStatus( vObjectStringZValue( vp ) ) ); } // add the attendee anEvent->addAttendee( a ); } } // This isn't strictly true. An event that doesn't have a start time // or an end time isn't all-day, it has an anchor in time but it doesn't // "take up" any time. /*if ((isAPropertyOf(vevent, VCDTstartProp) == 0) || (isAPropertyOf(vevent, VCDTendProp) == 0)) { anEvent->setAllDay(true); } else { }*/ anEvent->setAllDay( false ); // start time if ( ( vo = isAPropertyOf( vevent, VCDTstartProp ) ) != 0 ) { anEvent->setDtStart( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); if ( anEvent->dtStart().time().isNull() ) { anEvent->setAllDay( true ); } } // stop time if ( ( vo = isAPropertyOf( vevent, VCDTendProp ) ) != 0 ) { anEvent->setDtEnd( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); if ( anEvent->dtEnd().time().isNull() ) { anEvent->setAllDay( true ); } } // at this point, there should be at least a start or end time. // fix up for events that take up no time but have a time associated if ( !( vo = isAPropertyOf( vevent, VCDTstartProp ) ) ) { anEvent->setDtStart( anEvent->dtEnd() ); } if ( !( vo = isAPropertyOf( vevent, VCDTendProp ) ) ) { anEvent->setDtEnd( anEvent->dtStart() ); } /////////////////////////////////////////////////////////////////////////// // repeat stuff if ( ( vo = isAPropertyOf( vevent, VCRRuleProp ) ) != 0 ) { QString tmpStr = ( s = fakeCString( vObjectUStringZValue( vo ) ) ); deleteStr( s ); tmpStr.simplified(); tmpStr = tmpStr.toUpper(); // first, read the type of the recurrence int typelen = 1; uint type = Recurrence::rNone; if ( tmpStr.left(1) == "D" ) { type = Recurrence::rDaily; } else if ( tmpStr.left(1) == "W" ) { type = Recurrence::rWeekly; } else { typelen = 2; if ( tmpStr.left(2) == "MP" ) { type = Recurrence::rMonthlyPos; } else if ( tmpStr.left(2) == "MD" ) { type = Recurrence::rMonthlyDay; } else if ( tmpStr.left(2) == "YM" ) { type = Recurrence::rYearlyMonth; } else if ( tmpStr.left(2) == "YD" ) { type = Recurrence::rYearlyDay; } } if ( type != Recurrence::rNone ) { // Immediately after the type is the frequency int index = tmpStr.indexOf( ' ' ); int last = tmpStr.lastIndexOf( ' ' ) + 1; // find last entry int rFreq = tmpStr.mid( typelen, ( index - 1 ) ).toInt(); ++index; // advance to beginning of stuff after freq // Read the type-specific settings switch ( type ) { case Recurrence::rDaily: anEvent->recurrence()->setDaily(rFreq); break; case Recurrence::rWeekly: { QBitArray qba(7); QString dayStr; if ( index == last ) { // e.g. W1 #0 qba.setBit( anEvent->dtStart().date().dayOfWeek() - 1 ); } else { // e.g. W1 SU #0 while ( index < last ) { dayStr = tmpStr.mid( index, 3 ); int dayNum = numFromDay( dayStr ); qba.setBit( dayNum ); index += 3; // advance to next day, or possibly "#" } } anEvent->recurrence()->setWeekly( rFreq, qba ); break; } case Recurrence::rMonthlyPos: { anEvent->recurrence()->setMonthly( rFreq ); QBitArray qba(7); short tmpPos; if ( index == last ) { // e.g. MP1 #0 tmpPos = anEvent->dtStart().date().day() / 7 + 1; if ( tmpPos == 5 ) { tmpPos = -1; } qba.setBit( anEvent->dtStart().date().dayOfWeek() - 1 ); anEvent->recurrence()->addMonthlyPos( tmpPos, qba ); } else { // e.g. MP1 1+ SU #0 while ( index < last ) { tmpPos = tmpStr.mid( index, 1 ).toShort(); index += 1; if ( tmpStr.mid( index, 1 ) == "-" ) { // convert tmpPos to negative tmpPos = 0 - tmpPos; } index += 2; // advance to day(s) while ( numFromDay( tmpStr.mid( index, 3 ) ) >= 0 ) { int dayNum = numFromDay( tmpStr.mid( index, 3 ) ); qba.setBit( dayNum ); index += 3; // advance to next day, or possibly pos or "#" } anEvent->recurrence()->addMonthlyPos( tmpPos, qba ); qba.detach(); qba.fill( false ); // clear out } // while != "#" } break; } case Recurrence::rMonthlyDay: anEvent->recurrence()->setMonthly( rFreq ); if( index == last ) { // e.g. MD1 #0 short tmpDay = anEvent->dtStart().date().day(); anEvent->recurrence()->addMonthlyDate( tmpDay ); } else { // e.g. MD1 3 #0 while ( index < last ) { int index2 = tmpStr.indexOf( ' ', index ); short tmpDay = tmpStr.mid( index, ( index2 - index ) ).toShort(); index = index2 - 1; if ( tmpStr.mid( index, 1 ) == "-" ) { tmpDay = 0 - tmpDay; } index += 2; // advance the index; anEvent->recurrence()->addMonthlyDate( tmpDay ); } // while != # } break; case Recurrence::rYearlyMonth: anEvent->recurrence()->setYearly( rFreq ); if ( index == last ) { // e.g. YM1 #0 short tmpMonth = anEvent->dtStart().date().month(); anEvent->recurrence()->addYearlyMonth( tmpMonth ); } else { // e.g. YM1 3 #0 while ( index < last ) { int index2 = tmpStr.indexOf( ' ', index ); short tmpMonth = tmpStr.mid( index, ( index2 - index ) ).toShort(); index = index2 + 1; anEvent->recurrence()->addYearlyMonth( tmpMonth ); } // while != # } break; case Recurrence::rYearlyDay: anEvent->recurrence()->setYearly( rFreq ); if ( index == last ) { // e.g. YD1 #0 short tmpDay = anEvent->dtStart().date().dayOfYear(); anEvent->recurrence()->addYearlyDay( tmpDay ); } else { // e.g. YD1 123 #0 while ( index < last ) { int index2 = tmpStr.indexOf( ' ', index ); short tmpDay = tmpStr.mid( index, ( index2 - index ) ).toShort(); index = index2 + 1; anEvent->recurrence()->addYearlyDay( tmpDay ); } // while != # } break; default: break; } // find the last field, which is either the duration or the end date index = last; if ( tmpStr.mid( index, 1 ) == "#" ) { // Nr of occurrences index++; int rDuration = tmpStr.mid( index, tmpStr.length() - index ).toInt(); if ( rDuration > 0 ) { anEvent->recurrence()->setDuration( rDuration ); } } else if ( tmpStr.indexOf( 'T', index ) != -1 ) { KDateTime rEndDate = ISOToKDateTime( tmpStr.mid( index, tmpStr.length() - index ) ); rEndDate.setDateOnly( true ); anEvent->recurrence()->setEndDateTime( rEndDate ); } // anEvent->recurrence()->dump(); } else { kDebug() << "we don't understand this type of recurrence!"; } // if known recurrence type } // repeats // recurrence exceptions - if ( ( vo = isAPropertyOf( vevent, VCExDateProp ) ) != 0 ) { + if ( ( vo = isAPropertyOf( vevent, VCExpDateProp ) ) != 0 ) { s = fakeCString( vObjectUStringZValue( vo ) ); QStringList exDates = QString::fromLocal8Bit( s ).split( ',' ); QStringList::ConstIterator it; for ( it = exDates.constBegin(); it != exDates.constEnd(); ++it ) { anEvent->recurrence()->addExDate( ISOToQDate(*it) ); } deleteStr( s ); } // summary if ( ( vo = isAPropertyOf( vevent, VCSummaryProp ) ) ) { s = fakeCString( vObjectUStringZValue( vo ) ); anEvent->setSummary( QString::fromLocal8Bit( s ), Qt::mightBeRichText( s ) ); deleteStr( s ); } // description if ( ( vo = isAPropertyOf( vevent, VCDescriptionProp ) ) != 0 ) { s = fakeCString( vObjectUStringZValue( vo ) ); bool isRich = Qt::mightBeRichText( s ); if ( !anEvent->description().isEmpty() ) { anEvent->setDescription( anEvent->description() + '\n' + QString::fromLocal8Bit( s ), isRich ); } else { anEvent->setDescription( QString::fromLocal8Bit( s ), isRich ); } deleteStr( s ); } // location if ( ( vo = isAPropertyOf( vevent, VCLocationProp ) ) != 0 ) { s = fakeCString( vObjectUStringZValue( vo ) ); anEvent->setLocation( QString::fromLocal8Bit( s ), Qt::mightBeRichText( s ) ); deleteStr( s ); } // some stupid vCal exporters ignore the standard and use Description // instead of Summary for the default field. Correct for this. if ( anEvent->summary().isEmpty() && !( anEvent->description().isEmpty() ) ) { QString tmpStr = anEvent->description().simplified(); anEvent->setDescription( "" ); anEvent->setSummary( tmpStr ); } #if 0 // status if ( ( vo = isAPropertyOf( vevent, VCStatusProp ) ) != 0 ) { QString tmpStr( s = fakeCString( vObjectUStringZValue( vo ) ) ); deleteStr( s ); // TODO: Define Event status // anEvent->setStatus( tmpStr ); } else { // anEvent->setStatus( "NEEDS ACTION" ); } #endif // secrecy Incidence::Secrecy secrecy = Incidence::SecrecyPublic; if ( ( vo = isAPropertyOf( vevent, VCClassProp ) ) != 0 ) { s = fakeCString( vObjectUStringZValue( vo ) ); if ( strcmp( s, "PRIVATE" ) == 0 ) { secrecy = Incidence::SecrecyPrivate; } else if ( strcmp( s, "CONFIDENTIAL" ) == 0 ) { secrecy = Incidence::SecrecyConfidential; } deleteStr( s ); } anEvent->setSecrecy( secrecy ); // categories if ( ( vo = isAPropertyOf( vevent, VCCategoriesProp ) ) != 0 ) { s = fakeCString( vObjectUStringZValue( vo ) ); QString categories = QString::fromLocal8Bit( s ); deleteStr( s ); QStringList tmpStrList = categories.split( ',' ); anEvent->setCategories( tmpStrList ); } // attachments initPropIterator( &voi, vevent ); while ( moreIteration( &voi ) ) { vo = nextVObject( &voi ); if ( strcmp( vObjectName( vo ), VCAttachProp ) == 0 ) { s = fakeCString( vObjectUStringZValue( vo ) ); anEvent->addAttachment( new Attachment( QString( s ) ) ); deleteStr( s ); } } // resources if ( ( vo = isAPropertyOf( vevent, VCResourcesProp ) ) != 0 ) { QString resources = ( s = fakeCString( vObjectUStringZValue( vo ) ) ); deleteStr( s ); QStringList tmpStrList = resources.split( ';' ); anEvent->setResources( tmpStrList ); } // alarm stuff if ( ( vo = isAPropertyOf( vevent, VCDAlarmProp ) ) ) { Alarm *alarm = anEvent->newAlarm(); VObject *a; if ( ( a = isAPropertyOf( vo, VCRunTimeProp ) ) ) { alarm->setTime( ISOToKDateTime( s = fakeCString( vObjectUStringZValue( a ) ) ) ); deleteStr( s ); } alarm->setEnabled( true ); if ( ( vo = isAPropertyOf( vevent, VCPAlarmProp ) ) ) { if ( ( a = isAPropertyOf( vo, VCProcedureNameProp ) ) ) { s = fakeCString( vObjectUStringZValue( a ) ); alarm->setProcedureAlarm( QFile::decodeName( s ) ); deleteStr( s ); } } if ( ( vo = isAPropertyOf( vevent, VCAAlarmProp ) ) ) { if ( ( a = isAPropertyOf( vo, VCAudioContentProp ) ) ) { s = fakeCString( vObjectUStringZValue( a ) ); alarm->setAudioAlarm( QFile::decodeName( s ) ); deleteStr( s ); } } } // priority if ( ( vo = isAPropertyOf( vevent, VCPriorityProp ) ) ) { anEvent->setPriority( atoi( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); } // transparency if ( ( vo = isAPropertyOf( vevent, VCTranspProp ) ) != 0 ) { int i = atoi( s = fakeCString( vObjectUStringZValue( vo ) ) ); anEvent->setTransparency( i == 1 ? Event::Transparent : Event::Opaque ); deleteStr( s ); } // related event if ( ( vo = isAPropertyOf( vevent, VCRelatedToProp ) ) != 0 ) { anEvent->setRelatedToUid( s = fakeCString( vObjectUStringZValue( vo ) ) ); deleteStr( s ); d->mEventsRelate.append( anEvent ); } /* PILOT SYNC STUFF */ if ( ( vo = isAPropertyOf( vevent, KPilotIdProp ) ) ) { anEvent->setNonKDECustomProperty( KPilotIdProp, QString::fromLocal8Bit( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); if ( ( vo = isAPropertyOf( vevent, KPilotStatusProp ) ) ) { anEvent->setNonKDECustomProperty( KPilotStatusProp, QString::fromLocal8Bit( s = fakeCString( vObjectUStringZValue( vo ) ) ) ); deleteStr( s ); } else { anEvent->setNonKDECustomProperty( KPilotStatusProp, QString::number( SYNCMOD ) ); } } return anEvent; } QString VCalFormat::qDateToISO( const QDate &qd ) { QString tmpStr; if ( !qd.isValid() ) { return QString(); } tmpStr.sprintf( "%.2d%.2d%.2d", qd.year(), qd.month(), qd.day() ); return tmpStr; } QString VCalFormat::kDateTimeToISO( const KDateTime &dt, bool zulu ) { QString tmpStr; if ( !dt.isValid() ) { return QString(); } QDateTime tmpDT; if ( zulu ) { tmpDT = dt.toUtc().dateTime(); } else { tmpDT = dt.toTimeSpec( d->mCalendar->timeSpec() ).dateTime(); } tmpStr.sprintf( "%.2d%.2d%.2dT%.2d%.2d%.2d", tmpDT.date().year(), tmpDT.date().month(), tmpDT.date().day(), tmpDT.time().hour(), tmpDT.time().minute(), tmpDT.time().second() ); if ( zulu ) { tmpStr += 'Z'; } return tmpStr; } KDateTime VCalFormat::ISOToKDateTime( const QString &dtStr ) { QDate tmpDate; QTime tmpTime; QString tmpStr; int year, month, day, hour, minute, second; tmpStr = dtStr; year = tmpStr.left( 4 ).toInt(); month = tmpStr.mid( 4, 2 ).toInt(); day = tmpStr.mid( 6, 2 ).toInt(); hour = tmpStr.mid( 9, 2 ).toInt(); minute = tmpStr.mid( 11, 2 ).toInt(); second = tmpStr.mid( 13, 2 ).toInt(); tmpDate.setYMD( year, month, day ); tmpTime.setHMS( hour, minute, second ); if ( tmpDate.isValid() && tmpTime.isValid() ) { // correct for GMT if string is in Zulu format if ( dtStr.at( dtStr.length() - 1 ) == 'Z' ) { return KDateTime( tmpDate, tmpTime, KDateTime::UTC ); } else { return KDateTime( tmpDate, tmpTime, d->mCalendar->timeSpec() ); } } else { return KDateTime(); } } QDate VCalFormat::ISOToQDate( const QString &dateStr ) { int year, month, day; year = dateStr.left( 4 ).toInt(); month = dateStr.mid( 4, 2 ).toInt(); day = dateStr.mid( 6, 2 ).toInt(); return QDate( year, month, day ); } // take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc. // and break it down from it's tree-like format into the dictionary format // that is used internally in the VCalFormat. void VCalFormat::populate( VObject *vcal ) { // this function will populate the caldict dictionary and other event // lists. It turns vevents into Events and then inserts them. VObjectIterator i; VObject *curVO, *curVOProp; Event *anEvent; if ( ( curVO = isAPropertyOf( vcal, ICMethodProp ) ) != 0 ) { char *methodType = 0; methodType = fakeCString( vObjectUStringZValue( curVO ) ); kDebug() << "This calendar is an iTIP transaction of type '" << methodType << "'"; deleteStr( methodType ); } // warn the user that we might have trouble reading non-known calendar. if ( ( curVO = isAPropertyOf( vcal, VCProdIdProp ) ) != 0 ) { char *s = fakeCString( vObjectUStringZValue( curVO ) ); if ( strcmp( productId().toLocal8Bit(), s ) != 0 ) { kDebug() << "This vCalendar file was not created by KOrganizer or" << "any other product we support. Loading anyway..."; } setLoadedProductId( s ); deleteStr( s ); } // warn the user we might have trouble reading this unknown version. if ( ( curVO = isAPropertyOf( vcal, VCVersionProp ) ) != 0 ) { char *s = fakeCString( vObjectUStringZValue( curVO ) ); if ( strcmp( _VCAL_VERSION, s ) != 0 ) { kDebug() << "This vCalendar file has version" << s << "We only support" << _VCAL_VERSION; } deleteStr( s ); } #if 0 // set the time zone (this is a property of the view, so just discard!) if ( ( curVO = isAPropertyOf( vcal, VCTimeZoneProp ) ) != 0 ) { char *s = fakeCString( vObjectUStringZValue( curVO ) ); d->mCalendar->setTimeZone( s ); deleteStr( s ); } #endif // Store all events with a relatedTo property in a list for post-processing d->mEventsRelate.clear(); d->mTodosRelate.clear(); initPropIterator( &i, vcal ); // go through all the vobjects in the vcal while ( moreIteration( &i ) ) { curVO = nextVObject( &i ); /************************************************************************/ // now, check to see that the object is an event or todo. if ( strcmp( vObjectName( curVO ), VCEventProp ) == 0 ) { if ( ( curVOProp = isAPropertyOf( curVO, KPilotStatusProp ) ) != 0 ) { char *s; s = fakeCString( vObjectUStringZValue( curVOProp ) ); // check to see if event was deleted by the kpilot conduit if ( atoi( s ) == SYNCDEL ) { deleteStr( s ); kDebug() << "skipping pilot-deleted event"; goto SKIP; } deleteStr( s ); } // this code checks to see if we are trying to read in an event // that we already find to be in the calendar. If we find this // to be the case, we skip the event. if ( ( curVOProp = isAPropertyOf( curVO, VCUniqueStringProp ) ) != 0 ) { char *s = fakeCString( vObjectUStringZValue( curVOProp ) ); QString tmpStr( s ); deleteStr( s ); if ( d->mCalendar->incidence( tmpStr ) ) { goto SKIP; } } if ( ( !( curVOProp = isAPropertyOf( curVO, VCDTstartProp ) ) ) && ( !( curVOProp = isAPropertyOf( curVO, VCDTendProp ) ) ) ) { kDebug() << "found a VEvent with no DTSTART and no DTEND! Skipping..."; goto SKIP; } anEvent = VEventToEvent( curVO ); // we now use addEvent instead of insertEvent so that the // signal/slot get connected. if ( anEvent ) { if ( anEvent->dtStart().isValid() && anEvent->dtEnd().isValid() ) { d->mCalendar->addEvent( anEvent ); } } else { // some sort of error must have occurred while in translation. goto SKIP; } } else if ( strcmp( vObjectName( curVO ), VCTodoProp ) == 0 ) { Todo *aTodo = VTodoToEvent( curVO ); Todo *old = d->mCalendar->todo( aTodo->uid() ); if ( old ) { d->mCalendar->deleteTodo( old ); d->mTodosRelate.removeAll( old ); } d->mCalendar->addTodo( aTodo ); } else if ( ( strcmp( vObjectName( curVO ), VCVersionProp ) == 0 ) || ( strcmp( vObjectName( curVO ), VCProdIdProp ) == 0 ) || ( strcmp( vObjectName( curVO ), VCTimeZoneProp ) == 0 ) ) { // do nothing, we know these properties and we want to skip them. // we have either already processed them or are ignoring them. ; } else { kDebug() << "Ignoring unknown vObject \"" << vObjectName(curVO) << "\""; } SKIP: ; } // while // Post-Process list of events with relations, put Event objects in relation Event::List::ConstIterator eIt; for ( eIt = d->mEventsRelate.constBegin(); eIt != d->mEventsRelate.constEnd(); ++eIt ) { (*eIt)->setRelatedTo( d->mCalendar->incidence( (*eIt)->relatedToUid() ) ); } Todo::List::ConstIterator tIt; for ( tIt = d->mTodosRelate.constBegin(); tIt != d->mTodosRelate.constEnd(); ++tIt ) { (*tIt)->setRelatedTo( d->mCalendar->incidence( (*tIt)->relatedToUid() ) ); } } const char *VCalFormat::dayFromNum( int day ) { const char *days[7] = { "MO ", "TU ", "WE ", "TH ", "FR ", "SA ", "SU " }; return days[day]; } int VCalFormat::numFromDay( const QString &day ) { if ( day == "MO " ) { return 0; } if ( day == "TU " ) { return 1; } if ( day == "WE " ) { return 2; } if ( day == "TH " ) { return 3; } if ( day == "FR " ) { return 4; } if ( day == "SA " ) { return 5; } if ( day == "SU " ) { return 6; } return -1; // something bad happened. :) } Attendee::PartStat VCalFormat::readStatus( const char *s ) const { QString statStr = s; statStr = statStr.toUpper(); Attendee::PartStat status; if ( statStr == "X-ACTION" ) { status = Attendee::NeedsAction; } else if ( statStr == "NEEDS ACTION" ) { status = Attendee::NeedsAction; } else if ( statStr == "ACCEPTED" ) { status = Attendee::Accepted; } else if ( statStr == "SENT" ) { status = Attendee::NeedsAction; } else if ( statStr == "TENTATIVE" ) { status = Attendee::Tentative; } else if ( statStr == "CONFIRMED" ) { status = Attendee::Accepted; } else if ( statStr == "DECLINED" ) { status = Attendee::Declined; } else if ( statStr == "COMPLETED" ) { status = Attendee::Completed; } else if ( statStr == "DELEGATED" ) { status = Attendee::Delegated; } else { kDebug() << "error setting attendee mStatus, unknown mStatus!"; status = Attendee::NeedsAction; } return status; } QByteArray VCalFormat::writeStatus( Attendee::PartStat status ) const { switch( status ) { default: case Attendee::NeedsAction: return "NEEDS ACTION"; break; case Attendee::Accepted: return "ACCEPTED"; break; case Attendee::Declined: return "DECLINED"; break; case Attendee::Tentative: return "TENTATIVE"; break; case Attendee::Delegated: return "DELEGATED"; break; case Attendee::Completed: return "COMPLETED"; break; case Attendee::InProcess: return "NEEDS ACTION"; break; } } diff --git a/kcal/versit/vobject.c b/kcal/versit/vobject.c index 33e48592d..35536f331 100644 --- a/kcal/versit/vobject.c +++ b/kcal/versit/vobject.c @@ -1,1438 +1,1438 @@ /*************************************************************************** (C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International Business Machines Corporation and Siemens Rolm Communications Inc. For purposes of this license notice, the term Licensors shall mean, collectively, Apple Computer, Inc., AT&T Corp., International Business Machines Corporation and Siemens Rolm Communications Inc. The term Licensor shall mean any of the Licensors. Subject to acceptance of the following conditions, permission is hereby granted by Licensors without the need for written agreement and without license or royalty fees, to use, copy, modify and distribute this software for any purpose. The above copyright notice and the following four paragraphs must be reproduced in all copies of this software and any software including this software. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS. IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. The software is provided with RESTRICTED RIGHTS. Use, duplication, or disclosure by the government are subject to restrictions set forth in DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. ***************************************************************************/ /* * src: vobject.c * doc: vobject and APIs to construct vobject, APIs pretty print * vobject, and convert a vobject into its textual representation. */ #include #include "vobject.h" #include #include #define NAME_OF(o) o->id #define VALUE_TYPE(o) o->valType #define STRINGZ_VALUE_OF(o) o->val.strs #define USTRINGZ_VALUE_OF(o) o->val.ustrs #define INTEGER_VALUE_OF(o) o->val.i #define LONG_VALUE_OF(o) o->val.l #define ANY_VALUE_OF(o) o->val.any #define VOBJECT_VALUE_OF(o) o->val.vobj const char** fieldedProp; /*---------------------------------------------------------------------- The following functions involve with memory allocation: newVObject deleteVObject dupStr deleteStr newStrItem deleteStrItem ----------------------------------------------------------------------*/ VObject* newVObject_(const char *id) { VObject *p = (VObject*)malloc(sizeof(VObject)); p->next = 0; p->id = id; p->prop = 0; VALUE_TYPE(p) = 0; ANY_VALUE_OF(p) = 0; return p; } VObject* newVObject(const char *id) { return newVObject_(lookupStr(id)); } void deleteVObject(VObject *p) { if (!p) return; if (p->id) unUseStr(p->id); free(p); p = NULL; } char* dupStr(const char *s, unsigned int size) { char *t; if (size == 0) { size = strlen(s); } t = (char*)malloc(size+1); if (t) { memcpy(t,s,size); t[size] = 0; return t; } else { return (char*)0; } } void deleteStr(const char *p) { if (p) free((void*)p); p = NULL; } static StrItem* newStrItem(const char *s, StrItem *next) { StrItem *p = (StrItem*)malloc(sizeof(StrItem)); p->next = next; p->s = s; p->refCnt = 1; return p; } static void deleteStrItem(StrItem *p) { if (p) free((void*)p); p = NULL; } /*---------------------------------------------------------------------- The following function provide accesses to VObject's value. ----------------------------------------------------------------------*/ const char* vObjectName(VObject *o) { return NAME_OF(o); } void setVObjectName(VObject *o, const char* id) { NAME_OF(o) = id; } const char* vObjectStringZValue(VObject *o) { return STRINGZ_VALUE_OF(o); } void setVObjectStringZValue(VObject *o, const char *s) { STRINGZ_VALUE_OF(o) = dupStr(s,0); VALUE_TYPE(o) = VCVT_STRINGZ; } void setVObjectStringZValue_(VObject *o, const char *s) { STRINGZ_VALUE_OF(o) = s; VALUE_TYPE(o) = VCVT_STRINGZ; } const wchar_t* vObjectUStringZValue(VObject *o) { return USTRINGZ_VALUE_OF(o); } void setVObjectUStringZValue(VObject *o, const wchar_t *s) { USTRINGZ_VALUE_OF(o) = (wchar_t*) dupStr((char*)s,(unsigned)(uStrLen(s)+1)*2); VALUE_TYPE(o) = VCVT_USTRINGZ; } void setVObjectUStringZValue_(VObject *o, const wchar_t *s) { USTRINGZ_VALUE_OF(o) = s; VALUE_TYPE(o) = VCVT_USTRINGZ; } unsigned int vObjectIntegerValue(VObject *o) { return INTEGER_VALUE_OF(o); } void setVObjectIntegerValue(VObject *o, unsigned int i) { INTEGER_VALUE_OF(o) = i; VALUE_TYPE(o) = VCVT_UINT; } unsigned long vObjectLongValue(VObject *o) { return LONG_VALUE_OF(o); } void setVObjectLongValue(VObject *o, unsigned long l) { LONG_VALUE_OF(o) = l; VALUE_TYPE(o) = VCVT_ULONG; } void* vObjectAnyValue(VObject *o) { return ANY_VALUE_OF(o); } void setVObjectAnyValue(VObject *o, void *t) { ANY_VALUE_OF(o) = t; VALUE_TYPE(o) = VCVT_RAW; } VObject* vObjectVObjectValue(VObject *o) { return VOBJECT_VALUE_OF(o); } void setVObjectVObjectValue(VObject *o, VObject *p) { VOBJECT_VALUE_OF(o) = p; VALUE_TYPE(o) = VCVT_VOBJECT; } int vObjectValueType(VObject *o) { return VALUE_TYPE(o); } /*---------------------------------------------------------------------- The following functions can be used to build VObject. ----------------------------------------------------------------------*/ VObject* addVObjectProp(VObject *o, VObject *p) { /* circular link list pointed to tail */ /* o {next,id,prop,val} V pn {next,id,prop,val} V ... p1 {next,id,prop,val} V pn --> o {next,id,prop,val} V pn {next,id,prop,val} V p {next,id,prop,val} ... p1 {next,id,prop,val} V pn */ VObject *tail = o->prop; if (tail) { p->next = tail->next; o->prop = tail->next = p; } else { o->prop = p->next = p; } return p; } VObject* addProp(VObject *o, const char *id) { return addVObjectProp(o,newVObject(id)); } VObject* addProp_(VObject *o, const char *id) { return addVObjectProp(o,newVObject_(id)); } void addList(VObject **o, VObject *p) { p->next = 0; if (*o == 0) { *o = p; } else { VObject *t = *o; while (t->next) { t = t->next; } t->next = p; } } VObject* nextVObjectInList(VObject *o) { return o->next; } VObject* setValueWithSize_(VObject *prop, void *val, unsigned int size) { VObject *sizeProp; setVObjectAnyValue(prop, val); sizeProp = addProp(prop,VCDataSizeProp); setVObjectLongValue(sizeProp, size); return prop; } VObject* setValueWithSize(VObject *prop, void *val, unsigned int size) { void *p = dupStr(val,size); return setValueWithSize_(prop,p,p?size:0); } void initPropIterator(VObjectIterator *i, VObject *o) { i->start = o->prop; i->next = 0; } void initVObjectIterator(VObjectIterator *i, VObject *o) { i->start = o->next; i->next = 0; } int moreIteration(VObjectIterator *i) { return (i->start && (i->next==0 || i->next!=i->start)); } VObject* nextVObject(VObjectIterator *i) { if (i->start && i->next != i->start) { if (i->next == 0) { i->next = i->start->next; return i->next; } else { i->next = i->next->next; return i->next; } } else return (VObject*)0; } VObject* isAPropertyOf(VObject *o, const char *id) { VObjectIterator i; initPropIterator(&i,o); while (moreIteration(&i)) { VObject *each = nextVObject(&i); if (!strcasecmp(id,each->id)) return each; } return (VObject*)0; } VObject* addGroup(VObject *o, const char *g) { /* a.b.c --> prop(c) prop(VCGrouping=b) prop(VCGrouping=a) */ char *dot = strrchr(g,'.'); if (dot) { VObject *p, *t; char *gs, *n = dot+1; gs = dupStr(g,0); /* so we can write to it. */ /* used to be * t = p = addProp_(o,lookupProp_(n)); */ t = p = addProp_(o,lookupProp(n)); dot = strrchr(gs,'.'); *dot = 0; do { dot = strrchr(gs,'.'); if (dot) { n = dot+1; *dot=0; } else n = gs; /* property(VCGroupingProp=n); * and the value may have VCGrouping property */ t = addProp(t,VCGroupingProp); setVObjectStringZValue(t,lookupProp_(n)); } while (n != gs); deleteStr(gs); return p; } else return addProp_(o,lookupProp(g)); } VObject* addPropValue(VObject *o, const char *p, const char *v) { VObject *prop; prop = addProp(o,p); setVObjectUStringZValue_(prop, fakeUnicode(v,0)); return prop; } VObject* addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size) { VObject *prop; prop = addProp(o,p); setValueWithSize_(prop, (void*)v, size); return prop; } VObject* addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size) { return addPropSizedValue_(o,p,dupStr(v,size),size); } /*---------------------------------------------------------------------- The following pretty print a VObject ----------------------------------------------------------------------*/ static void printVObject_(FILE *fp, VObject *o, int level); static void indent(FILE *fp, int level) { int i; for (i=0;ifail) return; slen = strlen(s); if (fp->fp) { fwrite(s,1,slen,fp->fp); } else { stuff: if (fp->len + slen < fp->limit) { memcpy(fp->s+fp->len,s,slen); fp->len += slen; return; } else if (fp->alloc) { fp->limit = fp->limit + OFILE_REALLOC_SIZE; if (OFILE_REALLOC_SIZE <= slen) fp->limit += slen; if (fp->s) fp->s = realloc(fp->s,fp->limit); else fp->s = malloc(fp->limit); if (fp->s) goto stuff; } if (fp->alloc) free(fp->s); fp->s = 0; fp->fail = 1; } } static void appendcOFile(OFile *fp, char c) { if (fp->fail) return; if (fp->fp) { fputc(c,fp->fp); } else { stuff: if (fp->len+1 < fp->limit) { fp->s[fp->len] = c; fp->len++; return; } else if (fp->alloc) { fp->limit = fp->limit + OFILE_REALLOC_SIZE; fp->s = realloc(fp->s,fp->limit); if (fp->s) goto stuff; } if (fp->alloc) free(fp->s); fp->s = 0; fp->fail = 1; } } #else static void appendcOFile_(OFile *fp, char c) { if (fp->fail) return; if (fp->fp) { fputc(c,fp->fp); } else { stuff: if (fp->len+1 < fp->limit) { fp->s[fp->len] = c; fp->len++; return; } else if (fp->alloc) { fp->limit = fp->limit + OFILE_REALLOC_SIZE; fp->s = realloc(fp->s,(unsigned int)fp->limit); if (fp->s) goto stuff; } if (fp->alloc) free(fp->s); fp->s = 0; fp->fail = 1; } } static void appendcOFile(OFile *fp, char c) { if (c == '\n') { /* write out as */ appendcOFile_(fp,0xd); appendcOFile_(fp,0xa); } else appendcOFile_(fp,c); } static void appendsOFile(OFile *fp, const char *s) { int i, slen; slen = strlen(s); for (i=0; ifp = ofp; fp->s = 0; fp->len = 0; fp->limit = 0; fp->alloc = 0; fp->fail = 0; } static void initMemOFile(OFile *fp, char *s, int len) { fp->fp = 0; fp->s = s; fp->len = 0; fp->limit = s?len:0; fp->alloc = s?0:1; fp->fail = 0; } static int writeBase64(OFile *fp, unsigned char *s, unsigned long len) { unsigned long cur = 0; int i, numQuads = 0; unsigned long trip; unsigned char b; char quad[5]; #define MAXQUADS 16 quad[4] = 0; while (cur < len) { /* collect the triplet of bytes into 'trip' */ trip = 0; for (i = 0; i < 3; i++) { b = (cur < len) ? *(s + cur) : 0; cur++; trip = trip << 8 | b; } /* fill in 'quad' with the appropriate four characters */ for (i = 3; i >= 0; i--) { b = (unsigned char)(trip & 0x3F); trip = trip >> 6; if ((unsigned long)(3 - i) < (cur - len)) quad[i] = '='; /* pad char */ else if (b < 26) quad[i] = (char)b + 'A'; else if (b < 52) quad[i] = (char)(b - 26) + 'a'; else if (b < 62) quad[i] = (char)(b - 52) + '0'; else if (b == 62) quad[i] = '+'; else quad[i] = '/'; } /* now output 'quad' with appropriate whitespace and line ending */ appendsOFile(fp, (numQuads == 0 ? " " : "")); appendsOFile(fp, quad); appendsOFile(fp, ((cur >= len)?"\n" :(numQuads==MAXQUADS-1?"\n" : ""))); numQuads = (numQuads + 1) % MAXQUADS; } appendcOFile(fp,'\n'); return 1; } /* this function really sucks. Too basic. */ static void writeQPString(OFile *fp, const char *s, int qp) { const char *p = s; while (*p) { if (*p == '\n') { if (p[1]) appendsOFile(fp,"=0A="); } if (*p == '=' && qp) appendsOFile(fp,"=3D"); else appendcOFile(fp,*p); p++; } } static void writeVObject_(OFile *fp, VObject *o); static void writeValue(OFile *fp, VObject *o, unsigned long size) { if (o == 0) return; switch (VALUE_TYPE(o)) { case VCVT_USTRINGZ: { char *s = fakeCString(USTRINGZ_VALUE_OF(o)); if (isAPropertyOf(o, VCQuotedPrintableProp)) writeQPString(fp, s, 1); else writeQPString(fp, s, 0); deleteStr(s); break; } case VCVT_STRINGZ: { if (isAPropertyOf(o, VCQuotedPrintableProp)) writeQPString(fp, STRINGZ_VALUE_OF(o), 1); else writeQPString(fp, STRINGZ_VALUE_OF(o), 0); break; } case VCVT_UINT: { char buf[16]; snprintf(buf,sizeof(buf),"%u", INTEGER_VALUE_OF(o)); appendsOFile(fp,buf); break; } case VCVT_ULONG: { char buf[16]; snprintf(buf,sizeof(buf),"%lu", LONG_VALUE_OF(o)); appendsOFile(fp,buf); break; } case VCVT_RAW: { appendcOFile(fp,'\n'); writeBase64(fp,(unsigned char*)(ANY_VALUE_OF(o)),size); break; } case VCVT_VOBJECT: appendcOFile(fp,'\n'); writeVObject_(fp,VOBJECT_VALUE_OF(o)); break; } } static void writeAttrValue(OFile *fp, VObject *o) { if (NAME_OF(o)) { struct PreDefProp *pi; pi = lookupPropInfo(NAME_OF(o)); if (pi && ((pi->flags & PD_INTERNAL) != 0)) return; appendcOFile(fp,';'); appendsOFile(fp,NAME_OF(o)); } else appendcOFile(fp,';'); if (VALUE_TYPE(o)) { appendcOFile(fp,'='); writeValue(fp,o,0); } } static void writeGroup(OFile *fp, VObject *o) { char buf1[256]; char buf2[256]; strcpy(buf1,NAME_OF(o)); while ((o=isAPropertyOf(o,VCGroupingProp)) != 0) { strncpy(buf2,STRINGZ_VALUE_OF(o),sizeof(buf2)); buf2[sizeof(buf2)-1] = '\0'; strncat(buf2,".",sizeof(buf2)-strlen(buf2)-1); strncat(buf2,buf1,sizeof(buf2)-strlen(buf2)-1); strcpy(buf1,buf2); } appendsOFile(fp,buf1); } static int inList(const char **list, const char *s) { if (list == 0) return 0; while (*list) { if (strcasecmp(*list,s) == 0) return 1; list++; } return 0; } static void writeProp(OFile *fp, VObject *o) { if (NAME_OF(o)) { struct PreDefProp *pi; VObjectIterator t; const char **fields_ = 0; pi = lookupPropInfo(NAME_OF(o)); if (pi && ((pi->flags & PD_BEGIN) != 0)) { writeVObject_(fp,o); return; } if (isAPropertyOf(o,VCGroupingProp)) writeGroup(fp,o); else appendsOFile(fp,NAME_OF(o)); if (pi) fields_ = pi->fields; initPropIterator(&t,o); while (moreIteration(&t)) { const char *s; VObject *eachProp = nextVObject(&t); s = NAME_OF(eachProp); if (strcasecmp(VCGroupingProp,s) && !inList(fields_,s)) writeAttrValue(fp,eachProp); } if (fields_) { int i = 0, n = 0; const char** fields = fields_; /* output prop as fields */ appendcOFile(fp,':'); while (*fields) { VObject *tl = isAPropertyOf(o,*fields); i++; if (tl) n = i; fields++; } fields = fields_; for (i=0;iflags & PD_BEGIN) != 0)) { VObjectIterator t; const char *begin = NAME_OF(o); appendsOFile(fp,"BEGIN:"); appendsOFile(fp,begin); appendcOFile(fp,'\n'); initPropIterator(&t,o); while (moreIteration(&t)) { VObject *eachProp = nextVObject(&t); writeProp(fp, eachProp); } appendsOFile(fp,"END:"); appendsOFile(fp,begin); appendsOFile(fp,"\n\n"); } } } void writeVObject(FILE *fp, VObject *o) { OFile ofp; initOFile(&ofp,fp); writeVObject_(&ofp,o); } void writeVObjectToFile(char *fname, VObject *o) { FILE *fp = fopen(fname,"w"); if (fp) { writeVObject(fp,o); fclose(fp); } } void writeVObjectsToFile(char *fname, VObject *list) { FILE *fp = fopen(fname,"w"); if (fp) { while (list) { writeVObject(fp,list); list = nextVObjectInList(list); } fclose(fp); } } char* writeMemVObject(char *s, int *len, VObject *o) { OFile ofp; initMemOFile(&ofp,s,len?*len:0); writeVObject_(&ofp,o); if (len) *len = ofp.len; appendcOFile(&ofp,0); return ofp.s; } char* writeMemVObjects(char *s, int *len, VObject *list) { OFile ofp; initMemOFile(&ofp,s,len?*len:0); while (list) { writeVObject_(&ofp,list); list = nextVObjectInList(list); } if (len) *len = ofp.len; appendcOFile(&ofp,0); return ofp.s; } /*---------------------------------------------------------------------- APIs to do fake Unicode stuff. ----------------------------------------------------------------------*/ wchar_t* fakeUnicode(const char *ps, int *bytes) { wchar_t *r, *pw; int len = strlen(ps)+1; pw = r = (wchar_t*)malloc(sizeof(wchar_t)*len); if (bytes) *bytes = len * sizeof(wchar_t); while (*ps) { if (*ps == '\n') *pw = (wchar_t)0x2028; else if (*ps == '\r') *pw = (wchar_t)0x2029; else *pw = (wchar_t)(unsigned char)*ps; ps++; pw++; } *pw = (wchar_t)0; return r; } unsigned int uStrLen(const wchar_t *u) { int i = 0; if(u == NULL) return 0; while (*u != (wchar_t)0) { u++; i++; } return i; } char* fakeCString(const wchar_t *u) { char *s, *t; unsigned int len; if(u == NULL) return NULL; len = uStrLen(u) + 1; t = s = (char*)malloc(len+1); while (*u) { if (*u == (wchar_t)0x2028) *t = '\n'; else if (*u == (wchar_t)0x2029) *t = '\r'; else *t = (char)*u; u++; t++; } *t = 0; return s; } /* end of source file vobject.c */ diff --git a/kcal/versit/vobject.h b/kcal/versit/vobject.h index 67396d553..74f83214b 100644 --- a/kcal/versit/vobject.h +++ b/kcal/versit/vobject.h @@ -1,384 +1,384 @@ /*************************************************************************** (C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International Business Machines Corporation and Siemens Rolm Communications Inc. For purposes of this license notice, the term Licensors shall mean, collectively, Apple Computer, Inc., AT&T Corp., International Business Machines Corporation and Siemens Rolm Communications Inc. The term Licensor shall mean any of the Licensors. Subject to acceptance of the following conditions, permission is hereby granted by Licensors without the need for written agreement and without license or royalty fees, to use, copy, modify and distribute this software for any purpose. The above copyright notice and the following four paragraphs must be reproduced in all copies of this software and any software including this software. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS. IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. The software is provided with RESTRICTED RIGHTS. Use, duplication, or disclosure by the government are subject to restrictions set forth in DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. ***************************************************************************/ /* The vCard/vCalendar C interface is implemented in the set of files as follows: vcc.y, yacc source, and vcc.c, the yacc output you will use implements the core parser vobject.c implements an API that insulates the caller from the parser and changes in the vCard/vCalendar BNF port.h defines compilation environment dependent stuff vcc.h and vobject.h are header files for their .c counterparts vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions which you may find useful. test.c is a standalone test driver that exercises some of the features of the APIs provided. Invoke test.exe on a VCARD/VCALENDAR input text file and you will see the pretty print output of the internal representation (this pretty print output should give you a good idea of how the internal representation looks like -- there is one such output in the following too). Also, a file with the .out suffix is generated to show that the internal representation can be written back in the original text format. For more information on this API see the readme.txt file which accompanied this distribution. Also visit: http://www.versit.com http://www.ralden.com */ #ifndef __VOBJECT_H__ #define __VOBJECT_H__ 1 #include "port.h" #include #include #if defined(__CPLUSPLUS__) || defined(__cplusplus) extern "C" { #endif #define VC7bitProp "7BIT" #define VC8bitProp "8BIT" #define VCAAlarmProp "AALARM" #define VCAdditionalNamesProp "ADDN" #define VCAdrProp "ADR" #define VCAgentProp "AGENT" #define VCAIFFProp "AIFF" #define VCAOLProp "AOL" #define VCAppleLinkProp "APPLELINK" #define VCAttachProp "ATTACH" #define VCAttendeeProp "ATTENDEE" #define VCATTMailProp "ATTMAIL" #define VCAudioContentProp "AUDIOCONTENT" #define VCAVIProp "AVI" #define VCBase64Prop "BASE64" #define VCBBSProp "BBS" #define VCBirthDateProp "BDAY" #define VCBMPProp "BMP" #define VCBodyProp "BODY" #define VCBusinessRoleProp "ROLE" #define VCCalProp "VCALENDAR" #define VCCaptionProp "CAP" #define VCCardProp "VCARD" #define VCCarProp "CAR" #define VCCategoriesProp "CATEGORIES" #define VCCellularProp "CELL" #define VCCGMProp "CGM" #define VCCharSetProp "CS" #define VCCIDProp "CID" #define VCCISProp "CIS" #define VCCityProp "L" #define VCClassProp "CLASS" #define VCCommentProp "NOTE" #define VCCompletedProp "COMPLETED" #define VCContentIDProp "CONTENT-ID" #define VCCountryNameProp "C" #define VCDAlarmProp "DALARM" #define VCDataSizeProp "DATASIZE" #define VCDayLightProp "DAYLIGHT" #define VCDCreatedProp "DCREATED" #define VCDeliveryLabelProp "LABEL" #define VCDescriptionProp "DESCRIPTION" #define VCDIBProp "DIB" #define VCDisplayStringProp "DISPLAYSTRING" #define VCDomesticProp "DOM" #define VCDTendProp "DTEND" #define VCDTstartProp "DTSTART" #define VCDueProp "DUE" #define VCEmailAddressProp "EMAIL" #define VCEncodingProp "ENCODING" #define VCEndProp "END" #define VCEventProp "VEVENT" #define VCEWorldProp "EWORLD" #define VCExNumProp "EXNUM" -#define VCExDateProp "EXDATE" +#define VCExpDateProp "EXDATE" #define VCExpectProp "EXPECT" #define VCExtAddressProp "EXT ADD" #define VCFamilyNameProp "F" #define VCFaxProp "FAX" #define VCFullNameProp "FN" #define VCGeoProp "GEO" #define VCGeoLocationProp "GEO" #define VCGIFProp "GIF" #define VCGivenNameProp "G" #define VCGroupingProp "Grouping" #define VCHomeProp "HOME" #define VCIBMMailProp "IBMMail" #define VCInlineProp "INLINE" #define VCInternationalProp "INTL" #define VCInternetProp "INTERNET" #define VCISDNProp "ISDN" #define VCJPEGProp "JPEG" #define VCLanguageProp "LANG" #define VCLastModifiedProp "LAST-MODIFIED" #define VCLastRevisedProp "REV" #define VCLocationProp "LOCATION" #define VCLogoProp "LOGO" #define VCMailerProp "MAILER" #define VCMAlarmProp "MALARM" #define VCMCIMailProp "MCIMAIL" #define VCMessageProp "MSG" #define VCMETProp "MET" #define VCModemProp "MODEM" #define VCMPEG2Prop "MPEG2" #define VCMPEGProp "MPEG" #define VCMSNProp "MSN" #define VCNamePrefixesProp "NPRE" #define VCNameProp "N" #define VCNameSuffixesProp "NSUF" #define VCNoteProp "NOTE" #define VCOrgNameProp "ORGNAME" #define VCOrgProp "ORG" #define VCOrgUnit2Prop "OUN2" #define VCOrgUnit3Prop "OUN3" #define VCOrgUnit4Prop "OUN4" #define VCOrgUnitProp "OUN" #define VCPagerProp "PAGER" #define VCPAlarmProp "PALARM" #define VCParcelProp "PARCEL" #define VCPartProp "PART" #define VCPCMProp "PCM" #define VCPDFProp "PDF" #define VCPGPProp "PGP" #define VCPhotoProp "PHOTO" #define VCPICTProp "PICT" #define VCPMBProp "PMB" #define VCPostalBoxProp "BOX" #define VCPostalCodeProp "PC" #define VCPostalProp "POSTAL" #define VCPowerShareProp "POWERSHARE" #define VCPreferredProp "PREF" #define VCPriorityProp "PRIORITY" #define VCProcedureNameProp "PROCEDURENAME" #define VCProdIdProp "PRODID" #define VCProdigyProp "PRODIGY" #define VCPronunciationProp "SOUND" #define VCPSProp "PS" #define VCPublicKeyProp "KEY" #define VCQPProp "QP" #define VCQuickTimeProp "QTIME" #define VCQuotedPrintableProp "QUOTED-PRINTABLE" #define VCRDateProp "RDATE" #define VCRegionProp "R" #define VCRelatedToProp "RELATED-TO" #define VCRepeatCountProp "REPEATCOUNT" #define VCResourcesProp "RESOURCES" #define VCRNumProp "RNUM" #define VCRoleProp "ROLE" #define VCRRuleProp "RRULE" #define VCRSVPProp "RSVP" #define VCRunTimeProp "RUNTIME" #define VCSequenceProp "SEQUENCE" #define VCSnoozeTimeProp "SNOOZETIME" #define VCStartProp "START" #define VCStatusProp "STATUS" #define VCStreetAddressProp "STREET" #define VCSubTypeProp "SUBTYPE" #define VCSummaryProp "SUMMARY" #define VCTelephoneProp "TEL" #define VCTIFFProp "TIFF" #define VCTimeZoneProp "TZ" #define VCTitleProp "TITLE" #define VCTLXProp "TLX" #define VCTodoProp "VTODO" #define VCTranspProp "TRANSP" #define VCUniqueStringProp "UID" #define VCURLProp "URL" #define VCURLValueProp "URLVAL" #define VCValueProp "VALUE" #define VCVersionProp "VERSION" #define VCVideoProp "VIDEO" #define VCVoiceProp "VOICE" #define VCWAVEProp "WAVE" #define VCWMFProp "WMF" #define VCWorkProp "WORK" #define VCX400Prop "X400" #define VCX509Prop "X509" #define VCXRuleProp "XRULE" /* extensions for KOrganizer / KPilot */ #define KPilotIdProp "X-PILOTID" #define KPilotStatusProp "X-PILOTSTAT" /* extensions for iMIP / iTIP */ #define ICOrganizerProp "X-ORGANIZER" #define ICMethodProp "X-METHOD" #define ICRequestStatusProp "X-REQUEST-STATUS" typedef struct VObject VObject; typedef union ValueItem { const char *strs; const wchar_t *ustrs; unsigned int i; unsigned long l; void *any; VObject *vobj; } ValueItem; struct VObject { VObject *next; const char *id; VObject *prop; unsigned short valType; ValueItem val; }; typedef struct StrItem StrItem; struct StrItem { StrItem *next; const char *s; unsigned int refCnt; }; typedef struct VObjectIterator { VObject* start; VObject* next; } VObjectIterator; extern VObject* newVObject(const char *id); extern void deleteVObject(VObject *p); extern char* dupStr(const char *s, unsigned int size); extern void deleteStr(const char *p); extern void unUseStr(const char *s); extern void setVObjectName(VObject *o, const char* id); extern void setVObjectStringZValue(VObject *o, const char *s); extern void setVObjectStringZValue_(VObject *o, const char *s); extern void setVObjectUStringZValue(VObject *o, const wchar_t *s); extern void setVObjectUStringZValue_(VObject *o, const wchar_t *s); extern void setVObjectIntegerValue(VObject *o, unsigned int i); extern void setVObjectLongValue(VObject *o, unsigned long l); extern void setVObjectAnyValue(VObject *o, void *t); extern VObject* setValueWithSize(VObject *prop, void *val, unsigned int size); extern VObject* setValueWithSize_(VObject *prop, void *val, unsigned int size); extern const char* vObjectName(VObject *o); extern const char* vObjectStringZValue(VObject *o); extern const wchar_t* vObjectUStringZValue(VObject *o); extern unsigned int vObjectIntegerValue(VObject *o); extern unsigned long vObjectLongValue(VObject *o); extern void* vObjectAnyValue(VObject *o); extern VObject* vObjectVObjectValue(VObject *o); extern void setVObjectVObjectValue(VObject *o, VObject *p); extern VObject* addVObjectProp(VObject *o, VObject *p); extern VObject* addProp(VObject *o, const char *id); extern VObject* addProp_(VObject *o, const char *id); extern VObject* addPropValue(VObject *o, const char *p, const char *v); extern VObject* addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size); extern VObject* addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size); extern VObject* addGroup(VObject *o, const char *g); extern void addList(VObject **o, VObject *p); extern VObject* isAPropertyOf(VObject *o, const char *id); extern VObject* nextVObjectInList(VObject *o); extern void initPropIterator(VObjectIterator *i, VObject *o); extern int moreIteration(VObjectIterator *i); extern VObject* nextVObject(VObjectIterator *i); extern char* writeMemVObject(char *s, int *len, VObject *o); extern char* writeMemVObjects(char *s, int *len, VObject *list); extern const char* lookupStr(const char *s); extern void cleanStrTbl(); extern void cleanVObject(VObject *o); extern void cleanVObjects(VObject *list); extern const char* lookupProp(const char* str); extern const char* lookupProp_(const char* str); extern wchar_t* fakeUnicode(const char *ps, int *bytes); extern unsigned int uStrLen(const wchar_t *u); extern char* fakeCString(const wchar_t *u); extern void printVObjectToFile(char *fname,VObject *o); extern void printVObjectsToFile(char *fname,VObject *list); extern void writeVObjectToFile(char *fname, VObject *o); extern void writeVObjectsToFile(char *fname, VObject *list); extern int vObjectValueType(VObject *o); /* return type of vObjectValueType: */ #define VCVT_NOVALUE 0 /* if the VObject has no value associated with it. */ #define VCVT_STRINGZ 1 /* if the VObject has value set by setVObjectStringZValue. */ #define VCVT_USTRINGZ 2 /* if the VObject has value set by setVObjectUStringZValue. */ #define VCVT_UINT 3 /* if the VObject has value set by setVObjectIntegerValue. */ #define VCVT_ULONG 4 /* if the VObject has value set by setVObjectLongValue. */ #define VCVT_RAW 5 /* if the VObject has value set by setVObjectAnyValue. */ #define VCVT_VOBJECT 6 /* if the VObject has value set by setVObjectVObjectValue. */ extern const char** fieldedProp; extern void printVObject(FILE *fp,VObject *o); extern void writeVObject(FILE *fp, VObject *o); #if defined(__CPLUSPLUS__) || defined(__cplusplus) } #endif #endif /* __VOBJECT_H__ */