/* This file is part of libkcal. Copyright (c) 2001 Cornelius Schumacher Copyright (C) 2003-2004 Reinhold Kainhofer 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 #include #include #include #include #include #include #include extern "C" { #include #include #include } #include "calendar.h" #include "journal.h" #include "icalformat.h" #include "icalformatimpl.h" #include "compat.h" #include "config.h" #define _ICAL_VERSION "2.0" using namespace KCal; /* Static helpers */ static TQDateTime ICalDate2TQDate(const icaltimetype& t) { // Outlook sends dates starting from 1601-01-01, but TQDate() // can only handle dates starting 1752-09-14. const int year = (t.year>=1754) ? t.year : 1754; return TQDateTime(TQDate(year,t.month,t.day), TQTime(t.hour,t.minute,t.second)); } /* static void _dumpIcaltime( const icaltimetype& t) { kdDebug(5800) << "--- Y: " << t.year << " M: " << t.month << " D: " << t.day << endl; kdDebug(5800) << "--- H: " << t.hour << " M: " << t.minute << " S: " << t.second << endl; kdDebug(5800) << "--- isUtc: " << icaltime_is_utc( t )<< endl; kdDebug(5800) << "--- zoneId: " << icaltimezone_get_tzid( const_cast( t.zone ) )<< endl; } */ static TQString quoteForParam( const TQString &text ) { TQString tmp = text; tmp.remove( '"' ); if ( tmp.contains( ';' ) || tmp.contains( ':' ) || tmp.contains( ',' ) ) return tmp; // libical quotes in this case already, see icalparameter_as_ical_string() return TQString::fromLatin1( "\"" ) + tmp + TQString::fromLatin1( "\"" ); } const int gSecondsPerMinute = 60; const int gSecondsPerHour = gSecondsPerMinute * 60; const int gSecondsPerDay = gSecondsPerHour * 24; const int gSecondsPerWeek = gSecondsPerDay * 7; ICalFormatImpl::ICalFormatImpl( ICalFormat *parent ) : mParent( parent ), mCompat( new Compat ) { } ICalFormatImpl::~ICalFormatImpl() { delete mCompat; } class ICalFormatImpl::ToComponentVisitor : public IncidenceBase::Visitor { public: ToComponentVisitor( ICalFormatImpl *impl, Scheduler::Method 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; Scheduler::Method mMethod; }; icalcomponent *ICalFormatImpl::writeIncidence( IncidenceBase *incidence, Scheduler::Method method ) { ToComponentVisitor v( this, method ); if ( incidence->accept(v) ) return v.component(); else return 0; } icalcomponent *ICalFormatImpl::writeTodo(Todo *todo) { TQString tmpStr; TQStringList tmpStrList; icalcomponent *vtodo = icalcomponent_new(ICAL_VTODO_COMPONENT); writeIncidence(vtodo,todo); // due date if (todo->hasDueDate()) { icaltimetype due; if (todo->doesFloat()) { due = writeICalDate(todo->dtDue(true).date()); } else { due = writeICalDateTime(todo->dtDue(true)); } icalcomponent_add_property(vtodo,icalproperty_new_due(due)); } // start time if ( todo->hasStartDate() || todo->doesRecur() ) { icaltimetype start; if (todo->doesFloat()) { // kdDebug(5800) << " Incidence " << todo->summary() << " floats." << endl; start = writeICalDate(todo->dtStart(true).date()); } else { // kdDebug(5800) << " incidence " << todo->summary() << " has time." << endl; start = writeICalDateTime(todo->dtStart(true)); } icalcomponent_add_property(vtodo,icalproperty_new_dtstart(start)); } // completion date if (todo->isCompleted()) { if (!todo->hasCompletedDate()) { // If todo was created by KOrganizer <2.2 it has no correct completion // date. Set it to now. todo->setCompleted(TQDateTime::currentDateTime()); } icaltimetype completed = writeICalDateTime(todo->completed()); icalcomponent_add_property(vtodo,icalproperty_new_completed(completed)); } icalcomponent_add_property(vtodo, icalproperty_new_percentcomplete(todo->percentComplete())); if( todo->doesRecur() ) { icalcomponent_add_property(vtodo, icalproperty_new_recurrenceid( writeICalDateTime( todo->dtDue()))); } return vtodo; } icalcomponent *ICalFormatImpl::writeEvent(Event *event) { #if 0 kdDebug(5800) << "Write Event '" << event->summary() << "' (" << event->uid() << ")" << endl; #endif TQString tmpStr; TQStringList tmpStrList; icalcomponent *vevent = icalcomponent_new(ICAL_VEVENT_COMPONENT); writeIncidence(vevent,event); // start time icaltimetype start; if (event->doesFloat()) { // kdDebug(5800) << " Incidence " << event->summary() << " floats." << endl; start = writeICalDate(event->dtStart().date()); } else { // kdDebug(5800) << " incidence " << event->summary() << " has time." << endl; start = writeICalDateTime(event->dtStart()); } icalcomponent_add_property(vevent,icalproperty_new_dtstart(start)); if (event->hasEndDate()) { // End time. // RFC2445 says that if DTEND is present, it has to be greater than DTSTART. icaltimetype end; if (event->doesFloat()) { // kdDebug(5800) << " Event " << event->summary() << " floats." << endl; // +1 day because end date is non-inclusive. end = writeICalDate( event->dtEnd().date().addDays( 1 ) ); icalcomponent_add_property(vevent,icalproperty_new_dtend(end)); } else { // kdDebug(5800) << " Event " << event->summary() << " has time." << endl; if (event->dtEnd() != event->dtStart()) { end = writeICalDateTime(event->dtEnd()); icalcomponent_add_property(vevent,icalproperty_new_dtend(end)); } } } // TODO: resources #if 0 // resources tmpStrList = anEvent->resources(); tmpStr = tmpStrList.join(";"); if (!tmpStr.isEmpty()) addPropValue(vevent, VCResourcesProp, tmpStr.utf8()); #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, Scheduler::Method method) { kdDebug(5800) << "icalformatimpl: writeFreeBusy: startDate: " << freebusy->dtStart().toString("ddd MMMM d yyyy: h:m:s ap") << " End Date: " << freebusy->dtEnd().toString("ddd MMMM d yyyy: h:m:s ap") << endl; icalcomponent *vfreebusy = icalcomponent_new(ICAL_VFREEBUSY_COMPONENT); writeIncidenceBase(vfreebusy,freebusy); icalcomponent_add_property(vfreebusy, icalproperty_new_dtstart( writeICalDateTime(freebusy->dtStart()))); icalcomponent_add_property(vfreebusy, icalproperty_new_dtend( writeICalDateTime(freebusy->dtEnd()))); if (method == Scheduler::Request) { icalcomponent_add_property(vfreebusy,icalproperty_new_uid( freebusy->uid().utf8())); } //Loops through all the periods in the freebusy object TQValueList list = freebusy->busyPeriods(); TQValueList::Iterator it; icalperiodtype period = icalperiodtype_null_period(); for (it = list.begin(); it!= list.end(); ++it) { period.start = writeICalDateTime((*it).start()); if ( (*it).hasDuration() ) { period.duration = writeICalDuration( (*it).duration().asSeconds() ); } else { period.end = writeICalDateTime((*it).end()); } icalcomponent_add_property(vfreebusy, icalproperty_new_freebusy(period) ); } return vfreebusy; } icalcomponent *ICalFormatImpl::writeJournal(Journal *journal) { icalcomponent *vjournal = icalcomponent_new(ICAL_VJOURNAL_COMPONENT); writeIncidence(vjournal,journal); // start time if (journal->dtStart().isValid()) { icaltimetype start; if (journal->doesFloat()) { // kdDebug(5800) << " Incidence " << event->summary() << " floats." << endl; start = writeICalDate(journal->dtStart().date()); } else { // kdDebug(5800) << " incidence " << event->summary() << " has time." << endl; start = writeICalDateTime(journal->dtStart()); } icalcomponent_add_property(vjournal,icalproperty_new_dtstart(start)); } return vjournal; } void ICalFormatImpl::writeIncidence(icalcomponent *parent,Incidence *incidence) { // pilot sync stuff // TODO: move this application-specific code to kpilot if (incidence->pilotId()) { // NOTE: we can't do setNonKDECustomProperty here because this changes // data and triggers an updated() event... // incidence->setNonKDECustomProperty("X-PILOTSTAT", TQString::number(incidence->syncStatus())); // incidence->setNonKDECustomProperty("X-PILOTID", TQString::number(incidence->pilotId())); icalproperty *p = 0; p = icalproperty_new_x(TQString::number(incidence->syncStatus()).utf8()); icalproperty_set_x_name(p,"X-PILOTSTAT"); icalcomponent_add_property(parent,p); p = icalproperty_new_x(TQString::number(incidence->pilotId()).utf8()); icalproperty_set_x_name(p,"X-PILOTID"); icalcomponent_add_property(parent,p); } TQString modifiedUid; if ( incidence->hasRecurrenceID() ) { // Recurring incidences are special; they must match their parent's UID // Each child has the parent set as the first item in the list // So, get and set the UID... IncidenceList il = incidence->childIncidences(); IncidenceListIterator it; it = il.begin(); modifiedUid = (*it); } else { modifiedUid = incidence->uid(); } if ( incidence->schedulingID() != modifiedUid ) // We need to store the UID in here. The rawSchedulingID will // go into the iCal UID component incidence->setCustomProperty( "LIBKCAL", "ID", modifiedUid ); else incidence->removeCustomProperty( "LIBKCAL", "ID" ); writeIncidenceBase(parent,incidence); // creation date icalcomponent_add_property(parent,icalproperty_new_created( writeICalDateTime(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->hasRecurrenceID() ) { // Recurring incidences are special; they must match their parent's UID icalcomponent_add_property(parent,icalproperty_new_uid(modifiedUid.utf8())); } else { if ( !incidence->schedulingID().isEmpty() ) { icalcomponent_add_property(parent,icalproperty_new_uid( incidence->schedulingID().utf8())); } } // 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,icalproperty_new_lastmodified( writeICalDateTime(incidence->lastModified()))); } // description if (!incidence->description().isEmpty()) { icalcomponent_add_property(parent,icalproperty_new_description( incidence->description().utf8())); } // summary if (!incidence->summary().isEmpty()) { icalcomponent_add_property(parent,icalproperty_new_summary( incidence->summary().utf8())); } // location if (!incidence->location().isEmpty()) { icalcomponent_add_property(parent,icalproperty_new_location( incidence->location().utf8())); } // 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().utf8()); 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 TQStringList categories = incidence->categories(); TQStringList::Iterator it; for(it = categories.begin(); it != categories.end(); ++it ) { icalcomponent_add_property(parent,icalproperty_new_categories((*it).utf8())); } // related event if ( !incidence->relatedToUid().isEmpty() ) { icalcomponent_add_property(parent,icalproperty_new_relatedto( incidence->relatedToUid().utf8())); } // recurrenceid if ( incidence->hasRecurrenceID() ) { icalcomponent_add_property(parent, icalproperty_new_recurrenceid( writeICalDateTime( incidence->recurrenceID() ) )); } // kdDebug(5800) << "Write recurrence for '" << incidence->summary() << "' (" << incidence->uid() // << ")" << endl; 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,icalproperty_new_exdate( writeICalDateTime(*extIt))); } 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, icalproperty_new_rdate( writeICalDateTimePeriod(*rdtIt) ) ); } // 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() ) { // kdDebug(5800) << "Write alarm for " << incidence->summary() << endl; icalcomponent_add_component( parent, writeAlarm( *alarmIt ) ); } } // duration if (incidence->hasDuration()) { icaldurationtype duration; duration = writeICalDuration( incidence->duration() ); icalcomponent_add_property(parent,icalproperty_new_duration(duration)); } } void ICalFormatImpl::writeIncidenceBase( icalcomponent *parent, IncidenceBase * incidenceBase ) { icalcomponent_add_property( parent, icalproperty_new_dtstamp( writeICalDateTime( TQDateTime::currentDateTime() ) ) ); // organizer stuff if ( !incidenceBase->organizer().isEmpty() ) { icalcomponent_add_property( parent, 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, writeAttendee( *it ) ); } } // comments TQStringList comments = incidenceBase->comments(); for (TQStringList::Iterator it=comments.begin(); it!=comments.end(); ++it) { icalcomponent_add_property(parent, icalproperty_new_comment((*it).utf8())); } // custom properties writeCustomProperties( parent, incidenceBase ); } void ICalFormatImpl::writeCustomProperties(icalcomponent *parent,CustomProperties *properties) { TQMap custom = properties->customProperties(); for (TQMap::Iterator c = custom.begin(); c != custom.end(); ++c) { icalproperty *p = icalproperty_new_x(c.data().utf8()); icalproperty_set_x_name(p,c.key()); icalcomponent_add_property(parent,p); } } icalproperty *ICalFormatImpl::writeOrganizer( const Person &organizer ) { icalproperty *p = icalproperty_new_organizer("MAILTO:" + organizer.email().utf8()); if (!organizer.name().isEmpty()) { icalproperty_add_parameter( p, icalparameter_new_cn(quoteForParam(organizer.name()).utf8()) ); } // TODO: Write dir, sent-by and language return p; } icalproperty *ICalFormatImpl::writeAttendee(Attendee *attendee) { icalproperty *p = icalproperty_new_attendee("mailto:" + attendee->email().utf8()); if (!attendee->name().isEmpty()) { icalproperty_add_parameter(p,icalparameter_new_cn(quoteForParam(attendee->name()).utf8())); } 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().utf8()); 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().utf8() ); icalproperty_add_parameter( p, icalparameter_delegate ); } if ( !attendee->delegator().isEmpty() ) { icalparameter* icalparameter_delegator = icalparameter_new_delegatedfrom( attendee->delegator().utf8() ); 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().utf8().data() ); } else { #ifdef USE_LIBICAL_0_46 attach = icalattach_new_from_data ( (const char *)att->data(), 0, 0 ); #else attach = icalattach_new_from_data ( (unsigned char *)att->data(), 0, 0 ); #endif } icalproperty *p = icalproperty_new_attach( attach ); if ( !att->mimeType().isEmpty() ) { icalproperty_add_parameter( p, icalparameter_new_fmttype( att->mimeType().utf8().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().utf8() ); icalparameter_set_xname( icalparameter_label, "X-LABEL" ); icalproperty_add_parameter( p, icalparameter_label ); } return p; } icalrecurrencetype ICalFormatImpl::writeRecurrenceRule( RecurrenceRule *recur ) { // kdDebug(5800) << "ICalFormatImpl::writeRecurrenceRule()" << endl; 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; kdDebug(5800) << "ICalFormatImpl::writeRecurrence(): no recurrence" << endl; break; } int index = 0; TQValueList bys; TQValueList::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; } TQValueList byd = recur->byDays(); int day; index = 0; for ( TQValueList::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( 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->doesFloat() ) r.until = writeICalDate(recur->endDt().date()); else r.until = writeICalDateTime(recur->endDt()); } // Debug output #if 0 const char *str = icalrecurrencetype_as_string(&r); if (str) { kdDebug(5800) << " String: " << str << endl; } else { kdDebug(5800) << " No String" << endl; } #endif return r; } icalcomponent *ICalFormatImpl::writeAlarm(Alarm *alarm) { // kdDebug(5800) << " ICalFormatImpl::writeAlarm" << endl; 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(TQFile::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().utf8())); } break; case Alarm::Audio: action = ICAL_ACTION_AUDIO; // kdDebug(5800) << " It's an audio action, file: " << alarm->audioFile() << endl; if (!alarm->audioFile().isEmpty()) { attach = icalattach_new_from_url(TQFile::encodeName( alarm->audioFile() ).data()); icalcomponent_add_property(a,icalproperty_new_attach(attach)); } break; case Alarm::Email: { action = ICAL_ACTION_EMAIL; TQValueList addresses = alarm->mailAddresses(); for (TQValueList::Iterator ad = addresses.begin(); ad != addresses.end(); ++ad) { icalproperty *p = icalproperty_new_attendee("MAILTO:" + (*ad).email().utf8()); if (!(*ad).name().isEmpty()) { icalproperty_add_parameter(p,icalparameter_new_cn(quoteForParam((*ad).name()).utf8())); } icalcomponent_add_property(a,p); } icalcomponent_add_property(a,icalproperty_new_summary(alarm->mailSubject().utf8())); icalcomponent_add_property(a,icalproperty_new_description(alarm->mailText().utf8())); TQStringList attachments = alarm->mailAttachments(); if (attachments.count() > 0) { for (TQStringList::Iterator at = attachments.begin(); at != attachments.end(); ++at) { attach = icalattach_new_from_url(TQFile::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().utf8())); break; case Alarm::Invalid: default: kdDebug(5800) << "Unknown type of alarm" << endl; action = ICAL_ACTION_NONE; break; } icalcomponent_add_property(a,icalproperty_new_action(action)); // Trigger time icaltriggertype trigger; if ( alarm->hasTime() ) { trigger.time = writeICalDateTime(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.asSeconds() ); } 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().value()))); } // Custom properties TQMap custom = alarm->customProperties(); for (TQMap::Iterator c = custom.begin(); c != custom.end(); ++c) { icalproperty *p = icalproperty_new_x(c.data().utf8()); icalproperty_set_x_name(p,c.key()); icalcomponent_add_property(a,p); } return a; } Todo *ICalFormatImpl::readTodo(icalcomponent *vtodo) { Todo *todo = new Todo; readIncidence(vtodo, 0, todo); // FIXME timezone icalproperty *p = icalcomponent_get_first_property(vtodo,ICAL_ANY_PROPERTY); // int intvalue; icaltimetype icaltime; TQStringList categories; while (p) { icalproperty_kind kind = icalproperty_isa(p); switch (kind) { case ICAL_DUE_PROPERTY: // due date icaltime = icalproperty_get_due(p); if (icaltime.is_date) { todo->setDtDue(TQDateTime(readICalDate(icaltime),TQTime(0,0,0)),true); } else { todo->setDtDue(readICalDateTime(p, icaltime),true); todo->setFloats(false); } todo->setHasDueDate(true); break; case ICAL_COMPLETED_PROPERTY: // completion date icaltime = icalproperty_get_completed(p); todo->setCompleted(readICalDateTime(p, icaltime)); break; case ICAL_PERCENTCOMPLETE_PROPERTY: // Percent completed todo->setPercentComplete(icalproperty_get_percentcomplete(p)); break; case ICAL_RELATEDTO_PROPERTY: // related todo (parent) todo->setRelatedToUid(TQString::fromUtf8(icalproperty_get_relatedto(p))); mTodosRelate.append(todo); break; case ICAL_DTSTART_PROPERTY: { // Flag that todo has start date. Value is read in by readIncidence(). if ( todo->comments().grep("NoStartDate").count() ) todo->setHasStartDate( false ); else todo->setHasStartDate( true ); break; } case ICAL_RECURRENCEID_PROPERTY: icaltime = icalproperty_get_recurrenceid(p); todo->setDtRecurrence( readICalDateTime(p, icaltime) ); break; default: // kdDebug(5800) << "ICALFormat::readTodo(): Unknown property: " << kind // << endl; break; } p = icalcomponent_get_next_property(vtodo,ICAL_ANY_PROPERTY); } if (mCompat) mCompat->fixEmptySummary( todo ); return todo; } Event *ICalFormatImpl::readEvent( icalcomponent *vevent, icalcomponent *vtimezone ) { Event *event = new Event; // FIXME where is this freed? icaltimezone *tz = icaltimezone_new(); if ( !icaltimezone_set_component( tz, vtimezone ) ) { icaltimezone_free( tz, 1 ); tz = 0; } readIncidence( vevent, tz, event); icalproperty *p = icalcomponent_get_first_property( vevent, ICAL_ANY_PROPERTY ); // int intvalue; icaltimetype icaltime; TQStringList categories; icalproperty_transp transparency; bool dtEndProcessed = false; while ( p ) { icalproperty_kind kind = icalproperty_isa( p ); switch ( kind ) { case ICAL_DTEND_PROPERTY: // start date and time icaltime = icalproperty_get_dtend( p ); if ( icaltime.is_date ) { // End date is non-inclusive TQDate endDate = readICalDate( icaltime ).addDays( -1 ); if ( mCompat ) { mCompat->fixFloatingEnd( endDate ); } if ( endDate < event->dtStart().date() ) { endDate = event->dtStart().date(); } event->setDtEnd( TQDateTime( endDate, TQTime( 0, 0, 0 ) ) ); } else { event->setDtEnd(readICalDateTime(p, icaltime, tz)); event->setFloats( false ); } dtEndProcessed = true; break; case ICAL_RELATEDTO_PROPERTY: // related event (parent) event->setRelatedToUid( TQString::fromUtf8( icalproperty_get_relatedto( p ) ) ); 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: // kdDebug(5800) << "ICALFormat::readEvent(): Unknown property: " << kind // << endl; 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() ); } const TQString msade = event->nonKDECustomProperty("X-MICROSOFT-CDO-ALLDAYEVENT"); if ( !msade.isEmpty() ) { const bool floats = ( msade == TQString::fromLatin1("TRUE") ); event->setFloats(floats); } if ( mCompat ) { mCompat->fixEmptySummary( event ); } return event; } FreeBusy *ICalFormatImpl::readFreeBusy(icalcomponent *vfreebusy) { FreeBusy *freebusy = new FreeBusy; readIncidenceBase(vfreebusy, freebusy); icalproperty *p = icalcomponent_get_first_property(vfreebusy,ICAL_ANY_PROPERTY); icaltimetype icaltime; PeriodList periods; while (p) { icalproperty_kind kind = icalproperty_isa(p); switch (kind) { case ICAL_DTSTART_PROPERTY: // start date and time icaltime = icalproperty_get_dtstart(p); freebusy->setDtStart(readICalDateTime(p, icaltime)); break; case ICAL_DTEND_PROPERTY: // end Date and Time icaltime = icalproperty_get_dtend(p); freebusy->setDtEnd(readICalDateTime(p, icaltime)); break; case ICAL_FREEBUSY_PROPERTY: //Any FreeBusy Times { icalperiodtype icalperiod = icalproperty_get_freebusy(p); TQDateTime period_start = readICalDateTime(p, icalperiod.start); Period period; if ( !icaltime_is_null_time(icalperiod.end) ) { TQDateTime period_end = readICalDateTime(p, icalperiod.end); period = Period(period_start, period_end); } else { Duration duration = readICalDuration( icalperiod.duration ); period = Period(period_start, duration); } icalparameter *param = icalproperty_get_first_parameter( p, ICAL_X_PARAMETER ); while ( param ) { if ( strncmp( icalparameter_get_xname( param ), "X-SUMMARY", 9 ) == 0 ) { period.setSummary( TQString::fromUtf8( KCodecs::base64Decode( TQCString( icalparameter_get_xvalue( param ) ) ) ) ); } if ( strncmp( icalparameter_get_xname( param ), "X-LOCATION", 10 ) == 0 ) { period.setLocation( TQString::fromUtf8( KCodecs::base64Decode( TQCString( icalparameter_get_xvalue( param ) ) ) ) ); } param = icalproperty_get_next_parameter( p, ICAL_X_PARAMETER ); } periods.append( period ); break; } default: // kdDebug(5800) << "ICalFormatImpl::readFreeBusy(): Unknown property: " // << kind << endl; break; } p = icalcomponent_get_next_property(vfreebusy,ICAL_ANY_PROPERTY); } freebusy->addPeriods( periods ); return freebusy; } Journal *ICalFormatImpl::readJournal(icalcomponent *vjournal) { Journal *journal = new Journal; readIncidence(vjournal, 0, journal); // FIXME tz? return journal; } Attendee *ICalFormatImpl::readAttendee(icalproperty *attendee) { icalparameter *p = 0; TQString email = TQString::fromUtf8(icalproperty_get_attendee(attendee)); if ( email.startsWith( "mailto:", false ) ) { email = email.mid( 7 ); } TQString name; TQString uid = TQString(); p = icalproperty_get_first_parameter(attendee,ICAL_CN_PARAMETER); if (p) { name = TQString::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 ) { TQString email = TQString::fromUtf8(icalproperty_get_organizer(organizer)); if ( email.startsWith( "mailto:", false ) ) { email = email.mid( 7 ); } TQString cn; icalparameter *p = icalproperty_get_first_parameter( organizer, ICAL_CN_PARAMETER ); if ( p ) { cn = TQString::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 ) ) { p = (const char *)icalattach_get_data( a ); if ( p ) { attachment = new Attachment( p ); } } else { p = icalattach_get_url( a ); if ( p ) { attachment = new Attachment( TQString::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( TQString::fromUtf8( p ) ); break; default: break; } if ( attachment ) { icalparameter *p = icalproperty_get_first_parameter( attach, ICAL_FMTTYPE_PARAMETER ); if ( p ) { attachment->setMimeType( TQString( icalparameter_get_fmttype( p ) ) ); } p = icalproperty_get_first_parameter( attach, ICAL_X_PARAMETER ); while ( p ) { TQString xname = TQString( icalparameter_get_xname( p ) ).upper(); TQString xvalue = TQString::fromUtf8( icalparameter_get_xvalue( p ) ); if ( xname == "X-CONTENT-DISPOSITION" ) { attachment->setShowInline( xvalue.lower() == "inline" ); } if ( xname == "X-LABEL" ) { attachment->setLabel( xvalue ); } 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( TQString::fromUtf8( icalparameter_get_xvalue( p ) ) ); } p = icalproperty_get_next_parameter( attach, ICAL_X_PARAMETER ); } } return attachment; } void ICalFormatImpl::readIncidence(icalcomponent *parent, icaltimezone *tz, Incidence *incidence) { readIncidenceBase(parent,incidence); icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY); const char *text; int intvalue, inttext; icaltimetype icaltime; icaldurationtype icalduration; TQStringList categories; while (p) { icalproperty_kind kind = icalproperty_isa(p); switch (kind) { case ICAL_CREATED_PROPERTY: icaltime = icalproperty_get_created(p); incidence->setCreated(readICalDateTime(p, icaltime, tz)); break; case ICAL_SEQUENCE_PROPERTY: // sequence intvalue = icalproperty_get_sequence(p); incidence->setRevision(intvalue); break; case ICAL_LASTMODIFIED_PROPERTY: // last modification date icaltime = icalproperty_get_lastmodified(p); incidence->setLastModified(readICalDateTime(p, icaltime, tz)); break; case ICAL_DTSTART_PROPERTY: // start date and time icaltime = icalproperty_get_dtstart(p); if (icaltime.is_date) { incidence->setDtStart(TQDateTime(readICalDate(icaltime),TQTime(0,0,0))); incidence->setFloats( true ); } else { incidence->setDtStart(readICalDateTime(p, icaltime, tz)); incidence->setFloats( false ); } break; case ICAL_DURATION_PROPERTY: // start date and time icalduration = icalproperty_get_duration(p); incidence->setDuration(readICalDuration(icalduration)); break; case ICAL_DESCRIPTION_PROPERTY: // description text = icalproperty_get_description(p); incidence->setDescription(TQString::fromUtf8(text)); break; case ICAL_SUMMARY_PROPERTY: // summary text = icalproperty_get_summary(p); incidence->setSummary(TQString::fromUtf8(text)); break; case ICAL_LOCATION_PROPERTY: // location text = icalproperty_get_location(p); incidence->setLocation(TQString::fromUtf8(text)); 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(TQString::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 ( mCompat ) intvalue = mCompat->fixPriority( intvalue ); incidence->setPriority( intvalue ); break; case ICAL_CATEGORIES_PROPERTY: // categories text = icalproperty_get_categories(p); categories.append(TQString::fromUtf8(text)); break; case ICAL_RECURRENCEID_PROPERTY: // recurrenceID icaltime = icalproperty_get_recurrenceid(p); incidence->setRecurrenceID( readICalDateTime( p, icaltime ) ); incidence->setHasRecurrenceID( true ); break; case ICAL_RRULE_PROPERTY: readRecurrenceRule( p, incidence ); break; // case ICAL_CONTACT_PROPERTY: // incidenceBase->addContact( // TQString::fromUtf8( icalproperty_get_contact( p ) ) ); // break; case ICAL_RDATE_PROPERTY: { icaldatetimeperiodtype rd = icalproperty_get_rdate( p ); if ( icaltime_is_valid_time( rd.time ) ) { if ( icaltime_is_date( rd.time ) ) { incidence->recurrence()->addRDate( readICalDate( rd.time ) ); } else { incidence->recurrence()->addRDateTime( readICalDateTime(p, rd.time, tz ) ); } } else { // TODO: RDates as period are not yet implemented! } break; } case ICAL_EXRULE_PROPERTY: readExceptionRule( p, incidence ); break; case ICAL_EXDATE_PROPERTY: icaltime = icalproperty_get_exdate(p); if ( icaltime_is_date(icaltime) ) { incidence->recurrence()->addExDate( readICalDate(icaltime) ); } else { incidence->recurrence()->addExDateTime( readICalDateTime(p, icaltime, tz) ); } 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: // kdDebug(5800) << "ICALFormat::readIncidence(): Unknown property: " << kind // << endl; break; } p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY); } // Set the scheduling ID const TQString 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->doesRecur() && mCompat ) 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); } // Fix incorrect alarm settings by other applications (like outloook 9) if ( mCompat ) mCompat->fixAlarms( incidence ); } void ICalFormatImpl::readIncidenceBase(icalcomponent *parent,IncidenceBase *incidenceBase) { icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY); bool uidProcessed = false; while ( p ) { icalproperty_kind kind = icalproperty_isa( p ); switch (kind) { case ICAL_UID_PROPERTY: // unique id uidProcessed = true; incidenceBase->setUid( TQString::fromUtf8(icalproperty_get_uid( p ) ) ); break; case ICAL_ORGANIZER_PROPERTY: // organizer incidenceBase->setOrganizer( readOrganizer( p ) ); break; case ICAL_ATTENDEE_PROPERTY: // attendee incidenceBase->addAttendee( readAttendee( p ) ); break; case ICAL_COMMENT_PROPERTY: incidenceBase->addComment( TQString::fromUtf8( icalproperty_get_comment( p ) ) ); break; default: break; } p = icalcomponent_get_next_property( parent, ICAL_ANY_PROPERTY ); } if ( !uidProcessed ) { kdWarning() << "The incidence didn't have any UID! Report a bug " << "to the application that generated this file." << endl; // Our in-memory incidence has a random uid generated in Event's ctor. // Make it empty so it matches what's in the file: incidenceBase->setUid( TQString() ); // Otherwise, next time we read the file, this function will return // an event with another random uid and we will have two events in the calendar. } // kpilot stuff // TODO: move this application-specific code to kpilot // need to get X-PILOT* attributes out, set correct properties, and get // rid of them... // Pointer fun, as per libical documentation // (documented in UsingLibical.txt) icalproperty *next =0; for ( p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY); p != 0; p = next ) { next = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY); TQString value = TQString::fromUtf8(icalproperty_get_x(p)); TQString name = icalproperty_get_x_name(p); if (name == "X-PILOTID" && !value.isEmpty()) { incidenceBase->setPilotId(value.toInt()); icalcomponent_remove_property(parent,p); } else if (name == "X-PILOTSTAT" && !value.isEmpty()) { incidenceBase->setSyncStatus(value.toInt()); icalcomponent_remove_property(parent,p); } } // custom properties readCustomProperties(parent, incidenceBase); } void ICalFormatImpl::readCustomProperties(icalcomponent *parent,CustomProperties *properties) { TQMap customProperties; TQString lastProperty; icalproperty *p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY); while (p) { TQString value = TQString::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 ); } // kdDebug(5800) << "Set custom property [" << name << '=' << value << ']' << endl; p = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY); lastProperty = name; } properties->setCustomProperties(customProperties); } void ICalFormatImpl::readRecurrenceRule(icalproperty *rrule,Incidence *incidence ) { // kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl; 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 ) { // kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl; 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->mRRule = TQString( icalrecurrencetype_as_string( const_cast(&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; t = r.until; // Convert to the correct time zone! it's in UTC by specification. TQDateTime endDate( readICalDateTime(0, t) ); recur->setEndDt( endDate ); } 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* TQValueList lst; int i; int index = 0; #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 ); // 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 TQValueList 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 ) ); // kdDebug(5800)<< " o) By day, index="<summary() << endl; 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 ) { kdDebug(5800) << "Unknown type of alarm, using default" << endl; // return; } 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: kdDebug(5800) << "Unknown type of alarm: " << action << endl; // type = Alarm::Invalid; } } ialarm->setType(type); // kdDebug(5800) << " alarm type =" << type << endl; 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)) { kdDebug(5800) << "ICalFormatImpl::readAlarm(): Trigger has no time and no duration." << endl; } else { Duration duration = icaldurationtype_as_int( 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(readICalDateTime(p, trigger.time)); } 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: { TQString description = TQString::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; } // Only in EMAIL alarm case ICAL_SUMMARY_PROPERTY: ialarm->setMailSubject(TQString::fromUtf8(icalproperty_get_summary(p))); break; // Only in EMAIL alarm case ICAL_ATTENDEE_PROPERTY: { TQString email = TQString::fromUtf8(icalproperty_get_attendee(p)); if ( email.startsWith("mailto:", false ) ) { email = email.mid( 7 ); } TQString name; icalparameter *param = icalproperty_get_first_parameter(p,ICAL_CN_PARAMETER); if (param) { name = TQString::fromUtf8(icalparameter_get_cn(param)); } ialarm->addMailAddress(Person(name, email)); break; } // Only in AUDIO and EMAIL and PROCEDURE alarms case ICAL_ATTACH_PROPERTY: { 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 { kdDebug() << "Alarm attachments currently only support URIs, but " "no binary data" << endl; } delete attach; break; } default: break; } p = icalcomponent_get_next_property(alarm,ICAL_ANY_PROPERTY); } // custom properties readCustomProperties(alarm, ialarm); // TODO: check for consistency of alarm properties } icaldatetimeperiodtype ICalFormatImpl::writeICalDatePeriod( const TQDate &date ) { icaldatetimeperiodtype t; t.time = writeICalDate( date ); t.period = icalperiodtype_null_period(); return t; } icaldatetimeperiodtype ICalFormatImpl::writeICalDateTimePeriod( const TQDateTime &date ) { icaldatetimeperiodtype t; t.time = writeICalDateTime( date ); t.period = icalperiodtype_null_period(); return t; } icaltimetype ICalFormatImpl::writeICalDate(const TQDate &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.zone = 0; return t; } icaltimetype ICalFormatImpl::writeICalDateTime(const TQDateTime &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 = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() ); // _dumpIcaltime( t ); /* The TQDateTime we get passed in is to be considered in the timezone of * the current calendar (mParent's), or, if there is none, to be floating. * In the later case store a floating time, in the former normalize to utc. */ if (mParent->timeZoneId().isEmpty()) t = icaltime_convert_to_zone( t, 0 ); //make floating timezone else { icaltimezone* tz = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() ); icaltimezone* utc = icaltimezone_get_utc_timezone(); if ( tz != utc ) { t.zone = tz; t = icaltime_convert_to_zone( t, utc ); } else { t.zone = utc; } } // _dumpIcaltime( t ); return t; } TQDateTime ICalFormatImpl::readICalDateTime( icalproperty *p, icaltimetype& t, icaltimezone* tz ) { // kdDebug(5800) << "ICalFormatImpl::readICalDateTime()" << endl; if (!icaltime_is_utc(t)) { // Only use the TZ if time is not UTC. // FIXME: We'll need to make sure to apply the appropriate TZ, not just // the first one found. icalparameter *param = p ? icalproperty_get_first_parameter(p, ICAL_TZID_PARAMETER) : 0; const char *tzid = param ? icalparameter_get_tzid(param) : 0; if ( tzid ) { icaltimezone* icaltz; // Try to match the ID with the libical time zone's location property icaltz = icaltimezone_get_builtin_timezone( tzid ); if ( icaltz ) { //kdDebug(5800) << "ICalFormatImpl::readICalDateTime(): time zone '" << tzid << "' read from libical database" << endl; } t.zone = icaltz; } else { if (tz && tz != icaltimezone_get_utc_timezone()) { t.zone = tz; } else { t.zone = icaltimezone_get_utc_timezone(); } } } else { t.zone = icaltimezone_get_utc_timezone(); } //_dumpIcaltime( t ); // Convert to view time if ( !mParent->timeZoneId().isEmpty() && t.zone ) { // kdDebug(5800) << "--- Converting time from: " << icaltimezone_get_tzid( const_cast( t.zone ) ) << " (" << ICalDate2TQDate(t) << ")." << endl; icaltimezone* viewTimeZone = icaltimezone_get_builtin_timezone ( mParent->timeZoneId().latin1() ); icaltimezone_convert_time( &t, const_cast(t.zone), viewTimeZone ); // kdDebug(5800) << "--- Converted to zone " << mParent->timeZoneId() << " (" << ICalDate2TQDate(t) << ")." << endl; } return ICalDate2TQDate(t); } TQDate ICalFormatImpl::readICalDate(icaltimetype t) { return ICalDate2TQDate(t).date(); } icaldurationtype ICalFormatImpl::writeICalDuration(int seconds) { // should be able to use icaldurationtype_from_int(), except we know // that some older tools do not properly support weeks. So we never // set a week duration, only days icaldurationtype d; d.is_neg = (seconds<0)?1:0; if (seconds<0) seconds = -seconds; d.weeks = 0; d.days = seconds / gSecondsPerDay; seconds %= gSecondsPerDay; d.hours = seconds / gSecondsPerHour; seconds %= gSecondsPerHour; d.minutes = seconds / gSecondsPerMinute; seconds %= gSecondsPerMinute; d.seconds = seconds; return d; } int ICalFormatImpl::readICalDuration(icaldurationtype d) { int result = 0; result += d.weeks * gSecondsPerWeek; result += d.days * gSecondsPerDay; result += d.hours * gSecondsPerHour; result += d.minutes * gSecondsPerMinute; result += d.seconds; if (d.is_neg) result *= -1; return result; } 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().utf8()); icalcomponent_add_property(calendar,p); // TODO: Add time zone // iCalendar version (2.0) p = icalproperty_new_version(const_cast(_ICAL_VERSION)); icalcomponent_add_property(calendar,p); // Custom properties if( cal != 0 ) 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) { kdDebug(5800) << "No PRODID property found" << endl; mLoadedProductId = ""; } else { mLoadedProductId = TQString::fromUtf8(icalproperty_get_prodid(p)); // kdDebug(5800) << "VCALENDAR prodid: '" << mLoadedProductId << "'" << endl; delete mCompat; mCompat = CompatFactory::createCompat( mLoadedProductId ); } p = icalcomponent_get_first_property(calendar,ICAL_VERSION_PROPERTY); if (!p) { kdDebug(5800) << "No VERSION property found" << endl; mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown)); return false; } else { const char *version = icalproperty_get_version(p); if ( !version ) { kdDebug(5800) << "No VERSION property found" << endl; mParent->setException( new ErrorFormat( ErrorFormat::CalVersionUnknown, i18n( "No VERSION property found" ) ) ); return false; } // kdDebug(5800) << "VCALENDAR version: '" << version << "'" << endl; if (strcmp(version,"1.0") == 0) { kdDebug(5800) << "Expected iCalendar, got vCalendar" << endl; mParent->setException(new ErrorFormat(ErrorFormat::CalVersion1, i18n("Expected iCalendar format"))); return false; } else if (strcmp(version,"2.0") != 0) { kdDebug(5800) << "Expected iCalendar, got unknown format" << endl; mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown)); return false; } } // custom properties readCustomProperties(calendar, cal); // TODO: set time zone // read a VTIMEZONE if there is one icalcomponent *ctz = icalcomponent_get_first_component( calendar, ICAL_VTIMEZONE_COMPONENT ); // Store all events with a relatedTo property in a list for post-processing mEventsRelate.clear(); 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) { // kdDebug(5800) << "----Todo found" << endl; Todo *todo = readTodo(c); if (todo) { if (todo->hasRecurrenceID()) { TQString originalUid = todo->uid(); todo->setUid(originalUid + TQString("-recur-%1").arg(todo->recurrenceID().toTime_t())); if (!cal->todo(todo->uid())) { if ( !cal->addTodo( todo ) ) { cal->endBatchAdding(); // If the user pressed cancel, return true, it's not an error. return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel; } if (!cal->event(originalUid)) { printf("FIXME! [WARNING] Parent for child event does not yet exist!\n"); } else { // Add this todo to its parent cal->todo(originalUid)->addChildIncidence(todo->uid()); // And the parent to the child todo->addChildIncidence(cal->todo(originalUid)->uid()); } } } else { if (!cal->todo(todo->uid())) { if ( !cal->addTodo( todo ) ) { cal->endBatchAdding(); // If the user pressed cancel, return true, it's not an error. return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel; } } else { delete todo; mTodosRelate.remove( 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) { // kdDebug(5800) << "----Event found" << endl; Event *event = readEvent(c, ctz); if (event) { if (event->hasRecurrenceID()) { TQString originalUid = event->uid(); event->setUid(originalUid + TQString("-recur-%1").arg(event->recurrenceID().toTime_t())); if (!cal->event(event->uid())) { cal->addEvent(event); if (!cal->event(originalUid)) { printf("FIXME! [WARNING] Parent for child event does not yet exist!\n"); } else { // Add this event to its parent cal->event(originalUid)->addChildIncidence(event->uid()); // And the parent to the child event->addChildIncidence(cal->event(originalUid)->uid()); } } } else { if (!cal->event(event->uid())) { if ( !cal->addEvent( event ) ) { cal->endBatchAdding(); // If the user pressed cancel, return true, it's not an error. return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel; } } else { delete event; mEventsRelate.remove( 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) { // kdDebug(5800) << "----Journal found" << endl; Journal *journal = readJournal(c); if (journal) { if (journal->hasRecurrenceID()) { TQString originalUid = journal->uid(); journal->setUid(originalUid + TQString("-recur-%1").arg(journal->recurrenceID().toTime_t())); if (!cal->journal(journal->uid())) { cal->addJournal(journal); if (!cal->event(originalUid)) { printf("FIXME! [WARNING] Parent for child event does not yet exist!\n"); } else { // Add this journal to its parent cal->journal(originalUid)->addChildIncidence(journal->uid()); // And the parent to the child journal->addChildIncidence(cal->journal(originalUid)->uid()); } } } else { if (!cal->journal(journal->uid())) { if ( !cal->addJournal(journal) ) { cal->endBatchAdding(); // If the user pressed cancel, return true, it's not an error. return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel; } } else { delete journal; } } } c = icalcomponent_get_next_component(calendar,ICAL_VJOURNAL_COMPONENT); } cal->endBatchAdding(); // Post-Process list of events with relations, put Event objects in relation Event::List::ConstIterator eIt; for ( eIt = mEventsRelate.begin(); eIt != mEventsRelate.end(); ++eIt ) { (*eIt)->setRelatedTo( cal->incidence( (*eIt)->relatedToUid() ) ); } Todo::List::ConstIterator tIt; for ( tIt = mTodosRelate.begin(); tIt != mTodosRelate.end(); ++tIt ) { (*tIt)->setRelatedTo( cal->incidence( (*tIt)->relatedToUid() ) ); } return true; } TQString ICalFormatImpl::extractErrorProperty(icalcomponent *c) { // kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: " // << icalcomponent_as_ical_string(c) << endl; TQString 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); } // kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: " << errorMessage << endl; return errorMessage; } void ICalFormatImpl::dumpIcalRecurrence(icalrecurrencetype r) { int i; kdDebug(5800) << " Freq: " << r.freq << endl; kdDebug(5800) << " Until: " << icaltime_as_ical_string(r.until) << endl; kdDebug(5800) << " Count: " << r.count << endl; if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { int index = 0; TQString out = " By Day: "; while((i = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { out.append(TQString::number(i) + " "); } kdDebug(5800) << out << endl; } if (r.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { int index = 0; TQString out = " By Month Day: "; while((i = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { out.append(TQString::number(i) + " "); } kdDebug(5800) << out << endl; } if (r.by_year_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { int index = 0; TQString out = " By Year Day: "; while((i = r.by_year_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { out.append(TQString::number(i) + " "); } kdDebug(5800) << out << endl; } if (r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX) { int index = 0; TQString out = " By Month: "; while((i = r.by_month[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { out.append(TQString::number(i) + " "); } kdDebug(5800) << out << endl; } if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) { int index = 0; TQString out = " By Set Pos: "; while((i = r.by_set_pos[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { kdDebug(5800) << "========= " << i << endl; out.append(TQString::number(i) + " "); } kdDebug(5800) << out << endl; } } icalcomponent *ICalFormatImpl::createScheduleComponent(IncidenceBase *incidence, Scheduler::Method method) { icalcomponent *message = createCalendarComponent(); icalproperty_method icalmethod = ICAL_METHOD_NONE; switch (method) { case Scheduler::Publish: icalmethod = ICAL_METHOD_PUBLISH; break; case Scheduler::Request: icalmethod = ICAL_METHOD_REQUEST; break; case Scheduler::Refresh: icalmethod = ICAL_METHOD_REFRESH; break; case Scheduler::Cancel: icalmethod = ICAL_METHOD_CANCEL; break; case Scheduler::Add: icalmethod = ICAL_METHOD_ADD; break; case Scheduler::Reply: icalmethod = ICAL_METHOD_REPLY; break; case Scheduler::Counter: icalmethod = ICAL_METHOD_COUNTER; break; case Scheduler::Declinecounter: icalmethod = ICAL_METHOD_DECLINECOUNTER; break; default: kdDebug(5800) << "ICalFormat::createScheduleMessage(): Unknow method" << endl; 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; }