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