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