Page MenuHomePhorge

No OneTemporary

diff --git a/kcal/icalformat_p.cpp b/kcal/icalformat_p.cpp
index 1fbebc5f4..3a171b939 100644
--- a/kcal/icalformat_p.cpp
+++ b/kcal/icalformat_p.cpp
@@ -1,2533 +1,2533 @@
/*
This file is part of the kcal library.
Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
Copyright (c) 2006 David Jarvie <software@astrojar.org.uk>
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 internal ICalFormat classes.
@brief
This class provides the libical dependent functions for ICalFormat.
@author Cornelius Schumacher \<schumacher@kde.org\>
@author Reinhold Kainhofer \<reinhold@kainhofer.com\>
@author David Jarvie \<software@astrojar.org.uk\>
*/
#include "icalformat_p.h"
#include "icalformat.h"
#include "icaltimezones.h"
#include "calendar.h"
#include "compat.h"
#include "journal.h"
extern "C" {
#include <ical.h>
#include <icalparser.h>
#include <icalrestriction.h>
}
#include <QtCore/QString>
#include <QtCore/QFile>
#include <QtCore/QList>
#include <QtCore/QByteArray>
#include <kdebug.h>
#include <kdatetime.h>
#include <ktzfiletimezone.h>
#include <ksystemtimezone.h>
#include <klocale.h>
#include <kcodecs.h>
#include <cstdlib>
using namespace KCal;
/* Static helpers */
/*
static void _dumpIcaltime( const icaltimetype& t)
{
kDebug() << "--- Y:" << t.year << "M:" << t.month << "D:" << t.day;
kDebug() << "--- H:" << t.hour << "M:" << t.minute << "S:" << t.second;
kDebug() << "--- isUtc:" << icaltime_is_utc( t );
kDebug() << "--- zoneId:" << icaltimezone_get_tzid( const_cast<icaltimezone*>( t.zone ) );
}
*/
//@cond PRIVATE
const int gSecondsPerMinute = 60;
const int gSecondsPerHour = gSecondsPerMinute * 60;
const int gSecondsPerDay = gSecondsPerHour * 24;
const int gSecondsPerWeek = gSecondsPerDay * 7;
class ToComponentVisitor : public IncidenceBase::Visitor
{
public:
ToComponentVisitor( ICalFormatImpl *impl, iTIPMethod m )
: mImpl( impl ), mComponent( 0 ), mMethod( m ) {}
bool visit( Event *e )
{
mComponent = mImpl->writeEvent( e );
return true;
}
bool visit( Todo *e )
{
mComponent = mImpl->writeTodo( e );
return true;
}
bool visit( Journal *e )
{
mComponent = mImpl->writeJournal( e );
return true;
}
bool visit( FreeBusy *fb )
{
mComponent = mImpl->writeFreeBusy( fb, mMethod );
return true;
}
icalcomponent *component()
{
return mComponent;
}
private:
ICalFormatImpl *mImpl;
icalcomponent *mComponent;
iTIPMethod mMethod;
};
class ICalFormatImpl::Private
{
public:
Private( ICalFormatImpl *impl, ICalFormat *parent )
: mImpl( impl ), mParent( parent ), mCompat( new Compat ) {}
~Private() { delete mCompat; }
void writeIncidenceBase( icalcomponent *parent, IncidenceBase * );
void readIncidenceBase( icalcomponent *parent, IncidenceBase * );
void writeCustomProperties( icalcomponent *parent, CustomProperties * );
void readCustomProperties( icalcomponent *parent, CustomProperties * );
ICalFormatImpl *mImpl;
ICalFormat *mParent;
QString mLoadedProductId; // PRODID string loaded from calendar file
Event::List mEventsRelate; // events with relations
Todo::List mTodosRelate; // todos with relations
Compat *mCompat;
};
//@endcond
inline icaltimetype ICalFormatImpl::writeICalUtcDateTime ( const KDateTime &dt )
{
return writeICalDateTime( dt.toUtc() );
}
ICalFormatImpl::ICalFormatImpl( ICalFormat *parent )
: d( new Private( this, parent ) )
{
}
ICalFormatImpl::~ICalFormatImpl()
{
delete d;
}
QString ICalFormatImpl::loadedProductId() const
{
return d->mLoadedProductId;
}
icalcomponent *ICalFormatImpl::writeIncidence( IncidenceBase *incidence,
iTIPMethod method )
{
ToComponentVisitor v( this, method );
if ( incidence->accept(v) ) {
return v.component();
} else {
return 0;
}
}
icalcomponent *ICalFormatImpl::writeTodo( Todo *todo, ICalTimeZones *tzlist,
ICalTimeZones *tzUsedList )
{
QString tmpStr;
QStringList tmpStrList;
icalcomponent *vtodo = icalcomponent_new( ICAL_VTODO_COMPONENT );
writeIncidence( vtodo, todo, tzlist, tzUsedList );
// due date
icalproperty *prop;
if ( todo->hasDueDate() ) {
icaltimetype due;
if ( todo->allDay() ) {
due = writeICalDate( todo->dtDue( true ).date() );
prop = icalproperty_new_due(due);
} else {
prop = writeICalDateTimeProperty(
ICAL_DUE_PROPERTY, todo->dtDue(true), tzlist, tzUsedList );
}
icalcomponent_add_property( vtodo, prop );
}
// start time
if ( todo->hasStartDate() || todo->recurs() ) {
icaltimetype start;
if ( todo->allDay() ) {
start = writeICalDate( todo->dtStart( true ).date() );
prop = icalproperty_new_dtstart( start );
} else {
prop = writeICalDateTimeProperty(
ICAL_DTSTART_PROPERTY, todo->dtStart( true ), tzlist, tzUsedList );
}
icalcomponent_add_property( vtodo, prop );
}
// completion date (UTC)
if ( todo->isCompleted() ) {
if ( !todo->hasCompletedDate() ) {
// If the todo was created by KOrganizer<2.2 it does not have
// a correct completion date. Set one now.
todo->setCompleted( KDateTime::currentUtcDateTime() );
}
icaltimetype completed = writeICalUtcDateTime( todo->completed() );
icalcomponent_add_property(
vtodo, icalproperty_new_completed ( completed ) );
}
icalcomponent_add_property(
vtodo, icalproperty_new_percentcomplete( todo->percentComplete() ) );
if ( todo->recurs() ) {
icalcomponent_add_property(
vtodo, writeICalDateTimeProperty(
ICAL_RECURRENCEID_PROPERTY, todo->dtDue(), tzlist, tzUsedList ) );
}
return vtodo;
}
icalcomponent *ICalFormatImpl::writeEvent( Event *event,
ICalTimeZones *tzlist,
ICalTimeZones *tzUsedList )
{
icalcomponent *vevent = icalcomponent_new( ICAL_VEVENT_COMPONENT );
writeIncidence( vevent, event, tzlist, tzUsedList );
// start time
icalproperty *prop;
icaltimetype start;
if ( event->allDay() ) {
start = writeICalDate( event->dtStart().date() );
prop = icalproperty_new_dtstart( start );
} else {
prop = writeICalDateTimeProperty(
ICAL_DTSTART_PROPERTY, event->dtStart(), tzlist, tzUsedList );
}
icalcomponent_add_property( vevent, prop );
if ( event->hasEndDate() ) {
// End time.
// RFC2445 says that if DTEND is present, it has to be greater than DTSTART.
icaltimetype end;
KDateTime dt = event->dtEnd();
if ( event->allDay() ) {
// +1 day because end date is non-inclusive.
end = writeICalDate( dt.date().addDays( 1 ) );
icalcomponent_add_property( vevent, icalproperty_new_dtend(end) );
} else {
if ( dt != event->dtStart() ) {
icalcomponent_add_property(
vevent, writeICalDateTimeProperty(
ICAL_DTEND_PROPERTY, dt, tzlist, tzUsedList ) );
}
}
}
// TODO: resources
#if 0
// resources
QStringList tmpStrList = anEvent->resources();
QString tmpStr = tmpStrList.join( ";" );
if ( !tmpStr.isEmpty() ) {
addPropValue( vevent, VCResourcesProp, tmpStr.toUtf8() );
}
#endif
// Transparency
switch( event->transparency() ) {
case Event::Transparent:
icalcomponent_add_property(
vevent,
icalproperty_new_transp( ICAL_TRANSP_TRANSPARENT ) );
break;
case Event::Opaque:
icalcomponent_add_property(
vevent,
icalproperty_new_transp( ICAL_TRANSP_OPAQUE ) );
break;
}
return vevent;
}
icalcomponent *ICalFormatImpl::writeFreeBusy( FreeBusy *freebusy,
iTIPMethod method )
{
icalcomponent *vfreebusy = icalcomponent_new( ICAL_VFREEBUSY_COMPONENT );
d->writeIncidenceBase( vfreebusy, freebusy );
icalcomponent_add_property(
vfreebusy, icalproperty_new_dtstart( writeICalUtcDateTime( freebusy->dtStart() ) ) );
icalcomponent_add_property(
vfreebusy, icalproperty_new_dtend( writeICalUtcDateTime( freebusy->dtEnd() ) ) );
if ( method == iTIPRequest ) {
icalcomponent_add_property(
vfreebusy, icalproperty_new_uid( freebusy->uid().toUtf8() ) );
}
//Loops through all the periods in the freebusy object
QList<Period> list = freebusy->busyPeriods();
icalperiodtype period = icalperiodtype_null_period();
for ( int i = 0, count = list.count(); i < count; ++i ) {
period.start = writeICalUtcDateTime( list[i].start() );
if ( list[i].hasDuration() ) {
period.duration = writeICalDuration( list[i].duration() );
} else {
period.end = writeICalUtcDateTime( list[i].end() );
}
icalcomponent_add_property(
vfreebusy, icalproperty_new_freebusy( period ) );
}
return vfreebusy;
}
icalcomponent *ICalFormatImpl::writeJournal( Journal *journal,
ICalTimeZones *tzlist,
ICalTimeZones *tzUsedList )
{
icalcomponent *vjournal = icalcomponent_new( ICAL_VJOURNAL_COMPONENT );
writeIncidence( vjournal, journal, tzlist, tzUsedList );
// start time
icalproperty *prop;
KDateTime dt = journal->dtStart();
if ( dt.isValid() ) {
icaltimetype start;
if ( journal->allDay() ) {
start = writeICalDate( dt.date() );
prop = icalproperty_new_dtstart( start );
} else {
prop = writeICalDateTimeProperty(
ICAL_DTSTART_PROPERTY, dt, tzlist, tzUsedList );
}
icalcomponent_add_property( vjournal, prop );
}
return vjournal;
}
void ICalFormatImpl::writeIncidence( icalcomponent *parent,
Incidence *incidence,
ICalTimeZones *tzlist,
ICalTimeZones *tzUsedList )
{
if ( incidence->schedulingID() != incidence->uid() ) {
// We need to store the UID in here. The rawSchedulingID will
// go into the iCal UID component
incidence->setCustomProperty( "LIBKCAL", "ID", incidence->uid() );
} else {
incidence->removeCustomProperty( "LIBKCAL", "ID" );
}
d->writeIncidenceBase( parent, incidence );
// creation date
icalcomponent_add_property(
parent, writeICalDateTimeProperty(
ICAL_CREATED_PROPERTY, incidence->created() ) );
// unique id
// If the scheduling ID is different from the real UID, the real
// one is stored on X-REALID above
if ( !incidence->schedulingID().isEmpty() ) {
icalcomponent_add_property(
parent, icalproperty_new_uid( incidence->schedulingID().toUtf8() ) );
}
// revision
if ( incidence->revision() > 0 ) { // 0 is default, so don't write that out
icalcomponent_add_property(
parent, icalproperty_new_sequence( incidence->revision() ) );
}
// last modification date
if ( incidence->lastModified().isValid() ) {
icalcomponent_add_property(
parent, writeICalDateTimeProperty(
ICAL_LASTMODIFIED_PROPERTY, incidence->lastModified() ) );
}
// description
if ( !incidence->description().isEmpty() ) {
icalcomponent_add_property(
parent, writeDescription(
incidence->description(), incidence->descriptionIsRich() ) );
}
// summary
if ( !incidence->summary().isEmpty() ) {
icalcomponent_add_property(
parent, writeSummary(
incidence->summary(), incidence->summaryIsRich() ) );
}
// location
if ( !incidence->location().isEmpty() ) {
icalcomponent_add_property(
parent, writeLocation(
incidence->location(), incidence->locationIsRich() ) );
}
// status
icalproperty_status status = ICAL_STATUS_NONE;
switch ( incidence->status() ) {
case Incidence::StatusTentative:
status = ICAL_STATUS_TENTATIVE;
break;
case Incidence::StatusConfirmed:
status = ICAL_STATUS_CONFIRMED;
break;
case Incidence::StatusCompleted:
status = ICAL_STATUS_COMPLETED;
break;
case Incidence::StatusNeedsAction:
status = ICAL_STATUS_NEEDSACTION;
break;
case Incidence::StatusCanceled:
status = ICAL_STATUS_CANCELLED;
break;
case Incidence::StatusInProcess:
status = ICAL_STATUS_INPROCESS;
break;
case Incidence::StatusDraft:
status = ICAL_STATUS_DRAFT;
break;
case Incidence::StatusFinal:
status = ICAL_STATUS_FINAL;
break;
case Incidence::StatusX:
{
icalproperty *p = icalproperty_new_status( ICAL_STATUS_X );
icalvalue_set_x( icalproperty_get_value( p ), incidence->statusStr().toUtf8() );
icalcomponent_add_property( parent, p );
break;
}
case Incidence::StatusNone:
default:
break;
}
if ( status != ICAL_STATUS_NONE ) {
icalcomponent_add_property( parent, icalproperty_new_status( status ) );
}
// secrecy
icalproperty_class secClass;
switch ( incidence->secrecy() ) {
case Incidence::SecrecyPublic:
secClass = ICAL_CLASS_PUBLIC;
break;
case Incidence::SecrecyConfidential:
secClass = ICAL_CLASS_CONFIDENTIAL;
break;
case Incidence::SecrecyPrivate:
default:
secClass = ICAL_CLASS_PRIVATE;
break;
}
if ( secClass != ICAL_CLASS_PUBLIC ) {
icalcomponent_add_property( parent, icalproperty_new_class( secClass ) );
}
// priority
if ( incidence->priority() > 0 ) { // 0 is undefined priority
icalcomponent_add_property(
parent, icalproperty_new_priority( incidence->priority() ) );
}
// categories
QStringList categories = incidence->categories();
QStringList::Iterator it;
for ( it = categories.begin(); it != categories.end(); ++it ) {
icalcomponent_add_property(
parent, icalproperty_new_categories( (*it).toUtf8() ) );
}
// related event
if ( !incidence->relatedToUid().isEmpty() ) {
icalcomponent_add_property(
parent, icalproperty_new_relatedto( incidence->relatedToUid().toUtf8() ) );
}
RecurrenceRule::List rrules( incidence->recurrence()->rRules() );
RecurrenceRule::List::ConstIterator rit;
for ( rit = rrules.begin(); rit != rrules.end(); ++rit ) {
icalcomponent_add_property(
parent, icalproperty_new_rrule( writeRecurrenceRule( (*rit) ) ) );
}
RecurrenceRule::List exrules( incidence->recurrence()->exRules() );
RecurrenceRule::List::ConstIterator exit;
for ( exit = exrules.begin(); exit != exrules.end(); ++exit ) {
icalcomponent_add_property(
parent, icalproperty_new_rrule( writeRecurrenceRule( (*exit) ) ) );
}
DateList dateList = incidence->recurrence()->exDates();
DateList::ConstIterator exIt;
for ( exIt = dateList.begin(); exIt != dateList.end(); ++exIt ) {
icalcomponent_add_property(
parent, icalproperty_new_exdate( writeICalDate(*exIt) ) );
}
DateTimeList dateTimeList = incidence->recurrence()->exDateTimes();
DateTimeList::ConstIterator extIt;
for ( extIt = dateTimeList.begin(); extIt != dateTimeList.end(); ++extIt ) {
icalcomponent_add_property(
parent, writeICalDateTimeProperty( ICAL_EXDATE_PROPERTY, *extIt, tzlist, tzUsedList ) );
}
dateList = incidence->recurrence()->rDates();
DateList::ConstIterator rdIt;
for ( rdIt = dateList.begin(); rdIt != dateList.end(); ++rdIt ) {
icalcomponent_add_property(
parent, icalproperty_new_rdate( writeICalDatePeriod(*rdIt) ) );
}
dateTimeList = incidence->recurrence()->rDateTimes();
DateTimeList::ConstIterator rdtIt;
for ( rdtIt = dateTimeList.begin(); rdtIt != dateTimeList.end(); ++rdtIt ) {
icalcomponent_add_property(
parent, writeICalDateTimeProperty( ICAL_RDATE_PROPERTY, *rdtIt, tzlist, tzUsedList ) );
}
// attachments
Attachment::List attachments = incidence->attachments();
Attachment::List::ConstIterator atIt;
for ( atIt = attachments.begin(); atIt != attachments.end(); ++atIt ) {
icalcomponent_add_property( parent, writeAttachment( *atIt ) );
}
// alarms
Alarm::List::ConstIterator alarmIt;
for ( alarmIt = incidence->alarms().begin();
alarmIt != incidence->alarms().end(); ++alarmIt ) {
if ( (*alarmIt)->enabled() ) {
icalcomponent_add_component( parent, writeAlarm( *alarmIt ) );
}
}
// duration
if ( incidence->hasDuration() ) {
icaldurationtype duration;
duration = writeICalDuration( incidence->duration() );
icalcomponent_add_property( parent, icalproperty_new_duration( duration ) );
}
}
//@cond PRIVATE
void ICalFormatImpl::Private::writeIncidenceBase( icalcomponent *parent,
IncidenceBase *incidenceBase )
{
icalcomponent_add_property(
parent, writeICalDateTimeProperty(
ICAL_DTSTAMP_PROPERTY, KDateTime::currentUtcDateTime() ) );
// organizer stuff
if ( !incidenceBase->organizer().isEmpty() ) {
icalcomponent_add_property(
parent, mImpl->writeOrganizer( incidenceBase->organizer() ) );
}
// attendees
if ( incidenceBase->attendeeCount() > 0 ) {
Attendee::List::ConstIterator it;
for ( it = incidenceBase->attendees().begin();
it != incidenceBase->attendees().end(); ++it ) {
icalcomponent_add_property( parent, mImpl->writeAttendee( *it ) );
}
}
// comments
QStringList comments = incidenceBase->comments();
for ( QStringList::Iterator it = comments.begin(); it != comments.end(); ++it ) {
icalcomponent_add_property(
parent, icalproperty_new_comment( (*it).toUtf8() ) );
}
// custom properties
writeCustomProperties( parent, incidenceBase );
}
void ICalFormatImpl::Private::writeCustomProperties( icalcomponent *parent,
CustomProperties *properties )
{
QMap<QByteArray, QString> custom = properties->customProperties();
for ( QMap<QByteArray, QString>::Iterator c = custom.begin(); c != custom.end(); ++c ) {
icalproperty *p = icalproperty_new_x( c.value().toUtf8() );
icalproperty_set_x_name( p, c.key() );
icalcomponent_add_property( parent, p );
}
}
//@endcond
icalproperty *ICalFormatImpl::writeOrganizer( const Person &organizer )
{
icalproperty *p =
icalproperty_new_organizer( "MAILTO:" + organizer.email().toUtf8() );
if ( !organizer.name().isEmpty() ) {
icalproperty_add_parameter(
p, icalparameter_new_cn( organizer.name().toUtf8() ) );
}
// TODO: Write dir, sent-by and language
return p;
}
icalproperty *ICalFormatImpl::writeDescription( const QString &description, bool isRich )
{
icalproperty *p = icalproperty_new_description( description.toUtf8() );
if ( isRich ) {
icalproperty_add_parameter( p, icalparameter_new_from_string( "X-KDE-TEXTFORMAT=HTML" ) );
}
return p;
}
icalproperty *ICalFormatImpl::writeSummary( const QString &summary, bool isRich )
{
icalproperty *p = icalproperty_new_summary( summary.toUtf8() );
if ( isRich ) {
icalproperty_add_parameter( p, icalparameter_new_from_string( "X-KDE-TEXTFORMAT=HTML" ) );
}
return p;
}
icalproperty *ICalFormatImpl::writeLocation( const QString &location, bool isRich )
{
icalproperty *p = icalproperty_new_location( location.toUtf8() );
if ( isRich ) {
icalproperty_add_parameter( p, icalparameter_new_from_string( "X-KDE-TEXTFORMAT=HTML" ) );
}
return p;
}
icalproperty *ICalFormatImpl::writeAttendee( Attendee *attendee )
{
icalproperty *p =
icalproperty_new_attendee( "mailto:" + attendee->email().toUtf8() );
if ( !attendee->name().isEmpty() ) {
icalproperty_add_parameter(
p, icalparameter_new_cn( attendee->name().toUtf8() ) );
}
icalproperty_add_parameter(
p, icalparameter_new_rsvp( attendee->RSVP() ? ICAL_RSVP_TRUE : ICAL_RSVP_FALSE ) );
icalparameter_partstat status = ICAL_PARTSTAT_NEEDSACTION;
switch ( attendee->status() ) {
default:
case Attendee::NeedsAction:
status = ICAL_PARTSTAT_NEEDSACTION;
break;
case Attendee::Accepted:
status = ICAL_PARTSTAT_ACCEPTED;
break;
case Attendee::Declined:
status = ICAL_PARTSTAT_DECLINED;
break;
case Attendee::Tentative:
status = ICAL_PARTSTAT_TENTATIVE;
break;
case Attendee::Delegated:
status = ICAL_PARTSTAT_DELEGATED;
break;
case Attendee::Completed:
status = ICAL_PARTSTAT_COMPLETED;
break;
case Attendee::InProcess:
status = ICAL_PARTSTAT_INPROCESS;
break;
}
icalproperty_add_parameter( p, icalparameter_new_partstat( status ) );
icalparameter_role role = ICAL_ROLE_REQPARTICIPANT;
switch ( attendee->role() ) {
case Attendee::Chair:
role = ICAL_ROLE_CHAIR;
break;
default:
case Attendee::ReqParticipant:
role = ICAL_ROLE_REQPARTICIPANT;
break;
case Attendee::OptParticipant:
role = ICAL_ROLE_OPTPARTICIPANT;
break;
case Attendee::NonParticipant:
role = ICAL_ROLE_NONPARTICIPANT;
break;
}
icalproperty_add_parameter( p, icalparameter_new_role( role ) );
if ( !attendee->uid().isEmpty() ) {
icalparameter *icalparameter_uid =
icalparameter_new_x( attendee->uid().toUtf8() );
icalparameter_set_xname( icalparameter_uid, "X-UID" );
icalproperty_add_parameter( p, icalparameter_uid );
}
if ( !attendee->delegate().isEmpty() ) {
icalparameter *icalparameter_delegate =
icalparameter_new_delegatedto( attendee->delegate().toUtf8() );
icalproperty_add_parameter( p, icalparameter_delegate );
}
if ( !attendee->delegator().isEmpty() ) {
icalparameter *icalparameter_delegator =
icalparameter_new_delegatedfrom( attendee->delegator().toUtf8() );
icalproperty_add_parameter( p, icalparameter_delegator );
}
return p;
}
icalproperty *ICalFormatImpl::writeAttachment( Attachment *att )
{
icalattach *attach;
if ( att->isUri() ) {
attach = icalattach_new_from_url( att->uri().toUtf8().data() );
} else {
attach = icalattach_new_from_data ( ( unsigned char * )att->data(), 0, 0 );
}
icalproperty *p = icalproperty_new_attach( attach );
if ( !att->mimeType().isEmpty() ) {
icalproperty_add_parameter(
p, icalparameter_new_fmttype( att->mimeType().toUtf8().data() ) );
}
if ( att->isBinary() ) {
icalproperty_add_parameter(
p, icalparameter_new_value( ICAL_VALUE_BINARY ) );
icalproperty_add_parameter(
p, icalparameter_new_encoding( ICAL_ENCODING_BASE64 ) );
}
if ( att->showInline() ) {
icalparameter *icalparameter_inline = icalparameter_new_x( "inline" );
icalparameter_set_xname( icalparameter_inline, "X-CONTENT-DISPOSITION" );
icalproperty_add_parameter( p, icalparameter_inline );
}
if ( !att->label().isEmpty() ) {
icalparameter *icalparameter_label =
icalparameter_new_x( att->label().toUtf8() );
icalparameter_set_xname( icalparameter_label, "X-LABEL" );
icalproperty_add_parameter( p, icalparameter_label );
}
if ( att->isLocal() ) {
icalparameter *icalparameter_local = icalparameter_new_x( "local" );
icalparameter_set_xname( icalparameter_local, "X-KONTACT-TYPE" );
icalproperty_add_parameter( p, icalparameter_local );
}
return p;
}
icalrecurrencetype ICalFormatImpl::writeRecurrenceRule( RecurrenceRule *recur )
{
icalrecurrencetype r;
icalrecurrencetype_clear( &r );
switch( recur->recurrenceType() ) {
case RecurrenceRule::rSecondly:
r.freq = ICAL_SECONDLY_RECURRENCE;
break;
case RecurrenceRule::rMinutely:
r.freq = ICAL_MINUTELY_RECURRENCE;
break;
case RecurrenceRule::rHourly:
r.freq = ICAL_HOURLY_RECURRENCE;
break;
case RecurrenceRule::rDaily:
r.freq = ICAL_DAILY_RECURRENCE;
break;
case RecurrenceRule::rWeekly:
r.freq = ICAL_WEEKLY_RECURRENCE;
break;
case RecurrenceRule::rMonthly:
r.freq = ICAL_MONTHLY_RECURRENCE;
break;
case RecurrenceRule::rYearly:
r.freq = ICAL_YEARLY_RECURRENCE;
break;
default:
r.freq = ICAL_NO_RECURRENCE;
kDebug() << "no recurrence";
break;
}
int index = 0;
QList<int> bys;
QList<int>::ConstIterator it;
// Now write out the BY* parts:
bys = recur->bySeconds();
index = 0;
for ( it = bys.begin(); it != bys.end(); ++it ) {
r.by_second[index++] = *it;
}
bys = recur->byMinutes();
index = 0;
for ( it = bys.begin(); it != bys.end(); ++it ) {
r.by_minute[index++] = *it;
}
bys = recur->byHours();
index = 0;
for ( it = bys.begin(); it != bys.end(); ++it ) {
r.by_hour[index++] = *it;
}
bys = recur->byMonthDays();
index = 0;
for ( it = bys.begin(); it != bys.end(); ++it ) {
r.by_month_day[index++] = icalrecurrencetype_day_position( (*it) * 8 );
}
bys = recur->byYearDays();
index = 0;
for ( it = bys.begin(); it != bys.end(); ++it ) {
r.by_year_day[index++] = *it;
}
bys = recur->byWeekNumbers();
index = 0;
for ( it = bys.begin(); it != bys.end(); ++it ) {
r.by_week_no[index++] = *it;
}
bys = recur->byMonths();
index = 0;
for ( it = bys.begin(); it != bys.end(); ++it ) {
r.by_month[index++] = *it;
}
bys = recur->bySetPos();
index = 0;
for ( it = bys.begin(); it != bys.end(); ++it ) {
r.by_set_pos[index++] = *it;
}
QList<RecurrenceRule::WDayPos> byd = recur->byDays();
int day;
index = 0;
for ( QList<RecurrenceRule::WDayPos>::ConstIterator dit = byd.begin();
dit != byd.end(); ++dit ) {
day = (*dit).day() % 7 + 1; // convert from Monday=1 to Sunday=1
if ( (*dit).pos() < 0 ) {
day += ( -(*dit).pos() ) * 8;
day = -day;
} else {
day += (*dit).pos() * 8;
}
r.by_day[index++] = day;
}
r.week_start =
static_cast<icalrecurrencetype_weekday>( recur->weekStart() % 7 + 1 );
if ( recur->frequency() > 1 ) {
// Dont' write out INTERVAL=1, because that's the default anyway
r.interval = recur->frequency();
}
if ( recur->duration() > 0 ) {
r.count = recur->duration();
} else if ( recur->duration() == -1 ) {
r.count = 0;
} else {
if ( recur->allDay() ) {
r.until = writeICalDate( recur->endDt().date() );
} else {
r.until = writeICalUtcDateTime( recur->endDt() );
}
}
return r;
}
icalcomponent *ICalFormatImpl::writeAlarm( Alarm *alarm )
{
icalcomponent *a = icalcomponent_new( ICAL_VALARM_COMPONENT );
icalproperty_action action;
icalattach *attach = 0;
switch ( alarm->type() ) {
case Alarm::Procedure:
action = ICAL_ACTION_PROCEDURE;
attach = icalattach_new_from_url(
QFile::encodeName( alarm->programFile() ).data() );
icalcomponent_add_property( a, icalproperty_new_attach( attach ) );
if ( !alarm->programArguments().isEmpty() ) {
icalcomponent_add_property(
a, icalproperty_new_description( alarm->programArguments().toUtf8() ) );
}
break;
case Alarm::Audio:
action = ICAL_ACTION_AUDIO;
if ( !alarm->audioFile().isEmpty() ) {
attach = icalattach_new_from_url(
QFile::encodeName( alarm->audioFile() ).data() );
icalcomponent_add_property( a, icalproperty_new_attach( attach ) );
}
break;
case Alarm::Email:
{
action = ICAL_ACTION_EMAIL;
QList<Person> addresses = alarm->mailAddresses();
for ( QList<Person>::Iterator ad = addresses.begin();
ad != addresses.end(); ++ad ) {
icalproperty *p = icalproperty_new_attendee(
"MAILTO:" + (*ad).email().toUtf8() );
if ( !(*ad).name().isEmpty() ) {
icalproperty_add_parameter(
p, icalparameter_new_cn( (*ad).name().toUtf8() ) );
}
icalcomponent_add_property( a, p );
}
icalcomponent_add_property(
a, icalproperty_new_summary( alarm->mailSubject().toUtf8() ) );
icalcomponent_add_property(
a, icalproperty_new_description( alarm->mailText().toUtf8() ) );
QStringList attachments = alarm->mailAttachments();
if ( attachments.count() > 0 ) {
for ( QStringList::Iterator at = attachments.begin();
at != attachments.end(); ++at ) {
attach = icalattach_new_from_url( QFile::encodeName( *at ).data() );
icalcomponent_add_property( a, icalproperty_new_attach( attach ) );
}
}
break;
}
case Alarm::Display:
action = ICAL_ACTION_DISPLAY;
icalcomponent_add_property(
a, icalproperty_new_description( alarm->text().toUtf8() ) );
break;
case Alarm::Invalid:
default:
kDebug() << "Unknown type of alarm";
action = ICAL_ACTION_NONE;
break;
}
icalcomponent_add_property( a, icalproperty_new_action( action ) );
// Trigger time
icaltriggertype trigger;
if ( alarm->hasTime() ) {
trigger.time = writeICalUtcDateTime( alarm->time() );
trigger.duration = icaldurationtype_null_duration();
} else {
trigger.time = icaltime_null_time();
Duration offset;
if ( alarm->hasStartOffset() ) {
offset = alarm->startOffset();
} else {
offset = alarm->endOffset();
}
trigger.duration = writeICalDuration( offset );
}
icalproperty *p = icalproperty_new_trigger( trigger );
if ( alarm->hasEndOffset() ) {
icalproperty_add_parameter( p, icalparameter_new_related( ICAL_RELATED_END ) );
}
icalcomponent_add_property( a, p );
// Repeat count and duration
if ( alarm->repeatCount() ) {
icalcomponent_add_property(
a, icalproperty_new_repeat( alarm->repeatCount() ) );
icalcomponent_add_property(
a, icalproperty_new_duration( writeICalDuration( alarm->snoozeTime() ) ) );
}
// Custom properties
QMap<QByteArray, QString> custom = alarm->customProperties();
for ( QMap<QByteArray, QString>::Iterator c = custom.begin(); c != custom.end(); ++c ) {
icalproperty *p = icalproperty_new_x( c.value().toUtf8() );
icalproperty_set_x_name( p, c.key() );
icalcomponent_add_property( a, p );
}
return a;
}
Todo *ICalFormatImpl::readTodo( icalcomponent *vtodo, ICalTimeZones *tzlist )
{
Todo *todo = new Todo;
readIncidence( vtodo, todo, tzlist );
icalproperty *p = icalcomponent_get_first_property( vtodo, ICAL_ANY_PROPERTY );
QStringList categories;
while ( p ) {
icalproperty_kind kind = icalproperty_isa(p);
switch ( kind ) {
case ICAL_DUE_PROPERTY:
{ // due date/time
KDateTime kdt = readICalDateTimeProperty( p, tzlist );
if ( kdt.isDateOnly() ) {
todo->setDtDue( KDateTime( kdt.date(), todo->dtStart().timeSpec() ), true );
} else {
todo->setDtDue( kdt, true );
todo->setAllDay( false );
}
todo->setHasDueDate( true );
break;
}
case ICAL_COMPLETED_PROPERTY: // completion date/time
todo->setCompleted( readICalDateTimeProperty( p, tzlist ) );
break;
case ICAL_PERCENTCOMPLETE_PROPERTY: // Percent completed
todo->setPercentComplete( icalproperty_get_percentcomplete( p ) );
break;
case ICAL_RELATEDTO_PROPERTY: // related todo (parent)
todo->setRelatedToUid( QString::fromUtf8( icalproperty_get_relatedto( p ) ) );
d->mTodosRelate.append( todo );
break;
case ICAL_DTSTART_PROPERTY:
// Flag that todo has start date. Value is read in by readIncidence().
if ( todo->comments().filter( "NoStartDate" ).count() ) {
todo->setHasStartDate( false );
} else {
todo->setHasStartDate( true );
}
break;
case ICAL_RECURRENCEID_PROPERTY:
todo->setDtRecurrence( readICalDateTimeProperty( p, tzlist ) );
break;
default:
// TODO: do something about unknown properties?
break;
}
p = icalcomponent_get_next_property( vtodo, ICAL_ANY_PROPERTY );
}
if ( d->mCompat ) {
d->mCompat->fixEmptySummary( todo );
}
return todo;
}
Event *ICalFormatImpl::readEvent( icalcomponent *vevent, ICalTimeZones *tzlist )
{
Event *event = new Event;
readIncidence( vevent, event, tzlist );
icalproperty *p = icalcomponent_get_first_property( vevent, ICAL_ANY_PROPERTY );
QStringList categories;
icalproperty_transp transparency;
bool dtEndProcessed = false;
while ( p ) {
icalproperty_kind kind = icalproperty_isa( p );
switch ( kind ) {
case ICAL_DTEND_PROPERTY:
{ // end date and time
KDateTime kdt = readICalDateTimeProperty( p, tzlist );
if ( kdt.isDateOnly() ) {
// End date is non-inclusive
QDate endDate = kdt.date().addDays( -1 );
if ( d->mCompat ) {
d->mCompat->fixFloatingEnd( endDate );
}
if ( endDate < event->dtStart().date() ) {
endDate = event->dtStart().date();
}
event->setDtEnd( KDateTime( endDate, event->dtStart().timeSpec() ) );
} else {
event->setDtEnd( kdt );
event->setAllDay( false );
}
dtEndProcessed = true;
break;
}
case ICAL_RELATEDTO_PROPERTY: // related event (parent)
event->setRelatedToUid( QString::fromUtf8( icalproperty_get_relatedto( p ) ) );
d->mEventsRelate.append( event );
break;
case ICAL_TRANSP_PROPERTY: // Transparency
transparency = icalproperty_get_transp( p );
if ( transparency == ICAL_TRANSP_TRANSPARENT ) {
event->setTransparency( Event::Transparent );
} else {
event->setTransparency( Event::Opaque );
}
break;
default:
// TODO: do something about unknown properties?
break;
}
p = icalcomponent_get_next_property( vevent, ICAL_ANY_PROPERTY );
}
// according to rfc2445 the dtend shouldn't be written when it equals
// start date. so assign one equal to start date.
if ( !dtEndProcessed && !event->hasDuration() ) {
event->setDtEnd( event->dtStart() );
event->setHasEndDate( false );
}
QString msade = event->nonKDECustomProperty( "X-MICROSOFT-CDO-ALLDAYEVENT" );
if ( !msade.isEmpty() ) {
bool allDay = ( msade == QLatin1String( "TRUE" ) );
event->setAllDay( allDay );
}
if ( d->mCompat ) {
d->mCompat->fixEmptySummary( event );
}
return event;
}
FreeBusy *ICalFormatImpl::readFreeBusy( icalcomponent *vfreebusy )
{
FreeBusy *freebusy = new FreeBusy;
d->readIncidenceBase( vfreebusy, freebusy );
icalproperty *p = icalcomponent_get_first_property( vfreebusy, ICAL_ANY_PROPERTY );
FreeBusyPeriod::List periods;
while ( p ) {
icalproperty_kind kind = icalproperty_isa( p );
switch ( kind ) {
case ICAL_DTSTART_PROPERTY: // start date and time (UTC)
freebusy->setDtStart( readICalUtcDateTimeProperty( p ) );
break;
case ICAL_DTEND_PROPERTY: // end Date and Time (UTC)
freebusy->setDtEnd( readICalUtcDateTimeProperty( p ) );
break;
case ICAL_FREEBUSY_PROPERTY: //Any FreeBusy Times (UTC)
{
icalperiodtype icalperiod = icalproperty_get_freebusy( p );
KDateTime period_start = readICalUtcDateTime( p, icalperiod.start );
FreeBusyPeriod period;
if ( !icaltime_is_null_time( icalperiod.end ) ) {
KDateTime period_end = readICalUtcDateTime( p, icalperiod.end );
period = FreeBusyPeriod( period_start, period_end );
} else {
Duration duration ( readICalDuration( icalperiod.duration ) );
period = FreeBusyPeriod( period_start, duration );
}
QByteArray param = icalproperty_get_parameter_as_string( p, "X-SUMMARY" );
period.setSummary( QString::fromUtf8( KCodecs::base64Decode( param ) ) );
param = icalproperty_get_parameter_as_string( p, "X-LOCATION" );
period.setLocation( QString::fromUtf8( KCodecs::base64Decode( param ) ) );
periods.append( period );
break;
}
default:
// TODO: do something about unknown properties?
break;
}
p = icalcomponent_get_next_property( vfreebusy, ICAL_ANY_PROPERTY );
}
freebusy->addPeriods( periods );
return freebusy;
}
Journal *ICalFormatImpl::readJournal( icalcomponent *vjournal,
ICalTimeZones *tzlist )
{
Journal *journal = new Journal;
readIncidence( vjournal, journal, tzlist );
return journal;
}
Attendee *ICalFormatImpl::readAttendee( icalproperty *attendee )
{
icalparameter *p = 0;
QString email = QString::fromUtf8( icalproperty_get_attendee( attendee ) );
if ( email.startsWith( "mailto:", Qt::CaseInsensitive ) ) {
email = email.mid( 7 );
}
QString name;
- QString uid = QString();
+ QString uid;
p = icalproperty_get_first_parameter( attendee, ICAL_CN_PARAMETER );
if ( p ) {
name = QString::fromUtf8( icalparameter_get_cn( p ) );
} else {
}
bool rsvp = false;
p = icalproperty_get_first_parameter( attendee, ICAL_RSVP_PARAMETER );
if ( p ) {
icalparameter_rsvp rsvpParameter = icalparameter_get_rsvp( p );
if ( rsvpParameter == ICAL_RSVP_TRUE ) {
rsvp = true;
}
}
Attendee::PartStat status = Attendee::NeedsAction;
p = icalproperty_get_first_parameter( attendee, ICAL_PARTSTAT_PARAMETER );
if ( p ) {
icalparameter_partstat partStatParameter = icalparameter_get_partstat( p );
switch( partStatParameter ) {
default:
case ICAL_PARTSTAT_NEEDSACTION:
status = Attendee::NeedsAction;
break;
case ICAL_PARTSTAT_ACCEPTED:
status = Attendee::Accepted;
break;
case ICAL_PARTSTAT_DECLINED:
status = Attendee::Declined;
break;
case ICAL_PARTSTAT_TENTATIVE:
status = Attendee::Tentative;
break;
case ICAL_PARTSTAT_DELEGATED:
status = Attendee::Delegated;
break;
case ICAL_PARTSTAT_COMPLETED:
status = Attendee::Completed;
break;
case ICAL_PARTSTAT_INPROCESS:
status = Attendee::InProcess;
break;
}
}
Attendee::Role role = Attendee::ReqParticipant;
p = icalproperty_get_first_parameter( attendee, ICAL_ROLE_PARAMETER );
if ( p ) {
icalparameter_role roleParameter = icalparameter_get_role( p );
switch( roleParameter ) {
case ICAL_ROLE_CHAIR:
role = Attendee::Chair;
break;
default:
case ICAL_ROLE_REQPARTICIPANT:
role = Attendee::ReqParticipant;
break;
case ICAL_ROLE_OPTPARTICIPANT:
role = Attendee::OptParticipant;
break;
case ICAL_ROLE_NONPARTICIPANT:
role = Attendee::NonParticipant;
break;
}
}
p = icalproperty_get_first_parameter( attendee, ICAL_X_PARAMETER );
uid = icalparameter_get_xvalue( p );
// This should be added, but there seems to be a libical bug here.
// TODO: does this work now in libical-0.24 or greater?
/*while (p) {
// if (icalparameter_get_xname(p) == "X-UID") {
uid = icalparameter_get_xvalue(p);
p = icalproperty_get_next_parameter(attendee, ICAL_X_PARAMETER);
} */
Attendee *a = new Attendee( name, email, rsvp, status, role, uid );
p = icalproperty_get_first_parameter( attendee, ICAL_DELEGATEDTO_PARAMETER );
if ( p ) {
a->setDelegate( icalparameter_get_delegatedto( p ) );
}
p = icalproperty_get_first_parameter( attendee, ICAL_DELEGATEDFROM_PARAMETER );
if ( p ) {
a->setDelegator( icalparameter_get_delegatedfrom( p ) );
}
return a;
}
Person ICalFormatImpl::readOrganizer( icalproperty *organizer )
{
QString email = QString::fromUtf8( icalproperty_get_organizer( organizer ) );
if ( email.startsWith( "mailto:", Qt::CaseInsensitive ) ) {
email = email.mid( 7 );
}
QString cn;
icalparameter *p = icalproperty_get_first_parameter( organizer, ICAL_CN_PARAMETER );
if ( p ) {
cn = QString::fromUtf8( icalparameter_get_cn( p ) );
}
Person org( cn, email );
// TODO: Treat sent-by, dir and language here, too
return org;
}
Attachment *ICalFormatImpl::readAttachment( icalproperty *attach )
{
Attachment *attachment = 0;
const char *p;
icalvalue *value = icalproperty_get_value( attach );
switch( icalvalue_isa( value ) ) {
case ICAL_ATTACH_VALUE:
{
icalattach *a = icalproperty_get_attach( attach );
if ( icalattach_get_is_url( a ) == 0 ) {
p = (const char *)icalattach_get_data( a );
if ( p ) {
attachment = new Attachment( p );
}
} else {
p = icalattach_get_url( a );
if ( p ) {
attachment = new Attachment( QString::fromUtf8( p ) );
}
}
break;
}
case ICAL_BINARY_VALUE:
{
icalattach *a = icalproperty_get_attach( attach );
p = (const char *)icalattach_get_data( a );
if ( p ) {
attachment = new Attachment( p );
}
break;
}
case ICAL_URI_VALUE:
p = icalvalue_get_uri( value );
attachment = new Attachment( QString::fromUtf8( p ) );
break;
default:
break;
}
if ( attachment ) {
icalparameter *p =
icalproperty_get_first_parameter( attach, ICAL_FMTTYPE_PARAMETER );
if ( p ) {
attachment->setMimeType( QString( icalparameter_get_fmttype( p ) ) );
}
p = icalproperty_get_first_parameter( attach, ICAL_X_PARAMETER );
while ( p ) {
QString xname = QString( icalparameter_get_xname( p ) ).toUpper();
QString xvalue = QString::fromUtf8( icalparameter_get_xvalue( p ) );
if ( xname == "X-CONTENT-DISPOSITION" ) {
attachment->setShowInline( xvalue.toLower() == "inline" );
}
if ( xname == "X-LABEL" ) {
attachment->setLabel( xvalue );
}
if ( xname == "X-KONTACT-TYPE" ) {
attachment->setLocal( xvalue.toLower() == "local" );
}
p = icalproperty_get_next_parameter( attach, ICAL_X_PARAMETER );
}
p = icalproperty_get_first_parameter( attach, ICAL_X_PARAMETER );
while ( p ) {
if ( strncmp ( icalparameter_get_xname( p ), "X-LABEL", 7 ) == 0 ) {
attachment->setLabel( icalparameter_get_xvalue( p ) );
}
p = icalproperty_get_next_parameter( attach, ICAL_X_PARAMETER );
}
}
return attachment;
}
void ICalFormatImpl::readIncidence( icalcomponent *parent,
Incidence *incidence,
ICalTimeZones *tzlist )
{
d->readIncidenceBase( parent, incidence );
icalproperty *p = icalcomponent_get_first_property( parent, ICAL_ANY_PROPERTY );
const char *text;
int intvalue, inttext;
icaldurationtype icalduration;
KDateTime kdt;
QStringList categories;
while ( p ) {
icalproperty_kind kind = icalproperty_isa( p );
switch ( kind ) {
case ICAL_CREATED_PROPERTY:
incidence->setCreated( readICalDateTimeProperty( p, tzlist ) );
break;
case ICAL_SEQUENCE_PROPERTY: // sequence
intvalue = icalproperty_get_sequence( p );
incidence->setRevision( intvalue );
break;
case ICAL_LASTMODIFIED_PROPERTY: // last modification UTC date/time
incidence->setLastModified( readICalDateTimeProperty( p, tzlist ) );
break;
case ICAL_DTSTART_PROPERTY: // start date and time
kdt = readICalDateTimeProperty( p, tzlist );
incidence->setDtStart( kdt );
incidence->setAllDay( kdt.isDateOnly() );
break;
case ICAL_DURATION_PROPERTY: // start date and time
icalduration = icalproperty_get_duration( p );
incidence->setDuration( readICalDuration( icalduration ) );
break;
case ICAL_DESCRIPTION_PROPERTY: // description
{
QString textStr = QString::fromUtf8( icalproperty_get_description( p ) );
if ( !textStr.isEmpty() ) {
QString valStr = QString::fromUtf8(
icalproperty_get_parameter_as_string( p, "X-KDE-TEXTFORMAT" ) );
if ( !valStr.compare( "HTML", Qt::CaseInsensitive ) ) {
incidence->setDescription( textStr, true );
} else {
incidence->setDescription( textStr, false );
}
}
}
break;
case ICAL_SUMMARY_PROPERTY: // summary
{
QString textStr = QString::fromUtf8( icalproperty_get_summary( p ) );
if ( !textStr.isEmpty() ) {
QString valStr = QString::fromUtf8(
icalproperty_get_parameter_as_string( p, "X-KDE-TEXTFORMAT" ) );
if ( !valStr.compare( "HTML", Qt::CaseInsensitive ) ) {
incidence->setSummary( textStr, true );
} else {
incidence->setSummary( textStr, false );
}
}
}
break;
case ICAL_LOCATION_PROPERTY: // location
{
QString textStr = QString::fromUtf8( icalproperty_get_location( p ) );
if ( !textStr.isEmpty() ) {
QString valStr = QString::fromUtf8(
icalproperty_get_parameter_as_string( p, "X-KDE-TEXTFORMAT" ) );
if ( !valStr.compare( "HTML", Qt::CaseInsensitive ) ) {
incidence->setLocation( textStr, true );
} else {
incidence->setLocation( textStr, false );
}
}
}
break;
case ICAL_STATUS_PROPERTY: // status
{
Incidence::Status stat;
switch ( icalproperty_get_status( p ) ) {
case ICAL_STATUS_TENTATIVE:
stat = Incidence::StatusTentative;
break;
case ICAL_STATUS_CONFIRMED:
stat = Incidence::StatusConfirmed;
break;
case ICAL_STATUS_COMPLETED:
stat = Incidence::StatusCompleted;
break;
case ICAL_STATUS_NEEDSACTION:
stat = Incidence::StatusNeedsAction;
break;
case ICAL_STATUS_CANCELLED:
stat = Incidence::StatusCanceled;
break;
case ICAL_STATUS_INPROCESS:
stat = Incidence::StatusInProcess;
break;
case ICAL_STATUS_DRAFT:
stat = Incidence::StatusDraft;
break;
case ICAL_STATUS_FINAL:
stat = Incidence::StatusFinal;
break;
case ICAL_STATUS_X:
incidence->setCustomStatus(
QString::fromUtf8( icalvalue_get_x( icalproperty_get_value( p ) ) ) );
stat = Incidence::StatusX;
break;
case ICAL_STATUS_NONE:
default:
stat = Incidence::StatusNone;
break;
}
if ( stat != Incidence::StatusX ) {
incidence->setStatus( stat );
}
break;
}
case ICAL_PRIORITY_PROPERTY: // priority
intvalue = icalproperty_get_priority( p );
if ( d->mCompat ) {
intvalue = d->mCompat->fixPriority( intvalue );
}
incidence->setPriority( intvalue );
break;
case ICAL_CATEGORIES_PROPERTY: // categories
text = icalproperty_get_categories( p );
categories.append( QString::fromUtf8( text ) );
break;
case ICAL_RRULE_PROPERTY:
readRecurrenceRule( p, incidence );
break;
case ICAL_RDATE_PROPERTY:
kdt = readICalDateTimeProperty( p, tzlist );
if ( kdt.isValid() ) {
if ( kdt.isDateOnly() ) {
incidence->recurrence()->addRDate( kdt.date() );
} else {
incidence->recurrence()->addRDateTime( kdt );
}
} else {
// TODO: RDates as period are not yet implemented!
}
break;
case ICAL_EXRULE_PROPERTY:
readExceptionRule( p, incidence );
break;
case ICAL_EXDATE_PROPERTY:
kdt = readICalDateTimeProperty( p, tzlist );
if ( kdt.isDateOnly() ) {
incidence->recurrence()->addExDate( kdt.date() );
} else {
incidence->recurrence()->addExDateTime( kdt );
}
break;
case ICAL_CLASS_PROPERTY:
inttext = icalproperty_get_class( p );
if ( inttext == ICAL_CLASS_PUBLIC ) {
incidence->setSecrecy( Incidence::SecrecyPublic );
} else if ( inttext == ICAL_CLASS_CONFIDENTIAL ) {
incidence->setSecrecy( Incidence::SecrecyConfidential );
} else {
incidence->setSecrecy( Incidence::SecrecyPrivate );
}
break;
case ICAL_ATTACH_PROPERTY: // attachments
incidence->addAttachment( readAttachment( p ) );
break;
default:
// TODO: do something about unknown properties?
break;
}
p = icalcomponent_get_next_property( parent, ICAL_ANY_PROPERTY );
}
// Set the scheduling ID
const QString uid = incidence->customProperty( "LIBKCAL", "ID" );
if ( !uid.isNull() ) {
// The UID stored in incidencebase is actually the scheduling ID
// It has to be stored in the iCal UID component for compatibility
// with other iCal applications
incidence->setSchedulingID( incidence->uid() );
incidence->setUid( uid );
}
// Now that recurrence and exception stuff is completely set up,
// do any backwards compatibility adjustments.
if ( incidence->recurs() && d->mCompat ) {
d->mCompat->fixRecurrence( incidence );
}
// add categories
incidence->setCategories( categories );
// iterate through all alarms
for ( icalcomponent *alarm = icalcomponent_get_first_component( parent, ICAL_VALARM_COMPONENT );
alarm;
alarm = icalcomponent_get_next_component( parent, ICAL_VALARM_COMPONENT ) ) {
readAlarm( alarm, incidence, tzlist );
}
// Fix incorrect alarm settings by other applications (like outloook 9)
if ( d->mCompat ) {
d->mCompat->fixAlarms( incidence );
}
}
//@cond PRIVATE
void ICalFormatImpl::Private::readIncidenceBase( icalcomponent *parent,
IncidenceBase *incidenceBase )
{
icalproperty *p = icalcomponent_get_first_property( parent, ICAL_ANY_PROPERTY );
while ( p ) {
icalproperty_kind kind = icalproperty_isa( p );
switch ( kind ) {
case ICAL_UID_PROPERTY: // unique id
incidenceBase->setUid( QString::fromUtf8( icalproperty_get_uid( p ) ) );
break;
case ICAL_ORGANIZER_PROPERTY: // organizer
incidenceBase->setOrganizer( mImpl->readOrganizer( p ) );
break;
case ICAL_ATTENDEE_PROPERTY: // attendee
incidenceBase->addAttendee( mImpl->readAttendee( p ) );
break;
case ICAL_COMMENT_PROPERTY:
incidenceBase->addComment(
QString::fromUtf8( icalproperty_get_comment( p ) ) );
break;
default:
break;
}
p = icalcomponent_get_next_property( parent, ICAL_ANY_PROPERTY );
}
// custom properties
readCustomProperties( parent, incidenceBase );
}
void ICalFormatImpl::Private::readCustomProperties( icalcomponent *parent,
CustomProperties *properties )
{
QMap<QByteArray, QString> customProperties;
- QString lastProperty = QString();
+ QString lastProperty;
icalproperty *p = icalcomponent_get_first_property( parent, ICAL_X_PROPERTY );
while ( p ) {
QString value = QString::fromUtf8( icalproperty_get_x( p ) );
const char *name = icalproperty_get_x_name( p );
if ( lastProperty != name ) {
customProperties[name] = value;
} else {
customProperties[name] = customProperties[name].append( "," ).append( value );
}
p = icalcomponent_get_next_property( parent, ICAL_X_PROPERTY );
lastProperty = name;
}
properties->setCustomProperties( customProperties );
}
//@endcond
void ICalFormatImpl::readRecurrenceRule( icalproperty *rrule,
Incidence *incidence )
{
Recurrence *recur = incidence->recurrence();
struct icalrecurrencetype r = icalproperty_get_rrule( rrule );
// dumpIcalRecurrence(r);
RecurrenceRule *recurrule = new RecurrenceRule( /*incidence*/);
recurrule->setStartDt( incidence->dtStart() );
readRecurrence( r, recurrule );
recur->addRRule( recurrule );
}
void ICalFormatImpl::readExceptionRule( icalproperty *rrule,
Incidence *incidence )
{
struct icalrecurrencetype r = icalproperty_get_exrule( rrule );
// dumpIcalRecurrence(r);
RecurrenceRule *recurrule = new RecurrenceRule( /*incidence*/);
recurrule->setStartDt( incidence->dtStart() );
readRecurrence( r, recurrule );
Recurrence *recur = incidence->recurrence();
recur->addExRule( recurrule );
}
void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype &r,
RecurrenceRule *recur )
{
// Generate the RRULE string
recur->setRRule(
QString( icalrecurrencetype_as_string( const_cast<struct icalrecurrencetype*>( &r ) ) ) );
// Period
switch ( r.freq ) {
case ICAL_SECONDLY_RECURRENCE:
recur->setRecurrenceType( RecurrenceRule::rSecondly );
break;
case ICAL_MINUTELY_RECURRENCE:
recur->setRecurrenceType( RecurrenceRule::rMinutely );
break;
case ICAL_HOURLY_RECURRENCE:
recur->setRecurrenceType( RecurrenceRule::rHourly );
break;
case ICAL_DAILY_RECURRENCE:
recur->setRecurrenceType( RecurrenceRule::rDaily );
break;
case ICAL_WEEKLY_RECURRENCE:
recur->setRecurrenceType( RecurrenceRule::rWeekly );
break;
case ICAL_MONTHLY_RECURRENCE:
recur->setRecurrenceType( RecurrenceRule::rMonthly );
break;
case ICAL_YEARLY_RECURRENCE:
recur->setRecurrenceType( RecurrenceRule::rYearly );
break;
case ICAL_NO_RECURRENCE:
default:
recur->setRecurrenceType( RecurrenceRule::rNone );
}
// Frequency
recur->setFrequency( r.interval );
// Duration & End Date
if ( !icaltime_is_null_time( r.until ) ) {
icaltimetype t = r.until;
recur->setEndDt( readICalUtcDateTime( 0, t ) );
} else {
if ( r.count == 0 ) {
recur->setDuration( -1 );
} else {
recur->setDuration( r.count );
}
}
// Week start setting
int wkst = ( r.week_start + 5 ) % 7 + 1;
recur->setWeekStart( wkst );
// And now all BY*
QList<int> lst;
int i;
int index = 0;
//@cond PRIVATE
#define readSetByList( rrulecomp, setfunc ) \
index = 0; \
lst.clear(); \
while ( ( i = r.rrulecomp[index++] ) != ICAL_RECURRENCE_ARRAY_MAX ) { \
lst.append( i ); \
} \
if ( !lst.isEmpty() ) { \
recur->setfunc( lst ); \
}
//@endcond
// BYSECOND, MINUTE and HOUR, MONTHDAY, YEARDAY, WEEKNUMBER, MONTH
// and SETPOS are standard int lists, so we can treat them with the
// same macro
readSetByList( by_second, setBySeconds );
readSetByList( by_minute, setByMinutes );
readSetByList( by_hour, setByHours );
readSetByList( by_month_day, setByMonthDays );
readSetByList( by_year_day, setByYearDays );
readSetByList( by_week_no, setByWeekNumbers );
readSetByList( by_month, setByMonths );
readSetByList( by_set_pos, setBySetPos );
#undef readSetByList
// BYDAY is a special case, since it's not an int list
QList<RecurrenceRule::WDayPos> wdlst;
short day;
index=0;
while ( ( day = r.by_day[index++] ) != ICAL_RECURRENCE_ARRAY_MAX ) {
RecurrenceRule::WDayPos pos;
pos.setDay( ( icalrecurrencetype_day_day_of_week( day ) + 5 ) % 7 + 1 );
pos.setPos( icalrecurrencetype_day_position( day ) );
wdlst.append( pos );
}
if ( !wdlst.isEmpty() ) {
recur->setByDays( wdlst );
}
// TODO: Store all X- fields of the RRULE inside the recurrence (so they are
// preserved
}
void ICalFormatImpl::readAlarm( icalcomponent *alarm,
Incidence *incidence,
ICalTimeZones *tzlist )
{
Alarm *ialarm = incidence->newAlarm();
ialarm->setRepeatCount( 0 );
ialarm->setEnabled( true );
// Determine the alarm's action type
icalproperty *p = icalcomponent_get_first_property( alarm, ICAL_ACTION_PROPERTY );
Alarm::Type type = Alarm::Display;
icalproperty_action action = ICAL_ACTION_DISPLAY;
if ( !p ) {
kDebug() << "Unknown type of alarm, using default";
// TODO: do something about unknown alarm type?
} else {
action = icalproperty_get_action( p );
switch ( action ) {
case ICAL_ACTION_DISPLAY:
type = Alarm::Display;
break;
case ICAL_ACTION_AUDIO:
type = Alarm::Audio;
break;
case ICAL_ACTION_PROCEDURE:
type = Alarm::Procedure;
break;
case ICAL_ACTION_EMAIL:
type = Alarm::Email;
break;
default:
break;
// TODO: do something about invalid alarm type?
}
}
ialarm->setType( type );
p = icalcomponent_get_first_property( alarm, ICAL_ANY_PROPERTY );
while ( p ) {
icalproperty_kind kind = icalproperty_isa( p );
switch ( kind ) {
case ICAL_TRIGGER_PROPERTY:
{
icaltriggertype trigger = icalproperty_get_trigger( p );
if ( icaltime_is_null_time( trigger.time ) ) {
if ( icaldurationtype_is_null_duration( trigger.duration ) ) {
kDebug() << "Trigger has no time and no duration.";
} else {
Duration duration( readICalDuration( trigger.duration ) );
icalparameter *param =
icalproperty_get_first_parameter( p, ICAL_RELATED_PARAMETER );
if ( param && icalparameter_get_related( param ) == ICAL_RELATED_END ) {
ialarm->setEndOffset(duration);
} else {
ialarm->setStartOffset( duration );
}
}
} else {
ialarm->setTime( readICalUtcDateTime( p, trigger.time, tzlist ) );
}
break;
}
case ICAL_DURATION_PROPERTY:
{
icaldurationtype duration = icalproperty_get_duration( p );
ialarm->setSnoozeTime( readICalDuration( duration ) );
break;
}
case ICAL_REPEAT_PROPERTY:
ialarm->setRepeatCount( icalproperty_get_repeat( p ) );
break;
// Only in DISPLAY and EMAIL and PROCEDURE alarms
case ICAL_DESCRIPTION_PROPERTY:
{
QString description = QString::fromUtf8( icalproperty_get_description( p ) );
switch ( action ) {
case ICAL_ACTION_DISPLAY:
ialarm->setText( description );
break;
case ICAL_ACTION_PROCEDURE:
ialarm->setProgramArguments( description );
break;
case ICAL_ACTION_EMAIL:
ialarm->setMailText( description );
break;
default:
break;
}
break;
}
case ICAL_SUMMARY_PROPERTY:
// Only in EMAIL alarm
ialarm->setMailSubject( QString::fromUtf8( icalproperty_get_summary( p ) ) );
break;
case ICAL_ATTENDEE_PROPERTY:
{ // Only in EMAIL alarm
QString email = QString::fromUtf8( icalproperty_get_attendee( p ) );
if ( email.startsWith( "mailto:", Qt::CaseInsensitive ) ) {
email = email.mid( 7 );
}
QString name;
icalparameter *param = icalproperty_get_first_parameter( p, ICAL_CN_PARAMETER );
if ( param ) {
name = QString::fromUtf8( icalparameter_get_cn( param ) );
}
ialarm->addMailAddress( Person( name, email ) );
break;
}
case ICAL_ATTACH_PROPERTY:
{ // Only in AUDIO and EMAIL and PROCEDURE alarms
Attachment *attach = readAttachment( p );
if ( attach && attach->isUri() ) {
switch ( action ) {
case ICAL_ACTION_AUDIO:
ialarm->setAudioFile( attach->uri() );
break;
case ICAL_ACTION_PROCEDURE:
ialarm->setProgramFile( attach->uri() );
break;
case ICAL_ACTION_EMAIL:
ialarm->addMailAttachment( attach->uri() );
break;
default:
break;
}
} else {
kDebug() << "Alarm attachments currently only support URIs,"
<< "but no binary data";
}
delete attach;
break;
}
default:
break;
}
p = icalcomponent_get_next_property( alarm, ICAL_ANY_PROPERTY );
}
// custom properties
d->readCustomProperties( alarm, ialarm );
// TODO: check for consistency of alarm properties
}
icaldatetimeperiodtype ICalFormatImpl::writeICalDatePeriod( const QDate &date )
{
icaldatetimeperiodtype t;
t.time = writeICalDate( date );
t.period = icalperiodtype_null_period();
return t;
}
icaltimetype ICalFormatImpl::writeICalDate( const QDate &date )
{
icaltimetype t = icaltime_null_time();
t.year = date.year();
t.month = date.month();
t.day = date.day();
t.hour = 0;
t.minute = 0;
t.second = 0;
t.is_date = 1;
t.is_utc = 0;
t.zone = 0;
return t;
}
icaltimetype ICalFormatImpl::writeICalDateTime( const KDateTime &datetime )
{
icaltimetype t = icaltime_null_time();
t.year = datetime.date().year();
t.month = datetime.date().month();
t.day = datetime.date().day();
t.hour = datetime.time().hour();
t.minute = datetime.time().minute();
t.second = datetime.time().second();
t.is_date = 0;
t.zone = 0; // zone is NOT set
t.is_utc = datetime.isUtc() ? 1 : 0;
// _dumpIcaltime( t );
return t;
}
icalproperty *ICalFormatImpl::writeICalDateTimeProperty( const icalproperty_kind type,
const KDateTime &dt,
ICalTimeZones *tzlist,
ICalTimeZones *tzUsedList )
{
icaltimetype t;
switch ( type ) {
case ICAL_DTSTAMP_PROPERTY:
case ICAL_CREATED_PROPERTY:
case ICAL_LASTMODIFIED_PROPERTY:
t = writeICalDateTime( dt.toUtc() );
break;
default:
t = writeICalDateTime( dt );
break;
}
icalproperty *p;
switch ( type ) {
case ICAL_DTSTAMP_PROPERTY:
p = icalproperty_new_dtstamp( t );
break;
case ICAL_CREATED_PROPERTY:
p = icalproperty_new_created( t );
break;
case ICAL_LASTMODIFIED_PROPERTY:
p = icalproperty_new_lastmodified( t );
break;
case ICAL_DTSTART_PROPERTY: // start date and time
p = icalproperty_new_dtstart( t );
break;
case ICAL_DTEND_PROPERTY: // end date and time
p = icalproperty_new_dtend( t );
break;
case ICAL_DUE_PROPERTY:
p = icalproperty_new_due( t );
break;
case ICAL_RECURRENCEID_PROPERTY:
p = icalproperty_new_recurrenceid( t );
break;
case ICAL_EXDATE_PROPERTY:
p = icalproperty_new_exdate( t );
break;
default:
{
icaldatetimeperiodtype tp;
tp.time = t;
tp.period = icalperiodtype_null_period();
switch ( type ) {
case ICAL_RDATE_PROPERTY:
p = icalproperty_new_rdate( tp );
break;
default:
return 0;
}
}
}
KTimeZone ktz;
if ( !t.is_utc ) {
ktz = dt.timeZone();
}
if ( ktz.isValid() ) {
if ( tzlist ) {
ICalTimeZone tz = tzlist->zone( ktz.name() );
if ( !tz.isValid() ) {
// The time zone isn't in the list of known zones for the calendar
// - add it to the calendar's zone list
ICalTimeZone tznew( ktz );
tzlist->add( tznew );
tz = tznew;
}
if ( tzUsedList ) {
tzUsedList->add( tz );
}
}
icalproperty_add_parameter(
p, icalparameter_new_tzid( ktz.name().toUtf8() ) );
}
return p;
}
KDateTime ICalFormatImpl::readICalDateTime( icalproperty *p,
const icaltimetype &t,
ICalTimeZones *tzlist,
bool utc )
{
// kDebug();
// _dumpIcaltime( t );
KDateTime::Spec timeSpec;
if ( t.is_utc || t.zone == icaltimezone_get_utc_timezone() ) {
timeSpec = KDateTime::UTC; // the time zone is UTC
utc = false; // no need to convert to UTC
} else {
if ( !tzlist ) {
utc = true; // should be UTC, but it isn't
}
icalparameter *param =
p ? icalproperty_get_first_parameter( p, ICAL_TZID_PARAMETER ) : 0;
const char *tzid = param ? icalparameter_get_tzid( param ) : 0;
if ( !tzid ) {
timeSpec = KDateTime::ClockTime;
} else {
QString tzidStr = QString::fromUtf8( tzid );
ICalTimeZone tz;
if ( tzlist ) {
tz = tzlist->zone( tzidStr );
}
if ( !tz.isValid() ) {
// The time zone is not in the existing list for the calendar.
// Try to read it from the system or libical databases.
ICalTimeZoneSource tzsource;
ICalTimeZone newtz = tzsource.standardZone( tzidStr );
if ( newtz.isValid() && tzlist ) {
tzlist->add( newtz );
}
tz = newtz;
}
timeSpec = tz.isValid() ? KDateTime::Spec( tz ) : KDateTime::LocalZone;
}
}
KDateTime result( QDate( t.year, t.month, t.day ),
QTime( t.hour, t.minute, t.second ), timeSpec );
return utc ? result.toUtc() : result;
}
QDate ICalFormatImpl::readICalDate( icaltimetype t )
{
return QDate( t.year, t.month, t.day );
}
KDateTime ICalFormatImpl::readICalDateTimeProperty( icalproperty *p,
ICalTimeZones *tzlist,
bool utc )
{
icaldatetimeperiodtype tp;
icalproperty_kind kind = icalproperty_isa( p );
switch ( kind ) {
case ICAL_CREATED_PROPERTY: // UTC date/time
tp.time = icalproperty_get_created( p );
utc = true;
break;
case ICAL_LASTMODIFIED_PROPERTY: // last modification UTC date/time
tp.time = icalproperty_get_lastmodified( p );
utc = true;
break;
case ICAL_DTSTART_PROPERTY: // start date and time (UTC for freebusy)
tp.time = icalproperty_get_dtstart( p );
break;
case ICAL_DTEND_PROPERTY: // end date and time (UTC for freebusy)
tp.time = icalproperty_get_dtend( p );
break;
case ICAL_DUE_PROPERTY: // due date/time
tp.time = icalproperty_get_due( p );
break;
case ICAL_COMPLETED_PROPERTY: // UTC completion date/time
tp.time = icalproperty_get_completed( p );
utc = true;
break;
case ICAL_RECURRENCEID_PROPERTY:
tp.time = icalproperty_get_recurrenceid( p );
break;
case ICAL_EXDATE_PROPERTY:
tp.time = icalproperty_get_exdate( p );
break;
default:
switch ( kind ) {
case ICAL_RDATE_PROPERTY:
tp = icalproperty_get_rdate( p );
break;
default:
return KDateTime();
}
if ( !icaltime_is_valid_time( tp.time ) ) {
return KDateTime(); // a time period was found (not implemented yet)
}
break;
}
if ( tp.time.is_date ) {
return KDateTime( readICalDate( tp.time ), KDateTime::Spec::ClockTime() );
} else {
return readICalDateTime( p, tp.time, tzlist, utc );
}
}
icaldurationtype ICalFormatImpl::writeICalDuration( const Duration &duration )
{
icaldurationtype d;
int value = duration.value();
d.is_neg = ( value < 0 ) ? 1 : 0;
if ( value < 0 ) {
value = -value;
}
if ( duration.isDaily() ) {
d.weeks = value / 7;
d.days = value % 7;
d.hours = d.minutes = d.seconds = 0;
} else {
d.weeks = value / gSecondsPerWeek;
value %= gSecondsPerWeek;
d.days = value / gSecondsPerDay;
value %= gSecondsPerDay;
d.hours = value / gSecondsPerHour;
value %= gSecondsPerHour;
d.minutes = value / gSecondsPerMinute;
value %= gSecondsPerMinute;
d.seconds = value;
}
return d;
}
Duration ICalFormatImpl::readICalDuration( icaldurationtype d )
{
int days = d.weeks * 7;
days += d.days;
int seconds = d.hours * gSecondsPerHour;
seconds += d.minutes * gSecondsPerMinute;
seconds += d.seconds;
if ( seconds ) {
seconds += days * gSecondsPerDay;
if ( d.is_neg ) {
seconds = -seconds;
}
return Duration( seconds, Duration::Seconds );
} else {
if ( d.is_neg ) {
days = -days;
}
return Duration( days, Duration::Days );
}
}
icalcomponent *ICalFormatImpl::createCalendarComponent( Calendar *cal )
{
icalcomponent *calendar;
// Root component
calendar = icalcomponent_new( ICAL_VCALENDAR_COMPONENT );
icalproperty *p;
// Product Identifier
p = icalproperty_new_prodid( CalFormat::productId().toUtf8() );
icalcomponent_add_property( calendar, p );
// TODO: Add time zone
// iCalendar version (2.0)
p = icalproperty_new_version( const_cast<char *>(_ICAL_VERSION) );
icalcomponent_add_property( calendar, p );
// Custom properties
if( cal != 0 ) {
d->writeCustomProperties( calendar, cal );
}
return calendar;
}
// take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
// and break it down from its tree-like format into the dictionary format
// that is used internally in the ICalFormatImpl.
bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar )
{
// this function will populate the caldict dictionary and other event
// lists. It turns vevents into Events and then inserts them.
if ( !calendar ) {
return false;
}
// TODO: check for METHOD
icalproperty *p;
p = icalcomponent_get_first_property( calendar, ICAL_PRODID_PROPERTY );
if ( !p ) {
kDebug() << "No PRODID property found";
d->mLoadedProductId = "";
} else {
d->mLoadedProductId = QString::fromUtf8( icalproperty_get_prodid( p ) );
delete d->mCompat;
d->mCompat = CompatFactory::createCompat( d->mLoadedProductId );
}
p = icalcomponent_get_first_property( calendar, ICAL_VERSION_PROPERTY );
if ( !p ) {
kDebug() << "No VERSION property found";
d->mParent->setException( new ErrorFormat( ErrorFormat::CalVersionUnknown ) );
return false;
} else {
const char *version = icalproperty_get_version( p );
if ( strcmp( version, "1.0" ) == 0 ) {
kDebug() << "Expected iCalendar, got vCalendar";
d->mParent->setException(
new ErrorFormat( ErrorFormat::CalVersion1,
i18n( "Expected iCalendar format" ) ) );
return false;
} else if ( strcmp( version, "2.0" ) != 0 ) {
kDebug() << "Expected iCalendar, got unknown format";
d->mParent->setException( new ErrorFormat( ErrorFormat::CalVersionUnknown ) );
return false;
}
}
// Populate the calendar's time zone collection with all VTIMEZONE components
ICalTimeZones *tzlist = cal->timeZones();
ICalTimeZoneSource tzs;
tzs.parse( calendar, *tzlist );
// custom properties
d->readCustomProperties( calendar, cal );
// Store all events with a relatedTo property in a list for post-processing
d->mEventsRelate.clear();
d->mTodosRelate.clear();
// TODO: make sure that only actually added events go to this lists.
icalcomponent *c;
// Iterate through all todos
c = icalcomponent_get_first_component( calendar, ICAL_VTODO_COMPONENT );
while ( c ) {
Todo *todo = readTodo( c, tzlist );
if ( todo ) {
Todo *old = cal->todo( todo->uid() );
if ( old ) {
cal->deleteTodo( old );
d->mTodosRelate.removeAll( old );
}
cal->addTodo( todo );
}
c = icalcomponent_get_next_component( calendar, ICAL_VTODO_COMPONENT );
}
// Iterate through all events
c = icalcomponent_get_first_component( calendar, ICAL_VEVENT_COMPONENT );
while ( c ) {
Event *event = readEvent( c, tzlist );
if (event) {
Event *old = cal->event( event->uid() );
if ( old ) {
cal->deleteEvent( old );
d->mEventsRelate.removeAll( old );
}
cal->addEvent( event );
}
c = icalcomponent_get_next_component( calendar, ICAL_VEVENT_COMPONENT );
}
// Iterate through all journals
c = icalcomponent_get_first_component( calendar, ICAL_VJOURNAL_COMPONENT );
while ( c ) {
Journal *journal = readJournal( c, tzlist );
if ( journal ) {
Journal *old = cal->journal( journal->uid() );
if ( old ) {
cal->deleteJournal( old );
}
cal->addJournal( journal );
}
c = icalcomponent_get_next_component( calendar, ICAL_VJOURNAL_COMPONENT );
}
// Post-Process list of events with relations, put Event objects in relation
Event::List::ConstIterator eIt;
for ( eIt = d->mEventsRelate.begin(); eIt != d->mEventsRelate.end(); ++eIt ) {
(*eIt)->setRelatedTo( cal->incidence( (*eIt)->relatedToUid() ) );
}
Todo::List::ConstIterator tIt;
for ( tIt = d->mTodosRelate.begin(); tIt != d->mTodosRelate.end(); ++tIt ) {
(*tIt)->setRelatedTo( cal->incidence( (*tIt)->relatedToUid() ) );
}
// TODO: Remove any previous time zones no longer referenced in the calendar
return true;
}
QString ICalFormatImpl::extractErrorProperty( icalcomponent *c )
{
QString errorMessage;
icalproperty *error;
error = icalcomponent_get_first_property( c, ICAL_XLICERROR_PROPERTY );
while ( error ) {
errorMessage += icalproperty_get_xlicerror( error );
errorMessage += '\n';
error = icalcomponent_get_next_property( c, ICAL_XLICERROR_PROPERTY );
}
return errorMessage;
}
void ICalFormatImpl::dumpIcalRecurrence( icalrecurrencetype r )
{
int i;
kDebug() << " Freq:" << r.freq;
kDebug() << " Until:" << icaltime_as_ical_string( r.until );
kDebug() << " Count:" << r.count;
if ( r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX ) {
int index = 0;
QString out = " By Day: ";
while ( ( i = r.by_day[index++] ) != ICAL_RECURRENCE_ARRAY_MAX ) {
out.append( QString::number( i ) + ' ' );
}
kDebug() << out;
}
if ( r.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX ) {
int index = 0;
QString out = " By Month Day: ";
while ( ( i = r.by_month_day[index++] ) != ICAL_RECURRENCE_ARRAY_MAX ) {
out.append( QString::number( i ) + ' ' );
}
kDebug() << out;
}
if ( r.by_year_day[0] != ICAL_RECURRENCE_ARRAY_MAX ) {
int index = 0;
QString out = " By Year Day: ";
while ( ( i = r.by_year_day[index++] ) != ICAL_RECURRENCE_ARRAY_MAX ) {
out.append( QString::number( i ) + ' ' );
}
kDebug() << out;
}
if ( r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX ) {
int index = 0;
QString out = " By Month: ";
while ( ( i = r.by_month[index++] ) != ICAL_RECURRENCE_ARRAY_MAX ) {
out.append( QString::number( i ) + ' ' );
}
kDebug() << out;
}
if ( r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX ) {
int index = 0;
QString out = " By Set Pos: ";
while ( ( i = r.by_set_pos[index++] ) != ICAL_RECURRENCE_ARRAY_MAX ) {
kDebug() << "=========" << i;
out.append( QString::number( i ) + ' ' );
}
kDebug() << out;
}
}
icalcomponent *ICalFormatImpl::createScheduleComponent( IncidenceBase *incidence,
iTIPMethod method )
{
icalcomponent *message = createCalendarComponent();
icalproperty_method icalmethod = ICAL_METHOD_NONE;
switch (method) {
case iTIPPublish:
icalmethod = ICAL_METHOD_PUBLISH;
break;
case iTIPRequest:
icalmethod = ICAL_METHOD_REQUEST;
break;
case iTIPRefresh:
icalmethod = ICAL_METHOD_REFRESH;
break;
case iTIPCancel:
icalmethod = ICAL_METHOD_CANCEL;
break;
case iTIPAdd:
icalmethod = ICAL_METHOD_ADD;
break;
case iTIPReply:
icalmethod = ICAL_METHOD_REPLY;
break;
case iTIPCounter:
icalmethod = ICAL_METHOD_COUNTER;
break;
case iTIPDeclineCounter:
icalmethod = ICAL_METHOD_DECLINECOUNTER;
break;
default:
kDebug() << "Unknown method";
return message;
}
icalcomponent_add_property( message, icalproperty_new_method( icalmethod ) );
icalcomponent *inc = writeIncidence( incidence, method );
/*
* RFC 2446 states in section 3.4.3 ( REPLY to a VTODO ), that
* a REQUEST-STATUS property has to be present. For the other two, event and
* free busy, it can be there, but is optional. Until we do more
* fine grained handling, assume all is well. Note that this is the
* status of the _request_, not the attendee. Just to avoid confusion.
* - till
*/
if ( icalmethod == ICAL_METHOD_REPLY ) {
struct icalreqstattype rst;
rst.code = ICAL_2_0_SUCCESS_STATUS;
rst.desc = 0;
rst.debug = 0;
icalcomponent_add_property( inc, icalproperty_new_requeststatus( rst ) );
}
icalcomponent_add_component( message, inc );
return message;
}
diff --git a/kcal/resourcecalendar.cpp b/kcal/resourcecalendar.cpp
index 84f758a77..5ce4661ad 100644
--- a/kcal/resourcecalendar.cpp
+++ b/kcal/resourcecalendar.cpp
@@ -1,334 +1,334 @@
/*
This file is part of the kcal library.
Copyright (c) 1998 Preston Brown <pbrown@kde.org>
Copyright (c) 2001-2004 Cornelius Schumacher <schumacher@kde.org>
Copyright (c) 2002 Jan-Pascal van Best <janpascal@vanbest.org>
Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
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.
*/
#include "resourcecalendar.h"
#include <kconfig.h>
#include <kdebug.h>
#include <klocale.h>
#include "resourcecalendar.moc"
using namespace KCal;
//@cond PRIVATE
class ResourceCalendar::Private
{
public:
Private()
: mResolveConflict( false ),
mNoReadOnlyOnLoad( false ),
mInhibitSave( false )
{}
bool mResolveConflict;
bool mNoReadOnlyOnLoad;
bool mInhibitSave; // true to prevent saves
bool mReceivedLoadError;
bool mReceivedSaveError;
QString mLastError;
};
//@endcond
ResourceCalendar::ResourceCalendar()
: KRES::Resource(), d( new Private )
{
}
ResourceCalendar::ResourceCalendar( const KConfigGroup &group )
: KRES::Resource( group ),
d( new Private )
{
}
ResourceCalendar::~ResourceCalendar()
{
delete d;
}
bool ResourceCalendar::isResolveConflictSet() const
{
return d->mResolveConflict;
}
void ResourceCalendar::setResolveConflict( bool b )
{
d->mResolveConflict = b;
}
QString ResourceCalendar::infoText() const
{
QString txt;
txt += "<b>" + resourceName() + "</b>";
txt += "<br>";
KRES::Factory *factory = KRES::Factory::self( "calendar" );
QString t = factory->typeName( type() );
txt += i18n( "Type: %1", t );
addInfoText( txt );
return txt;
}
void ResourceCalendar::writeConfig( KConfigGroup &group )
{
KRES::Resource::writeConfig( group );
}
Incidence *ResourceCalendar::incidence( const QString &uid )
{
Incidence *i = event( uid );
if ( i ) {
return i;
}
i = todo( uid );
if ( i ) {
return i;
}
i = journal( uid );
return i;
}
bool ResourceCalendar::addIncidence( Incidence *incidence )
{
Incidence::AddVisitor<ResourceCalendar> v( this );
return incidence->accept( v );
}
bool ResourceCalendar::deleteIncidence( Incidence *incidence )
{
Incidence::DeleteVisitor<ResourceCalendar> v( this );
return incidence->accept( v );
}
Incidence::List ResourceCalendar::rawIncidences()
{
return Calendar::mergeIncidenceList( rawEvents(), rawTodos(), rawJournals() );
}
void ResourceCalendar::setSubresourceActive( const QString &, bool )
{
}
bool ResourceCalendar::removeSubresource( const QString &resource )
{
Q_UNUSED( resource )
return true;
}
bool ResourceCalendar::addSubresource( const QString &resource, const QString &parent )
{
Q_UNUSED( resource )
Q_UNUSED( parent )
return true;
}
QString ResourceCalendar::subresourceType( const QString &resource )
{
Q_UNUSED( resource )
return QString();
}
bool ResourceCalendar::load()
{
kDebug() << resourceName();
d->mReceivedLoadError = false;
bool success = true;
if ( !isOpen() ) {
success = open(); //krazy:exclude=syscalls open is a class method
}
if ( success ) {
success = doLoad( false );
}
if ( !success && !d->mReceivedLoadError ) {
loadError();
}
// If the resource is read-only, we need to set its incidences to read-only,
// too. This can't be done at a lower-level, since the read-only setting
// happens at this level
if ( !d->mNoReadOnlyOnLoad && readOnly() ) {
Incidence::List incidences( rawIncidences() );
Incidence::List::Iterator it;
for ( it = incidences.begin(); it != incidences.end(); ++it ) {
(*it)->setReadOnly( true );
}
}
kDebug() << "Done loading resource" << resourceName();
return success;
}
void ResourceCalendar::loadError( const QString &err )
{
kDebug() << "Error loading resource:" << err;
d->mReceivedLoadError = true;
QString msg = i18n( "Error while loading %1.\n", resourceName() );
if ( !err.isEmpty() ) {
msg += err;
}
emit resourceLoadError( this, msg );
}
bool ResourceCalendar::receivedLoadError() const
{
return d->mReceivedLoadError;
}
void ResourceCalendar::setReceivedLoadError( bool b )
{
d->mReceivedLoadError = b;
}
bool ResourceCalendar::save( Incidence *incidence )
{
if ( d->mInhibitSave ) {
return true;
}
if ( !readOnly() ) {
kDebug() << resourceName();
d->mReceivedSaveError = false;
if ( !isOpen() ) {
kDebug() << "Trying to save into a closed resource" << resourceName();
return true;
}
bool success = incidence ? doSave( false, incidence ) : doSave( false );
if ( !success && !d->mReceivedSaveError ) {
saveError();
}
return success;
} else {
// Read-only, just don't save...
kDebug() << "Don't save read-only resource" << resourceName();
return true;
}
}
bool ResourceCalendar::save( QString &err, Incidence *incidence )
{
- d->mLastError = QString();
- bool ret = save( incidence );
+ d->mLastError.clear();
+ bool ret = save( incidence ); // a new mLastError may be set in here
err = d->mLastError;
return ret;
}
bool ResourceCalendar::isSaving()
{
return false;
}
bool ResourceCalendar::doSave( bool syncCache, Incidence *incidence )
{
return doSave( syncCache, incidence );
}
void ResourceCalendar::saveError( const QString &err )
{
kDebug() << "Error saving resource:" << err;
d->mReceivedSaveError = true;
QString msg = i18n( "Error while saving %1.\n", resourceName() );
if ( !err.isEmpty() ) {
msg += err;
}
d->mLastError = err;
emit resourceSaveError( this, msg );
}
QStringList ResourceCalendar::subresources() const
{
return QStringList();
}
bool ResourceCalendar::canHaveSubresources() const
{
return false;
}
bool ResourceCalendar::subresourceActive( const QString &resource ) const
{
Q_UNUSED( resource );
return true;
}
QString ResourceCalendar::labelForSubresource( const QString &resource ) const
{
// the resource identifier is a sane fallback
return resource;
}
QString ResourceCalendar::subresourceIdentifier( Incidence *incidence )
{
Q_UNUSED( incidence );
return QString();
}
bool ResourceCalendar::receivedSaveError() const
{
return d->mReceivedSaveError;
}
void ResourceCalendar::setReceivedSaveError( bool b )
{
d->mReceivedSaveError = b;
}
void ResourceCalendar::setInhibitSave( bool inhibit )
{
d->mInhibitSave = inhibit;
}
bool ResourceCalendar::saveInhibited() const
{
return d->mInhibitSave;
}
bool ResourceCalendar::setValue( const QString &key, const QString &value )
{
Q_UNUSED( key );
Q_UNUSED( value );
return false;
}
void ResourceCalendar::setNoReadOnlyOnLoad( bool noReadOnly )
{
d->mNoReadOnlyOnLoad = noReadOnly;
}
bool ResourceCalendar::noReadOnlyOnLoad() const
{
return d->mNoReadOnlyOnLoad;
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 9:32 AM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10075965
Default Alt Text
(84 KB)

Event Timeline