libkcal Library API Documentation

icalformatimpl.cpp

00001 /* 00002 This file is part of libkcal. 00003 00004 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to 00018 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00019 Boston, MA 02111-1307, USA. 00020 */ 00021 00022 #include <qdatetime.h> 00023 #include <qstring.h> 00024 #include <qptrlist.h> 00025 #include <qfile.h> 00026 #include <cstdlib> 00027 00028 #include <kdebug.h> 00029 #include <klocale.h> 00030 00031 extern "C" { 00032 #include <ical.h> 00033 #include <icalss.h> 00034 #include <icalparser.h> 00035 #include <icalrestriction.h> 00036 } 00037 00038 #include "calendar.h" 00039 #include "journal.h" 00040 #include "icalformat.h" 00041 #include "icalformatimpl.h" 00042 #include "compat.h" 00043 00044 #define _ICAL_VERSION "2.0" 00045 00046 using namespace KCal; 00047 00048 namespace KCal { 00049 00054 typedef struct icaltimezonephase icaltimezonephase; 00055 class TimezonePhase : private icaltimezonephase { 00056 public: 00060 TimezonePhase(ICalFormatImpl *parent, icalcomponent *c) 00061 { 00062 tzname = (const char *)0; 00063 is_stdandard = 1; 00064 mIsStandard = 1; 00065 dtstart = icaltime_null_time(); 00066 offsetto = 0; 00067 tzoffsetfrom = 0; 00068 comment = (const char *)0; 00069 rdate.time = icaltime_null_time(); 00070 rdate.period = icalperiodtype_null_period(); 00071 rrule = (const char *)0; 00072 mRrule = new Recurrence((Incidence *)0); 00073 00074 // Now do the ical reading. 00075 icalproperty *p = icalcomponent_get_first_property(c,ICAL_ANY_PROPERTY); 00076 while (p) { 00077 icalproperty_kind kind = icalproperty_isa(p); 00078 switch (kind) { 00079 00080 case ICAL_TZNAME_PROPERTY: 00081 tzname = icalproperty_get_tzname(p); 00082 break; 00083 00084 case ICAL_DTSTART_PROPERTY: 00085 dtstart = icalproperty_get_dtstart(p); 00086 break; 00087 00088 case ICAL_TZOFFSETTO_PROPERTY: 00089 offsetto = icalproperty_get_tzoffsetto(p); 00090 break; 00091 00092 case ICAL_TZOFFSETFROM_PROPERTY: 00093 tzoffsetfrom = icalproperty_get_tzoffsetfrom(p); 00094 break; 00095 00096 case ICAL_COMMENT_PROPERTY: 00097 comment = icalproperty_get_comment(p); 00098 break; 00099 00100 case ICAL_RDATE_PROPERTY: 00101 rdate = icalproperty_get_rdate(p); 00102 break; 00103 00104 case ICAL_RRULE_PROPERTY: 00105 { 00106 struct icalrecurrencetype r = icalproperty_get_rrule(p); 00107 00108 parent->readRecurrence(r,mRrule); 00109 } 00110 break; 00111 00112 default: 00113 kdDebug(5800) << "TimezonePhase::TimezonePhase(): Unknown property: " << kind 00114 << endl; 00115 break; 00116 } 00117 p = icalcomponent_get_next_property(c,ICAL_ANY_PROPERTY); 00118 } 00119 } 00120 00124 ~TimezonePhase() 00125 { 00126 delete mRrule; 00127 } 00128 00132 QDateTime nearestStart(const QDateTime &t) const 00133 { 00134 QDateTime tmp(QDate(dtstart.year,dtstart.month,dtstart.day), QTime(dtstart.hour,dtstart.minute,dtstart.second)); 00135 // If this phase was not valid at the given time, give up. 00136 if (tmp > t) { 00137 kdDebug(5800) << "TimezonePhase::nearestStart(): Phase not valid" << endl; 00138 return QDateTime(); 00139 } 00140 00141 // The Recurrance class's getPreviousDateTime() logic was not designed for 00142 // start times which are not aligned with a reference time, but a little 00143 // magic is sufficient to work around that... 00144 QDateTime previous = mRrule->getPreviousDateTime(tmp); 00145 if (mRrule->getNextDateTime(previous) < tmp) 00146 previous = mRrule->getNextDateTime(previous); 00147 return previous; 00148 } 00149 00153 int offset() const 00154 { 00155 return offsetto; 00156 } 00157 00158 // Hide the missnamed "is_stdandard" variable in the base class. 00159 int mIsStandard; 00160 00161 // Supplement the "rrule" in the base class. 00162 Recurrence *mRrule; 00163 }; 00164 00168 typedef struct icaltimezonetype icaltimezonetype; 00169 class Timezone : private icaltimezonetype { 00170 public: 00174 Timezone(ICalFormatImpl *parent, icalcomponent *vtimezone) 00175 { 00176 tzid = (const char *)0; 00177 last_mod = icaltime_null_time(); 00178 tzurl = (const char *)0; 00179 00180 // The phases list is defined to be terminated by a phase with a 00181 // null name. 00182 phases = (icaltimezonephase *)malloc(sizeof(*phases)); 00183 phases[0].tzname = (const char *)0; 00184 mPhases.setAutoDelete( true ); 00185 00186 // Now do the ical reading. 00187 icalproperty *p = icalcomponent_get_first_property(vtimezone,ICAL_ANY_PROPERTY); 00188 while (p) { 00189 icalproperty_kind kind = icalproperty_isa(p); 00190 switch (kind) { 00191 00192 case ICAL_TZID_PROPERTY: 00193 // The timezone id is basically a unique string which is used to 00194 // identify this timezone. Note that if it begins with a "/", then it 00195 // is suppsed to have some externally specified meaning, but we are 00196 // just after its unique value. 00197 tzid = icalproperty_get_tzid(p); 00198 break; 00199 00200 case ICAL_TZURL_PROPERTY: 00201 tzurl = icalproperty_get_tzurl(p); 00202 break; 00203 00204 default: 00205 kdDebug(5800) << "Timezone::Timezone(): Unknown property: " << kind 00206 << endl; 00207 break; 00208 } 00209 p = icalcomponent_get_next_property(vtimezone,ICAL_ANY_PROPERTY); 00210 } 00211 kdDebug(5800) << "---zoneId: \"" << tzid << '"' << endl; 00212 00213 icalcomponent *c; 00214 00215 TimezonePhase *phase; 00216 00217 // Iterate through all timezones before we do anything else. That way, the 00218 // information needed to interpret times in actually usefulobject is 00219 // available below. 00220 c = icalcomponent_get_first_component(vtimezone,ICAL_ANY_COMPONENT); 00221 while (c) { 00222 icalcomponent_kind kind = icalcomponent_isa(c); 00223 switch (kind) { 00224 00225 case ICAL_XSTANDARD_COMPONENT: 00226 kdDebug(5800) << "---standard phase: found" << endl; 00227 phase = new TimezonePhase(parent,c); 00228 phase->mIsStandard = 1; 00229 mPhases.append(phase); 00230 break; 00231 00232 case ICAL_XDAYLIGHT_COMPONENT: 00233 kdDebug(5800) << "---daylight phase: found" << endl; 00234 phase = new TimezonePhase(parent,c); 00235 phase->mIsStandard = 0; 00236 mPhases.append(phase); 00237 break; 00238 00239 default: 00240 kdDebug(5800) << "Timezone::Timezone(): Unknown component: " << kind 00241 << endl; 00242 break; 00243 } 00244 c = icalcomponent_get_next_component(vtimezone,ICAL_ANY_COMPONENT); 00245 } 00246 } 00247 00251 ~Timezone() 00252 { 00253 free(phases); 00254 } 00255 00259 QString id() const 00260 { 00261 if (tzid[0] != '"') { 00262 return QString("\"") + tzid + '"'; 00263 } else { 00264 return tzid; 00265 } 00266 } 00267 00271 const TimezonePhase *nearestStart(const QDateTime &t) 00272 { 00273 unsigned i; 00274 unsigned result = 0; 00275 QDateTime previous; 00276 QDateTime next; 00277 00278 // Main loop. Find the phase with the latest start date before t. 00279 for (i = 0; i < mPhases.count(); i++) { 00280 next = mPhases.at(i)->nearestStart(t); 00281 if (previous.isNull() || previous < next) { 00282 previous = next; 00283 result = i; 00284 } 00285 } 00286 return mPhases.at(result); 00287 } 00288 00292 int offset(icaltimetype t) 00293 { 00294 QDateTime tmp(QDate(t.year,t.month,t.day), QTime(t.hour,t.minute,t.second)); 00295 const TimezonePhase *phase = nearestStart(tmp); 00296 00297 if (phase) { 00298 return phase->offset(); 00299 } else { 00300 kdError(5800) << "Timezone::offset() cannot find phase for " << tmp << endl; 00301 return 0; 00302 } 00303 } 00304 00305 // Phases we have seen. 00306 QPtrList<TimezonePhase> mPhases; 00307 }; 00308 00309 } 00310 00311 const int gSecondsPerMinute = 60; 00312 const int gSecondsPerHour = gSecondsPerMinute * 60; 00313 const int gSecondsPerDay = gSecondsPerHour * 24; 00314 const int gSecondsPerWeek = gSecondsPerDay * 7; 00315 00316 ICalFormatImpl::ICalFormatImpl( ICalFormat *parent ) : 00317 mParent( parent ), mCalendarVersion( 0 ) 00318 { 00319 mCompat = new Compat; 00320 mTimezones.setAutoDelete( true ); 00321 } 00322 00323 ICalFormatImpl::~ICalFormatImpl() 00324 { 00325 delete mCompat; 00326 } 00327 00328 class ToStringVisitor : public Incidence::Visitor 00329 { 00330 public: 00331 ToStringVisitor( ICalFormatImpl *impl ) : mImpl( impl ), mComponent( 0 ) {} 00332 00333 bool visit( Event *e ) { mComponent = mImpl->writeEvent( e ); return true; } 00334 bool visit( Todo *e ) { mComponent = mImpl->writeTodo( e ); return true; } 00335 bool visit( Journal *e ) { mComponent = mImpl->writeJournal( e ); return true; } 00336 00337 icalcomponent *component() { return mComponent; } 00338 00339 private: 00340 ICalFormatImpl *mImpl; 00341 icalcomponent *mComponent; 00342 }; 00343 00344 icalcomponent *ICalFormatImpl::writeIncidence(Incidence *incidence) 00345 { 00346 ToStringVisitor v( this ); 00347 incidence->accept(v); 00348 return v.component(); 00349 } 00350 00351 icalcomponent *ICalFormatImpl::writeTodo(Todo *todo) 00352 { 00353 QString tmpStr; 00354 QStringList tmpStrList; 00355 00356 icalcomponent *vtodo = icalcomponent_new(ICAL_VTODO_COMPONENT); 00357 00358 writeIncidence(vtodo,todo); 00359 00360 // due date 00361 if (todo->hasDueDate()) { 00362 icaltimetype due; 00363 if (todo->doesFloat()) { 00364 due = writeICalDate(todo->dtDue().date()); 00365 } else { 00366 due = writeICalDateTime(todo->dtDue()); 00367 } 00368 icalcomponent_add_property(vtodo,icalproperty_new_due(due)); 00369 } 00370 00371 // start time 00372 if (todo->hasStartDate()) { 00373 icaltimetype start; 00374 if (todo->doesFloat()) { 00375 // kdDebug(5800) << " Incidence " << todo->summary() << " floats." << endl; 00376 start = writeICalDate(todo->dtStart().date()); 00377 } else { 00378 // kdDebug(5800) << " incidence " << todo->summary() << " has time." << endl; 00379 start = writeICalDateTime(todo->dtStart()); 00380 } 00381 icalcomponent_add_property(vtodo,icalproperty_new_dtstart(start)); 00382 } 00383 00384 // completion date 00385 if (todo->isCompleted()) { 00386 if (!todo->hasCompletedDate()) { 00387 // If todo was created by KOrganizer <2.2 it has no correct completion 00388 // date. Set it to now. 00389 todo->setCompleted(QDateTime::currentDateTime()); 00390 } 00391 icaltimetype completed = writeICalDateTime(todo->completed()); 00392 icalcomponent_add_property(vtodo,icalproperty_new_completed(completed)); 00393 } 00394 00395 icalcomponent_add_property(vtodo, 00396 icalproperty_new_percentcomplete(todo->percentComplete())); 00397 00398 return vtodo; 00399 } 00400 00401 icalcomponent *ICalFormatImpl::writeEvent(Event *event) 00402 { 00403 #if 0 00404 kdDebug(5800) << "Write Event '" << event->summary() << "' (" << event->uid() 00405 << ")" << endl; 00406 #endif 00407 00408 QString tmpStr; 00409 QStringList tmpStrList; 00410 00411 icalcomponent *vevent = icalcomponent_new(ICAL_VEVENT_COMPONENT); 00412 00413 writeIncidence(vevent,event); 00414 00415 // start time 00416 icaltimetype start; 00417 if (event->doesFloat()) { 00418 // kdDebug(5800) << " Incidence " << event->summary() << " floats." << endl; 00419 start = writeICalDate(event->dtStart().date()); 00420 } else { 00421 // kdDebug(5800) << " incidence " << event->summary() << " has time." << endl; 00422 start = writeICalDateTime(event->dtStart()); 00423 } 00424 icalcomponent_add_property(vevent,icalproperty_new_dtstart(start)); 00425 00426 if (event->hasEndDate()) { 00427 // end time 00428 icaltimetype end; 00429 if (event->doesFloat()) { 00430 // kdDebug(5800) << " Event " << event->summary() << " floats." << endl; 00431 // +1 day because end date is non-inclusive. 00432 end = writeICalDate( event->dtEnd().date().addDays( 1 ) ); 00433 } else { 00434 // kdDebug(5800) << " Event " << event->summary() << " has time." << endl; 00435 end = writeICalDateTime(event->dtEnd()); 00436 } 00437 icalcomponent_add_property(vevent,icalproperty_new_dtend(end)); 00438 } 00439 00440 // TODO: resources 00441 #if 0 00442 // resources 00443 tmpStrList = anEvent->resources(); 00444 tmpStr = tmpStrList.join(";"); 00445 if (!tmpStr.isEmpty()) 00446 addPropValue(vevent, VCResourcesProp, tmpStr.utf8()); 00447 00448 #endif 00449 00450 // Transparency 00451 switch( event->transparency() ) { 00452 case Event::Transparent: 00453 icalcomponent_add_property(vevent, icalproperty_new_transp("TRANSPARENT")); 00454 break; 00455 case Event::Opaque: 00456 icalcomponent_add_property(vevent, icalproperty_new_transp("OPAQUE")); 00457 break; 00458 } 00459 00460 return vevent; 00461 } 00462 00463 icalcomponent *ICalFormatImpl::writeFreeBusy(FreeBusy *freebusy, 00464 Scheduler::Method method) 00465 { 00466 #if QT_VERSION >= 300 00467 kdDebug(5800) << "icalformatimpl: writeFreeBusy: startDate: " 00468 << freebusy->dtStart().toString("ddd MMMM d yyyy: h:m:s ap") << " End Date: " 00469 << freebusy->dtEnd().toString("ddd MMMM d yyyy: h:m:s ap") << endl; 00470 #endif 00471 00472 icalcomponent *vfreebusy = icalcomponent_new(ICAL_VFREEBUSY_COMPONENT); 00473 00474 writeIncidenceBase(vfreebusy,freebusy); 00475 00476 icalcomponent_add_property(vfreebusy, icalproperty_new_dtstart( 00477 writeICalDateTime(freebusy->dtStart()))); 00478 00479 icalcomponent_add_property(vfreebusy, icalproperty_new_dtend( 00480 writeICalDateTime(freebusy->dtEnd()))); 00481 00482 if (method == Scheduler::Request) { 00483 icalcomponent_add_property(vfreebusy,icalproperty_new_uid( 00484 freebusy->uid().utf8())); 00485 } 00486 00487 //Loops through all the periods in the freebusy object 00488 QValueList<Period> list = freebusy->busyPeriods(); 00489 QValueList<Period>::Iterator it; 00490 icalperiodtype period; 00491 for (it = list.begin(); it!= list.end(); ++it) { 00492 period.start = writeICalDateTime((*it).start()); 00493 period.end = writeICalDateTime((*it).end()); 00494 icalcomponent_add_property(vfreebusy, icalproperty_new_freebusy(period) ); 00495 } 00496 00497 return vfreebusy; 00498 } 00499 00500 icalcomponent *ICalFormatImpl::writeJournal(Journal *journal) 00501 { 00502 icalcomponent *vjournal = icalcomponent_new(ICAL_VJOURNAL_COMPONENT); 00503 00504 writeIncidence(vjournal,journal); 00505 00506 // start time 00507 if (journal->dtStart().isValid()) { 00508 icaltimetype start; 00509 if (journal->doesFloat()) { 00510 // kdDebug(5800) << " Incidence " << event->summary() << " floats." << endl; 00511 start = writeICalDate(journal->dtStart().date()); 00512 } else { 00513 // kdDebug(5800) << " incidence " << event->summary() << " has time." << endl; 00514 start = writeICalDateTime(journal->dtStart()); 00515 } 00516 icalcomponent_add_property(vjournal,icalproperty_new_dtstart(start)); 00517 } 00518 00519 return vjournal; 00520 } 00521 00522 void ICalFormatImpl::writeIncidence(icalcomponent *parent,Incidence *incidence) 00523 { 00524 // pilot sync stuff 00525 // TODO: move this application-specific code to kpilot 00526 if (incidence->pilotId()) { 00527 incidence->setNonKDECustomProperty("X-PILOTID", QString::number(incidence->pilotId())); 00528 incidence->setNonKDECustomProperty("X-PILOTSTAT", QString::number(incidence->syncStatus())); 00529 } 00530 00531 writeIncidenceBase(parent,incidence); 00532 00533 // creation date 00534 icalcomponent_add_property(parent,icalproperty_new_created( 00535 writeICalDateTime(incidence->created()))); 00536 00537 // unique id 00538 icalcomponent_add_property(parent,icalproperty_new_uid( 00539 incidence->uid().utf8())); 00540 00541 // revision 00542 icalcomponent_add_property(parent,icalproperty_new_sequence( 00543 incidence->revision())); 00544 00545 // last modification date 00546 icalcomponent_add_property(parent,icalproperty_new_lastmodified( 00547 writeICalDateTime(incidence->lastModified()))); 00548 00549 // description 00550 if (!incidence->description().isEmpty()) { 00551 icalcomponent_add_property(parent,icalproperty_new_description( 00552 incidence->description().utf8())); 00553 } 00554 00555 // summary 00556 if (!incidence->summary().isEmpty()) { 00557 icalcomponent_add_property(parent,icalproperty_new_summary( 00558 incidence->summary().utf8())); 00559 } 00560 00561 // location 00562 if (!incidence->location().isEmpty()) { 00563 icalcomponent_add_property(parent,icalproperty_new_location( 00564 incidence->location().utf8())); 00565 } 00566 00567 // TODO: 00568 // status 00569 // addPropValue(parent, VCStatusProp, incidence->getStatusStr().utf8()); 00570 00571 // secrecy 00572 const char *classStr; 00573 switch (incidence->secrecy()) { 00574 case Incidence::SecrecyPublic: 00575 classStr = "PUBLIC"; 00576 break; 00577 case Incidence::SecrecyConfidential: 00578 classStr = "CONFIDENTIAL"; 00579 break; 00580 case Incidence::SecrecyPrivate: 00581 default: 00582 classStr = "PRIVATE"; 00583 break; 00584 } 00585 icalcomponent_add_property(parent,icalproperty_new_class(classStr)); 00586 00587 // priority 00588 icalcomponent_add_property(parent,icalproperty_new_priority( 00589 incidence->priority())); 00590 00591 // categories 00592 QStringList categories = incidence->categories(); 00593 QStringList::Iterator it; 00594 for(it = categories.begin(); it != categories.end(); ++it ) { 00595 icalcomponent_add_property(parent,icalproperty_new_categories((*it).utf8())); 00596 } 00597 // TODO: Ensure correct concatenation of categories properties. 00598 00599 /* 00600 // categories 00601 tmpStrList = incidence->getCategories(); 00602 tmpStr = ""; 00603 QString catStr; 00604 for ( QStringList::Iterator it = tmpStrList.begin(); 00605 it != tmpStrList.end(); 00606 ++it ) { 00607 catStr = *it; 00608 if (catStr[0] == ' ') 00609 tmpStr += catStr.mid(1); 00610 else 00611 tmpStr += catStr; 00612 // this must be a ';' character as the vCalendar specification requires! 00613 // vcc.y has been hacked to translate the ';' to a ',' when the vcal is 00614 // read in. 00615 tmpStr += ";"; 00616 } 00617 if (!tmpStr.isEmpty()) { 00618 tmpStr.truncate(tmpStr.length()-1); 00619 icalcomponent_add_property(parent,icalproperty_new_categories( 00620 writeText(incidence->getCategories().join(";")))); 00621 } 00622 */ 00623 00624 // related event 00625 if (incidence->relatedTo()) { 00626 icalcomponent_add_property(parent,icalproperty_new_relatedto( 00627 incidence->relatedTo()->uid().utf8())); 00628 } 00629 00630 // recurrence rule stuff 00631 if (incidence->doesRecur()) { 00632 kdDebug(5800) << "Write recurrence for '" << incidence->summary() << "' (" << incidence->uid() 00633 << ")" << endl; 00634 icalcomponent_add_property(parent,writeRecurrenceRule(incidence->recurrence())); 00635 } 00636 00637 // recurrence exception dates and date/times 00638 DateList dateList = incidence->exDates(); 00639 DateList::ConstIterator exIt; 00640 for(exIt = dateList.begin(); exIt != dateList.end(); ++exIt) { 00641 icalcomponent_add_property(parent,icalproperty_new_exdate( 00642 writeICalDate(*exIt))); 00643 } 00644 DateTimeList dateTimeList = incidence->exDateTimes(); 00645 DateTimeList::ConstIterator extIt; 00646 for(extIt = dateTimeList.begin(); extIt != dateTimeList.end(); ++extIt) { 00647 icalcomponent_add_property(parent,icalproperty_new_exdate( 00648 writeICalDateTime(*extIt))); 00649 } 00650 00651 // attachments 00652 Attachment::List attachments = incidence->attachments(); 00653 Attachment::List::ConstIterator atIt; 00654 for ( atIt = attachments.begin(); atIt != attachments.end(); ++atIt ) 00655 icalcomponent_add_property( parent, writeAttachment( *atIt ) ); 00656 00657 // alarms 00658 Alarm::List::ConstIterator alarmIt; 00659 for ( alarmIt = incidence->alarms().begin(); 00660 alarmIt != incidence->alarms().end(); ++alarmIt ) { 00661 if ( (*alarmIt)->enabled() ) { 00662 kdDebug(5800) << "Write alarm for " << incidence->summary() << endl; 00663 icalcomponent_add_component( parent, writeAlarm( *alarmIt ) ); 00664 } 00665 } 00666 00667 // duration 00668 00669 // turned off as it always is set to PTS0 (and must not occur together with DTEND 00670 00671 // if (incidence->hasDuration()) { 00672 // icaldurationtype duration; 00673 // duration = writeICalDuration(incidence->duration()); 00674 // icalcomponent_add_property(parent,icalproperty_new_duration(duration)); 00675 // } 00676 } 00677 00678 void ICalFormatImpl::writeIncidenceBase( icalcomponent *parent, 00679 IncidenceBase * incidenceBase ) 00680 { 00681 icalcomponent_add_property( parent, icalproperty_new_dtstamp( 00682 writeICalDateTime( QDateTime::currentDateTime() ) ) ); 00683 00684 // organizer stuff 00685 icalcomponent_add_property( parent, icalproperty_new_organizer( 00686 ( "MAILTO:" + incidenceBase->organizer() ).utf8() ) ); 00687 00688 // attendees 00689 if ( incidenceBase->attendeeCount() > 0 ) { 00690 Attendee::List::ConstIterator it; 00691 for( it = incidenceBase->attendees().begin(); 00692 it != incidenceBase->attendees().end(); ++it ) { 00693 icalcomponent_add_property( parent, writeAttendee( *it ) ); 00694 } 00695 } 00696 00697 // custom properties 00698 writeCustomProperties( parent, incidenceBase ); 00699 } 00700 00701 void ICalFormatImpl::writeCustomProperties(icalcomponent *parent,CustomProperties *properties) 00702 { 00703 QMap<QCString, QString> custom = properties->customProperties(); 00704 for (QMap<QCString, QString>::Iterator c = custom.begin(); c != custom.end(); ++c) { 00705 icalproperty *p = icalproperty_new_x(c.data().utf8()); 00706 icalproperty_set_x_name(p,c.key()); 00707 icalcomponent_add_property(parent,p); 00708 } 00709 } 00710 00711 icalproperty *ICalFormatImpl::writeAttendee(Attendee *attendee) 00712 { 00713 icalproperty *p = icalproperty_new_attendee("mailto:" + attendee->email().utf8()); 00714 00715 if (!attendee->name().isEmpty()) { 00716 icalproperty_add_parameter(p,icalparameter_new_cn(attendee->name().utf8())); 00717 } 00718 00719 00720 icalproperty_add_parameter(p,icalparameter_new_rsvp( 00721 attendee->RSVP() ? ICAL_RSVP_TRUE : ICAL_RSVP_FALSE )); 00722 00723 icalparameter_partstat status = ICAL_PARTSTAT_NEEDSACTION; 00724 switch (attendee->status()) { 00725 default: 00726 case Attendee::NeedsAction: 00727 status = ICAL_PARTSTAT_NEEDSACTION; 00728 break; 00729 case Attendee::Accepted: 00730 status = ICAL_PARTSTAT_ACCEPTED; 00731 break; 00732 case Attendee::Declined: 00733 status = ICAL_PARTSTAT_DECLINED; 00734 break; 00735 case Attendee::Tentative: 00736 status = ICAL_PARTSTAT_TENTATIVE; 00737 break; 00738 case Attendee::Delegated: 00739 status = ICAL_PARTSTAT_DELEGATED; 00740 break; 00741 case Attendee::Completed: 00742 status = ICAL_PARTSTAT_COMPLETED; 00743 break; 00744 case Attendee::InProcess: 00745 status = ICAL_PARTSTAT_INPROCESS; 00746 break; 00747 } 00748 icalproperty_add_parameter(p,icalparameter_new_partstat(status)); 00749 00750 icalparameter_role role = ICAL_ROLE_REQPARTICIPANT; 00751 switch (attendee->role()) { 00752 case Attendee::Chair: 00753 role = ICAL_ROLE_CHAIR; 00754 break; 00755 default: 00756 case Attendee::ReqParticipant: 00757 role = ICAL_ROLE_REQPARTICIPANT; 00758 break; 00759 case Attendee::OptParticipant: 00760 role = ICAL_ROLE_OPTPARTICIPANT; 00761 break; 00762 case Attendee::NonParticipant: 00763 role = ICAL_ROLE_NONPARTICIPANT; 00764 break; 00765 } 00766 icalproperty_add_parameter(p,icalparameter_new_role(role)); 00767 00768 if (!attendee->uid().isEmpty()) { 00769 icalparameter* icalparameter_uid = icalparameter_new_x(attendee->uid().utf8()); 00770 icalparameter_set_xname(icalparameter_uid,"X-UID"); 00771 icalproperty_add_parameter(p,icalparameter_uid); 00772 } 00773 00774 return p; 00775 } 00776 00777 icalproperty *ICalFormatImpl::writeAttachment(Attachment *att) 00778 { 00779 icalattachtype *attach = icalattachtype_new(); 00780 if ( att->isUri() ) 00781 icalattachtype_set_url( attach, att->uri().utf8().data() ); 00782 else 00783 icalattachtype_set_base64( attach, att->data(), 0 ); 00784 00785 icalproperty *p = icalproperty_new_attach( attach ); 00786 icalattachtype_free( attach ); 00787 00788 if ( !att->mimeType().isEmpty() ) 00789 icalproperty_add_parameter( p, 00790 icalparameter_new_fmttype( att->mimeType().utf8().data() ) ); 00791 00792 if ( att->isBinary() ) { 00793 icalproperty_add_parameter( p, 00794 icalparameter_new_value( ICAL_VALUE_BINARY ) ); 00795 icalproperty_add_parameter( p, 00796 icalparameter_new_encoding( ICAL_ENCODING_BASE64 ) ); 00797 } 00798 return p; 00799 } 00800 00801 icalproperty *ICalFormatImpl::writeRecurrenceRule(Recurrence *recur) 00802 { 00803 // kdDebug(5800) << "ICalFormatImpl::writeRecurrenceRule()" << endl; 00804 00805 icalrecurrencetype r; 00806 00807 icalrecurrencetype_clear(&r); 00808 00809 int index = 0; 00810 int index2 = 0; 00811 00812 QPtrList<Recurrence::rMonthPos> tmpPositions; 00813 QPtrList<int> tmpDays; 00814 int *tmpDay; 00815 Recurrence::rMonthPos *tmpPos; 00816 bool datetime = false; 00817 int day; 00818 int i; 00819 00820 switch(recur->doesRecur()) { 00821 case Recurrence::rMinutely: 00822 r.freq = ICAL_MINUTELY_RECURRENCE; 00823 datetime = true; 00824 break; 00825 case Recurrence::rHourly: 00826 r.freq = ICAL_HOURLY_RECURRENCE; 00827 datetime = true; 00828 break; 00829 case Recurrence::rDaily: 00830 r.freq = ICAL_DAILY_RECURRENCE; 00831 break; 00832 case Recurrence::rWeekly: 00833 r.freq = ICAL_WEEKLY_RECURRENCE; 00834 r.week_start = static_cast<icalrecurrencetype_weekday>(recur->weekStart()%7 + 1); 00835 for (i = 0; i < 7; i++) { 00836 if (recur->days().testBit(i)) { 00837 day = (i + 1)%7 + 1; // convert from Monday=0 to Sunday=1 00838 r.by_day[index++] = icalrecurrencetype_day_day_of_week(day); 00839 } 00840 } 00841 // r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX; 00842 break; 00843 case Recurrence::rMonthlyPos: 00844 r.freq = ICAL_MONTHLY_RECURRENCE; 00845 00846 tmpPositions = recur->monthPositions(); 00847 for (tmpPos = tmpPositions.first(); 00848 tmpPos; 00849 tmpPos = tmpPositions.next()) { 00850 for (i = 0; i < 7; i++) { 00851 if (tmpPos->rDays.testBit(i)) { 00852 day = (i + 1)%7 + 1; // convert from Monday=0 to Sunday=1 00853 day += tmpPos->rPos*8; 00854 if (tmpPos->negative) day = -day; 00855 r.by_day[index++] = day; 00856 } 00857 } 00858 } 00859 // r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX; 00860 break; 00861 case Recurrence::rMonthlyDay: 00862 r.freq = ICAL_MONTHLY_RECURRENCE; 00863 00864 tmpDays = recur->monthDays(); 00865 for (tmpDay = tmpDays.first(); 00866 tmpDay; 00867 tmpDay = tmpDays.next()) { 00868 r.by_month_day[index++] = icalrecurrencetype_day_position(*tmpDay*8); 00869 } 00870 // r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX; 00871 break; 00872 case Recurrence::rYearlyMonth: 00873 case Recurrence::rYearlyPos: 00874 r.freq = ICAL_YEARLY_RECURRENCE; 00875 00876 tmpDays = recur->yearNums(); 00877 for (tmpDay = tmpDays.first(); 00878 tmpDay; 00879 tmpDay = tmpDays.next()) { 00880 r.by_month[index++] = *tmpDay; 00881 } 00882 // r.by_set_pos[index] = ICAL_RECURRENCE_ARRAY_MAX; 00883 if (recur->doesRecur() == Recurrence::rYearlyPos) { 00884 tmpPositions = recur->monthPositions(); 00885 for (tmpPos = tmpPositions.first(); 00886 tmpPos; 00887 tmpPos = tmpPositions.next()) { 00888 for (i = 0; i < 7; i++) { 00889 if (tmpPos->rDays.testBit(i)) { 00890 day = (i + 1)%7 + 1; // convert from Monday=0 to Sunday=1 00891 day += tmpPos->rPos*8; 00892 if (tmpPos->negative) day = -day; 00893 r.by_day[index2++] = day; 00894 } 00895 } 00896 } 00897 // r.by_day[index2] = ICAL_RECURRENCE_ARRAY_MAX; 00898 } 00899 else { 00900 tmpDays = recur->monthDays(); 00901 for (tmpDay = tmpDays.first(); 00902 tmpDay; 00903 tmpDay = tmpDays.next()) { 00904 r.by_month_day[index2++] = icalrecurrencetype_day_position(*tmpDay*8); 00905 } 00906 // r.by_month_day[index2] = ICAL_RECURRENCE_ARRAY_MAX; 00907 } 00908 break; 00909 case Recurrence::rYearlyDay: 00910 r.freq = ICAL_YEARLY_RECURRENCE; 00911 00912 tmpDays = recur->yearNums(); 00913 for (tmpDay = tmpDays.first(); 00914 tmpDay; 00915 tmpDay = tmpDays.next()) { 00916 r.by_year_day[index++] = *tmpDay; 00917 } 00918 // r.by_year_day[index] = ICAL_RECURRENCE_ARRAY_MAX; 00919 break; 00920 default: 00921 r.freq = ICAL_NO_RECURRENCE; 00922 kdDebug(5800) << "ICalFormatImpl::writeRecurrence(): no recurrence" << endl; 00923 break; 00924 } 00925 00926 r.interval = recur->frequency(); 00927 00928 if (recur->duration() > 0) { 00929 r.count = recur->duration(); 00930 } else if (recur->duration() == -1) { 00931 r.count = 0; 00932 } else { 00933 if (datetime) 00934 r.until = writeICalDateTime(recur->endDateTime()); 00935 else 00936 r.until = writeICalDate(recur->endDate()); 00937 } 00938 00939 // Debug output 00940 #if 0 00941 const char *str = icalrecurrencetype_as_string(&r); 00942 if (str) { 00943 kdDebug(5800) << " String: " << str << endl; 00944 } else { 00945 kdDebug(5800) << " No String" << endl; 00946 } 00947 #endif 00948 00949 return icalproperty_new_rrule(r); 00950 } 00951 00952 icalcomponent *ICalFormatImpl::writeAlarm(Alarm *alarm) 00953 { 00954 icalcomponent *a = icalcomponent_new(ICAL_VALARM_COMPONENT); 00955 00956 icalproperty_action action; 00957 icalattachtype *attach = 0; 00958 00959 switch (alarm->type()) { 00960 case Alarm::Procedure: 00961 action = ICAL_ACTION_PROCEDURE; 00962 attach = icalattachtype_new(); 00963 icalattachtype_set_url(attach,QFile::encodeName(alarm->programFile()).data()); 00964 icalcomponent_add_property(a,icalproperty_new_attach(attach)); 00965 icalattachtype_free(attach); 00966 if (!alarm->programArguments().isEmpty()) { 00967 icalcomponent_add_property(a,icalproperty_new_description(alarm->programArguments().utf8())); 00968 } 00969 break; 00970 case Alarm::Audio: 00971 action = ICAL_ACTION_AUDIO; 00972 if (!alarm->audioFile().isEmpty()) { 00973 attach = icalattachtype_new(); 00974 icalattachtype_set_url(attach,QFile::encodeName( alarm->audioFile() ).data()); 00975 icalcomponent_add_property(a,icalproperty_new_attach(attach)); 00976 icalattachtype_free(attach); 00977 } 00978 break; 00979 case Alarm::Email: { 00980 action = ICAL_ACTION_EMAIL; 00981 QValueList<Person> addresses = alarm->mailAddresses(); 00982 for (QValueList<Person>::Iterator ad = addresses.begin(); ad != addresses.end(); ++ad) { 00983 icalproperty *p = icalproperty_new_attendee("MAILTO:" + (*ad).email().utf8()); 00984 if (!(*ad).name().isEmpty()) { 00985 icalproperty_add_parameter(p,icalparameter_new_cn((*ad).name().utf8())); 00986 } 00987 icalcomponent_add_property(a,p); 00988 } 00989 icalcomponent_add_property(a,icalproperty_new_summary(alarm->mailSubject().utf8())); 00990 icalcomponent_add_property(a,icalproperty_new_description(alarm->mailText().utf8())); 00991 QStringList attachments = alarm->mailAttachments(); 00992 if (attachments.count() > 0) { 00993 for (QStringList::Iterator at = attachments.begin(); at != attachments.end(); ++at) { 00994 attach = icalattachtype_new(); 00995 icalattachtype_set_url(attach,QFile::encodeName( *at ).data()); 00996 icalcomponent_add_property(a,icalproperty_new_attach(attach)); 00997 icalattachtype_free(attach); 00998 } 00999 } 01000 break; 01001 } 01002 case Alarm::Display: 01003 action = ICAL_ACTION_DISPLAY; 01004 icalcomponent_add_property(a,icalproperty_new_description(alarm->text().utf8())); 01005 break; 01006 case Alarm::Invalid: 01007 default: 01008 kdDebug(5800) << "Unknown type of alarm" << endl; 01009 action = ICAL_ACTION_NONE; 01010 break; 01011 } 01012 icalcomponent_add_property(a,icalproperty_new_action(action)); 01013 01014 // Trigger time 01015 icaltriggertype trigger; 01016 if ( alarm->hasTime() ) { 01017 trigger.time = writeICalDateTime(alarm->time()); 01018 trigger.duration = icaldurationtype_null_duration(); 01019 } else { 01020 trigger.time = icaltime_null_time(); 01021 Duration offset; 01022 if ( alarm->hasStartOffset() ) 01023 offset = alarm->startOffset(); 01024 else 01025 offset = alarm->endOffset(); 01026 trigger.duration = icaldurationtype_from_int( offset.asSeconds() ); 01027 } 01028 icalproperty *p = icalproperty_new_trigger(trigger); 01029 if ( alarm->hasEndOffset() ) 01030 icalproperty_add_parameter(p,icalparameter_new_related(ICAL_RELATED_END)); 01031 icalcomponent_add_property(a,p); 01032 01033 // Repeat count and duration 01034 if (alarm->repeatCount()) { 01035 icalcomponent_add_property(a,icalproperty_new_repeat(alarm->repeatCount())); 01036 icalcomponent_add_property(a,icalproperty_new_duration( 01037 icaldurationtype_from_int(alarm->snoozeTime()*60))); 01038 } 01039 01040 // Custom properties 01041 QMap<QCString, QString> custom = alarm->customProperties(); 01042 for (QMap<QCString, QString>::Iterator c = custom.begin(); c != custom.end(); ++c) { 01043 icalproperty *p = icalproperty_new_x(c.data().utf8()); 01044 icalproperty_set_x_name(p,c.key()); 01045 icalcomponent_add_property(a,p); 01046 } 01047 01048 return a; 01049 } 01050 01051 // Read a timezone and store it in a list where it can be accessed as needed 01052 // by the other readXXX() routines. Note that no writeTimezone is needed 01053 // because we always store in UTC. 01054 void ICalFormatImpl::readTimezone(icalcomponent *vtimezone) 01055 { 01056 Timezone *timezone = new Timezone(this, vtimezone); 01057 01058 mTimezones.insert(timezone->id(), timezone); 01059 } 01060 01061 Todo *ICalFormatImpl::readTodo(icalcomponent *vtodo) 01062 { 01063 Todo *todo = new Todo; 01064 01065 readIncidence(vtodo,todo); 01066 01067 icalproperty *p = icalcomponent_get_first_property(vtodo,ICAL_ANY_PROPERTY); 01068 01069 // int intvalue; 01070 icaltimetype icaltime; 01071 01072 QStringList categories; 01073 01074 while (p) { 01075 icalproperty_kind kind = icalproperty_isa(p); 01076 switch (kind) { 01077 01078 case ICAL_DUE_PROPERTY: // due date 01079 icaltime = icalproperty_get_due(p); 01080 readTzidParameter(p,icaltime); 01081 if (icaltime.is_date) { 01082 todo->setDtDue(QDateTime(readICalDate(icaltime),QTime(0,0,0))); 01083 todo->setFloats(true); 01084 01085 } else { 01086 todo->setDtDue(readICalDateTime(icaltime)); 01087 todo->setFloats(false); 01088 } 01089 todo->setHasDueDate(true); 01090 break; 01091 01092 case ICAL_COMPLETED_PROPERTY: // completion date 01093 icaltime = icalproperty_get_completed(p); 01094 readTzidParameter(p,icaltime); 01095 todo->setCompleted(readICalDateTime(icaltime)); 01096 break; 01097 01098 case ICAL_PERCENTCOMPLETE_PROPERTY: // Percent completed 01099 todo->setPercentComplete(icalproperty_get_percentcomplete(p)); 01100 break; 01101 01102 case ICAL_RELATEDTO_PROPERTY: // related todo (parent) 01103 todo->setRelatedToUid(QString::fromUtf8(icalproperty_get_relatedto(p))); 01104 mTodosRelate.append(todo); 01105 break; 01106 01107 case ICAL_DTSTART_PROPERTY: 01108 // Flag that todo has start date. Value is read in by readIncidence(). 01109 todo->setHasStartDate(true); 01110 break; 01111 01112 default: 01113 // kdDebug(5800) << "ICALFormat::readTodo(): Unknown property: " << kind 01114 // << endl; 01115 break; 01116 } 01117 01118 p = icalcomponent_get_next_property(vtodo,ICAL_ANY_PROPERTY); 01119 } 01120 01121 mCompat->fixEmptySummary( todo ); 01122 01123 return todo; 01124 } 01125 01126 Event *ICalFormatImpl::readEvent(icalcomponent *vevent) 01127 { 01128 Event *event = new Event; 01129 event->setFloats(false); 01130 01131 readIncidence(vevent,event); 01132 01133 icalproperty *p = icalcomponent_get_first_property(vevent,ICAL_ANY_PROPERTY); 01134 01135 // int intvalue; 01136 icaltimetype icaltime; 01137 01138 QStringList categories; 01139 QString transparency; 01140 01141 while (p) { 01142 icalproperty_kind kind = icalproperty_isa(p); 01143 switch (kind) { 01144 01145 case ICAL_DTEND_PROPERTY: // start date and time 01146 icaltime = icalproperty_get_dtend(p); 01147 readTzidParameter(p,icaltime); 01148 if (icaltime.is_date) { 01149 event->setFloats( true ); 01150 // End date is non-inclusive 01151 QDate endDate = readICalDate( icaltime ).addDays( -1 ); 01152 mCompat->fixFloatingEnd( endDate ); 01153 if ( endDate < event->dtStart().date() ) { 01154 endDate = event->dtStart().date(); 01155 } 01156 event->setDtEnd( QDateTime( endDate, QTime( 0, 0, 0 ) ) ); 01157 } else { 01158 event->setDtEnd(readICalDateTime(icaltime)); 01159 } 01160 break; 01161 01162 // TODO: 01163 // at this point, there should be at least a start or end time. 01164 // fix up for events that take up no time but have a time associated 01165 #if 0 01166 if (!(vo = isAPropertyOf(vevent, VCDTstartProp))) 01167 anEvent->setDtStart(anEvent->dtEnd()); 01168 if (!(vo = isAPropertyOf(vevent, VCDTendProp))) 01169 anEvent->setDtEnd(anEvent->dtStart()); 01170 #endif 01171 01172 #if 0 01173 // secrecy 01174 if ((vo = isAPropertyOf(vevent, VCClassProp)) != 0) { 01175 anEvent->setSecrecy(s = fakeCString(vObjectUStringZValue(vo))); 01176 deleteStr(s); 01177 } 01178 else 01179 anEvent->setSecrecy("PUBLIC"); 01180 01181 // attachments 01182 tmpStrList.clear(); 01183 initPropIterator(&voi, vevent); 01184 while (moreIteration(&voi)) { 01185 vo = nextVObject(&voi); 01186 if (strcmp(vObjectName(vo), VCAttachProp) == 0) { 01187 tmpStrList.append(s = fakeCString(vObjectUStringZValue(vo))); 01188 deleteStr(s); 01189 } 01190 } 01191 anEvent->setAttachments(tmpStrList); 01192 01193 // resources 01194 if ((vo = isAPropertyOf(vevent, VCResourcesProp)) != 0) { 01195 QString resources = (s = fakeCString(vObjectUStringZValue(vo))); 01196 deleteStr(s); 01197 tmpStrList.clear(); 01198 index1 = 0; 01199 index2 = 0; 01200 QString resource; 01201 while ((index2 = resources.find(';', index1)) != -1) { 01202 resource = resources.mid(index1, (index2 - index1)); 01203 tmpStrList.append(resource); 01204 index1 = index2; 01205 } 01206 anEvent->setResources(tmpStrList); 01207 } 01208 #endif 01209 01210 case ICAL_RELATEDTO_PROPERTY: // related event (parent) 01211 event->setRelatedToUid(QString::fromUtf8(icalproperty_get_relatedto(p))); 01212 mEventsRelate.append(event); 01213 break; 01214 01215 01216 case ICAL_TRANSP_PROPERTY: // Transparency 01217 transparency = QString::fromUtf8(icalproperty_get_transp(p)); 01218 if( transparency == "TRANSPARENT" ) 01219 event->setTransparency( Event::Transparent ); 01220 else 01221 event->setTransparency( Event::Opaque ); 01222 break; 01223 01224 default: 01225 // kdDebug(5800) << "ICALFormat::readEvent(): Unknown property: " << kind 01226 // << endl; 01227 break; 01228 } 01229 01230 p = icalcomponent_get_next_property(vevent,ICAL_ANY_PROPERTY); 01231 } 01232 01233 QString msade = event->nonKDECustomProperty("X-MICROSOFT-CDO-ALLDAYEVENT"); 01234 if (!msade.isNull()) { 01235 bool floats = (msade == QString::fromLatin1("TRUE")); 01236 kdDebug(5800) << "ICALFormat::readEvent(): all day event: " << floats << endl; 01237 event->setFloats(floats); 01238 if (floats) { 01239 QDateTime endDate = event->dtEnd(); 01240 event->setDtEnd(endDate.addDays(-1)); 01241 } 01242 } 01243 01244 mCompat->fixEmptySummary( event ); 01245 01246 return event; 01247 } 01248 01249 FreeBusy *ICalFormatImpl::readFreeBusy(icalcomponent *vfreebusy) 01250 { 01251 FreeBusy *freebusy = new FreeBusy; 01252 01253 readIncidenceBase(vfreebusy,freebusy); 01254 01255 icalproperty *p = icalcomponent_get_first_property(vfreebusy,ICAL_ANY_PROPERTY); 01256 01257 icaltimetype icaltime; 01258 icalperiodtype icalperiod; 01259 QDateTime period_start, period_end; 01260 01261 while (p) { 01262 icalproperty_kind kind = icalproperty_isa(p); 01263 switch (kind) { 01264 01265 case ICAL_DTSTART_PROPERTY: // start date and time 01266 icaltime = icalproperty_get_dtstart(p); 01267 readTzidParameter(p,icaltime); 01268 freebusy->setDtStart(readICalDateTime(icaltime)); 01269 break; 01270 01271 case ICAL_DTEND_PROPERTY: // start End Date and Time 01272 icaltime = icalproperty_get_dtend(p); 01273 readTzidParameter(p,icaltime); 01274 freebusy->setDtEnd(readICalDateTime(icaltime)); 01275 break; 01276 01277 case ICAL_FREEBUSY_PROPERTY: //Any FreeBusy Times 01278 icalperiod = icalproperty_get_freebusy(p); 01279 readTzidParameter(p,icalperiod.start); 01280 readTzidParameter(p,icalperiod.end); 01281 period_start = readICalDateTime(icalperiod.start); 01282 period_end = readICalDateTime(icalperiod.end); 01283 freebusy->addPeriod(period_start, period_end); 01284 break; 01285 01286 default: 01287 kdDebug(5800) << "ICALFormat::readIncidence(): Unknown property: " << kind 01288 << endl; 01289 break; 01290 } 01291 p = icalcomponent_get_next_property(vfreebusy,ICAL_ANY_PROPERTY); 01292 } 01293 01294 return freebusy; 01295 } 01296 01297 Journal *ICalFormatImpl::readJournal(icalcomponent *vjournal) 01298 { 01299 Journal *journal = new Journal; 01300 01301 readIncidence(vjournal,journal); 01302 01303 return journal; 01304 } 01305 01306 Attendee *ICalFormatImpl::readAttendee(icalproperty *attendee) 01307 { 01308 icalparameter *p = 0; 01309 01310 QString email = QString::fromUtf8(icalproperty_get_attendee(attendee)); 01311 01312 QString name; 01313 QString uid = QString::null; 01314 p = icalproperty_get_first_parameter(attendee,ICAL_CN_PARAMETER); 01315 if (p) { 01316 name = QString::fromUtf8(icalparameter_get_cn(p)); 01317 } else { 01318 } 01319 01320 bool rsvp=false; 01321 p = icalproperty_get_first_parameter(attendee,ICAL_RSVP_PARAMETER); 01322 if (p) { 01323 icalparameter_rsvp rsvpParameter = icalparameter_get_rsvp(p); 01324 if (rsvpParameter == ICAL_RSVP_TRUE) rsvp = true; 01325 } 01326 01327 Attendee::PartStat status = Attendee::NeedsAction; 01328 p = icalproperty_get_first_parameter(attendee,ICAL_PARTSTAT_PARAMETER); 01329 if (p) { 01330 icalparameter_partstat partStatParameter = icalparameter_get_partstat(p); 01331 switch(partStatParameter) { 01332 default: 01333 case ICAL_PARTSTAT_NEEDSACTION: 01334 status = Attendee::NeedsAction; 01335 break; 01336 case ICAL_PARTSTAT_ACCEPTED: 01337 status = Attendee::Accepted; 01338 break; 01339 case ICAL_PARTSTAT_DECLINED: 01340 status = Attendee::Declined; 01341 break; 01342 case ICAL_PARTSTAT_TENTATIVE: 01343 status = Attendee::Tentative; 01344 break; 01345 case ICAL_PARTSTAT_DELEGATED: 01346 status = Attendee::Delegated; 01347 break; 01348 case ICAL_PARTSTAT_COMPLETED: 01349 status = Attendee::Completed; 01350 break; 01351 case ICAL_PARTSTAT_INPROCESS: 01352 status = Attendee::InProcess; 01353 break; 01354 } 01355 } 01356 01357 Attendee::Role role = Attendee::ReqParticipant; 01358 p = icalproperty_get_first_parameter(attendee,ICAL_ROLE_PARAMETER); 01359 if (p) { 01360 icalparameter_role roleParameter = icalparameter_get_role(p); 01361 switch(roleParameter) { 01362 case ICAL_ROLE_CHAIR: 01363 role = Attendee::Chair; 01364 break; 01365 default: 01366 case ICAL_ROLE_REQPARTICIPANT: 01367 role = Attendee::ReqParticipant; 01368 break; 01369 case ICAL_ROLE_OPTPARTICIPANT: 01370 role = Attendee::OptParticipant; 01371 break; 01372 case ICAL_ROLE_NONPARTICIPANT: 01373 role = Attendee::NonParticipant; 01374 break; 01375 } 01376 } 01377 01378 p = icalproperty_get_first_parameter(attendee,ICAL_X_PARAMETER); 01379 uid = icalparameter_get_xvalue(p); 01380 // This should be added, but there seems to be a libical bug here. 01381 /*while (p) { 01382 // if (icalparameter_get_xname(p) == "X-UID") { 01383 uid = icalparameter_get_xvalue(p); 01384 p = icalproperty_get_next_parameter(attendee,ICAL_X_PARAMETER); 01385 } */ 01386 01387 return new Attendee( name, email, rsvp, status, role, uid ); 01388 } 01389 01390 Attachment *ICalFormatImpl::readAttachment(icalproperty *attach) 01391 { 01392 icalattachtype *a = icalproperty_get_attach(attach); 01393 icalparameter_value v = ICAL_VALUE_NONE; 01394 icalparameter_encoding e = ICAL_ENCODING_NONE; 01395 01396 Attachment *attachment = 0; 01397 01398 icalparameter *vp = icalproperty_get_first_parameter(attach, ICAL_VALUE_PARAMETER); 01399 if (vp) 01400 v = icalparameter_get_value(vp); 01401 01402 icalparameter *ep = icalproperty_get_first_parameter(attach, ICAL_ENCODING_PARAMETER); 01403 if (ep) 01404 e = icalparameter_get_encoding(ep); 01405 01406 if (v == ICAL_VALUE_BINARY && e == ICAL_ENCODING_BASE64) 01407 attachment = new Attachment(icalattachtype_get_base64(a)); 01408 else if ((v == ICAL_VALUE_NONE || v == ICAL_VALUE_URI) && (e == ICAL_ENCODING_NONE || e == ICAL_ENCODING_8BIT)) { 01409 attachment = new Attachment(QString(icalattachtype_get_url(a))); 01410 } else { 01411 kdWarning(5800) << "Unsupported attachment format, discarding it!" << endl; 01412 return 0; 01413 } 01414 01415 icalparameter *p = icalproperty_get_first_parameter(attach, ICAL_FMTTYPE_PARAMETER); 01416 if (p) 01417 attachment->setMimeType(QString(icalparameter_get_fmttype(p))); 01418 01419 return attachment; 01420 } 01421 01422 void ICalFormatImpl::readIncidence(icalcomponent *parent,Incidence *incidence) 01423 { 01424 readIncidenceBase(parent,incidence); 01425 01426 icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY); 01427 01428 const char *text; 01429 int intvalue; 01430 icaltimetype icaltime; 01431 icaldurationtype icalduration; 01432 01433 QStringList categories; 01434 01435 while (p) { 01436 icalproperty_kind kind = icalproperty_isa(p); 01437 switch (kind) { 01438 01439 case ICAL_CREATED_PROPERTY: 01440 icaltime = icalproperty_get_created(p); 01441 readTzidParameter(p,icaltime); 01442 incidence->setCreated(readICalDateTime(icaltime)); 01443 break; 01444 01445 case ICAL_SEQUENCE_PROPERTY: // sequence 01446 intvalue = icalproperty_get_sequence(p); 01447 incidence->setRevision(intvalue); 01448 break; 01449 01450 case ICAL_LASTMODIFIED_PROPERTY: // last modification date 01451 icaltime = icalproperty_get_lastmodified(p); 01452 readTzidParameter(p,icaltime); 01453 incidence->setLastModified(readICalDateTime(icaltime)); 01454 break; 01455 01456 case ICAL_DTSTART_PROPERTY: // start date and time 01457 icaltime = icalproperty_get_dtstart(p); 01458 readTzidParameter(p,icaltime); 01459 if (icaltime.is_date) { 01460 incidence->setDtStart(QDateTime(readICalDate(icaltime),QTime(0,0,0))); 01461 incidence->setFloats(true); 01462 } else { 01463 incidence->setDtStart(readICalDateTime(icaltime)); 01464 } 01465 break; 01466 01467 case ICAL_DURATION_PROPERTY: // start date and time 01468 icalduration = icalproperty_get_duration(p); 01469 incidence->setDuration(readICalDuration(icalduration)); 01470 break; 01471 01472 case ICAL_DESCRIPTION_PROPERTY: // description 01473 text = icalproperty_get_description(p); 01474 incidence->setDescription(QString::fromUtf8(text)); 01475 break; 01476 01477 case ICAL_SUMMARY_PROPERTY: // summary 01478 text = icalproperty_get_summary(p); 01479 incidence->setSummary(QString::fromUtf8(text)); 01480 break; 01481 01482 case ICAL_LOCATION_PROPERTY: // location 01483 text = icalproperty_get_location(p); 01484 incidence->setLocation(QString::fromUtf8(text)); 01485 break; 01486 01487 #if 0 01488 // status 01489 if ((vo = isAPropertyOf(vincidence, VCStatusProp)) != 0) { 01490 incidence->setStatus(s = fakeCString(vObjectUStringZValue(vo))); 01491 deleteStr(s); 01492 } 01493 else 01494 incidence->setStatus("NEEDS ACTION"); 01495 #endif 01496 01497 case ICAL_PRIORITY_PROPERTY: // priority 01498 intvalue = icalproperty_get_priority(p); 01499 incidence->setPriority(intvalue); 01500 break; 01501 01502 case ICAL_CATEGORIES_PROPERTY: // categories 01503 text = icalproperty_get_categories(p); 01504 categories.append(QString::fromUtf8(text)); 01505 break; 01506 01507 case ICAL_RRULE_PROPERTY: 01508 readRecurrenceRule(p,incidence); 01509 break; 01510 01511 case ICAL_EXDATE_PROPERTY: 01512 icaltime = icalproperty_get_exdate(p); 01513 readTzidParameter(p,icaltime); 01514 if (icaltime.is_date) { 01515 incidence->addExDate(readICalDate(icaltime)); 01516 } else { 01517 incidence->addExDateTime(readICalDateTime(icaltime)); 01518 } 01519 break; 01520 01521 case ICAL_CLASS_PROPERTY: 01522 text = icalproperty_get_class(p); 01523 if (strcmp(text,"PUBLIC") == 0) { 01524 incidence->setSecrecy(Incidence::SecrecyPublic); 01525 } else if (strcmp(text,"CONFIDENTIAL") == 0) { 01526 incidence->setSecrecy(Incidence::SecrecyConfidential); 01527 } else { 01528 incidence->setSecrecy(Incidence::SecrecyPrivate); 01529 } 01530 break; 01531 01532 case ICAL_ATTACH_PROPERTY: // attachments 01533 incidence->addAttachment(readAttachment(p)); 01534 break; 01535 01536 default: 01537 // kdDebug(5800) << "ICALFormat::readIncidence(): Unknown property: " << kind 01538 // << endl; 01539 break; 01540 } 01541 01542 p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY); 01543 } 01544 01545 // kpilot stuff 01546 // TODO: move this application-specific code to kpilot 01547 QString kp = incidence->nonKDECustomProperty("X-PILOTID"); 01548 if (!kp.isNull()) { 01549 incidence->setPilotId(kp.toInt()); 01550 } 01551 kp = incidence->nonKDECustomProperty("X-PILOTSTAT"); 01552 if (!kp.isNull()) { 01553 incidence->setSyncStatus(kp.toInt()); 01554 } 01555 01556 // Now that recurrence and exception stuff is completely set up, 01557 // do any backwards compatibility adjustments. 01558 mCompat->fixRecurrence( incidence ); 01559 01560 // add categories 01561 incidence->setCategories(categories); 01562 01563 // iterate through all alarms 01564 for (icalcomponent *alarm = icalcomponent_get_first_component(parent,ICAL_VALARM_COMPONENT); 01565 alarm; 01566 alarm = icalcomponent_get_next_component(parent,ICAL_VALARM_COMPONENT)) { 01567 readAlarm(alarm,incidence); 01568 } 01569 } 01570 01571 void ICalFormatImpl::readIncidenceBase(icalcomponent *parent,IncidenceBase *incidenceBase) 01572 { 01573 icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY); 01574 01575 while (p) { 01576 icalproperty_kind kind = icalproperty_isa(p); 01577 switch (kind) { 01578 01579 case ICAL_UID_PROPERTY: // unique id 01580 incidenceBase->setUid(QString::fromUtf8(icalproperty_get_uid(p))); 01581 break; 01582 01583 case ICAL_ORGANIZER_PROPERTY: // organizer 01584 incidenceBase->setOrganizer(QString::fromUtf8(icalproperty_get_organizer(p))); 01585 break; 01586 01587 case ICAL_ATTENDEE_PROPERTY: // attendee 01588 incidenceBase->addAttendee(readAttendee(p)); 01589 break; 01590 01591 default: 01592 break; 01593 } 01594 01595 p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY); 01596 } 01597 01598 // custom properties 01599 readCustomProperties(parent, incidenceBase); 01600 } 01601 01602 void ICalFormatImpl::readCustomProperties(icalcomponent *parent,CustomProperties *properties) 01603 { 01604 QMap<QCString, QString> customProperties; 01605 01606 icalproperty *p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY); 01607 01608 while (p) { 01609 01610 QString value = QString::fromUtf8(icalproperty_get_x(p)); 01611 customProperties[icalproperty_get_name(p)] = value; 01612 01613 p = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY); 01614 } 01615 01616 properties->setCustomProperties(customProperties); 01617 } 01618 01619 void ICalFormatImpl::readRecurrenceRule(icalproperty *rrule,Incidence *incidence) 01620 { 01621 // kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl; 01622 01623 Recurrence *recur = incidence->recurrence(); 01624 recur->setCompatVersion(mCalendarVersion); 01625 recur->unsetRecurs(); 01626 01627 struct icalrecurrencetype r = icalproperty_get_rrule(rrule); 01628 01629 dumpIcalRecurrence(r); 01630 01631 readRecurrence( r, recur ); 01632 } 01633 01634 void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype &r, Recurrence* recur ) 01635 { 01636 int wkst; 01637 int index = 0; 01638 short day = 0; 01639 QBitArray qba(7); 01640 01641 switch (r.freq) { 01642 case ICAL_MINUTELY_RECURRENCE: 01643 if (!icaltime_is_null_time(r.until)) { 01644 recur->setMinutely(r.interval,readICalDateTime(r.until)); 01645 } else { 01646 if (r.count == 0) 01647 recur->setMinutely(r.interval,-1); 01648 else 01649 recur->setMinutely(r.interval,r.count); 01650 } 01651 break; 01652 case ICAL_HOURLY_RECURRENCE: 01653 if (!icaltime_is_null_time(r.until)) { 01654 recur->setHourly(r.interval,readICalDateTime(r.until)); 01655 } else { 01656 if (r.count == 0) 01657 recur->setHourly(r.interval,-1); 01658 else 01659 recur->setHourly(r.interval,r.count); 01660 } 01661 break; 01662 case ICAL_DAILY_RECURRENCE: 01663 if (!icaltime_is_null_time(r.until)) { 01664 recur->setDaily(r.interval,readICalDate(r.until)); 01665 } else { 01666 if (r.count == 0) 01667 recur->setDaily(r.interval,-1); 01668 else 01669 recur->setDaily(r.interval,r.count); 01670 } 01671 break; 01672 case ICAL_WEEKLY_RECURRENCE: 01673 // kdDebug(5800) << "WEEKLY_RECURRENCE" << endl; 01674 wkst = (r.week_start + 5)%7 + 1; 01675 if (!icaltime_is_null_time(r.until)) { 01676 recur->setWeekly(r.interval,qba,readICalDate(r.until),wkst); 01677 } else { 01678 if (r.count == 0) 01679 recur->setWeekly(r.interval,qba,-1,wkst); 01680 else 01681 recur->setWeekly(r.interval,qba,r.count,wkst); 01682 } 01683 while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 01684 // kdDebug(5800) << " " << day << endl; 01685 qba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0 01686 } 01687 break; 01688 case ICAL_MONTHLY_RECURRENCE: 01689 if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { 01690 if (!icaltime_is_null_time(r.until)) { 01691 recur->setMonthly(Recurrence::rMonthlyPos,r.interval, 01692 readICalDate(r.until)); 01693 } else { 01694 if (r.count == 0) 01695 recur->setMonthly(Recurrence::rMonthlyPos,r.interval,-1); 01696 else 01697 recur->setMonthly(Recurrence::rMonthlyPos,r.interval,r.count); 01698 } 01699 bool useSetPos = false; 01700 short pos = 0; 01701 while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 01702 // kdDebug(5800) << "----a " << index << ": " << day << endl; 01703 pos = icalrecurrencetype_day_position(day); 01704 if (pos) { 01705 day = icalrecurrencetype_day_day_of_week(day); 01706 QBitArray ba(7); // don't wipe qba 01707 ba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0 01708 recur->addMonthlyPos(pos,ba); 01709 } else { 01710 qba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0 01711 useSetPos = true; 01712 } 01713 } 01714 if (useSetPos) { 01715 if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) { 01716 recur->addMonthlyPos(r.by_set_pos[0],qba); 01717 } 01718 } 01719 } else if (r.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { 01720 if (!icaltime_is_null_time(r.until)) { 01721 recur->setMonthly(Recurrence::rMonthlyDay,r.interval, 01722 readICalDate(r.until)); 01723 } else { 01724 if (r.count == 0) 01725 recur->setMonthly(Recurrence::rMonthlyDay,r.interval,-1); 01726 else 01727 recur->setMonthly(Recurrence::rMonthlyDay,r.interval,r.count); 01728 } 01729 while((day = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 01730 // kdDebug(5800) << "----b " << day << endl; 01731 recur->addMonthlyDay(day); 01732 } 01733 } 01734 break; 01735 case ICAL_YEARLY_RECURRENCE: 01736 if (r.by_year_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { 01737 if (!icaltime_is_null_time(r.until)) { 01738 recur->setYearly(Recurrence::rYearlyDay,r.interval, 01739 readICalDate(r.until)); 01740 } else { 01741 if (r.count == 0) 01742 recur->setYearly(Recurrence::rYearlyDay,r.interval,-1); 01743 else 01744 recur->setYearly(Recurrence::rYearlyDay,r.interval,r.count); 01745 } 01746 while((day = r.by_year_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 01747 recur->addYearlyNum(day); 01748 } 01749 } if (r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX) { 01750 if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { 01751 if (!icaltime_is_null_time(r.until)) { 01752 recur->setYearly(Recurrence::rYearlyPos,r.interval, 01753 readICalDate(r.until)); 01754 } else { 01755 if (r.count == 0) 01756 recur->setYearly(Recurrence::rYearlyPos,r.interval,-1); 01757 else 01758 recur->setYearly(Recurrence::rYearlyPos,r.interval,r.count); 01759 } 01760 bool useSetPos = false; 01761 short pos = 0; 01762 while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 01763 // kdDebug(5800) << "----a " << index << ": " << day << endl; 01764 pos = icalrecurrencetype_day_position(day); 01765 if (pos) { 01766 day = icalrecurrencetype_day_day_of_week(day); 01767 QBitArray ba(7); // don't wipe qba 01768 ba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0 01769 recur->addYearlyMonthPos(pos,ba); 01770 } else { 01771 qba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0 01772 useSetPos = true; 01773 } 01774 } 01775 if (useSetPos) { 01776 if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) { 01777 recur->addYearlyMonthPos(r.by_set_pos[0],qba); 01778 } 01779 } 01780 } else { 01781 if (!icaltime_is_null_time(r.until)) { 01782 recur->setYearly(Recurrence::rYearlyMonth,r.interval, 01783 readICalDate(r.until)); 01784 } else { 01785 if (r.count == 0) 01786 recur->setYearly(Recurrence::rYearlyMonth,r.interval,-1); 01787 else 01788 recur->setYearly(Recurrence::rYearlyMonth,r.interval,r.count); 01789 } 01790 while((day = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 01791 recur->addMonthlyDay(day); 01792 } 01793 } 01794 index = 0; 01795 while((day = r.by_month[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 01796 recur->addYearlyNum(day); 01797 } 01798 } 01799 break; 01800 default: 01801 kdDebug(5800) << "Unknown type of recurrence: " << r.freq << endl; 01802 break; 01803 } 01804 } 01805 01806 void ICalFormatImpl::readAlarm(icalcomponent *alarm,Incidence *incidence) 01807 { 01808 //kdDebug(5800) << "Read alarm for " << incidence->summary() << endl; 01809 01810 Alarm* ialarm = incidence->newAlarm(); 01811 ialarm->setRepeatCount(0); 01812 ialarm->setEnabled(true); 01813 01814 // Determine the alarm's action type 01815 icalproperty *p = icalcomponent_get_first_property(alarm,ICAL_ACTION_PROPERTY); 01816 Alarm::Type type = Alarm::Display; 01817 icalproperty_action action = ICAL_ACTION_DISPLAY; 01818 if ( !p ) { 01819 kdDebug(5800) << "Unknown type of alarm, using default" << endl; 01820 // return; 01821 } else { 01822 01823 action = icalproperty_get_action(p); 01824 switch ( action ) { 01825 case ICAL_ACTION_DISPLAY: type = Alarm::Display; break; 01826 case ICAL_ACTION_AUDIO: type = Alarm::Audio; break; 01827 case ICAL_ACTION_PROCEDURE: type = Alarm::Procedure; break; 01828 case ICAL_ACTION_EMAIL: type = Alarm::Email; break; 01829 default: 01830 kdDebug(5800) << "Unknown type of alarm: " << action << endl; 01831 // type = Alarm::Invalid; 01832 } 01833 } 01834 ialarm->setType(type); 01835 01836 p = icalcomponent_get_first_property(alarm,ICAL_ANY_PROPERTY); 01837 while (p) { 01838 icalproperty_kind kind = icalproperty_isa(p); 01839 01840 switch (kind) { 01841 01842 case ICAL_TRIGGER_PROPERTY: { 01843 icaltriggertype trigger = icalproperty_get_trigger(p); 01844 if (icaltime_is_null_time(trigger.time)) { 01845 if (icaldurationtype_is_null_duration(trigger.duration)) { 01846 kdDebug(5800) << "ICalFormatImpl::readAlarm(): Trigger has no time and no duration." << endl; 01847 } else { 01848 Duration duration = icaldurationtype_as_int( trigger.duration ); 01849 icalparameter *param = icalproperty_get_first_parameter(p,ICAL_RELATED_PARAMETER); 01850 if (param && icalparameter_get_related(param) == ICAL_RELATED_END) 01851 ialarm->setEndOffset(duration); 01852 else 01853 ialarm->setStartOffset(duration); 01854 } 01855 } else { 01856 ialarm->setTime(readICalDateTime(trigger.time)); 01857 } 01858 break; 01859 } 01860 case ICAL_DURATION_PROPERTY: { 01861 icaldurationtype duration = icalproperty_get_duration(p); 01862 ialarm->setSnoozeTime(icaldurationtype_as_int(duration)/60); 01863 break; 01864 } 01865 case ICAL_REPEAT_PROPERTY: 01866 ialarm->setRepeatCount(icalproperty_get_repeat(p)); 01867 break; 01868 01869 // Only in DISPLAY and EMAIL and PROCEDURE alarms 01870 case ICAL_DESCRIPTION_PROPERTY: { 01871 QString description = QString::fromUtf8(icalproperty_get_description(p)); 01872 switch ( action ) { 01873 case ICAL_ACTION_DISPLAY: 01874 ialarm->setText( description ); 01875 break; 01876 case ICAL_ACTION_PROCEDURE: 01877 ialarm->setProgramArguments( description ); 01878 break; 01879 case ICAL_ACTION_EMAIL: 01880 ialarm->setMailText( description ); 01881 break; 01882 default: 01883 break; 01884 } 01885 break; 01886 } 01887 // Only in EMAIL alarm 01888 case ICAL_SUMMARY_PROPERTY: 01889 ialarm->setMailSubject(QString::fromUtf8(icalproperty_get_summary(p))); 01890 break; 01891 01892 // Only in EMAIL alarm 01893 case ICAL_ATTENDEE_PROPERTY: { 01894 QString email = QString::fromUtf8(icalproperty_get_attendee(p)); 01895 QString name; 01896 icalparameter *param = icalproperty_get_first_parameter(p,ICAL_CN_PARAMETER); 01897 if (param) { 01898 name = QString::fromUtf8(icalparameter_get_cn(param)); 01899 } 01900 ialarm->addMailAddress(Person(name, email)); 01901 break; 01902 } 01903 // Only in AUDIO and EMAIL and PROCEDURE alarms 01904 case ICAL_ATTACH_PROPERTY: { 01905 icalattachtype *attach = icalproperty_get_attach(p); 01906 QString url = QFile::decodeName(icalattachtype_get_url(attach)); 01907 switch ( action ) { 01908 case ICAL_ACTION_AUDIO: 01909 ialarm->setAudioFile( url ); 01910 break; 01911 case ICAL_ACTION_PROCEDURE: 01912 ialarm->setProgramFile( url ); 01913 break; 01914 case ICAL_ACTION_EMAIL: 01915 ialarm->addMailAttachment( url ); 01916 break; 01917 default: 01918 break; 01919 } 01920 break; 01921 } 01922 default: 01923 break; 01924 } 01925 01926 p = icalcomponent_get_next_property(alarm,ICAL_ANY_PROPERTY); 01927 } 01928 01929 // custom properties 01930 readCustomProperties(alarm, ialarm); 01931 01932 // TODO: check for consistency of alarm properties 01933 } 01934 01935 icaltimetype ICalFormatImpl::writeICalDate(const QDate &date) 01936 { 01937 icaltimetype t; 01938 01939 t.year = date.year(); 01940 t.month = date.month(); 01941 t.day = date.day(); 01942 01943 t.hour = 0; 01944 t.minute = 0; 01945 t.second = 0; 01946 01947 t.is_date = 1; 01948 01949 t.is_utc = 0; 01950 01951 t.zone = 0; 01952 01953 return t; 01954 } 01955 01956 icaltimetype ICalFormatImpl::writeICalDateTime(const QDateTime &datetime) 01957 { 01958 icaltimetype t; 01959 01960 t.year = datetime.date().year(); 01961 t.month = datetime.date().month(); 01962 t.day = datetime.date().day(); 01963 01964 t.hour = datetime.time().hour(); 01965 t.minute = datetime.time().minute(); 01966 t.second = datetime.time().second(); 01967 01968 t.is_date = 0; 01969 t.zone = 0; 01970 t.is_utc = 0; 01971 01972 if ( mParent->utc() ) { 01973 if (mParent->timeZoneId().isEmpty()) 01974 t = icaltime_as_utc(t, 0); 01975 else 01976 t = icaltime_as_utc(t,mParent->timeZoneId().utf8()); 01977 } 01978 01979 return t; 01980 } 01981 01982 QDateTime ICalFormatImpl::readICalDateTime(icaltimetype t) 01983 { 01984 /* 01985 kdDebug(5800) << "ICalFormatImpl::readICalDateTime()" << endl; 01986 kdDebug(5800) << "--- Y: " << t.year << " M: " << t.month << " D: " << t.day 01987 << endl; 01988 kdDebug(5800) << "--- H: " << t.hour << " M: " << t.minute << " S: " << t.second 01989 << endl; 01990 kdDebug(5800) << "--- isDate: " << t.is_date << endl; 01991 kdDebug(5800) << "--- isUtc: " << t.is_utc << endl; 01992 kdDebug(5800) << "--- zoneId: " << t.zone << endl; 01993 */ 01994 01995 // First convert the time into UTC if required. 01996 if ( !t.is_utc && t.zone ) { 01997 Timezone *timezone; 01998 01999 // Always lookup with quotes. 02000 if (t.zone[0] != '"') { 02001 timezone = mTimezones.find(QString("\"") + t.zone + '"'); 02002 } else { 02003 timezone = mTimezones.find(t.zone); 02004 } 02005 if (timezone) { 02006 // Apply the offset, and mark the structure as UTC! 02007 t.second -= timezone->offset(t); 02008 t = icaltime_normalize(t); 02009 t.is_utc = 1; 02010 } else { 02011 kdError(5800) << "ICalFormatImpl::readICalDateTime() cannot find timezone " 02012 << t.zone << endl; 02013 } 02014 } 02015 02016 if ( t.is_utc && mCompat->useTimeZoneShift() ) { 02017 // kdDebug(5800) << "--- Converting time to zone '" << cal->timeZoneId() << "'." << endl; 02018 if (mParent->timeZoneId().isEmpty()) 02019 t = icaltime_as_zone(t, 0); 02020 else 02021 t = icaltime_as_zone(t,mParent->timeZoneId().utf8()); 02022 } 02023 QDateTime result(QDate(t.year,t.month,t.day), 02024 QTime(t.hour,t.minute,t.second)); 02025 02026 return result; 02027 } 02028 02029 QDate ICalFormatImpl::readICalDate(icaltimetype t) 02030 { 02031 return QDate(t.year,t.month,t.day); 02032 } 02033 02034 icaldurationtype ICalFormatImpl::writeICalDuration(int seconds) 02035 { 02036 icaldurationtype d; 02037 02038 d.weeks = seconds % gSecondsPerWeek; 02039 seconds -= d.weeks * gSecondsPerWeek; 02040 d.days = seconds % gSecondsPerDay; 02041 seconds -= d.days * gSecondsPerDay; 02042 d.hours = seconds % gSecondsPerHour; 02043 seconds -= d.hours * gSecondsPerHour; 02044 d.minutes = seconds % gSecondsPerMinute; 02045 seconds -= d.minutes * gSecondsPerMinute; 02046 d.seconds = seconds; 02047 d.is_neg = 0; 02048 02049 return d; 02050 } 02051 02052 int ICalFormatImpl::readICalDuration(icaldurationtype d) 02053 { 02054 int result = 0; 02055 02056 result += d.weeks * gSecondsPerWeek; 02057 result += d.days * gSecondsPerDay; 02058 result += d.hours * gSecondsPerHour; 02059 result += d.minutes * gSecondsPerMinute; 02060 result += d.seconds; 02061 02062 if (d.is_neg) result *= -1; 02063 02064 return result; 02065 } 02066 02067 icalcomponent *ICalFormatImpl::createCalendarComponent(Calendar *cal) 02068 { 02069 icalcomponent *calendar; 02070 02071 // Root component 02072 calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT); 02073 02074 icalproperty *p; 02075 02076 // Product Identifier 02077 p = icalproperty_new_prodid(CalFormat::productId().utf8()); 02078 icalcomponent_add_property(calendar,p); 02079 02080 // TODO: Add time zone 02081 02082 // iCalendar version (2.0) 02083 p = icalproperty_new_version(const_cast<char *>(_ICAL_VERSION)); 02084 icalcomponent_add_property(calendar,p); 02085 02086 // Custom properties 02087 if( cal != 0 ) 02088 writeCustomProperties(calendar, cal); 02089 02090 return calendar; 02091 } 02092 02093 02094 02095 // take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc. 02096 // and break it down from its tree-like format into the dictionary format 02097 // that is used internally in the ICalFormatImpl. 02098 bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar) 02099 { 02100 // this function will populate the caldict dictionary and other event 02101 // lists. It turns vevents into Events and then inserts them. 02102 02103 if (!calendar) return false; 02104 02105 // TODO: check for METHOD 02106 #if 0 02107 if ((curVO = isAPropertyOf(vcal, ICMethodProp)) != 0) { 02108 char *methodType = 0; 02109 methodType = fakeCString(vObjectUStringZValue(curVO)); 02110 if (mEnableDialogs) 02111 KMessageBox::information(mTopWidget, 02112 i18n("This calendar is an iTIP transaction of type \"%1\".") 02113 .arg(methodType), 02114 i18n("%1: iTIP Transaction").arg(CalFormat::application())); 02115 delete methodType; 02116 } 02117 #endif 02118 02119 icalproperty *p; 02120 02121 p = icalcomponent_get_first_property(calendar,ICAL_PRODID_PROPERTY); 02122 if (!p) { 02123 kdDebug(5800) << "No PRODID property found" << endl; 02124 // TODO: does no PRODID really matter? 02125 // mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown)); 02126 // return false; 02127 mLoadedProductId = ""; 02128 mCalendarVersion = 0; 02129 } else { 02130 mLoadedProductId = QString::fromUtf8(icalproperty_get_prodid(p)); 02131 mCalendarVersion = CalFormat::calendarVersion(mLoadedProductId.latin1()); 02132 kdDebug(5800) << "VCALENDAR prodid: '" << mLoadedProductId << "'" << endl; 02133 02134 delete mCompat; 02135 mCompat = CompatFactory::createCompat( mLoadedProductId ); 02136 } 02137 02138 // TODO: check for unknown PRODID 02139 #if 0 02140 if (!mCalendarVersion 02141 && CalFormat::productId() != mLoadedProductId) { 02142 // warn the user that we might have trouble reading non-known calendar. 02143 if (mEnableDialogs) 02144 KMessageBox::information(mTopWidget, 02145 i18n("This vCalendar file was not created by KOrganizer " 02146 "or any other product we support. Loading anyway..."), 02147 i18n("%1: Unknown vCalendar Vendor").arg(CalFormat::application())); 02148 } 02149 #endif 02150 02151 p = icalcomponent_get_first_property(calendar,ICAL_VERSION_PROPERTY); 02152 if (!p) { 02153 kdDebug(5800) << "No VERSION property found" << endl; 02154 mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown)); 02155 return false; 02156 } else { 02157 const char *version = icalproperty_get_version(p); 02158 kdDebug(5800) << "VCALENDAR version: '" << version << "'" << endl; 02159 02160 if (strcmp(version,"1.0") == 0) { 02161 kdDebug(5800) << "Expected iCalendar, got vCalendar" << endl; 02162 mParent->setException(new ErrorFormat(ErrorFormat::CalVersion1, 02163 i18n("Expected iCalendar format"))); 02164 return false; 02165 } else if (strcmp(version,"2.0") != 0) { 02166 kdDebug(5800) << "Expected iCalendar, got unknown format" << endl; 02167 mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown)); 02168 return false; 02169 } 02170 } 02171 02172 02173 // TODO: check for calendar format version 02174 #if 0 02175 // warn the user we might have trouble reading this unknown version. 02176 if ((curVO = isAPropertyOf(vcal, VCVersionProp)) != 0) { 02177 char *s = fakeCString(vObjectUStringZValue(curVO)); 02178 if (strcmp(_VCAL_VERSION, s) != 0) 02179 if (mEnableDialogs) 02180 KMessageBox::sorry(mTopWidget, 02181 i18n("This vCalendar file has version %1.\n" 02182 "We only support %2.") 02183 .arg(s).arg(_VCAL_VERSION), 02184 i18n("%1: Unknown vCalendar Version").arg(CalFormat::application())); 02185 deleteStr(s); 02186 } 02187 #endif 02188 02189 // custom properties 02190 readCustomProperties(calendar, cal); 02191 02192 // TODO: set time zone 02193 #if 0 02194 // set the time zone 02195 if ((curVO = isAPropertyOf(vcal, VCTimeZoneProp)) != 0) { 02196 char *s = fakeCString(vObjectUStringZValue(curVO)); 02197 cal->setTimeZone(s); 02198 deleteStr(s); 02199 } 02200 #endif 02201 02202 // Store all events with a relatedTo property in a list for post-processing 02203 mEventsRelate.clear(); 02204 mTodosRelate.clear(); 02205 // TODO: make sure that only actually added ecvens go to this lists. 02206 02207 icalcomponent *c; 02208 02209 // Iterate through all timezones before we do anything else. That way, the 02210 // information needed to interpret times in actually useful objects is 02211 // available below. 02212 c = icalcomponent_get_first_component(calendar,ICAL_VTIMEZONE_COMPONENT); 02213 while (c) { 02214 // kdDebug(5800) << "----Timezone found" << endl; 02215 readTimezone(c); 02216 c = icalcomponent_get_next_component(calendar,ICAL_VTIMEZONE_COMPONENT); 02217 } 02218 02219 // Iterate through all todos 02220 c = icalcomponent_get_first_component(calendar,ICAL_VTODO_COMPONENT); 02221 while (c) { 02222 // kdDebug(5800) << "----Todo found" << endl; 02223 Todo *todo = readTodo(c); 02224 if (!cal->todo(todo->uid())) cal->addTodo(todo); 02225 c = icalcomponent_get_next_component(calendar,ICAL_VTODO_COMPONENT); 02226 } 02227 02228 // Iterate through all events 02229 c = icalcomponent_get_first_component(calendar,ICAL_VEVENT_COMPONENT); 02230 while (c) { 02231 // kdDebug(5800) << "----Event found" << endl; 02232 Event *event = readEvent(c); 02233 if (!cal->event(event->uid())) cal->addEvent(event); 02234 c = icalcomponent_get_next_component(calendar,ICAL_VEVENT_COMPONENT); 02235 } 02236 02237 // Iterate through all journals 02238 c = icalcomponent_get_first_component(calendar,ICAL_VJOURNAL_COMPONENT); 02239 while (c) { 02240 // kdDebug(5800) << "----Journal found" << endl; 02241 Journal *journal = readJournal(c); 02242 if (!cal->journal(journal->uid())) cal->addJournal(journal); 02243 c = icalcomponent_get_next_component(calendar,ICAL_VJOURNAL_COMPONENT); 02244 } 02245 02246 #if 0 02247 initPropIterator(&i, vcal); 02248 02249 // go through all the vobjects in the vcal 02250 while (moreIteration(&i)) { 02251 curVO = nextVObject(&i); 02252 02253 /************************************************************************/ 02254 02255 // now, check to see that the object is an event or todo. 02256 if (strcmp(vObjectName(curVO), VCEventProp) == 0) { 02257 02258 if ((curVOProp = isAPropertyOf(curVO, KPilotStatusProp)) != 0) { 02259 char *s; 02260 s = fakeCString(vObjectUStringZValue(curVOProp)); 02261 // check to see if event was deleted by the kpilot conduit 02262 if (atoi(s) == Event::SYNCDEL) { 02263 deleteStr(s); 02264 kdDebug(5800) << "skipping pilot-deleted event" << endl; 02265 goto SKIP; 02266 } 02267 deleteStr(s); 02268 } 02269 02270 // this code checks to see if we are trying to read in an event 02271 // that we already find to be in the calendar. If we find this 02272 // to be the case, we skip the event. 02273 if ((curVOProp = isAPropertyOf(curVO, VCUniqueStringProp)) != 0) { 02274 char *s = fakeCString(vObjectUStringZValue(curVOProp)); 02275 QString tmpStr(s); 02276 deleteStr(s); 02277 02278 if (cal->event(tmpStr)) { 02279 goto SKIP; 02280 } 02281 if (cal->todo(tmpStr)) { 02282 goto SKIP; 02283 } 02284 } 02285 02286 if ((!(curVOProp = isAPropertyOf(curVO, VCDTstartProp))) && 02287 (!(curVOProp = isAPropertyOf(curVO, VCDTendProp)))) { 02288 kdDebug(5800) << "found a VEvent with no DTSTART and no DTEND! Skipping..." << endl; 02289 goto SKIP; 02290 } 02291 02292 anEvent = VEventToEvent(curVO); 02293 // we now use addEvent instead of insertEvent so that the 02294 // signal/slot get connected. 02295 if (anEvent) 02296 cal->addEvent(anEvent); 02297 else { 02298 // some sort of error must have occurred while in translation. 02299 goto SKIP; 02300 } 02301 } else if (strcmp(vObjectName(curVO), VCTodoProp) == 0) { 02302 anEvent = VTodoToEvent(curVO); 02303 cal->addTodo(anEvent); 02304 } else if ((strcmp(vObjectName(curVO), VCVersionProp) == 0) || 02305 (strcmp(vObjectName(curVO), VCProdIdProp) == 0) || 02306 (strcmp(vObjectName(curVO), VCTimeZoneProp) == 0)) { 02307 // do nothing, we know these properties and we want to skip them. 02308 // we have either already processed them or are ignoring them. 02309 ; 02310 } else { 02311 kdDebug(5800) << "Ignoring unknown vObject \"" << vObjectName(curVO) << "\"" << endl; 02312 } 02313 SKIP: 02314 ; 02315 } // while 02316 #endif 02317 02318 // Post-Process list of events with relations, put Event objects in relation 02319 Event::List::ConstIterator eIt; 02320 for ( eIt = mEventsRelate.begin(); eIt != mEventsRelate.end(); ++eIt ) { 02321 (*eIt)->setRelatedTo( cal->incidence( (*eIt)->relatedToUid() ) ); 02322 } 02323 Todo::List::ConstIterator tIt; 02324 for ( tIt = mTodosRelate.begin(); tIt != mTodosRelate.end(); ++tIt ) { 02325 (*tIt)->setRelatedTo( cal->incidence( (*tIt)->relatedToUid() ) ); 02326 } 02327 02328 return true; 02329 } 02330 02331 QString ICalFormatImpl::extractErrorProperty(icalcomponent *c) 02332 { 02333 // kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: " 02334 // << icalcomponent_as_ical_string(c) << endl; 02335 02336 QString errorMessage; 02337 02338 icalproperty *error; 02339 error = icalcomponent_get_first_property(c,ICAL_XLICERROR_PROPERTY); 02340 while(error) { 02341 errorMessage += icalproperty_get_xlicerror(error); 02342 errorMessage += "\n"; 02343 error = icalcomponent_get_next_property(c,ICAL_XLICERROR_PROPERTY); 02344 } 02345 02346 // kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: " << errorMessage << endl; 02347 02348 return errorMessage; 02349 } 02350 02351 void ICalFormatImpl::dumpIcalRecurrence(icalrecurrencetype r) 02352 { 02353 int i; 02354 02355 kdDebug(5800) << " Freq: " << r.freq << endl; 02356 kdDebug(5800) << " Until: " << icaltime_as_ctime(r.until) << endl; 02357 kdDebug(5800) << " Count: " << r.count << endl; 02358 if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { 02359 int index = 0; 02360 QString out = " By Day: "; 02361 while((i = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 02362 out.append(QString::number(i) + " "); 02363 } 02364 kdDebug(5800) << out << endl; 02365 } 02366 if (r.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { 02367 int index = 0; 02368 QString out = " By Month Day: "; 02369 while((i = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 02370 out.append(QString::number(i) + " "); 02371 } 02372 kdDebug(5800) << out << endl; 02373 } 02374 if (r.by_year_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { 02375 int index = 0; 02376 QString out = " By Year Day: "; 02377 while((i = r.by_year_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 02378 out.append(QString::number(i) + " "); 02379 } 02380 kdDebug(5800) << out << endl; 02381 } 02382 if (r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX) { 02383 int index = 0; 02384 QString out = " By Month: "; 02385 while((i = r.by_month[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 02386 out.append(QString::number(i) + " "); 02387 } 02388 kdDebug(5800) << out << endl; 02389 } 02390 if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) { 02391 int index = 0; 02392 QString out = " By Set Pos: "; 02393 while((i = r.by_set_pos[index++]) != ICAL_RECURRENCE_ARRAY_MAX) { 02394 kdDebug(5800) << "========= " << i << endl; 02395 out.append(QString::number(i) + " "); 02396 } 02397 kdDebug(5800) << out << endl; 02398 } 02399 } 02400 02401 icalcomponent *ICalFormatImpl::createScheduleComponent(IncidenceBase *incidence, 02402 Scheduler::Method method) 02403 { 02404 icalcomponent *message = createCalendarComponent(); 02405 02406 icalproperty_method icalmethod = ICAL_METHOD_NONE; 02407 02408 switch (method) { 02409 case Scheduler::Publish: 02410 icalmethod = ICAL_METHOD_PUBLISH; 02411 break; 02412 case Scheduler::Request: 02413 icalmethod = ICAL_METHOD_REQUEST; 02414 break; 02415 case Scheduler::Refresh: 02416 icalmethod = ICAL_METHOD_REFRESH; 02417 break; 02418 case Scheduler::Cancel: 02419 icalmethod = ICAL_METHOD_CANCEL; 02420 break; 02421 case Scheduler::Add: 02422 icalmethod = ICAL_METHOD_ADD; 02423 break; 02424 case Scheduler::Reply: 02425 icalmethod = ICAL_METHOD_REPLY; 02426 break; 02427 case Scheduler::Counter: 02428 icalmethod = ICAL_METHOD_COUNTER; 02429 break; 02430 case Scheduler::Declinecounter: 02431 icalmethod = ICAL_METHOD_DECLINECOUNTER; 02432 break; 02433 default: 02434 kdDebug(5800) << "ICalFormat::createScheduleMessage(): Unknow method" << endl; 02435 return message; 02436 } 02437 02438 icalcomponent_add_property(message,icalproperty_new_method(icalmethod)); 02439 02440 // TODO: check, if dynamic cast is required 02441 if(incidence->type() == "Todo") { 02442 Todo *todo = static_cast<Todo *>(incidence); 02443 icalcomponent_add_component(message,writeTodo(todo)); 02444 } 02445 if(incidence->type() == "Event") { 02446 Event *event = static_cast<Event *>(incidence); 02447 icalcomponent_add_component(message,writeEvent(event)); 02448 } 02449 if(incidence->type() == "FreeBusy") { 02450 FreeBusy *freebusy = static_cast<FreeBusy *>(incidence); 02451 icalcomponent_add_component(message,writeFreeBusy(freebusy, method)); 02452 } 02453 02454 return message; 02455 } 02456 02457 // This function reads any TZID setting for an icaltime. TBD: incorporate 02458 // this into icalproperty_get_datetime() so it is picked up everywhere as 02459 // needed? 02460 void ICalFormatImpl::readTzidParameter( icalcomponent *p, 02461 icaltimetype &icaltime ) 02462 { 02463 icalproperty *tzp = icalproperty_get_first_parameter( p, 02464 ICAL_TZID_PARAMETER ); 02465 if ( tzp ) { 02466 icaltime.zone = icalparameter_get_tzid( tzp ); 02467 } 02468 } 02469
KDE Logo
This file is part of the documentation for libkcal Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:57:44 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003