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