00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 static const char *vcalconduit_id = "$Id: vcal-conduit.cc,v 1.96 2003/12/26 20:55:58 adridg Exp $";
00031
00032 #include <options.h>
00033 #include <unistd.h>
00034
00035 #include <qdatetime.h>
00036 #include <qtimer.h>
00037
00038 #include <pilotUser.h>
00039 #include <kconfig.h>
00040
00041 #include <libkcal/calendarlocal.h>
00042
00043
00044
00045
00046
00047 #ifdef KDE2
00048 #include <korecurrence.h>
00049 #define Recurrence_t KCal::KORecurrence
00050 #define DateList_t QDateList
00051 #define DateListIterator_t QDateListIterator
00052 #else
00053 #include <libkcal/recurrence.h>
00054 #define Recurrence_t KCal::Recurrence
00055 #define DateList_t KCal::DateList
00056 #define DateListIterator_t KCal::DateList::ConstIterator
00057 #endif
00058
00059 #include <pilotSerialDatabase.h>
00060 #include <pilotLocalDatabase.h>
00061
00062 #include "vcal-conduit.moc"
00063
00064
00065
00066
00067
00068 VCalConduitPrivate::VCalConduitPrivate(KCal::Calendar *b) :
00069 VCalConduitPrivateBase(b)
00070 {
00071 fAllEvents.setAutoDelete(false);
00072 }
00073
00074 void VCalConduitPrivate::addIncidence(KCal::Incidence*e)
00075 {
00076 fAllEvents.append(dynamic_cast<KCal::Event*>(e));
00077 fCalendar->addEvent(dynamic_cast<KCal::Event*>(e));
00078 }
00079
00080 int VCalConduitPrivate::updateIncidences()
00081 {
00082 FUNCTIONSETUP;
00083 if (!fCalendar) return 0;
00084 fAllEvents = fCalendar->events();
00085 fAllEvents.setAutoDelete(false);
00086 return fAllEvents.count();
00087 }
00088
00089
00090 void VCalConduitPrivate::removeIncidence(KCal::Incidence *e)
00091 {
00092
00093 fAllEvents.remove(dynamic_cast<KCal::Event*>(e));
00094 if (!fCalendar) return;
00095 fCalendar->deleteEvent(dynamic_cast<KCal::Event*>(e));
00096 }
00097
00098
00099 KCal::Incidence *VCalConduitPrivate::findIncidence(recordid_t id)
00100 {
00101 KCal::Event::List::ConstIterator it;
00102 for( it = fAllEvents.begin(); it != fAllEvents.end(); ++it ) {
00103 KCal::Event *event = *it;
00104 if ((recordid_t)event->pilotId() == id) return event;
00105 }
00106 return 0L;
00107 }
00108
00109 KCal::Incidence *VCalConduitPrivate::findIncidence(PilotAppCategory*tosearch)
00110 {
00111 PilotDateEntry*entry=dynamic_cast<PilotDateEntry*>(tosearch);
00112 if (!entry) return 0L;
00113
00114 QString title=entry->getDescription();
00115 QDateTime dt=readTm( entry->getEventStart() );
00116
00117 KCal::Event::List::ConstIterator it;
00118 for( it = fAllEvents.begin(); it != fAllEvents.end(); ++it ) {
00119 KCal::Event *event = *it;
00120 if ( (event->dtStart() == dt) && (event->summary() == title) ) return event;
00121 }
00122 return 0L;
00123 }
00124
00125
00126
00127 KCal::Incidence *VCalConduitPrivate::getNextIncidence()
00128 {
00129 FUNCTIONSETUP;
00130 if (reading) {
00131 ++fAllEventsIterator;
00132 if ( fAllEventsIterator == fAllEvents.end() ) return 0;
00133 } else {
00134 reading=true;
00135 fAllEventsIterator = fAllEvents.begin();
00136 }
00137 return *fAllEventsIterator;
00138 }
00139
00144 KCal::Incidence *VCalConduitPrivate::getNextModifiedIncidence()
00145 {
00146 FUNCTIONSETUP;
00147 KCal::Event*e=0L;
00148 if (!reading)
00149 {
00150 reading=true;
00151 fAllEventsIterator = fAllEvents.begin();
00152 if ( fAllEventsIterator != fAllEvents.end() ) e = *fAllEventsIterator;
00153 }
00154 else
00155 {
00156 ++fAllEventsIterator;
00157 }
00158 while ( fAllEventsIterator != fAllEvents.end() &&
00159 e && e->syncStatus()==KCal::Incidence::SYNCNONE)
00160 {
00161 ++fAllEventsIterator;
00162 e=*fAllEventsIterator;
00163 }
00164 if ( fAllEventsIterator == fAllEvents.end() ) return 0;
00165 else return *fAllEventsIterator;
00166 }
00167
00168
00169
00170
00171
00172
00173
00174 VCalConduit::VCalConduit(KPilotDeviceLink *d,
00175 const char *n,
00176 const QStringList &a) : VCalConduitBase(d,n,a)
00177 {
00178 FUNCTIONSETUP;
00179 #ifdef DEBUG
00180 DEBUGCONDUIT << vcalconduit_id << endl;
00181 #endif
00182 fConduitName=i18n("Calendar");
00183 (void) vcalconduit_id;
00184 }
00185
00186
00187 VCalConduit::~VCalConduit()
00188 {
00189
00190 }
00191
00192 VCalConduitPrivateBase* VCalConduit::newVCalPrivate(KCal::Calendar *fCalendar) {
00193 return new VCalConduitPrivate(fCalendar);
00194 }
00195
00196 const QString VCalConduit::getTitle(PilotAppCategory*de)
00197 {
00198 PilotDateEntry*d=dynamic_cast<PilotDateEntry*>(de);
00199 if (d) return QString(d->getDescription());
00200 return QString::null;
00201 }
00202
00203
00204
00205 PilotRecord*VCalConduit::recordFromIncidence(PilotAppCategory*de, const KCal::Incidence*e)
00206 {
00207 FUNCTIONSETUP;
00208 if (!de || !e)
00209 {
00210 #ifdef DEBUG
00211 DEBUGCONDUIT<<fname<<": got null entry or null incidence."<<endl;
00212 #endif
00213 return NULL;
00214 }
00215 return recordFromIncidence(dynamic_cast<PilotDateEntry*>(de), dynamic_cast<const KCal::Event*>(e));
00216 }
00217
00218 PilotRecord*VCalConduit::recordFromIncidence(PilotDateEntry*de, const KCal::Event*e)
00219 {
00220 FUNCTIONSETUP;
00221 if (!de || !e) {
00222 #ifdef DEBUG
00223 DEBUGCONDUIT<<fname<<": NULL event given... Skipping it"<<endl;
00224 #endif
00225 return NULL;
00226 }
00227
00228
00229 if (e->secrecy()!=KCal::Event::SecrecyPublic) de->makeSecret();
00230
00231 setStartEndTimes(de, e);
00232 setAlarms(de, e);
00233 setRecurrence(de, e);
00234 setExceptions(de, e);
00235 de->setDescription(e->summary());
00236 de->setNote(e->description());
00237 DEBUGCONDUIT<<"-------- "<<e->summary()<<endl;
00238 return de->pack();
00239 }
00240
00241
00242 KCal::Incidence *VCalConduit::incidenceFromRecord(KCal::Incidence *e, const PilotAppCategory *de)
00243 {
00244 return dynamic_cast<KCal::Incidence*>(incidenceFromRecord(dynamic_cast<KCal::Event*>(e), dynamic_cast<const PilotDateEntry*>(de)));
00245 }
00246
00247
00248 KCal::Event *VCalConduit::incidenceFromRecord(KCal::Event *e, const PilotDateEntry *de)
00249 {
00250 FUNCTIONSETUP;
00251 if (!e) {
00252 #ifdef DEBUG
00253 DEBUGCONDUIT<<fname<<": NULL event given... Skipping it"<<endl;
00254 #endif
00255 return NULL;
00256 }
00257
00258 e->setOrganizer(fCalendar->getEmail());
00259 e->setSyncStatus(KCal::Incidence::SYNCNONE);
00260 e->setSecrecy(de->isSecret() ?
00261 KCal::Event::SecrecyPrivate :
00262 KCal::Event::SecrecyPublic);
00263
00264 e->setPilotId(de->getID());
00265 e->setSyncStatus(KCal::Incidence::SYNCNONE);
00266
00267 setStartEndTimes(e,de);
00268 setAlarms(e,de);
00269 setRecurrence(e,de);
00270 setExceptions(e,de);
00271
00272 e->setSummary(de->getDescription());
00273 #ifdef DEBUG
00274 DEBUGCONDUIT<<fname<<": DESCRIPTION: "<<de->getDescription()<<" ---------------------------------------------------"<<endl;
00275 #endif
00276 e->setDescription(de->getNote());
00277
00278 return e;
00279 }
00280
00281
00282 void VCalConduit::setStartEndTimes(KCal::Event *e,const PilotDateEntry *de)
00283 {
00284 FUNCTIONSETUP;
00285 e->setDtStart(readTm(de->getEventStart()));
00286 #ifdef DEBUG
00287 DEBUGCONDUIT<<"Start time on Palm: "<<readTm(de->getEventStart()).toString()<<", on PC: "<<e->dtStart().toString()<<endl;
00288 #endif
00289 e->setFloats(de->isEvent());
00290
00291 if (de->isMultiDay())
00292 {
00293 e->setDtEnd(readTm(de->getRepeatEnd()));
00294 }
00295 else
00296 {
00297 e->setDtEnd(readTm(de->getEventEnd()));
00298 }
00299 }
00300
00301
00302 void VCalConduit::setStartEndTimes(PilotDateEntry*de, const KCal::Event *e)
00303 {
00304 FUNCTIONSETUP;
00305 struct tm ttm=writeTm(e->dtStart());
00306 de->setEventStart(ttm);
00307 de->setEvent(e->doesFloat());
00308
00309 if (e->hasEndDate() && e->dtEnd().isValid())
00310 {
00311 ttm=writeTm(e->dtEnd());
00312 }
00313 else
00314 {
00315 ttm=writeTm(e->dtStart());
00316 }
00317 de->setEventEnd(ttm);
00318 }
00319
00320
00321 void VCalConduit::setAlarms(KCal::Event *e, const PilotDateEntry *de)
00322 {
00323 FUNCTIONSETUP;
00324
00325 if (!e) return;
00326
00327 e->clearAlarms();
00328 if (!de->getAlarm()) return;
00329
00330
00331 int advanceUnits = de->getAdvanceUnits();
00332
00333 switch (advanceUnits)
00334 {
00335 case advMinutes:
00336 advanceUnits = 1;
00337 break;
00338 case advHours:
00339 advanceUnits = 60;
00340 break;
00341 case advDays:
00342 advanceUnits = 60*24;
00343 break;
00344 default:
00345 #ifdef DEBUG
00346 DEBUGCONDUIT << fname
00347 << ": Unknown advance units "
00348 << advanceUnits
00349 << endl;
00350 #endif
00351 advanceUnits=1;
00352 }
00353
00354 KCal::Duration adv(-60*advanceUnits*de->getAdvance());
00355 KCal::Alarm*alm=e->newAlarm();
00356 if (!alm) return;
00357
00358 alm->setStartOffset(adv);
00359 alm->setEnabled(true);
00360 }
00361
00362
00363
00364 void VCalConduit::setAlarms(PilotDateEntry*de, const KCal::Event *e)
00365 {
00366 FUNCTIONSETUP;
00367
00368 if (!de || !e )
00369 {
00370 #ifdef DEBUG
00371 DEBUGCONDUIT << fname << ": NULL entry given to setAlarms. "<<endl;
00372 #endif
00373 return;
00374 }
00375
00376 if ( !e->isAlarmEnabled() )
00377 {
00378 de->setAlarm(0);
00379 return;
00380 }
00381
00382
00383 KCal::Alarm::List alms=e->alarms();
00384 KCal::Alarm* alm=0;
00385 KCal::Alarm::List::ConstIterator it;
00386 for ( it = alms.begin(); it != alms.end(); ++it ) {
00387 if ((*it)->enabled()) alm=*it;
00388 }
00389
00390 if (!alm )
00391 {
00392 #ifdef DEBUG
00393 DEBUGCONDUIT << fname << ": no enabled alarm found (should exist!!!)"<<endl;
00394 #endif
00395 de->setAlarm(0);
00396 return;
00397 }
00398
00399
00400 int aoffs=-alm->startOffset().asSeconds()/60;
00401 int offs=(aoffs>0)?aoffs:-aoffs;
00402
00403
00404 if (offs>=100 || offs==60)
00405 {
00406 offs/=60;
00407 if (offs>=48 || offs==24)
00408 {
00409 offs/=24;
00410 de->setAdvanceUnits(advDays);
00411 }
00412 else
00413 {
00414 de->setAdvanceUnits(advHours);
00415 }
00416 }
00417 else
00418 {
00419 de->setAdvanceUnits(advMinutes);
00420 }
00421 de->setAdvance((aoffs>0)?offs:-offs);
00422 de->setAlarm(1);
00423 }
00424
00425
00426 void VCalConduit::setRecurrence(KCal::Event *event,const PilotDateEntry *dateEntry)
00427 {
00428 FUNCTIONSETUP;
00429
00430 if ((dateEntry->getRepeatType() == repeatNone) || dateEntry->isMultiDay())
00431 {
00432 #ifdef DEBUG
00433 DEBUGCONDUIT<<fname<<": no recurrence to set"<<endl;
00434 #endif
00435 return;
00436 }
00437
00438 Recurrence_t *recur = event->recurrence();
00439 int freq = dateEntry->getRepeatFrequency();
00440 bool repeatsForever = dateEntry->getRepeatForever();
00441 QDate endDate, evt;
00442
00443 if (!repeatsForever)
00444 {
00445 endDate = readTm(dateEntry->getRepeatEnd()).date();
00446 #ifdef DEBUG
00447 DEBUGCONDUIT << fname << "-- end " << endDate.toString() << endl;
00448 #endif
00449 }
00450 else
00451 {
00452 #ifdef DEBUG
00453 DEBUGCONDUIT << fname << "-- noend" << endl;
00454 #endif
00455 }
00456
00457 QBitArray dayArray(7);
00458
00459 switch(dateEntry->getRepeatType())
00460 {
00461 case repeatDaily:
00462 if (repeatsForever) recur->setDaily(freq,-1);
00463 else recur->setDaily(freq,endDate);
00464 break;
00465 case repeatWeekly:
00466 {
00467 const int *days = dateEntry->getRepeatDays();
00468
00469 #ifdef DEBUG
00470 DEBUGCONDUIT << fname
00471 << ": Got repeat-weekly entry, by-days="
00472 << days[0] << " "<< days[1] << " "<< days[2] << " "
00473 << days[3] << " "
00474 << days[4] << " "<< days[5] << " "<< days[6] << " "
00475 << endl;
00476 #endif
00477
00478
00479
00480
00481 if (days[0]) dayArray.setBit(6);
00482 for (int i = 1; i < 7; i++)
00483 {
00484 if (days[i]) dayArray.setBit(i-1);
00485 }
00486
00487 if (repeatsForever) recur->setWeekly(freq,dayArray,-1);
00488 else recur->setWeekly(freq,dayArray,endDate);
00489 }
00490 break;
00491 case repeatMonthlyByDay: {
00492
00493
00494
00495
00496
00497 if (repeatsForever)
00498 {
00499 recur->setMonthly(Recurrence_t::rMonthlyPos,freq,-1);
00500 }
00501 else
00502 {
00503 recur->setMonthly(Recurrence_t::rMonthlyPos,freq,endDate);
00504 }
00505
00506 int day=dateEntry->getRepeatDay();
00507 int week=day/7;
00508
00509 if (week==4) week=-1; else week++;
00510 dayArray.setBit((day+6) % 7);
00511 recur->addMonthlyPos(week, dayArray);
00512 break;}
00513 case repeatMonthlyByDate:
00514 if (repeatsForever)
00515 {
00516 recur->setMonthly(Recurrence_t::rMonthlyDay,freq,-1);
00517 }
00518 else
00519 {
00520 recur->setMonthly(Recurrence_t::rMonthlyDay,freq,endDate);
00521 }
00522 recur->addMonthlyDay( dateEntry->getEventStart().tm_mday );
00523 break;
00524 case repeatYearly:
00525 if (repeatsForever)
00526 {
00527 recur->setYearly(Recurrence_t::rYearlyMonth,freq,-1);
00528 }
00529 else
00530 {
00531 recur->setYearly(Recurrence_t::rYearlyMonth,freq,endDate);
00532 }
00533 evt=readTm(dateEntry->getEventStart()).date();
00534 recur->addYearlyNum( evt.month() );
00535
00536
00537 break;
00538 case repeatNone:
00539 default :
00540 #ifdef DEBUG
00541 DEBUGCONDUIT << fname
00542 << ": Can't handle repeat type "
00543 << dateEntry->getRepeatType()
00544 << endl;
00545 #endif
00546 break;
00547 }
00548 }
00549
00550
00551 void VCalConduit::setRecurrence(PilotDateEntry*dateEntry, const KCal::Event *event)
00552 {
00553 FUNCTIONSETUP;
00554 bool isMultiDay=false;
00555
00556
00557
00558
00559 QDateTime startDt(readTm(dateEntry->getEventStart())), endDt(readTm(dateEntry->getEventEnd()));
00560 if (startDt.daysTo(endDt))
00561 {
00562 isMultiDay=true;
00563 dateEntry->setRepeatType(repeatDaily);
00564 dateEntry->setRepeatFrequency(1);
00565 dateEntry->setRepeatEnd(dateEntry->getEventEnd());
00566 #ifdef DEBUG
00567 DEBUGCONDUIT << fname <<": Setting single-day recurrence (" << startDt.toString() << " - " << endDt.toString() << ")" <<endl;
00568 #endif
00569 }
00570
00571
00572 KCal::Recurrence*r=event->recurrence();
00573 if (!r) return;
00574 ushort recType=r->doesRecur();
00575 if (recType==KCal::Recurrence::rNone)
00576 {
00577 if (!isMultiDay) dateEntry->setRepeatType(repeatNone);
00578 return;
00579 }
00580
00581
00582 int freq=r->frequency();
00583 QDate endDate=r->endDate();
00584
00585 if (!endDate.isValid())
00586 {
00587 dateEntry->setRepeatForever();
00588 }
00589 else
00590 {
00591 dateEntry->setRepeatEnd(writeTm(endDate));
00592 }
00593 dateEntry->setRepeatFrequency(freq);
00594 #ifdef DEBUG
00595 DEBUGCONDUIT<<" Event: "<<event->summary()<<" ("<<event->description()<<")"<<endl;
00596 DEBUGCONDUIT<< "duration: "<<r->duration() << ", endDate: "<<endDate.toString()<< ", ValidEndDate: "<<endDate.isValid()<<", NullEndDate: "<<endDate.isNull()<<endl;
00597 #endif
00598
00599 QBitArray dayArray(7), dayArrayPalm(7);
00600 switch(recType)
00601 {
00602 case KCal::Recurrence::rDaily:
00603 dateEntry->setRepeatType(repeatDaily);
00604 break;
00605 case KCal::Recurrence::rWeekly:
00606 dateEntry->setRepeatType(repeatWeekly);
00607 dayArray=r->days();
00608
00609 for (int i=0; i<7; i++)
00610 {
00611 dayArrayPalm.setBit( (i+1)%7, dayArray[i]);
00612 }
00613 dateEntry->setRepeatDays(dayArrayPalm);
00614 break;
00615 case KCal::Recurrence::rMonthlyPos:
00616
00617
00618
00619
00620
00621 dateEntry->setRepeatType(repeatMonthlyByDay);
00622 if (r->monthPositions().count()>0)
00623 {
00624
00625 QPtrList<KCal::Recurrence::rMonthPos> mps=r->monthPositions();
00626 const KCal::Recurrence::rMonthPos*mp=mps.first();
00627 int pos=0;
00628 dayArray=mp->rDays;
00629
00630 for (int j=0; j<7; j++)
00631 if (dayArray[j]) pos=j;
00632 int week=mp->rPos;
00633 if (mp->negative) week*=-1;
00634 int day=(pos+1) % 7;
00635
00636 if (week==-1) week=4; else week--;
00637 dateEntry->setRepeatDay(static_cast<DayOfMonthType>(7*week + day));
00638 }
00639 break;
00640 case KCal::Recurrence::rMonthlyDay:
00641 dateEntry->setRepeatType(repeatMonthlyByDate);
00642
00643 break;
00644 case KCal::Recurrence::rYearlyDay:
00645 case KCal::Recurrence::rYearlyPos:
00646 emit logMessage(i18n("Event \"%1\" has a yearly recurrence other than by month, will change this to recurrence by month on handheld.").arg(event->summary()));
00647 case KCal::Recurrence::rYearlyMonth:
00648 dateEntry->setRepeatType(repeatYearly);
00649 break;
00650 case KCal::Recurrence::rNone:
00651 if (!isMultiDay) dateEntry->setRepeatType(repeatNone);
00652 break;
00653 default:
00654 #ifdef DEBUG
00655 DEBUGCONDUIT << fname << ": Unknown recurrence type "<< recType << " with frequency "
00656 << freq << " and duration " << r->duration() << endl;
00657 #endif
00658 break;
00659 }
00660 }
00661
00662
00663 void VCalConduit::setExceptions(KCal::Event *vevent,const PilotDateEntry *dateEntry)
00664 {
00665 FUNCTIONSETUP;
00666
00667
00668
00669 KCal::DateList dl;
00670
00671 if ( !(dateEntry->isMultiDay() ) && dateEntry->getExceptionCount()>0 )
00672 {
00673 for (int i = 0; i < dateEntry->getExceptionCount(); i++)
00674 {
00675
00676 dl.append(readTm(dateEntry->getExceptions()[i]).date());
00677 }
00678 }
00679 else
00680 {
00681 #ifdef DEBUG
00682 if (dateEntry->getExceptionCount()>0)
00683 DEBUGCONDUIT << fname
00684 << ": WARNING Exceptions ignored for multi-day event "
00685 << dateEntry->getDescription()
00686 << endl ;
00687 #endif
00688 return;
00689 }
00690 vevent->setExDates(dl);
00691 }
00692
00693 void VCalConduit::setExceptions(PilotDateEntry *dateEntry, const KCal::Event *vevent )
00694 {
00695 FUNCTIONSETUP;
00696 struct tm *ex_List;
00697
00698 if (!dateEntry || !vevent)
00699 {
00700 kdWarning() << k_funcinfo << ": NULL dateEntry or NULL vevent given for exceptions. Skipping exceptions" << endl;
00701 return;
00702 }
00703
00704
00705
00706
00707
00708
00709 size_t excount=vevent->exDates().size();
00710 if (excount<1)
00711 {
00712 dateEntry->setExceptionCount(0);
00713 dateEntry->setExceptions(0);
00714 return;
00715 }
00716
00717
00718 ex_List=new struct tm[excount];
00719 if (!ex_List)
00720 {
00721 kdWarning() << k_funcinfo << ": Couldn't allocate memory for the exceptions" << endl;
00722 dateEntry->setExceptionCount(0);
00723 dateEntry->setExceptions(0);
00724 return;
00725 }
00726
00727 size_t n=0;
00728
00729 KCal::DateList exDates = vevent->exDates();
00730 KCal::DateList::ConstIterator dit;
00731 for (dit = exDates.begin(); dit != exDates.end(); ++dit ) {
00732 struct tm ttm=writeTm(*dit);
00733 ex_List[n++]=ttm;
00734 }
00735 dateEntry->setExceptionCount(excount);
00736 dateEntry->setExceptions(ex_List);
00737 }