21 #include <config-kcalcore.h> 
   23 #include "icaltimezones.h" 
   26 #include "recurrence.h" 
   27 #include "recurrencerule.h" 
   31 #include <KSystemTimeZone> 
   33 #include <QtCore/QDateTime> 
   34 #include <QtCore/QFile> 
   35 #include <QtCore/QTextStream> 
   38 #include <libical/ical.h> 
   39 #include <icaltimezone.h> 
   42 #if defined(HAVE_UUID_UUID_H) 
   43 #include <uuid/uuid.h> 
   46 #if defined(Q_OS_WINCE) 
   49 using namespace KCalCore;
 
   52 static const int minRuleCount = 5;   
 
   53 static const int minPhaseCount = 8;  
 
   56 static QDateTime toQDateTime(
const icaltimetype &t)
 
   58     return QDateTime(QDate(t.year, t.month, t.day),
 
   59                      QTime(t.hour, t.minute, t.second),
 
   60                      (t.is_utc ? Qt::UTC : Qt::LocalTime));
 
   66 static QDateTime MAX_DATE()
 
   70         dt = QDateTime(QDate::currentDate().addYears(20), QTime(0, 0, 0));
 
   75 static icaltimetype writeLocalICalDateTime(
const QDateTime &utc, 
int offset)
 
   77     const QDateTime local = utc.addSecs(offset);
 
   78     icaltimetype t = icaltime_null_time();
 
   79     t.year = local.date().year();
 
   80     t.month = local.date().month();
 
   81     t.day = local.date().day();
 
   82     t.hour = local.time().hour();
 
   83     t.minute = local.time().minute();
 
   84     t.second = local.time().second();
 
   96 class ICalTimeZonesPrivate
 
   99     ICalTimeZonesPrivate() {}
 
  100     ICalTimeZones::ZoneMap zones;
 
  105     : d(new ICalTimeZonesPrivate)
 
  110     : d(new ICalTimeZonesPrivate())
 
  112     d->zones = rhs.d->
zones;
 
  137     if (!zone.isValid()) {
 
  140     if (d->zones.find(zone.name()) != d->zones.end()) {
 
  144     d->zones.insert(zone.name(), 
zone);
 
  150     if (zone.isValid()) {
 
  151         for (ZoneMap::Iterator it = d->zones.begin(), end = d->zones.end();  it != end;  ++it) {
 
  152             if (it.value() == 
zone) {
 
  163     if (!name.isEmpty()) {
 
  164         ZoneMap::Iterator it = d->zones.find(name);
 
  165         if (it != d->zones.end()) {
 
  181     return d->zones.count();
 
  186     if (!name.isEmpty()) {
 
  187         ZoneMap::ConstIterator it = d->zones.constFind(name);
 
  188         if (it != d->zones.constEnd()) {
 
  197     if (zone.isValid()) {
 
  198         QMapIterator<QString, ICalTimeZone> it(d->zones);
 
  199         while (it.hasNext()) {
 
  202             const QList<KTimeZone::Transition> list1 = tz.transitions();
 
  203             const QList<KTimeZone::Transition> list2 = zone.transitions();
 
  204             if (list1.size() == list2.size()) {
 
  207                 for (; i < list1.size(); ++i) {
 
  208                     const KTimeZone::Transition t1 = list1[ i ];
 
  209                     const KTimeZone::Transition t2 = list2[ i ];
 
  210                     if ((t1.time() == t2.time()) &&
 
  211                             (t1.phase().utcOffset() == t2.phase().utcOffset()) &&
 
  212                             (t1.phase().isDst() == t2.phase().isDst())) {
 
  234         const QString &countryCode,
 
  235         float latitude, 
float longitude,
 
  236         const QString &comment)
 
  237     : KTimeZoneBackend(source, name, countryCode, latitude, longitude, comment)
 
  241     : KTimeZoneBackend(0, tz.name(), tz.countryCode(), tz.latitude(), tz.longitude(), tz.comment())
 
  246 ICalTimeZoneBackend::~ICalTimeZoneBackend()
 
  256     return "ICalTimeZone";
 
  286                                         tz.latitude(), tz.longitude(),
 
  289     const KTimeZoneData *data = tz.data(
true);
 
  306     return dat ? dat->
city() : QString();
 
  312     return dat ? dat->
url() : QByteArray();
 
  324     return dat ? dat->
vtimezone() : QByteArray();
 
  335     if (!updateBase(other)) {
 
  339     KTimeZoneData *otherData = other.data() ? other.data()->clone() : 0;
 
  340     setData(otherData, other.source());
 
  347     if (!utcZone.isValid()) {
 
  349         utcZone = tzs.
parse(icaltimezone_get_utc_timezone());
 
  362 class ICalTimeZoneDataPrivate
 
  365     ICalTimeZoneDataPrivate() : icalComponent(0) {}
 
  367     ~ICalTimeZoneDataPrivate()
 
  370             icalcomponent_free(icalComponent);
 
  374     icalcomponent *component()
 const {
 
  375         return icalComponent;
 
  377     void setComponent(icalcomponent *c)
 
  380             icalcomponent_free(icalComponent);
 
  387     QDateTime     lastModified;   
 
  390     icalcomponent *icalComponent; 
 
  395     : d(new ICalTimeZoneDataPrivate())
 
  400     : KTimeZoneData(rhs),
 
  401       d(new ICalTimeZoneDataPrivate())
 
  403     d->location = rhs.d->location;
 
  406     d->setComponent(icalcomponent_new_clone(rhs.d->component()));
 
  411 static QDate find_nth_weekday_in_month_of_year(
int nth, 
int dayOfWeek, 
int month, 
int year) {
 
  412     const QDate first(year, month, 1);
 
  413     const int actualDayOfWeek = first.dayOfWeek();
 
  414     QDate candidate = first.addDays((nth - 1) * 7 + dayOfWeek - actualDayOfWeek);
 
  416         if (candidate.month() != month) {
 
  417             candidate = candidate.addDays(-7);
 
  425                                    const KTimeZone &tz, 
const QDate &earliest)
 
  426     : KTimeZoneData(rhs),
 
  427       d(new ICalTimeZoneDataPrivate())
 
  432         WEEKDAY_OF_MONTH      = 0x02,
 
  433         LAST_WEEKDAY_OF_MONTH = 0x04
 
  436     if (tz.type() == 
"KSystemTimeZone") {
 
  440         icalcomponent *c = 0;
 
  441         const KTimeZone ktz = KSystemTimeZones::readZone(tz.name());
 
  443             if (ktz.data(
true)) {
 
  447                     c = icalcomponent_new_clone(icaltimezone_get_component(itz));
 
  448                     icaltimezone_free(itz, 1);
 
  454             icaltimezone *itz = icaltimezone_get_builtin_timezone(tz.name().toUtf8());
 
  455             c = icalcomponent_new_clone(icaltimezone_get_component(itz));
 
  461             icalproperty *prop = icalcomponent_get_first_property(c, ICAL_TZID_PROPERTY);
 
  463                 icalvalue *value = icalproperty_get_value(prop);
 
  464                 const char *tzid = icalvalue_get_text(value);
 
  466                 const int len = icalprefix.size();
 
  467                 if (!strncmp(icalprefix, tzid, len)) {
 
  468                     const char *s = strchr(tzid + len, 
'/');      
 
  470                         const QByteArray tzidShort(s + 1);   
 
  471                         icalvalue_set_text(value, tzidShort);
 
  474                         prop = icalcomponent_get_first_property(c, ICAL_X_PROPERTY);
 
  475                         const char *xname = icalproperty_get_x_name(prop);
 
  476                         if (xname && !strcmp(xname, 
"X-LIC-LOCATION")) {
 
  477                             icalcomponent_remove_property(c, prop);
 
  478                             icalproperty_free(prop);
 
  487         icalcomponent *tzcomp = icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
 
  488         icalcomponent_add_property(tzcomp, icalproperty_new_tzid(tz.name().toUtf8()));
 
  493         QList<KTimeZone::Transition> transits = transitions();
 
  494         if (transits.isEmpty()) {
 
  499             TIME_ZONE_INFORMATION currentTimeZone;
 
  500             GetTimeZoneInformation(¤tTimeZone);
 
  501             if (QString::fromWCharArray(currentTimeZone.StandardName) != tz.name()) {
 
  502                 kDebug() << 
"VTIMEZONE entry will be invalid for: " << tz.name();
 
  504                 const SYSTEMTIME std = currentTimeZone.StandardDate;
 
  505                 const SYSTEMTIME dlt = currentTimeZone.DaylightDate;
 
  508                 const KTimeZone::Phase standardPhase =
 
  509                     KTimeZone::Phase((currentTimeZone.Bias +
 
  510                                       currentTimeZone.StandardBias) * -60,
 
  511                                      QByteArray(), 
false);
 
  512                 const KTimeZone::Phase daylightPhase =
 
  513                     KTimeZone::Phase((currentTimeZone.Bias +
 
  514                                       currentTimeZone.DaylightBias) * -60,
 
  518                 for (
int i = 2000; i <= 2050; i++) {
 
  519                     const QDateTime standardTime =
 
  520                         QDateTime(find_nth_weekday_in_month_of_year(
 
  522                                       std.wDayOfWeek ? std.wDayOfWeek : 7,
 
  524                                   QTime(std.wHour, std.wMinute,
 
  525                                         std.wSecond, std.wMilliseconds));
 
  527                     const QDateTime daylightTime =
 
  528                         QDateTime(find_nth_weekday_in_month_of_year(
 
  530                                       dlt.wDayOfWeek ? dlt.wDayOfWeek : 7,
 
  532                                   QTime(dlt.wHour, dlt.wMinute,
 
  533                                         dlt.wSecond, dlt.wMilliseconds));
 
  535                     transits << KTimeZone::Transition(standardTime, standardPhase)
 
  536                              << KTimeZone::Transition(daylightTime, daylightPhase);
 
  540             if (transits.isEmpty()) {
 
  541                 kDebug() << 
"No transition information available VTIMEZONE will be invalid.";
 
  544         if (earliest.isValid()) {
 
  546             for (
int i = 0, end = transits.count();  i < end;  ++i) {
 
  547                 if (transits.at(i).time().date() >= earliest) {
 
  549                         transits.erase(transits.begin(), transits.begin() + i);
 
  555         int trcount = transits.count();
 
  556         QVector<bool> transitionsDone(trcount);
 
  557         transitionsDone.fill(
false);
 
  561         icaldatetimeperiodtype dtperiod;
 
  562         dtperiod.period = icalperiodtype_null_period();
 
  565             for (;  i < trcount && transitionsDone[i];  ++i) {
 
  572             const int preOffset = (i > 0) ?
 
  573                                   transits.at(i - 1).phase().utcOffset() :
 
  574                                   rhs.previousUtcOffset();
 
  575             const KTimeZone::Phase phase = transits.at(i).phase();
 
  576             if (phase.utcOffset() == preOffset) {
 
  577                 transitionsDone[i] = 
true;
 
  578                 while (++i < trcount) {
 
  579                     if (transitionsDone[i] ||
 
  580                             transits.at(i).phase() != phase ||
 
  581                             transits.at(i - 1).phase().utcOffset() != preOffset) {
 
  584                     transitionsDone[i] = 
true;
 
  588             icalcomponent *phaseComp =
 
  589                 icalcomponent_new(phase.isDst() ? ICAL_XDAYLIGHT_COMPONENT : ICAL_XSTANDARD_COMPONENT);
 
  590             const QList<QByteArray> abbrevs = phase.abbreviations();
 
  591             for (
int a = 0, aend = abbrevs.count();  a < aend;  ++a) {
 
  592                 icalcomponent_add_property(phaseComp,
 
  593                                            icalproperty_new_tzname(
 
  594                                                static_cast<const char*>(abbrevs[a])));
 
  596             if (!phase.comment().isEmpty()) {
 
  597                 icalcomponent_add_property(phaseComp,
 
  598                                            icalproperty_new_comment(phase.comment().toUtf8()));
 
  600             icalcomponent_add_property(phaseComp,
 
  601                                        icalproperty_new_tzoffsetfrom(preOffset));
 
  602             icalcomponent_add_property(phaseComp,
 
  603                                        icalproperty_new_tzoffsetto(phase.utcOffset()));
 
  605             icalcomponent *phaseComp1 = icalcomponent_new_clone(phaseComp);
 
  606             icalcomponent_add_property(phaseComp1,
 
  607                                        icalproperty_new_dtstart(
 
  608                                            writeLocalICalDateTime(transits.at(i).time(),
 
  610             bool useNewRRULE = 
false;
 
  616             int year = 0, month = 0, daysInMonth = 0, dayOfMonth = 0; 
 
  618             int nthFromStart = 0;   
 
  622             QList<QDateTime> rdates;
 
  623             QList<QDateTime> times;
 
  624             QDateTime qdt = transits.at(i).time();     
 
  626             transitionsDone[i] = 
true;
 
  630                     rule = DAY_OF_MONTH | WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH;
 
  634                     month = date.month();
 
  635                     daysInMonth = date.daysInMonth();
 
  636                     dayOfWeek = date.dayOfWeek();   
 
  637                     dayOfMonth = date.day();
 
  638                     nthFromStart = (dayOfMonth - 1) / 7 + 1;     
 
  639                     nthFromEnd = (daysInMonth - dayOfMonth) / 7 + 1;     
 
  641                 if (++i >= trcount) {
 
  643                     times += QDateTime();   
 
  645                     if (transitionsDone[i] ||
 
  646                             transits.at(i).phase() != phase ||
 
  647                             transits.at(i - 1).phase().utcOffset() != preOffset) {
 
  650                     transitionsDone[i] = 
true;
 
  651                     qdt = transits.at(i).time();
 
  652                     if (!qdt.isValid()) {
 
  658                     if (qdt.time() != time ||
 
  659                             date.month() != month ||
 
  660                             date.year() != ++year) {
 
  663                         const int day = date.day();
 
  664                         if ((newRule & DAY_OF_MONTH) && day != dayOfMonth) {
 
  665                             newRule &= ~DAY_OF_MONTH;
 
  667                         if (newRule & (WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH)) {
 
  668                             if (date.dayOfWeek() != dayOfWeek) {
 
  669                                 newRule &= ~(WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH);
 
  671                                 if ((newRule & WEEKDAY_OF_MONTH) &&
 
  672                                         (day - 1) / 7 + 1 != nthFromStart) {
 
  673                                     newRule &= ~WEEKDAY_OF_MONTH;
 
  675                                 if ((newRule & LAST_WEEKDAY_OF_MONTH) &&
 
  676                                         (daysInMonth - day) / 7 + 1 != nthFromEnd) {
 
  677                                     newRule &= ~LAST_WEEKDAY_OF_MONTH;
 
  687                     int yr = times[0].date().year();
 
  688                     while (!rdates.isEmpty()) {
 
  691                         if (qdt.time() != time  ||
 
  692                                 date.month() != month ||
 
  693                                 date.year() != --yr) {
 
  696                         const int day = date.day();
 
  697                         if (rule & DAY_OF_MONTH) {
 
  698                             if (day != dayOfMonth) {
 
  702                             if (date.dayOfWeek() != dayOfWeek ||
 
  703                                     ((rule & WEEKDAY_OF_MONTH) &&
 
  704                                      (day - 1) / 7 + 1 != nthFromStart) ||
 
  705                                     ((rule & LAST_WEEKDAY_OF_MONTH) &&
 
  706                                      (daysInMonth - day) / 7 + 1 != nthFromEnd)) {
 
  713                     if (times.count() > (useNewRRULE ? minPhaseCount : minRuleCount)) {
 
  715                         icalrecurrencetype r;
 
  716                         icalrecurrencetype_clear(&r);
 
  717                         r.freq = ICAL_YEARLY_RECURRENCE;
 
  718                         r.count = (year >= 2030) ? 0 : times.count() - 1;
 
  719                         r.by_month[0] = month;
 
  720                         if (rule & DAY_OF_MONTH) {
 
  721                             r.by_month_day[0] = dayOfMonth;
 
  722                         } 
else if (rule & WEEKDAY_OF_MONTH) {
 
  723                             r.by_day[0] = (dayOfWeek % 7 + 1) + (nthFromStart * 8);       
 
  724                         } 
else if (rule & LAST_WEEKDAY_OF_MONTH) {
 
  725                             r.by_day[0] = -(dayOfWeek % 7 + 1) - (nthFromEnd * 8);       
 
  727                         icalproperty *prop = icalproperty_new_rrule(r);
 
  731                             icalcomponent *c = icalcomponent_new_clone(phaseComp);
 
  732                             icalcomponent_add_property(
 
  733                                 c, icalproperty_new_dtstart(writeLocalICalDateTime(times[0], preOffset)));
 
  734                             icalcomponent_add_property(c, prop);
 
  735                             icalcomponent_add_component(tzcomp, c);
 
  737                             icalcomponent_add_property(phaseComp1, prop);
 
  741                         for (
int t = 0, tend = times.count() - 1;  t < tend;  ++t) {
 
  753             } 
while (i < trcount);
 
  756             for (
int rd = 0, rdend = rdates.count();  rd < rdend;  ++rd) {
 
  757                 dtperiod.time = writeLocalICalDateTime(rdates[rd], preOffset);
 
  758                 icalcomponent_add_property(phaseComp1, icalproperty_new_rdate(dtperiod));
 
  760             icalcomponent_add_component(tzcomp, phaseComp1);
 
  761             icalcomponent_free(phaseComp);
 
  764         d->setComponent(tzcomp);
 
  780     KTimeZoneData::operator=(rhs);
 
  781     d->location = rhs.d->location;
 
  784     d->setComponent(icalcomponent_new_clone(rhs.d->component()));
 
  805     return d->lastModified;
 
  810     const QByteArray result(icalcomponent_as_ical_string(d->component()));
 
  811     icalmemory_free_ring();
 
  817     icaltimezone *icaltz = icaltimezone_new();
 
  821     icalcomponent *c = icalcomponent_new_clone(d->component());
 
  822     if (!icaltimezone_set_component(icaltz, c)) {
 
  823         icalcomponent_free(c);
 
  824         icaltimezone_free(icaltz, 1);
 
  844 class ICalTimeZoneSourcePrivate
 
  847     static QList<QDateTime> parsePhase(icalcomponent *, 
bool daylight,
 
  848                                        int &prevOffset, KTimeZone::Phase &);
 
  849     static QByteArray icalTzidPrefix;
 
  851 #if defined(HAVE_UUID_UUID_H) 
  852     static void parseTransitions(
const MSSystemTime &date, 
const KTimeZone::Phase &phase,
 
  853                                  int prevOffset, QList<KTimeZone::Transition> &transitions);
 
  857 QByteArray ICalTimeZoneSourcePrivate::icalTzidPrefix;
 
  861     : KTimeZoneSource(false),
 
  873     QFile file(fileName);
 
  874     if (!file.open(QIODevice::ReadOnly)) {
 
  877     QTextStream ts(&file);
 
  878     ts.setCodec(
"ISO 8859-1");
 
  879     const QByteArray text = ts.readAll().trimmed().toLatin1();
 
  883     icalcomponent *calendar = icalcomponent_new_from_string(text.data());
 
  885         if (icalcomponent_isa(calendar) == ICAL_VCALENDAR_COMPONENT) {
 
  886             result = 
parse(calendar, zones);
 
  888         icalcomponent_free(calendar);
 
  895     for (icalcomponent *c = icalcomponent_get_first_component(calendar, ICAL_VTIMEZONE_COMPONENT);
 
  896             c;  c = icalcomponent_get_next_component(calendar, ICAL_VTIMEZONE_COMPONENT)) {
 
  898         if (!zone.isValid()) {
 
  902         if (oldzone.isValid()) {
 
  906         } 
else if (!zones.
add(zone)) {
 
  920     icalproperty *p = icalcomponent_get_first_property(vtimezone, ICAL_ANY_PROPERTY);
 
  922         icalproperty_kind kind = icalproperty_isa(p);
 
  925         case ICAL_TZID_PROPERTY:
 
  926             name = QString::fromUtf8(icalproperty_get_tzid(p));
 
  929         case ICAL_TZURL_PROPERTY:
 
  930             data->d->
url = icalproperty_get_tzurl(p);
 
  933         case ICAL_LOCATION_PROPERTY:
 
  935             data->d->location = QString::fromUtf8(icalproperty_get_location(p));
 
  938         case ICAL_X_PROPERTY:
 
  940             const char *xname = icalproperty_get_x_name(p);
 
  941             if (xname && !strcmp(xname, 
"X-LIC-LOCATION")) {
 
  942                 xlocation = QString::fromUtf8(icalproperty_get_x(p));
 
  946         case ICAL_LASTMODIFIED_PROPERTY:
 
  948             const icaltimetype t = icalproperty_get_lastmodified(p);
 
  952                 kDebug() << 
"LAST-MODIFIED not UTC";
 
  959         p = icalcomponent_get_next_property(vtimezone, ICAL_ANY_PROPERTY);
 
  962     if (name.isEmpty()) {
 
  963         kDebug() << 
"TZID missing";
 
  967     if (data->d->location.isEmpty() && !xlocation.isEmpty()) {
 
  968         data->d->location = xlocation;
 
  971     if (name.startsWith(prefix)) {
 
  973         const int i = name.indexOf(QLatin1Char(
'/'), prefix.length());
 
  975             name = name.mid(i + 1);
 
  985     QList<KTimeZone::Transition> transitions;
 
  987     QList<KTimeZone::Phase> phases;
 
  988     for (icalcomponent *c = icalcomponent_get_first_component(vtimezone, ICAL_ANY_COMPONENT);
 
  989             c;  c = icalcomponent_get_next_component(vtimezone, ICAL_ANY_COMPONENT)) {
 
  991         KTimeZone::Phase phase;
 
  992         QList<QDateTime> times;
 
  993         icalcomponent_kind kind = icalcomponent_isa(c);
 
  996         case ICAL_XSTANDARD_COMPONENT:
 
  998             times = ICalTimeZoneSourcePrivate::parsePhase(c, 
false, prevoff, phase);
 
 1001         case ICAL_XDAYLIGHT_COMPONENT:
 
 1003             times = ICalTimeZoneSourcePrivate::parsePhase(c, 
true, prevoff, phase);
 
 1007             kDebug() << 
"Unknown component:" << int(kind);
 
 1010         const int tcount = times.count();
 
 1013             for (
int t = 0;  t < tcount;  ++t) {
 
 1014                 transitions += KTimeZone::Transition(times[t], phase);
 
 1016             if (!earliest.isValid() || times[0] < earliest) {
 
 1017                 prevOffset = prevoff;
 
 1018                 earliest = times[0];
 
 1024     data->setPhases(phases, prevOffset);
 
 1028     for (
int t = 1, tend = transitions.count();  t < tend;) {
 
 1029         if (transitions[t].phase() == transitions[t - 1].phase()) {
 
 1030             transitions.removeAt(t);
 
 1036     data->setTransitions(transitions);
 
 1038     data->d->setComponent(icalcomponent_new_clone(vtimezone));
 
 1043 #if defined(HAVE_UUID_UUID_H) 
 1047     if (!zone.isValid()) {
 
 1051     if (oldzone.isValid()) {
 
 1055     } 
else if (zones.
add(zone)) {
 
 1069     uuid_generate_random(uuid);
 
 1070     uuid_unparse(uuid, suuid);
 
 1071     QString name = QString::fromLatin1(suuid);
 
 1074     QList<KTimeZone::Phase> phases;
 
 1076     QList<QByteArray> standardAbbrevs;
 
 1077     standardAbbrevs += tz->StandardName.toLatin1();
 
 1078     const KTimeZone::Phase standardPhase(
 
 1079         (tz->Bias + tz->StandardBias) * -60,
 
 1080         standardAbbrevs, 
false,
 
 1081         QLatin1String(
"Microsoft TIME_ZONE_INFORMATION"));
 
 1082     phases += standardPhase;
 
 1084     QList<QByteArray> daylightAbbrevs;
 
 1085     daylightAbbrevs += tz->DaylightName.toLatin1();
 
 1086     const KTimeZone::Phase daylightPhase(
 
 1087         (tz->Bias + tz->DaylightBias) * -60,
 
 1088         daylightAbbrevs, 
true,
 
 1089         QLatin1String(
"Microsoft TIME_ZONE_INFORMATION"));
 
 1090     phases += daylightPhase;
 
 1094     const int prevOffset = tz->Bias * -60;
 
 1095     kdata.setPhases(phases, prevOffset);
 
 1098     QList<KTimeZone::Transition> transitions;
 
 1099     ICalTimeZoneSourcePrivate::parseTransitions(
 
 1100         tz->StandardDate, standardPhase, prevOffset, transitions);
 
 1101     ICalTimeZoneSourcePrivate::parseTransitions(
 
 1102         tz->DaylightDate, daylightPhase, prevOffset, transitions);
 
 1105     kdata.setTransitions(transitions);
 
 1111 #endif // HAVE_UUID_UUID_H 
 1117     if (!zone.isValid()) {
 
 1123     if (oldzone.isValid()) {
 
 1127     oldzone = zones.
zone(name);
 
 1128     if (oldzone.isValid()) {
 
 1132     } 
else if (zones.
add(zone)) {
 
 1142     QList<KTimeZone::Phase> phases;
 
 1143     QList<KTimeZone::Transition> transitions;
 
 1146     for (QStringList::ConstIterator it = tzList.begin(); it != tzList.end(); ++it) {
 
 1147         QString value = *it;
 
 1149         const QString tzName = value.mid(0, value.indexOf(QLatin1String(
";")));
 
 1150         value = value.mid((value.indexOf(QLatin1String(
";")) + 1));
 
 1151         const QString tzOffset = value.mid(0, value.indexOf(QLatin1String(
";")));
 
 1152         value = value.mid((value.indexOf(QLatin1String(
";")) + 1));
 
 1153         const QString tzDaylight = value.mid(0, value.indexOf(QLatin1String(
";")));
 
 1154         const KDateTime tzDate = KDateTime::fromString(value.mid((value.lastIndexOf(QLatin1String(
";")) + 1)));
 
 1155         if (tzDaylight == QLatin1String(
"true")) {
 
 1159         const KTimeZone::Phase tzPhase(
 
 1161             QByteArray(tzName.toLatin1()), daylight, QLatin1String(
"VCAL_TZ_INFORMATION"));
 
 1163         transitions += KTimeZone::Transition(tzDate.dateTime(), tzPhase);
 
 1166     kdata.setPhases(phases, 0);
 
 1168     kdata.setTransitions(transitions);
 
 1174 #if defined(HAVE_UUID_UUID_H) 
 1176 void ICalTimeZoneSourcePrivate::parseTransitions(
const MSSystemTime &date,
 
 1177         const KTimeZone::Phase &phase, 
int prevOffset,
 
 1178         QList<KTimeZone::Transition> &transitions)
 
 1182     const KDateTime klocalStart(QDateTime(QDate(2000, 1, 1), QTime(0, 0, 0)),
 
 1183                                 KDateTime::Spec::ClockTime());
 
 1184     const KDateTime maxTime(MAX_DATE(), KDateTime::Spec::ClockTime());
 
 1188         if (date.wYear >= 1601 && date.wYear <= 30827 &&
 
 1189                 date.wMonth >= 1 && date.wMonth <= 12 &&
 
 1190                 date.wDay >= 1 && date.wDay <= 31) {
 
 1191             const QDate dt(date.wYear, date.wMonth, date.wDay);
 
 1192             const QTime tm(date.wHour, date.wMinute, date.wSecond, date.wMilliseconds);
 
 1193             const QDateTime datetime(dt, tm);
 
 1194             if (datetime.isValid()) {
 
 1195                 transitions += KTimeZone::Transition(datetime, phase);
 
 1200         if (date.wDayOfWeek >= 0 && date.wDayOfWeek <= 6 &&
 
 1201                 date.wMonth >= 1 && date.wMonth <= 12 &&
 
 1202                 date.wDay >= 1 && date.wDay <= 5) {
 
 1204             r.setRecurrenceType(RecurrenceRule::rYearly);
 
 1208             lst.append(date.wMonth);
 
 1210             QList<RecurrenceRule::WDayPos> wdlst;
 
 1212             pos.setDay(date.wDayOfWeek ? date.wDayOfWeek : 7);
 
 1213             pos.setPos(date.wDay < 5 ? date.wDay : -1);
 
 1219             for (
int i = 0, end = dtl.count();  i < end;  ++i) {
 
 1220                 QDateTime utc = dtl[i].dateTime();
 
 1221                 utc.setTimeSpec(Qt::UTC);
 
 1222                 transitions += KTimeZone::Transition(utc.addSecs(-prevOffset), phase);
 
 1228 #endif // HAVE_UUID_UUID_H 
 1240 QList<QDateTime> ICalTimeZoneSourcePrivate::parsePhase(icalcomponent *c,
 
 1243         KTimeZone::Phase &phase)
 
 1245     QList<QDateTime> transitions;
 
 1248     QList<QByteArray> abbrevs;
 
 1252     bool recurs = 
false;
 
 1253     bool found_dtstart = 
false;
 
 1254     bool found_tzoffsetfrom = 
false;
 
 1255     bool found_tzoffsetto = 
false;
 
 1256     icaltimetype dtstart = icaltime_null_time();
 
 1259     icalproperty *p = icalcomponent_get_first_property(c, ICAL_ANY_PROPERTY);
 
 1261         icalproperty_kind kind = icalproperty_isa(p);
 
 1264         case ICAL_TZNAME_PROPERTY:     
 
 1270             QByteArray tzname = icalproperty_get_tzname(p);
 
 1273             if ((!daylight && tzname == 
"Standard Time") ||
 
 1274                     (daylight && tzname == 
"Daylight Time")) {
 
 1277             if (!abbrevs.contains(tzname)) {
 
 1282         case ICAL_DTSTART_PROPERTY:      
 
 1283             dtstart = icalproperty_get_dtstart(p);
 
 1284             found_dtstart = 
true;
 
 1287         case ICAL_TZOFFSETFROM_PROPERTY:    
 
 1288             prevOffset = icalproperty_get_tzoffsetfrom(p);
 
 1289             found_tzoffsetfrom = 
true;
 
 1292         case ICAL_TZOFFSETTO_PROPERTY:
 
 1293             utcOffset = icalproperty_get_tzoffsetto(p);
 
 1294             found_tzoffsetto = 
true;
 
 1297         case ICAL_COMMENT_PROPERTY:
 
 1298             comment = QString::fromUtf8(icalproperty_get_comment(p));
 
 1301         case ICAL_RDATE_PROPERTY:
 
 1302         case ICAL_RRULE_PROPERTY:
 
 1307             kDebug() << 
"Unknown property:" << int(kind);
 
 1310         p = icalcomponent_get_next_property(c, ICAL_ANY_PROPERTY);
 
 1314     if (!found_dtstart || !found_tzoffsetfrom || !found_tzoffsetto) {
 
 1315         kDebug() << 
"DTSTART/TZOFFSETFROM/TZOFFSETTO missing";
 
 1320     const QDateTime localStart = toQDateTime(dtstart);     
 
 1321     dtstart.second -= prevOffset;
 
 1323     const QDateTime utcStart = toQDateTime(icaltime_normalize(dtstart));       
 
 1325     transitions += utcStart;
 
 1332         const KDateTime klocalStart(localStart, KDateTime::Spec::ClockTime());
 
 1333         const KDateTime maxTime(MAX_DATE(), KDateTime::Spec::ClockTime());
 
 1335         icalproperty *p = icalcomponent_get_first_property(c, ICAL_ANY_PROPERTY);
 
 1337             icalproperty_kind kind = icalproperty_isa(p);
 
 1340             case ICAL_RDATE_PROPERTY:
 
 1342                 icaltimetype t = icalproperty_get_rdate(p).time;
 
 1343                 if (icaltime_is_date(t)) {
 
 1345                     t.hour = dtstart.hour;
 
 1346                     t.minute = dtstart.minute;
 
 1347                     t.second = dtstart.second;
 
 1354                     t.second -= prevOffset;    
 
 1356                     t = icaltime_normalize(t);
 
 1358                 transitions += toQDateTime(t);
 
 1361             case ICAL_RRULE_PROPERTY:
 
 1366                 impl.readRecurrence(icalproperty_get_rrule(p), &r);
 
 1371                     KDateTime end(r.
endDt());
 
 1372                     if (end.timeSpec() == KDateTime::Spec::UTC()) {
 
 1373                         end.setTimeSpec(KDateTime::Spec::ClockTime());
 
 1374                         r.
setEndDt(end.addSecs(prevOffset));
 
 1378                 for (
int i = 0, end = dts.count();  i < end;  ++i) {
 
 1379                     QDateTime utc = dts[i].dateTime();
 
 1380                     utc.setTimeSpec(Qt::UTC);
 
 1381                     transitions += utc.addSecs(-prevOffset);
 
 1388             p = icalcomponent_get_next_property(c, ICAL_ANY_PROPERTY);
 
 1390         qSortUnique(transitions);
 
 1393     phase = KTimeZone::Phase(utcOffset, abbrevs, daylight, comment);
 
 1404         QString tzid = zone;
 
 1406         if (zone.startsWith(prefix)) {
 
 1407             const int i = zone.indexOf(QLatin1Char(
'/'), prefix.length());
 
 1409                 tzid = zone.mid(i + 1);     
 
 1412         const KTimeZone ktz = KSystemTimeZones::readZone(tzid);
 
 1413         if (ktz.isValid()) {
 
 1414             if (ktz.data(
true)) {
 
 1423     const QByteArray zoneName = zone.toUtf8();
 
 1424     icaltimezone *icaltz = icaltimezone_get_builtin_timezone(zoneName);
 
 1427         icaltz = icaltimezone_get_builtin_timezone_from_tzid(zoneName);
 
 1432     return parse(icaltz);
 
 1437     if (ICalTimeZoneSourcePrivate::icalTzidPrefix.isEmpty()) {
 
 1438         icaltimezone *icaltz = icaltimezone_get_builtin_timezone(
"Europe/London");
 
 1439         const QByteArray tzid = icaltimezone_get_tzid(icaltz);
 
 1440         if (tzid.right(13) == 
"Europe/London") {
 
 1441             int i = tzid.indexOf(
'/', 1);
 
 1443                 ICalTimeZoneSourcePrivate::icalTzidPrefix = tzid.left(i + 1);
 
 1444                 return ICalTimeZoneSourcePrivate::icalTzidPrefix;
 
 1447         kError() << 
"failed to get libical TZID prefix";
 
 1449     return ICalTimeZoneSourcePrivate::icalTzidPrefix;
 
virtual ~ICalTimeZone()
Destructor. 
 
QString city() const 
Returns the name of the city for this time zone, if any. 
 
void clear()
Clears the collection. 
 
ICalTimeZone remove(const ICalTimeZone &zone)
Removes a time zone from the collection. 
 
virtual void virtual_hook(int id, void *data)
 
void setFrequency(int freq)
Sets the recurrence frequency, in terms of the recurrence time period type. 
 
ICalTimeZone()
Constructs a null time zone. 
 
structure for describing the n-th weekday of the month/year. 
 
virtual void virtual_hook(int id, void *data)
 
QDateTime lastModified() const 
Returns the LAST-MODIFIED time of the VTIMEZONE, if any. 
 
virtual void virtual_hook(int id, void *data)
 
ICalTimeZoneBackend()
Implements ICalTimeZone::ICalTimeZone(). 
 
QString city() const 
Returns the name of the city for this time zone, if any. 
 
A class which reads and parses iCalendar VTIMEZONE components, and accesses libical time zone data...
 
void setDuration(int duration)
Sets the total number of times the event is to occur, including both the first and last...
 
ICalTimeZoneData()
Default constructor. 
 
ICalTimeZoneSource()
Constructs an iCalendar time zone source. 
 
virtual QByteArray type() const 
Returns the class name of the data represented by this instance. 
 
QByteArray vtimezone() const 
Returns the VTIMEZONE string which represents this time zone. 
 
ICalTimeZoneData & operator=(const ICalTimeZoneData &rhs)
Assignment operator. 
 
ICalTimeZone standardZone(const QString &zone, bool icalBuiltIn=false)
Creates an ICalTimeZone instance for a standard time zone. 
 
~ICalTimeZones()
Destructor. 
 
static ICalTimeZone utc()
Returns a standard UTC time zone, with name "UTC". 
 
virtual bool hasTransitions() const 
Return whether daylight saving transitions are available for the time zone. 
 
void setEndDt(const KDateTime &endDateTime)
Sets the date and time of the last recurrence. 
 
virtual ~ICalTimeZoneSource()
Destructor. 
 
bool add(const ICalTimeZone &zone)
Adds a time zone to the collection. 
 
This class represents a recurrence rule for a calendar incidence. 
 
virtual bool hasTransitions(const KTimeZone *caller) const 
Implements ICalTimeZone::hasTransitions(). 
 
QByteArray url() const 
Returns the URL of the published VTIMEZONE definition, if any. 
 
QDateTime lastModified() const 
Returns the LAST-MODIFIED time of the VTIMEZONE, if any. 
 
A QList which can be sorted. 
 
Parsed iCalendar VTIMEZONE data. 
 
static QByteArray icalTzidPrefix()
Returns the prefix string used in the TZID field in built-in libical time zones. 
 
ICalTimeZone parse(icalcomponent *vtimezone)
Creates an ICalTimeZone instance containing the detailed information parsed from an iCalendar VTIMEZO...
 
int count()
Returns the number of zones kept in memory. 
 
QByteArray vtimezone() const 
Returns the VTIMEZONE string which represents this time zone. 
 
virtual KTimeZoneBackend * clone() const 
Creates a copy of this instance. 
 
KDateTime endDt(bool *result=0) const 
Returns the date and time of the last recurrence. 
 
virtual KTimeZoneData * clone() const 
Creates a new copy of this object. 
 
bool update(const ICalTimeZone &other)
Update the definition of the time zone to be identical to another ICalTimeZone instance. 
 
virtual ~ICalTimeZoneData()
Destructor. 
 
QByteArray url() const 
Returns the URL of the published VTIMEZONE definition, if any. 
 
Backend class for KICalTimeZone class. 
 
icaltimezone * icalTimezone() const 
Returns the ICal timezone structure which represents this time zone. 
 
ICalTimeZones()
Constructs an empty time zone collection. 
 
int duration() const 
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
 
The ICalTimeZones class represents a time zone database which consists of a collection of individual ...
 
The ICalTimeZone class represents an iCalendar VTIMEZONE component. 
 
void setStartDt(const KDateTime &start)
Sets the recurrence start date/time. 
 
DateTimeList timesInInterval(const KDateTime &start, const KDateTime &end) const 
Returns a list of all the times at which the recurrence will occur between two specified times...
 
const ZoneMap zones() const 
Returns all the time zones defined in this collection. 
 
ICalTimeZones & operator=(const ICalTimeZones &rhs)
Assignment operator. 
 
icaltimezone * icalTimezone() const 
Returns the ICal timezone structure which represents this time zone. 
 
virtual void virtual_hook(int id, void *data)
 
ICalTimeZone zone(const QString &name) const 
Returns the time zone with the given name. 
 
Placeholhers for Microsoft and ActiveSync timezone data. 
 
This class represents a recurrence rule for a calendar incidence.