From ab1ab8bf5207a34a3069c8003fadd4716c6d7ac0 Mon Sep 17 00:00:00 2001
From: Michele Calgaro <michele.calgaro@yahoo.it>
Date: Tue, 23 Jun 2026 14:45:21 +0900
Subject: libkcal: add support for libical 4

Co-authored-by: Opencode/DeepSeek V4 Flash
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
---
 libkcal/ConfigureChecks.cmake |  14 +-
 libkcal/icalformat.cpp        |  22 ++-
 libkcal/icalformatimpl.cpp    | 356 ++++++++++++++++++++++++++----------------
 libkcal/icalformatimpl.h      |   8 +-
 libkcal/tests/runtestcase.pl  |  15 ++
 5 files changed, 271 insertions(+), 144 deletions(-)

diff --git a/libkcal/ConfigureChecks.cmake b/libkcal/ConfigureChecks.cmake
index 4c27fa15..7e31f91d 100644
--- a/libkcal/ConfigureChecks.cmake
+++ b/libkcal/ConfigureChecks.cmake
@@ -12,6 +12,16 @@
 # libical
 pkg_search_module( LIBICAL libical )
 if( LIBICAL_FOUND )
+  if( LIBICAL_VERSION VERSION_GREATER_EQUAL "4.0.0" )
+    # Starting from version 4.0.0, libicalss and libicalvcal
+    # have their own package config files.
+    pkg_search_module( LIBICAL_EXTRA libicalss libicalvcal )
+    if( NOT LIBICAL_EXTRA_FOUND )
+      tde_message_fatal( "libicalss/libicalval are required but not found on your system" )
+    endif( )
+    list(APPEND LIBICAL_INCLUDE_DIRS ${LIBICAL_EXTRA_INCLUDE_DIRS})
+    list(APPEND LIBICAL_LIBRARIES    ${LIBICAL_EXTRA_LIBRARIES})
+  endif( )
 else( )
-  tde_message_fatal( "libical are required, but not found on your system" )
-endif()
+  tde_message_fatal( "libical is required but not found on your system" )
+endif( )
diff --git a/libkcal/icalformat.cpp b/libkcal/icalformat.cpp
index ab0ab532..6c024774 100644
--- a/libkcal/icalformat.cpp
+++ b/libkcal/icalformat.cpp
@@ -341,7 +341,14 @@ TQString ICalFormat::toString( Incidence *incidence, Calendar *calendar )
 TQString ICalFormat::toString( RecurrenceRule *recurrence )
 {
   icalproperty *property;
-  property = icalproperty_new_rrule( mImpl->writeRecurrenceRule( recurrence ) );
+  icalrecurrencetype *recur = mImpl->writeRecurrenceRule( recurrence );
+#if ICAL_CHECK_VERSION(4,0,0)
+  property = icalproperty_new_rrule( recur );
+  icalrecurrencetype_unref(recur);
+#else
+  property = icalproperty_new_rrule( *recur );
+  delete recur;
+#endif
   TQString text = TQString::fromUtf8( icalproperty_as_ical_string( property ) );
   icalproperty_free( property );
   return text;
@@ -352,7 +359,12 @@ bool ICalFormat::fromString( RecurrenceRule * recurrence, const TQString& rrule
   if ( !recurrence ) return false;
   bool success = true;
   icalerror_clear_errno();
-  struct icalrecurrencetype recur = icalrecurrencetype_from_string( rrule.latin1() );
+#if ICAL_CHECK_VERSION(4,0,0)
+  struct icalrecurrencetype *recur = icalrecurrencetype_new_from_string( rrule.latin1() );
+#else
+  struct icalrecurrencetype _recur = icalrecurrencetype_from_string( rrule.latin1() );
+  struct icalrecurrencetype *recur = &_recur;
+#endif
   if ( icalerrno != ICAL_NO_ERROR ) {
     kdDebug(5800) << "Recurrence parsing error: " << icalerror_strerror( icalerrno ) << endl;
     success = false;
@@ -362,6 +374,12 @@ bool ICalFormat::fromString( RecurrenceRule * recurrence, const TQString& rrule
     mImpl->readRecurrence( recur, recurrence );
   }
 
+#if ICAL_CHECK_VERSION(4,0,0)
+  if ( recur ) {
+    icalrecurrencetype_unref( recur );
+  }
+#endif
+
   return success;
 }
 
diff --git a/libkcal/icalformatimpl.cpp b/libkcal/icalformatimpl.cpp
index 2e686900..2254c06c 100644
--- a/libkcal/icalformatimpl.cpp
+++ b/libkcal/icalformatimpl.cpp
@@ -46,6 +46,28 @@ extern "C" {
 
 #define _ICAL_VERSION "2.0"
 
+#if ICAL_CHECK_VERSION(4,0,0)
+  #define FIELD_BY_SECOND    ICAL_BY_SECOND
+  #define FIELD_BY_MINUTE    ICAL_BY_MINUTE
+  #define FIELD_BY_HOUR      ICAL_BY_HOUR
+  #define FIELD_BY_DAY       ICAL_BY_DAY
+  #define FIELD_BY_MONTH_DAY ICAL_BY_MONTH_DAY
+  #define FIELD_BY_YEAR_DAY  ICAL_BY_YEAR_DAY
+  #define FIELD_BY_WEEK_NO   ICAL_BY_WEEK_NO
+  #define FIELD_BY_MONTH     ICAL_BY_MONTH
+  #define FIELD_BY_SET_POS   ICAL_BY_SET_POS
+#else
+  #define FIELD_BY_SECOND    by_second
+  #define FIELD_BY_MINUTE    by_minute
+  #define FIELD_BY_HOUR      by_hour
+  #define FIELD_BY_DAY       by_day
+  #define FIELD_BY_MONTH_DAY by_month_day
+  #define FIELD_BY_YEAR_DAY  by_year_day
+  #define FIELD_BY_WEEK_NO   by_week_no
+  #define FIELD_BY_MONTH     by_month
+  #define FIELD_BY_SET_POS   by_set_pos
+#endif
+
 using namespace KCal;
 
 /* Static helpers */
@@ -459,15 +481,27 @@ void ICalFormatImpl::writeIncidence(icalcomponent *parent,Incidence *incidence)
   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) ) ) );
+    icalrecurrencetype *recur = writeRecurrenceRule( (*rit) );
+#if ICAL_CHECK_VERSION(4,0,0)
+    icalcomponent_add_property( parent, icalproperty_new_rrule( recur ) );
+    icalrecurrencetype_unref( recur );
+#else
+    icalcomponent_add_property( parent, icalproperty_new_rrule( *recur ) );
+    delete recur;
+#endif
   }
 
   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) ) ) );
+    icalrecurrencetype *recur = writeRecurrenceRule( (*exit) );
+#if ICAL_CHECK_VERSION(4,0,0)
+    icalcomponent_add_property( parent, icalproperty_new_rrule( recur ) );
+    icalrecurrencetype_unref( recur );
+#else
+    icalcomponent_add_property( parent, icalproperty_new_rrule( *recur ) );
+    delete recur;
+#endif
   }
 
   DateList dateList = incidence->recurrence()->exDates();
@@ -688,37 +722,58 @@ icalproperty *ICalFormatImpl::writeAttachment( Attachment *att )
   return p;
 }
 
-icalrecurrencetype ICalFormatImpl::writeRecurrenceRule( RecurrenceRule *recur )
+#if ICAL_CHECK_VERSION(4,0,0)
+  #define writeByData(by_enum) \
+  if ( bys.count() > 0 ) { \
+    icalrecur_resize_by( &r->by[by_enum], bys.count() ); \
+    index = 0; \
+    for ( it = bys.begin(); it != bys.end(); ++it ) { \
+      r->by[by_enum].data[index++] = *it; \
+    } \
+  }
+#else
+  #define writeByData(by_enum) \
+    index = 0; \
+    for ( it = bys.begin(); it != bys.end(); ++it ) { \
+      r->by_enum[index++] = *it; \
+    }
+#endif
+icalrecurrencetype *ICalFormatImpl::writeRecurrenceRule( RecurrenceRule *recur )
 {
 //  kdDebug(5800) << "ICalFormatImpl::writeRecurrenceRule()" << endl;
 
-  icalrecurrencetype r;
-  icalrecurrencetype_clear(&r);
+#if ICAL_CHECK_VERSION(4,0,0)
+  icalrecurrencetype *r = icalrecurrencetype_new();
+#else
+  icalrecurrencetype *r = new icalrecurrencetype;
+  icalrecurrencetype_clear(r);
+#endif
+  if ( !r ) return 0;
 
   switch( recur->recurrenceType() ) {
     case RecurrenceRule::rSecondly:
-      r.freq = ICAL_SECONDLY_RECURRENCE;
+      r->freq = ICAL_SECONDLY_RECURRENCE;
       break;
     case RecurrenceRule::rMinutely:
-      r.freq = ICAL_MINUTELY_RECURRENCE;
+      r->freq = ICAL_MINUTELY_RECURRENCE;
       break;
     case RecurrenceRule::rHourly:
-      r.freq = ICAL_HOURLY_RECURRENCE;
+      r->freq = ICAL_HOURLY_RECURRENCE;
       break;
     case RecurrenceRule::rDaily:
-      r.freq = ICAL_DAILY_RECURRENCE;
+      r->freq = ICAL_DAILY_RECURRENCE;
       break;
     case RecurrenceRule::rWeekly:
-      r.freq = ICAL_WEEKLY_RECURRENCE;
+      r->freq = ICAL_WEEKLY_RECURRENCE;
       break;
     case RecurrenceRule::rMonthly:
-      r.freq = ICAL_MONTHLY_RECURRENCE;
+      r->freq = ICAL_MONTHLY_RECURRENCE;
       break;
     case RecurrenceRule::rYearly:
-      r.freq = ICAL_YEARLY_RECURRENCE;
+      r->freq = ICAL_YEARLY_RECURRENCE;
       break;
     default:
-      r.freq = ICAL_NO_RECURRENCE;
+      r->freq = ICAL_NO_RECURRENCE;
       kdDebug(5800) << "ICalFormatImpl::writeRecurrence(): no recurrence" << endl;
       break;
   }
@@ -729,91 +784,91 @@ icalrecurrencetype ICalFormatImpl::writeRecurrenceRule( RecurrenceRule *recur )
 
   // Now write out the BY* parts:
   bys = recur->bySeconds();
-  index = 0;
-  for ( it = bys.begin(); it != bys.end(); ++it ) {
-    r.by_second[index++] = *it;
-  }
+  writeByData(FIELD_BY_SECOND);
 
   bys = recur->byMinutes();
-  index = 0;
-  for ( it = bys.begin(); it != bys.end(); ++it ) {
-    r.by_minute[index++] = *it;
-  }
+  writeByData(FIELD_BY_MINUTE);
 
   bys = recur->byHours();
-  index = 0;
-  for ( it = bys.begin(); it != bys.end(); ++it ) {
-    r.by_hour[index++] = *it;
-  }
+  writeByData(FIELD_BY_HOUR);
 
   bys = recur->byMonthDays();
+#if ICAL_CHECK_VERSION(4,0,0)
+  if ( bys.count() > 0 ) {
+    icalrecur_resize_by( &r->by[ICAL_BY_MONTH_DAY], bys.count() );
+    index = 0;
+    for ( it = bys.begin(); it != bys.end(); ++it ) {
+      r->by[ICAL_BY_MONTH_DAY].data[index++] = icalrecurrencetype_day_position( (*it) * 8 );
+    }
+  }
+#else
   index = 0;
   for ( it = bys.begin(); it != bys.end(); ++it ) {
-    r.by_month_day[index++] = icalrecurrencetype_day_position( (*it) * 8 );
+    r->by_month_day[index++] = icalrecurrencetype_day_position( (*it) * 8 );
   }
+#endif
 
   bys = recur->byYearDays();
-  index = 0;
-  for ( it = bys.begin(); it != bys.end(); ++it ) {
-    r.by_year_day[index++] = *it;
-  }
+  writeByData(FIELD_BY_YEAR_DAY);
 
   bys = recur->byWeekNumbers();
-  index = 0;
-  for ( it = bys.begin(); it != bys.end(); ++it ) {
-     r.by_week_no[index++] = *it;
-  }
+  writeByData(FIELD_BY_WEEK_NO);
 
   bys = recur->byMonths();
-  index = 0;
-  for ( it = bys.begin(); it != bys.end(); ++it ) {
-    r.by_month[index++] = *it;
-  }
+  writeByData(FIELD_BY_MONTH);
 
   bys = recur->bySetPos();
-  index = 0;
-  for ( it = bys.begin(); it != bys.end(); ++it ) {
-     r.by_set_pos[index++] = *it;
-  }
-
+  writeByData(FIELD_BY_SET_POS);
 
   TQValueList<RecurrenceRule::WDayPos> byd = recur->byDays();
+#if ICAL_CHECK_VERSION(4,0,0)
+  if ( byd.count() > 0 )
+  {
+    icalrecur_resize_by( &r->by[ICAL_BY_DAY], byd.count() );
+  }
+#endif
   int day;
   index = 0;
   for ( TQValueList<RecurrenceRule::WDayPos>::ConstIterator dit = byd.begin();
         dit != byd.end(); ++dit ) {
     day = (*dit).day() % 7 + 1;     // convert from Monday=1 to Sunday=1
+#if ICAL_CHECK_VERSION(4,0,0)
+    r->by[ICAL_BY_DAY].data[index++] = icalrecurrencetype_encode_day(
+      static_cast<icalrecurrencetype_weekday>( day ),
+      (*dit).pos() );
+#else
     if ( (*dit).pos() < 0 ) {
       day += (-(*dit).pos())*8;
       day = -day;
     } else {
       day += (*dit).pos()*8;
     }
-    r.by_day[index++] = day;
+    r->by_day[index++] = day;
+#endif
   }
 
-  r.week_start = static_cast<icalrecurrencetype_weekday>(
-                                             recur->weekStart()%7 + 1);
+  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();
+    r->interval = recur->frequency();
   }
 
   if ( recur->duration() > 0 ) {
-    r.count = recur->duration();
+    r->count = recur->duration();
   } else if ( recur->duration() == -1 ) {
-    r.count = 0;
+    r->count = 0;
   } else {
     if ( recur->doesFloat() )
-      r.until = writeICalDate(recur->endDt().date());
+      r->until = writeICalDate(recur->endDt().date());
     else
-      r.until = writeICalDateTime(recur->endDt());
+      r->until = writeICalDateTime(recur->endDt());
   }
 
 // Debug output
 #if 0
-  const char *str = icalrecurrencetype_as_string(&r);
+  const char *str = icalrecurrencetype_as_string(r);
   if (str) {
     kdDebug(5800) << " String: " << str << endl;
   } else {
@@ -823,7 +878,7 @@ icalrecurrencetype ICalFormatImpl::writeRecurrenceRule( RecurrenceRule *recur )
 
   return r;
 }
-
+#undef writeByData
 
 icalcomponent *ICalFormatImpl::writeAlarm(Alarm *alarm)
 {
@@ -1242,11 +1297,23 @@ Attendee *ICalFormatImpl::readAttendee(icalproperty *attendee)
 
   p = icalproperty_get_first_parameter( attendee, ICAL_DELEGATEDTO_PARAMETER );
   if ( p )
+  {
+#if ICAL_CHECK_VERSION(4,0,0)
+    a->setDelegate( icalparameter_get_delegatedto_nth( p, 0 ) );
+#else
     a->setDelegate( icalparameter_get_delegatedto( p ) );
+#endif
+  }
 
   p = icalproperty_get_first_parameter( attendee, ICAL_DELEGATEDFROM_PARAMETER );
   if ( p )
+  {
+#if ICAL_CHECK_VERSION(4,0,0)
+    a->setDelegator( icalparameter_get_delegatedfrom_nth( p, 0 ) );
+#else
     a->setDelegator( icalparameter_get_delegatedfrom( p ) );
+#endif
+  }
 
   return a;
 }
@@ -1646,7 +1713,13 @@ void ICalFormatImpl::readRecurrenceRule(icalproperty *rrule,Incidence *incidence
 
   Recurrence *recur = incidence->recurrence();
 
-  struct icalrecurrencetype r = icalproperty_get_rrule(rrule);
+#if ICAL_CHECK_VERSION(4,0,0)
+  struct icalrecurrencetype *r = icalproperty_get_rrule(rrule);
+  if ( !r ) return;
+#else
+  struct icalrecurrencetype _r = icalproperty_get_rrule(rrule);
+  struct icalrecurrencetype *r = &_r;
+#endif
 //   dumpIcalRecurrence(r);
 
   RecurrenceRule *recurrule = new RecurrenceRule( /*incidence*/ );
@@ -1659,7 +1732,13 @@ void ICalFormatImpl::readExceptionRule( icalproperty *rrule, Incidence *incidenc
 {
 //  kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl;
 
-  struct icalrecurrencetype r = icalproperty_get_exrule(rrule);
+#if ICAL_CHECK_VERSION(4,0,0)
+  struct icalrecurrencetype *r = icalproperty_get_exrule(rrule);
+  if ( !r ) return;
+#else
+  struct icalrecurrencetype _r = icalproperty_get_exrule(rrule);
+  struct icalrecurrencetype *r = &_r;
+#endif
 //   dumpIcalRecurrence(r);
 
   RecurrenceRule *recurrule = new RecurrenceRule( /*incidence*/ );
@@ -1670,12 +1749,29 @@ void ICalFormatImpl::readExceptionRule( icalproperty *rrule, Incidence *incidenc
   recur->addExRule( recurrule );
 }
 
-void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype &r, RecurrenceRule* recur )
+#if ICAL_CHECK_VERSION(4,0,0)
+#define readSetByList(by_enum,setfunc) \
+  index = 0; \
+  lst.clear(); \
+  while ( index < r->by[by_enum].size ) { \
+    i = r->by[by_enum].data[index++]; \
+    lst.append( i ); \
+  } \
+  if ( !lst.isEmpty() ) recur->setfunc( lst );
+#else
+#define readSetByList(by_enum,setfunc) \
+  index = 0; \
+  lst.clear(); \
+  while ( (i = r->by_enum[index++] ) != ICAL_RECURRENCE_ARRAY_MAX ) \
+    lst.append( i ); \
+  if ( !lst.isEmpty() ) recur->setfunc( lst );
+#endif
+void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype *r, RecurrenceRule* recur )
 {
   // Generate the RRULE string
-  recur->mRRule = TQString( icalrecurrencetype_as_string( const_cast<struct icalrecurrencetype*>(&r) ) );
+  recur->mRRule = TQString( icalrecurrencetype_as_string( const_cast<struct icalrecurrencetype*>(r) ) );
   // Period
-  switch ( r.freq ) {
+  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;
@@ -1688,24 +1784,24 @@ void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype &r, Recurre
         recur->setRecurrenceType( RecurrenceRule::rNone );
   }
   // Frequency
-  recur->setFrequency( r.interval );
+  recur->setFrequency( r->interval );
 
   // Duration & End Date
-  if ( !icaltime_is_null_time( r.until ) ) {
+  if ( !icaltime_is_null_time( r->until ) ) {
     icaltimetype t;
-    t = r.until;
+    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)
+    if (r->count == 0)
       recur->setDuration( -1 );
     else
-      recur->setDuration( r.count );
+      recur->setDuration( r->count );
   }
 
   // Week start setting
-  int wkst = (r.week_start + 5)%7 + 1;
+  int wkst = (r->week_start + 5)%7 + 1;
   recur->setWeekStart( wkst );
 
   // And now all BY*
@@ -1713,44 +1809,36 @@ void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype &r, Recurre
   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
+  readSetByList( FIELD_BY_SECOND, setBySeconds );
+  readSetByList( FIELD_BY_MINUTE, setByMinutes );
+  readSetByList( FIELD_BY_HOUR, setByHours );
+  readSetByList( FIELD_BY_MONTH_DAY, setByMonthDays );
+  readSetByList( FIELD_BY_YEAR_DAY, setByYearDays );
+  readSetByList( FIELD_BY_WEEK_NO, setByWeekNumbers );
+  readSetByList( FIELD_BY_MONTH, setByMonths );
+  readSetByList( FIELD_BY_SET_POS, setBySetPos );
 
   // BYDAY is a special case, since it's not an int list
   TQValueList<RecurrenceRule::WDayPos> wdlst;
   short day;
-  index=0;
-  while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
+  index = 0;
+#if ICAL_CHECK_VERSION(4,0,0)
+  while( index < r->by[ICAL_BY_DAY].size && (day = r->by[ICAL_BY_DAY].data[index++]) )
+#else
+  while( (day = r->by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX )
+#endif
+  {
     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="<<index-1<<", pos="<<pos.Pos<<", day="<<pos.Day<<endl;
     wdlst.append( pos );
   }
   if ( !wdlst.isEmpty() ) recur->setByDays( wdlst );
 
-
   // TODO Store all X- fields of the RRULE inside the recurrence (so they are
   // preserved
 }
-
+#undef readSetByList
 
 void ICalFormatImpl::readAlarm(icalcomponent *alarm,Incidence *incidence)
 {
@@ -1795,7 +1883,12 @@ void ICalFormatImpl::readAlarm(icalcomponent *alarm,Incidence *incidence)
           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 );
+            Duration duration =
+#if ICAL_CHECK_VERSION(4,0,0)
+              icaldurationtype_as_utc_seconds( trigger.duration );
+#else
+              icaldurationtype_as_int( trigger.duration );
+#endif
             icalparameter *param = icalproperty_get_first_parameter(p,ICAL_RELATED_PARAMETER);
             if (param && icalparameter_get_related(param) == ICAL_RELATED_END)
               ialarm->setEndOffset(duration);
@@ -2315,55 +2408,46 @@ TQString ICalFormatImpl::extractErrorProperty(icalcomponent *c)
   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) + " ");
+#if ICAL_CHECK_VERSION(4,0,0)
+  #define dumpByData(by_enum,by_string) \
+    if (r->by[by_enum].size > 0) { \
+      int index = 0; \
+      TQString out = by_string; \
+      while( index < r->by[by_enum].size ) { \
+        out.append(TQString::number(r->by[by_enum].data[index++]) + " "); \
+      } \
+      kdDebug(5800) << out << endl; \
     }
-    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) + " ");
+#else
+  #define dumpByData(by_enum,by_string) \
+    if (r->by_enum[0] != ICAL_RECURRENCE_ARRAY_MAX) { \
+      int index = 0; \
+      int i; \
+      TQString out = by_string; \
+      while((i = r->by_enum[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { \
+        out.append(TQString::number(i) + " "); \
+      } \
+      kdDebug(5800) << out << endl; \
     }
-    kdDebug(5800) << out << endl;
+#endif
+void ICalFormatImpl::dumpIcalRecurrence(const icalrecurrencetype *r)
+{
+  if (!r)
+  {
+    return;
   }
+
+  kdDebug(5800) << " Freq: " << r->freq << endl;
+  kdDebug(5800) << " Until: " << icaltime_as_ical_string(r->until) << endl;
+  kdDebug(5800) << " Count: " << r->count << endl;
+
+  dumpByData(FIELD_BY_DAY, " By Day: ");
+  dumpByData(FIELD_BY_MONTH_DAY, " By Month Day: ");
+  dumpByData(FIELD_BY_YEAR_DAY, " By Year Day: ");
+  dumpByData(FIELD_BY_MONTH, " By Month: ");
+  dumpByData(FIELD_BY_SET_POS, " By Set Pos: ");
 }
+#undef dumpByData
 
 icalcomponent *ICalFormatImpl::createScheduleComponent(IncidenceBase *incidence,
                                                    Scheduler::Method method)
diff --git a/libkcal/icalformatimpl.h b/libkcal/icalformatimpl.h
index 9a2e9f62..d45c4d29 100644
--- a/libkcal/icalformatimpl.h
+++ b/libkcal/icalformatimpl.h
@@ -61,8 +61,7 @@ class ICalFormatImpl
     icalproperty *writeAttendee(Attendee *attendee);
     icalproperty *writeOrganizer( const Person &organizer );
     icalproperty *writeAttachment(Attachment *attach);
-    icalproperty *writeRecurrenceRule(Recurrence *);
-    icalrecurrencetype writeRecurrenceRule( RecurrenceRule *recur );
+    icalrecurrencetype *writeRecurrenceRule( RecurrenceRule *recur );
     icalcomponent *writeAlarm(Alarm *alarm);
 
     TQString extractErrorProperty(icalcomponent *);
@@ -76,7 +75,7 @@ class ICalFormatImpl
     void readIncidence(icalcomponent *parent, icaltimezone *timezone, Incidence *incidence);
     void readRecurrenceRule(icalproperty *rrule,Incidence *event );
     void readExceptionRule( icalproperty *rrule, Incidence *incidence );
-    void readRecurrence( const struct icalrecurrencetype &r, RecurrenceRule* recur );
+    void readRecurrence( const struct icalrecurrencetype *r, RecurrenceRule* recur );
     void readAlarm(icalcomponent *alarm,Incidence *incidence);
     /** Return the PRODID string loaded from calendar file */
     const TQString &loadedProductId()  { return mLoadedProductId; }
@@ -94,7 +93,8 @@ class ICalFormatImpl
     icalcomponent *createScheduleComponent(IncidenceBase *,Scheduler::Method);
 
   protected:
-    void dumpIcalRecurrence(icalrecurrencetype);
+    void dumpIcalRecurrence(const icalrecurrencetype *);
+
   private:
     void writeIncidenceBase(icalcomponent *parent,IncidenceBase *);
     void readIncidenceBase(icalcomponent *parent, IncidenceBase *);
diff --git a/libkcal/tests/runtestcase.pl b/libkcal/tests/runtestcase.pl
index 4cad27cc..29142992 100755
--- a/libkcal/tests/runtestcase.pl
+++ b/libkcal/tests/runtestcase.pl
@@ -112,6 +112,12 @@ sub checkfile()
       next;
     }
 
+    # Normalize RRULE parameter order (libical 3 vs 4 differ)
+    if ( $out =~ /^RRULE:/ && $ref =~ /^RRULE:/ ) {
+      $out = normalize_rrule($out);
+      $ref = normalize_rrule($ref);
+    }
+
     if ( $out ne $ref ) {
       if ( $errorlines == 0 ) {
         print $logentry;
@@ -162,3 +168,12 @@ sub checkfile()
 #    print "  OK\n";
   }
 }
+
+sub normalize_rrule {
+  my $line = shift;
+  if ( $line =~ /^(RRULE:)(.*)/ ) {
+    my @params = sort split(/;/, $2);
+    return $1 . join(';', @params);
+  }
+  return $line;
+}
-- 
cgit v1.2.3

