mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 10:52:52 +00:00
1689 lines
52 KiB
C++
1689 lines
52 KiB
C++
/*
|
|
This file is part of the kcal library.
|
|
|
|
Copyright (c) 1998 Preston Brown <pbrown@kde.org>
|
|
Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
|
|
|
|
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 \<pbrown@kde.org\>
|
|
@author Cornelius Schumacher \<schumacher@kde.org\>
|
|
*/
|
|
|
|
#include "vcalformat.h"
|
|
#include "calendar.h"
|
|
#include "versit/vcc.h"
|
|
#include "versit/vobject.h"
|
|
|
|
#include <kdebug.h>
|
|
#include <kdatetime.h>
|
|
#include <klocalizedstring.h>
|
|
|
|
#include <QtCore/QString>
|
|
#include <QtCore/QRegExp>
|
|
#include <QtCore/QFile>
|
|
#include <QtCore/QByteArray>
|
|
#include <QTextDocument>
|
|
|
|
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<char *>( 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 &string )
|
|
{
|
|
return fromRawString( calendar, string.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 *dObject = addPropValue( vtodo, VCDescriptionProp,
|
|
anEvent->description().toLocal8Bit() );
|
|
if ( anEvent->description().indexOf( '\n' ) != -1 ) {
|
|
addPropValue( dObject, 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<RecurrenceRule::WDayPos> tmpPositions = recur->monthPositions();
|
|
for ( QList<RecurrenceRule::WDayPos>::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<int> tmpDays = recur->monthDays();
|
|
for ( QList<int>::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<int> months = recur->yearMonths();
|
|
for ( QList<int>::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<int> tmpDays = recur->yearDays();
|
|
for ( QList<int>::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, VCExpDateProp, tmpStr2.toLocal8Bit() );
|
|
}
|
|
|
|
// description
|
|
if ( !anEvent->description().isEmpty() ) {
|
|
VObject *dObject = addPropValue( vevent, VCDescriptionProp,
|
|
anEvent->description().toLocal8Bit() );
|
|
if ( anEvent->description().indexOf( '\n' ) != -1 ) {
|
|
addPropValue( dObject, 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 ( s && 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 ) ) ) {
|
|
s = fakeCString( vObjectUStringZValue( vo ) );
|
|
if ( s ) {
|
|
anEvent->setPriority( atoi( s ) );
|
|
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...
|
|
anEvent->setRevision( 0 );
|
|
if ( ( vo = isAPropertyOf( vevent, VCSequenceProp ) ) != 0 ) {
|
|
s = fakeCString( vObjectUStringZValue( vo ) );
|
|
if ( s ) {
|
|
anEvent->setRevision( atoi( s ) );
|
|
deleteStr( s );
|
|
}
|
|
}
|
|
|
|
// 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 = 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 );
|
|
if ( dayNum >= 0 ) {
|
|
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, 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 ( s && strcmp( s, "PRIVATE" ) == 0 ) {
|
|
secrecy = Incidence::SecrecyPrivate;
|
|
} else if ( s && 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 ) ) ) {
|
|
s = fakeCString( vObjectUStringZValue( vo ) );
|
|
if ( s ) {
|
|
anEvent->setPriority( atoi( s ) );
|
|
deleteStr( s );
|
|
}
|
|
}
|
|
|
|
// transparency
|
|
if ( ( vo = isAPropertyOf( vevent, VCTranspProp ) ) != 0 ) {
|
|
s = fakeCString( vObjectUStringZValue( vo ) );
|
|
if ( s ) {
|
|
int i = atoi( s );
|
|
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 ( !s || 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 ( !s || 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 ( s ) {
|
|
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;
|
|
}
|
|
}
|