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
00031
00032
00033 static const char *vcalconduitbase_id = "$Id: vcal-conduitbase.cc,v 1.22.4.8 2003/03/12 23:25:11 adridg Exp $";
00034
00035 #include <options.h>
00036 #include <unistd.h>
00037
00038
00039 #include <qdatetime.h>
00040 #include <qtimer.h>
00041
00042
00043 #include <kconfig.h>
00044 #include <kmessagebox.h>
00045 #include <kstandarddirs.h>
00046 #include <ksimpleconfig.h>
00047
00048
00049 #include "libkcal/calendar.h"
00050 #include "libkcal/calendarlocal.h"
00051 #include "libkcal/incidence.h"
00052
00053
00054
00055 #ifdef KDE2
00056 #include <korecurrence.h>
00057 #define Recurrence_t KCal::KORecurrence
00058 #define DateList_t QDateList
00059 #define DateListIterator_t QDateListIterator
00060 #else
00061 #include "libkcal/recurrence.h"
00062 #define Recurrence_t KCal::Recurrence
00063 #define DateList_t KCal::DateList
00064 #define DateListIterator_t KCal::DateList::ConstIterator
00065 #endif
00066
00067
00068 #include "pilotSerialDatabase.h"
00069 #include "pilotLocalDatabase.h"
00070 #include "pilotDateEntry.h"
00071 #include "pilotUser.h"
00072
00073 #include "vcal-factorybase.h"
00074 #include "vcal-conduitbase.moc"
00075
00076
00077
00078 QDateTime readTm(const struct tm &t)
00079 {
00080 QDateTime dt;
00081 dt.setDate(QDate(1900 + t.tm_year, t.tm_mon + 1, t.tm_mday));
00082 dt.setTime(QTime(t.tm_hour, t.tm_min, t.tm_sec));
00083 return dt;
00084 }
00085
00086
00087
00088 struct tm writeTm(const QDateTime &dt)
00089 {
00090 struct tm t;
00091
00092 t.tm_wday = 0;
00093 t.tm_yday = 0;
00094 t.tm_isdst = 0;
00095
00096 t.tm_year = dt.date().year() - 1900;
00097 t.tm_mon = dt.date().month() - 1;
00098 t.tm_mday = dt.date().day();
00099 t.tm_hour = dt.time().hour();
00100 t.tm_min = dt.time().minute();
00101 t.tm_sec = dt.time().second();
00102
00103 return t;
00104 }
00105
00106
00107
00108 struct tm writeTm(const QDate &dt)
00109 {
00110 struct tm t;
00111
00112 t.tm_wday = 0;
00113 t.tm_yday = 0;
00114 t.tm_isdst = 0;
00115
00116 t.tm_year = dt.year() - 1900;
00117 t.tm_mon = dt.month() - 1;
00118 t.tm_mday = dt.day();
00119 t.tm_hour = 0;
00120 t.tm_min = 0;
00121 t.tm_sec = 0;
00122
00123 return t;
00124 }
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134 VCalConduitBase::VCalConduitBase(KPilotDeviceLink *d,
00135 const char *n,
00136 const QStringList &a) :
00137 ConduitAction(d,n,a),
00138 fCalendar(0L),
00139 fFullSync(false),
00140 fP(0L)
00141 {
00142 FUNCTIONSETUP;
00143 #ifdef DEBUG
00144 DEBUGCONDUIT<<vcalconduitbase_id<<endl;
00145 #endif
00146 }
00147
00148
00149
00150 VCalConduitBase::~VCalConduitBase()
00151 {
00152 FUNCTIONSETUP;
00153
00154 KPILOT_DELETE(fP);
00155 KPILOT_DELETE(fCalendar);
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 bool VCalConduitBase::exec()
00213 {
00214 FUNCTIONSETUP;
00215 DEBUGCONDUIT << vcalconduitbase_id << endl;
00216
00217 KPilotUser *usr;
00218
00219 if (!fConfig)
00220 {
00221 kdWarning() << k_funcinfo
00222 << ": No configuration set for vcal-conduit"
00223 << endl;
00224 return false;
00225 }
00226
00227 if (PluginUtility::isRunning("korganizer") ||
00228 PluginUtility::isRunning("alarmd"))
00229 {
00230 emit logError(i18n("KOrganizer is running, can't update datebook."));
00231 return false;
00232 }
00233
00234 readConfig();
00235
00236 if (fCalendarFile.isEmpty())
00237 {
00238 kdWarning() << k_funcinfo
00239 << ": No calendar file set." << endl;
00240 return false;
00241 }
00242
00243 #ifdef DEBUG
00244 if (isTest())
00245 {
00246 DEBUGCONDUIT << fname
00247 << ": Running conduit test. Using calendar "
00248 << fCalendarFile << endl;
00249 doTest();
00250 delayDone();
00251 return true;
00252 }
00253 #endif
00254
00255
00256
00257 fFirstTime = (syncAction==SYNC_FIRST || nextSyncAction!=0);
00258 usr=fHandle->getPilotUser();
00259
00260
00261
00262 fFullSync = fFullSync|| (syncAction==SYNC_FULL) ||
00263 ((usr->getLastSyncPC()!=(unsigned long) gethostid()) && fConfig->readBoolEntry(VCalConduitFactoryBase::fullSyncOnPCChange, true));
00264
00265 if (!openDatabases(dbname(), &fFullSync) ) goto error;
00266 if (!openCalendar() ) goto error;
00267
00268 preSync();
00269
00270
00271 #ifdef DEBUG
00272 DEBUGCONDUIT<<fname<<": fullsync="<<fFullSync<<", firstSync="<<fFirstTime<<endl;
00273 DEBUGCONDUIT<<fname<<": syncAction="<<syncAction<<", nextSyncAction = "<<nextSyncAction
00274 <<", conflictResolution = "<<conflictResolution<<", archive = "<<archive<<endl;
00275 #endif
00276
00277 addSyncLogEntry(i18n("Syncing with file \"%1\"").arg(fCalendarFile));
00278 pilotindex=0;
00279 switch (nextSyncAction)
00280 {
00281 case 2:
00282
00283
00284 QTimer::singleShot(0, this, SLOT(syncPCRecToPalm()));
00285 break;
00286 case 1:
00287
00288
00289 default:
00290 QTimer::singleShot(0, this, SLOT(syncPalmRecToPC()));
00291 }
00292 return true;
00293
00294 error:
00295
00296 emit logError(i18n("Couldn't open the calendar databases."));
00297
00298 KPILOT_DELETE(fCalendar);
00299 KPILOT_DELETE(fP);
00300 return false;
00301 }
00302
00303
00304
00305 void VCalConduitBase::readConfig()
00306 {
00307 fConfig->setGroup(configGroup());
00308
00309 fCalendarFile = fConfig->readEntry(VCalConduitFactoryBase::calendarFile);
00310 syncAction = fConfig->readNumEntry(VCalConduitFactoryBase::syncAction);
00311 nextSyncAction = fConfig->readNumEntry(VCalConduitFactoryBase::nextSyncAction);
00312 conflictResolution = fConfig->readNumEntry(VCalConduitFactoryBase::conflictResolution);
00313 archive = fConfig->readBoolEntry(VCalConduitFactoryBase::archive);
00314 }
00315
00316
00317
00318 bool VCalConduitBase::openCalendar()
00319 {
00320 FUNCTIONSETUP;
00321
00322 KConfig korgcfg( locate( "config", CSL1("korganizerrc") ) );
00323
00324 korgcfg.setGroup( "Time & Date" );
00325 QString tz(korgcfg.readEntry( "TimeZoneId" ) );
00326 #ifdef DEBUG
00327 DEBUGCONDUIT << fname<<": KOrganizer's time zone = "<<tz<<endl;
00328 #endif
00329
00330
00331 #ifdef DEBUG
00332 DEBUGCONDUIT << fname
00333 << ": Using calendar file "
00334 << fCalendarFile
00335 << endl;
00336 #endif
00337
00338
00339
00340
00341 fCalendar = new KCal::CalendarLocal(tz);
00342 if ( !fCalendar)
00343 {
00344 #ifdef DEBUG
00345 DEBUGCONDUIT << fname << ":Cannot initialize calendar object"<<endl;
00346 #endif
00347 return false;
00348 }
00349
00350
00351
00352 if (!fCalendar->load(fCalendarFile) )
00353 {
00354 #ifdef DEBUG
00355 DEBUGCONDUIT << "calendar file "<<fCalendarFile<<" could not be opened. Will create a new one"<<endl;
00356 #endif
00357 fFirstTime=true;
00358 }
00359
00360 fP = newVCalPrivate(fCalendar);
00361 if (!fP) return false;
00362 fP->updateIncidences();
00363 if (fP->count()<1)
00364 fFirstTime=true;
00365
00366 return (fCalendar && fP);
00367 }
00368
00369
00370
00371 void VCalConduitBase::syncPalmRecToPC()
00372 {
00373 FUNCTIONSETUP;
00374
00375 PilotRecord *r;
00376 if (fFirstTime || fFullSync)
00377 {
00378 r = fDatabase->readRecordByIndex(pilotindex++);
00379 }
00380 else
00381 {
00382 r = fDatabase->readNextModifiedRec();
00383 }
00384 PilotRecord *s = 0L;
00385
00386 if (!r)
00387 {
00388 fP->updateIncidences();
00389 if (nextSyncAction==1)
00390 {
00391 QTimer::singleShot(0, this, SLOT(cleanup()));
00392 return;
00393 }
00394 else
00395 {
00396 QTimer::singleShot(0 ,this,SLOT(syncPCRecToPalm()));
00397 return;
00398 }
00399 }
00400
00401
00402 preRecord(r);
00403
00404
00405
00406 bool archiveRecord=(r->isArchived());
00407
00408 s = fLocalDatabase->readRecordById(r->getID());
00409 if (!s || fFirstTime)
00410 {
00411 #ifdef DEBUG
00412 if (r->getID()>0 && !s)
00413 {
00414 DEBUGCONDUIT<<"---------------------------------------------------------------------------"<<endl;
00415 DEBUGCONDUIT<< fname<<": Could not read palm record with ID "<<r->getID()<<endl;
00416 }
00417 #endif
00418 if (!r->isDeleted() || (archive && archiveRecord))
00419 {
00420 KCal::Incidence*e=addRecord(r);
00421 if (archive && archiveRecord) {
00422 e->setSyncStatus(KCal::Incidence::SYNCDEL);
00423 }
00424 }
00425 }
00426 else
00427 {
00428 if (r->isDeleted())
00429 {
00430 if (archive && archiveRecord)
00431 {
00432 changeRecord(r,s);
00433 }
00434 else
00435 {
00436 deleteRecord(r,s);
00437 }
00438 }
00439 else
00440 {
00441 changeRecord(r,s);
00442 }
00443 }
00444
00445 KPILOT_DELETE(r);
00446 KPILOT_DELETE(s);
00447
00448 QTimer::singleShot(0,this,SLOT(syncPalmRecToPC()));
00449 }
00450
00451
00452 void VCalConduitBase::syncPCRecToPalm()
00453 {
00454 FUNCTIONSETUP;
00455 KCal::Incidence*e=0L;
00456 if (fFirstTime || fFullSync) e=fP->getNextIncidence();
00457 else e=fP->getNextModifiedIncidence();
00458
00459 if (!e)
00460 {
00461 pilotindex=0;
00462 if (nextSyncAction!=0)
00463 {
00464 QTimer::singleShot(0, this, SLOT(cleanup()));
00465 return;
00466 }
00467 QTimer::singleShot(0,this,SLOT(syncDeletedIncidence()));
00468 return;
00469 }
00470
00471
00472 preIncidence(e);
00473
00474
00475 recordid_t ix=e->pilotId();
00476 #ifdef DEBUG
00477 DEBUGCONDUIT<<fname<<": found PC entry with pilotID "<<ix<<endl;
00478 DEBUGCONDUIT<<fname<<": Description: "<<e->summary()<<endl;
00479 DEBUGCONDUIT<<fname<<": Time: "
00480 << e->dtStart().toString()
00481 #if KDE_VERSION > 0x030180
00482 << " until "
00483 << e->dtEnd()
00484 #endif
00485 << endl;
00486 #endif
00487 PilotRecord *s=0L;
00488 if (ix>0 && (s=fDatabase->readRecordById(ix)))
00489 {
00490 if (e->syncStatus()==KCal::Incidence::SYNCDEL)
00491 {
00492 deletePalmRecord(e, s);
00493 }
00494 else
00495 {
00496 changePalmRecord(e, s);
00497 }
00498 KPILOT_DELETE(s);
00499 } else {
00500 #ifdef DEBUG
00501 if (ix>0)
00502 {
00503 DEBUGCONDUIT<<"---------------------------------------------------------------------------"<<endl;
00504 DEBUGCONDUIT<< fname<<": Could not read palm record with ID "<<ix<<endl;
00505 }
00506 #endif
00507 addPalmRecord(e);
00508 }
00509 QTimer::singleShot(0, this, SLOT(syncPCRecToPalm()));
00510 }
00511
00512
00513 void VCalConduitBase::syncDeletedIncidence()
00514 {
00515 FUNCTIONSETUP;
00516
00517 PilotRecord *r = fLocalDatabase->readRecordByIndex(pilotindex++);
00518 if (!r || fFullSync || fFirstTime)
00519 {
00520 QTimer::singleShot(0 ,this,SLOT(cleanup()));
00521 return;
00522 }
00523
00524 KCal::Incidence *e = fP->findIncidence(r->getID());
00525 if (!e)
00526 {
00527 #ifdef DEBUG
00528 DEBUGCONDUIT<<"didn't find incidence with id="<<r->getID()<<", deleting it"<<endl;
00529 #endif
00530
00531
00532
00533
00534
00535
00537
00538
00539
00540 deletePalmRecord(NULL, r);
00541
00543
00544
00545 }
00546
00547 KPILOT_DELETE(r);
00548 QTimer::singleShot(0,this,SLOT(syncDeletedIncidence()));
00549 }
00550
00551
00552 void VCalConduitBase::cleanup()
00553 {
00554 FUNCTIONSETUP;
00555 postSync();
00556
00557 if (fDatabase)
00558 {
00559 fDatabase->resetSyncFlags();
00560 fDatabase->cleanup();
00561 }
00562 if (fLocalDatabase)
00563 {
00564 fLocalDatabase->resetSyncFlags();
00565 fLocalDatabase->cleanup();
00566 }
00567 KPILOT_DELETE(fDatabase);
00568 KPILOT_DELETE(fLocalDatabase);
00569 if (fCalendar) fCalendar->save(fCalendarFile);
00570 KPILOT_DELETE(fCalendar);
00571 KPILOT_DELETE(fP);
00572
00573 emit syncDone(this);
00574 }
00575
00576
00577
00578 void VCalConduitBase::postSync()
00579 {
00580 FUNCTIONSETUP;
00581 fConfig->setGroup(configGroup());
00582 fConfig->writeEntry(VCalConduitFactoryBase::nextSyncAction, 0);
00583 }
00584
00585
00586 KCal::Incidence* VCalConduitBase::addRecord(PilotRecord *r)
00587 {
00588 FUNCTIONSETUP;
00589
00590 recordid_t id=fLocalDatabase->writeRecord(r);
00591 #ifdef DEBUG
00592 DEBUGCONDUIT<<fname<<": Pilot Record ID="<<r->getID()<<", backup ID="<<id<<endl;
00593 #endif
00594
00595 PilotAppCategory *de=newPilotEntry(r);
00596 KCal::Incidence*e =0L;
00597
00598 if (de)
00599 {
00600 e=fP->findIncidence(de);
00601 if (!e)
00602 {
00603
00604 e=newIncidence();
00605 incidenceFromRecord(e,de);
00606 fP->addIncidence(e);
00607 }
00608 else
00609 {
00610
00611 incidenceFromRecord(e,de);
00612 }
00613
00614
00615
00616
00617
00618
00619
00620 }
00621 KPILOT_DELETE(de);
00622 return e;
00623 }
00624
00625
00626 int VCalConduitBase::resolveConflict(KCal::Incidence*e, PilotAppCategory*de) {
00627 if (conflictResolution==RES_ASK)
00628 {
00629 return KMessageBox::warningYesNo(NULL,
00630 i18n("The following item was modified both on the Pilot and on your PC:\nPC entry:\n\t")+e->summary()+i18n("\nPilot entry:\n\t")+getTitle(de)+
00631 i18n("\n\nShould the Pilot entry overwrite the PC entry? If you select \"No\", the PC entry will overwrite the Pilot entry."),
00632 i18n("Conflicting Entries")
00633 )==KMessageBox::No;
00634 }
00635 return conflictResolution;
00636 }
00637
00638 KCal::Incidence*VCalConduitBase::changeRecord(PilotRecord *r,PilotRecord *)
00639 {
00640 FUNCTIONSETUP;
00641
00642 PilotAppCategory*de=newPilotEntry(r);
00643 KCal::Incidence *e = fP->findIncidence(r->getID());
00644
00645 if (e && de)
00646 {
00647
00648 if ( (e->syncStatus()!=KCal::Incidence::SYNCNONE) && (r->getAttrib() &dlpRecAttrDirty) )
00649 {
00650
00651 if (resolveConflict(e, de))
00652 {
00653
00654 KPILOT_DELETE(de);
00655 return e;
00656 }
00657 }
00658
00659 incidenceFromRecord(e,de);
00660 e->setSyncStatus(KCal::Incidence::SYNCNONE);
00661 fLocalDatabase->writeRecord(r);
00662 }
00663 else
00664 {
00665 kdWarning() << k_funcinfo << ": While changing record -- not found in iCalendar" << endl;
00666 addRecord(r);
00667 }
00668 KPILOT_DELETE(de);
00669 return e;
00670 }
00671
00672
00673 KCal::Incidence*VCalConduitBase::deleteRecord(PilotRecord *r, PilotRecord *)
00674 {
00675 FUNCTIONSETUP;
00676
00677 KCal::Incidence *e = fP->findIncidence(r->getID());
00678 if (e)
00679 {
00680
00681 fP->removeIncidence(e);
00682 }
00683 fLocalDatabase->writeRecord(r);
00684 return NULL;
00685 }
00686
00687
00688 void VCalConduitBase::addPalmRecord(KCal::Incidence*e)
00689 {
00690 FUNCTIONSETUP;
00691
00692 PilotAppCategory*de=newPilotEntry(NULL);
00693 updateIncidenceOnPalm(e, de);
00694 KPILOT_DELETE(de);
00695 }
00696
00697
00698 void VCalConduitBase::changePalmRecord(KCal::Incidence*e, PilotRecord*s)
00699 {
00700 PilotAppCategory*de=newPilotEntry(s);
00701 updateIncidenceOnPalm(e, de);
00702 KPILOT_DELETE(de);
00703 }
00704
00705
00706 void VCalConduitBase::deletePalmRecord(KCal::Incidence*e, PilotRecord*s)
00707 {
00708 FUNCTIONSETUP;
00709 if (s)
00710 {
00711 #ifdef DEBUG
00712 DEBUGCONDUIT << fname << ": deleting record " << s->getID() << endl;
00713 #endif
00714 s->makeDeleted();
00715
00716 fDatabase->writeRecord(s);
00717 fLocalDatabase->writeRecord(s);
00718 }
00719 else
00720 {
00721 #ifdef DEBUG
00722 DEBUGCONDUIT << fname << ": could not find record to delete (" << e->pilotId() << ")" << endl;
00723 #endif
00724 }
00725 }
00726
00727
00728
00729
00730
00731 void VCalConduitBase::updateIncidenceOnPalm(KCal::Incidence*e, PilotAppCategory*de)
00732 {
00733 FUNCTIONSETUP;
00734 if (!de || !e ) {
00735 #ifdef DEBUG
00736 DEBUGCONDUIT<<fname<<": NULL event given... Skipping it"<<endl;
00737 #endif
00738 return;
00739 }
00740 if (e->syncStatus()==KCal::Incidence::SYNCDEL)
00741 {
00742 #ifdef DEBUG
00743 DEBUGCONDUIT<<fname<<": don't write deleted incidence "<<e->summary()<<" to the palm"<<endl;
00744 #endif
00745 return;
00746 }
00747 PilotRecord*r=recordFromIncidence(de, e);
00748
00749
00750 if (r)
00751 {
00752 recordid_t id=fDatabase->writeRecord(r);
00753 r->setID(id);
00754
00755 fLocalDatabase->writeRecord(r);
00756
00757 e->setSyncStatus(KCal::Incidence::SYNCNONE);
00758 e->setPilotId(id);
00759 KPILOT_DELETE(r);
00760 }
00761 }
00762