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
00034 #include <options.h>
00035
00036 #include <qtimer.h>
00037 #include <qfile.h>
00038
00039 #include <kmessagebox.h>
00040 #include <kio/netaccess.h>
00041
00042 #include "libkcal/calendar.h"
00043 #include "libkcal/calendarlocal.h"
00044 #include "libkcal/calendarresources.h"
00045 #include <kstandarddirs.h>
00046
00047 #include "pilotSerialDatabase.h"
00048 #include "pilotLocalDatabase.h"
00049 #include "pilotDateEntry.h"
00050
00051 #include "vcal-conduitbase.moc"
00052 #include "vcalconduitSettings.h"
00053
00054 #ifndef LIBKCAL_IS_VERSION
00055 #warning "Using an old version of libkcal with timezone bug."
00056 #define LIBKCAL_IS_VERSION(a,b,c) (0)
00057 #endif
00058
00059 #include "conduitstate.h"
00060 #include "initstate.h"
00061
00062
00063
00064
00065
00066
00067 VCalConduitBase::VCalConduitBase(KPilotLink *d,
00068 const char *n,
00069 const QStringList &a) :
00070 ConduitAction(d,n,a),
00071 fCalendar(0L),
00072 fP(0L)
00073 {
00074 FUNCTIONSETUP;
00075
00076 fState = new InitState();
00077 }
00078
00079 VCalConduitBase::~VCalConduitBase()
00080 {
00081 FUNCTIONSETUP;
00082
00083 KPILOT_DELETE(fP);
00084 KPILOT_DELETE(fState);
00085 KPILOT_DELETE(fCalendar);
00086 KPILOT_DELETE(fDatabase);
00087 KPILOT_DELETE(fLocalDatabase);
00088 }
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
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 bool VCalConduitBase::exec()
00160 {
00161 FUNCTIONSETUP;
00162
00163 readConfig();
00164
00165
00166
00167 setFirstSync( false );
00168
00169
00170 bool retrieved = false;
00171 if ( !openDatabases( dbname(), &retrieved ) ) goto error;
00172 setFirstSync( retrieved );
00173
00174
00175
00176 if (!syncMode().isTest() && !openCalendar() ) goto error;
00177
00178
00179 QTimer::singleShot(0, this, SLOT(slotProcess()));
00180 return true;
00181
00182 error:
00183 emit logError( i18n( "Could not open the calendar databases." ) );
00184
00185 KPILOT_DELETE(fCalendar);
00186 KPILOT_DELETE(fP);
00187 KPILOT_DELETE(fState);
00188 return false;
00189 }
00190
00191 void VCalConduitBase::slotProcess() {
00192 FUNCTIONSETUP;
00193
00194
00195 if( fState && !fState->started() ) {
00196 fState->startSync( this );
00197 }
00198
00199
00200 if( hasNextRecord )
00201 {
00202 fState->handleRecord( this );
00203 QTimer::singleShot( 0, this, SLOT( slotProcess() ) );
00204 }
00205
00206 else if( fState )
00207 {
00208 fState->finishSync( this );
00209 QTimer::singleShot( 0, this, SLOT( slotProcess() ) );
00210 }
00211
00212 else
00213 {
00214 DEBUGKPILOT << fname << ": Sync finished." << endl;
00215 delayDone();
00216 }
00217 }
00218
00219 void VCalConduitBase::readConfig()
00220 {
00221 config()->readConfig();
00222 SyncAction::ConflictResolution res = (SyncAction::ConflictResolution)
00223 (config()->conflictResolution());
00224 setConflictResolution( res );
00225 }
00226
00227 static void listResources( KCal::CalendarResources *p )
00228 {
00229 FUNCTIONSETUP;
00230 KCal::CalendarResourceManager *manager = p->resourceManager();
00231
00232 DEBUGKPILOT << fname << ": Resources in calendar:" << endl;
00233 KCal::CalendarResourceManager::Iterator it;
00234 for( it = manager->begin(); it != manager->end(); ++it )
00235 {
00236 DEBUGKPILOT << fname << ": " << (*it)->resourceName() << endl;
00237 }
00238 }
00239
00240 bool VCalConduitBase::openCalendar()
00241 {
00242 FUNCTIONSETUP;
00243
00244 KConfig korgcfg( locate( "config", CSL1("korganizerrc") ) );
00245
00246
00247 korgcfg.setGroup( "Time & Date" );
00248 QString tz(korgcfg.readEntry( "TimeZoneId" ) );
00249
00250 DEBUGKPILOT << fname << ": KOrganizer's time zone = " << tz << endl;
00251
00252
00253 KCal::CalendarResources *rescal = 0L;
00254
00255 DEBUGKPILOT << fname << ": Got calendar type " << config()->calendarType()
00256 << endl;
00257
00258 switch(config()->calendarType())
00259 {
00260 case VCalConduitSettings::eCalendarLocal:
00261 {
00262 DEBUGKPILOT << fname << "Using CalendarLocal, file = "
00263 << config()->calendarFile() << endl;
00264
00265 if ( config()->calendarFile().isEmpty() )
00266 {
00267 DEBUGKPILOT << fname << "Empty calendar file name." << endl;
00268
00269 emit logError( i18n( "You selected to sync with an iCalendar"
00270 " file, but did not give a filename. Please select a"
00271 " valid file name in the conduit's configuration"
00272 " dialog" ) );
00273 return false;
00274 }
00275
00276 fCalendar = new KCal::CalendarLocal( tz );
00277 if ( !fCalendar )
00278 {
00279 WARNINGKPILOT
00280 << "Cannot initialize calendar object for file "
00281 << config()->calendarFile() << endl;
00282 return false;
00283 }
00284
00285 DEBUGKPILOT << fname << "Calendar's timezone: "
00286 << fCalendar->timeZoneId() << endl;
00287 DEBUGKPILOT << fname << "Calendar is local time: "
00288 << fCalendar->isLocalTime() << endl;
00289
00290 emit logMessage( fCalendar->isLocalTime() ?
00291 i18n( "Using local time zone: %1" ).arg( tz ) :
00292 i18n( "Using non-local time zone: %1" ).arg( tz ) );
00293
00294 KURL kurl( config()->calendarFile() );
00295 if( !KIO::NetAccess::download( config()->calendarFile(),
00296 fCalendarFile, 0L ) && !kurl.isLocalFile() )
00297 {
00298 emit logError(i18n( "You chose to sync with the file \"%1\", which "
00299 "cannot be opened. Please make sure to supply a "
00300 "valid file name in the conduit's configuration dialog. "
00301 "Aborting the conduit." ).arg( config()->calendarFile() ) );
00302 KIO::NetAccess::removeTempFile( fCalendarFile );
00303 return false;
00304 }
00305
00306
00307
00308 if (!dynamic_cast<KCal::CalendarLocal*>(fCalendar)->load(fCalendarFile) )
00309 {
00310 DEBUGKPILOT << fname << "Calendar file " << fCalendarFile
00311 << " could not be opened. Will create a new one" << endl;
00312
00313
00314
00315 QFile fl(fCalendarFile);
00316 if (!fl.open(IO_WriteOnly | IO_Append))
00317 {
00318 DEBUGKPILOT << fname << "Invalid calendar file name "
00319 << fCalendarFile << endl;
00320
00321 emit logError( i18n( "You chose to sync with the file \"%1\", which "
00322 "cannot be opened or created. Please make sure to supply a "
00323 "valid file name in the conduit's configuration dialog. "
00324 "Aborting the conduit." ).arg( config()->calendarFile() ) );
00325 return false;
00326 }
00327 fl.close();
00328 setFirstSync( true );
00329 }
00330 addSyncLogEntry( i18n( "Syncing with file \"%1\"" )
00331 .arg( config()->calendarFile() ) );
00332 break;
00333 }
00334
00335 case VCalConduitSettings::eCalendarResource:
00336 DEBUGKPILOT << "Using CalendarResource!" << endl;
00337
00338 rescal = new KCal::CalendarResources( tz );
00339 listResources(rescal);
00340 fCalendar = rescal;
00341 if ( !fCalendar)
00342 {
00343 WARNINGKPILOT << "Cannot initialize calendar " <<
00344 "object for ResourceCalendar" << endl;
00345 return false;
00346 }
00347
00348 #if LIBKCAL_IS_VERSION(1,1,0)
00349 rescal->readConfig();
00350 rescal->load();
00351 #else
00352 #warning "Timezone bug is present."
00353 #endif
00354 addSyncLogEntry( i18n( "Syncing with standard calendar resource." ) );
00355 emit logMessage( fCalendar->isLocalTime() ?
00356 i18n( "Using local time zone: %1" ).arg( tz ) :
00357 i18n( "Using non-local time zone: %1" ).arg( tz ) );
00358 break;
00359 default:
00360 break;
00361 }
00362
00363 if ( !fCalendar )
00364 {
00365 WARNINGKPILOT << "Unable to initialize calendar object."
00366 << " Please check the conduit's setup." << endl;
00367 emit logError( i18n( "Unable to initialize the calendar object. Please"
00368 " check the conduit's setup") );
00369 return false;
00370 }
00371 fP = createPrivateCalendarData( fCalendar );
00372 if ( !fP )
00373 {
00374 return false;
00375 }
00376 int rc = fP->updateIncidences();
00377 DEBUGKPILOT << fname << ": return from updateIncidences: [" << rc
00378 << "]" << endl;
00379
00380 if ( fP->count() < 1 )
00381 {
00382 setFirstSync( true );
00383 }
00384
00385 return true;
00386 }
00387
00388 KCal::Incidence* VCalConduitBase::addRecord( PilotRecord *r )
00389 {
00390 FUNCTIONSETUP;
00391
00392 recordid_t id = fLocalDatabase->writeRecord( r );
00393 DEBUGKPILOT<<fname<<": Pilot Record ID = " << r->id() << ", backup ID = "
00394 << id << endl;
00395
00396 PilotRecordBase *de = newPilotEntry( r );
00397 KCal::Incidence*e = 0L;
00398
00399 if ( de )
00400 {
00401 e = fP->findIncidence( r->id() );
00402 if ( !e )
00403 {
00404
00405 e = newIncidence();
00406 incidenceFromRecord( e, de );
00407 fP->addIncidence( e );
00408 fCtrPC->created();
00409 }
00410 else
00411 {
00412
00413 incidenceFromRecord( e, de );
00414 fCtrPC->updated();
00415 }
00416 }
00417 KPILOT_DELETE( de );
00418 return e;
00419 }
00420
00421 int VCalConduitBase::resolveConflict( KCal::Incidence *e, PilotRecordBase *de ) {
00422 if ( getConflictResolution() == SyncAction::eAskUser )
00423 {
00424
00425 QString query = i18n( "The following item was modified "
00426 "both on the Handheld and on your PC:\nPC entry:\n\t" );
00427 query += e->summary();
00428 query += i18n( "\nHandheld entry:\n\t" );
00429 query += getTitle( de );
00430 query += i18n( "\n\nWhich entry do you want to keep? It will "
00431 "overwrite the other entry." );
00432
00433 return KMessageBox::No == questionYesNo(
00434 query,
00435 i18n( "Conflicting Entries" ),
00436 QString::null,
00437 0 ,
00438 i18n( "Handheld" ), i18n( "PC" ));
00439 }
00440 return getConflictResolution();
00441 }
00442
00443 KCal::Incidence*VCalConduitBase::changeRecord(PilotRecord *r,PilotRecord *)
00444 {
00445 FUNCTIONSETUP;
00446
00447 PilotRecordBase *de = newPilotEntry( r );
00448 KCal::Incidence *e = fP->findIncidence( r->id() );
00449
00450 DEBUGKPILOT << fname << ": Pilot Record ID: [" << r->id() << "]" << endl;
00451
00452 if ( e && de )
00453 {
00454
00455 if ( ( e->syncStatus() != KCal::Incidence::SYNCNONE )
00456 && r->isModified() )
00457 {
00458
00459 if (resolveConflict( e, de ) )
00460 {
00461
00462 KPILOT_DELETE( de );
00463 return e;
00464 }
00465 }
00466
00467 incidenceFromRecord( e, de );
00468
00469
00470
00471
00472 e->setSyncStatus(KCal::Incidence::SYNCNONE);
00473 fLocalDatabase->writeRecord( r );
00474 }
00475 else
00476 {
00477 WARNINGKPILOT
00478 << "While changing record -- not found in iCalendar" << endl;
00479 addRecord( r );
00480 }
00481
00482 KPILOT_DELETE( de );
00483 return e;
00484 }
00485
00486
00487 KCal::Incidence*VCalConduitBase::deleteRecord( PilotRecord *r, PilotRecord * )
00488 {
00489 FUNCTIONSETUP;
00490
00491 KCal::Incidence *e = fP->findIncidence(r->id());
00492 if (e)
00493 {
00494
00495 fP->removeIncidence(e);
00496 fCtrPC->deleted();
00497 }
00498 fLocalDatabase->writeRecord( r );
00499 return NULL;
00500 }
00501
00502
00503 void VCalConduitBase::addPalmRecord( KCal::Incidence *e )
00504 {
00505 FUNCTIONSETUP;
00506
00507 PilotRecordBase *de = newPilotEntry( 0L );
00508 updateIncidenceOnPalm( e, de );
00509 fCtrHH->created();
00510 KPILOT_DELETE( de );
00511 }
00512
00513
00514 void VCalConduitBase::changePalmRecord(KCal::Incidence*e, PilotRecord*s)
00515 {
00516 PilotRecordBase *de = newPilotEntry( s );
00517 updateIncidenceOnPalm( e, de );
00518 fCtrHH->updated();
00519 KPILOT_DELETE( de );
00520 }
00521
00522
00523 void VCalConduitBase::deletePalmRecord( KCal::Incidence *e, PilotRecord *s )
00524 {
00525 FUNCTIONSETUP;
00526 if ( s )
00527 {
00528 DEBUGKPILOT << fname << ": deleting record " << s->id() << endl;
00529 s->setDeleted();
00530 fDatabase->writeRecord( s );
00531 fLocalDatabase->writeRecord( s );
00532 fCtrHH->deleted();
00533 }
00534 else
00535 {
00536 DEBUGKPILOT << fname << ": could not find record to delete (";
00537 DEBUGKPILOT << e->pilotId() << ")" << endl;
00538 }
00539
00540 Q_UNUSED(e);
00541 }
00542
00543
00544
00545
00546 void VCalConduitBase::updateIncidenceOnPalm( KCal::Incidence *e,
00547 PilotRecordBase *de )
00548 {
00549 FUNCTIONSETUP;
00550 if ( !de || !e ) {
00551 DEBUGKPILOT << fname << ": NULL event given... Skipping it" << endl;
00552 return;
00553 }
00554
00555 if ( e->syncStatus() == KCal::Incidence::SYNCDEL )
00556 {
00557 DEBUGKPILOT << fname << ": don't write deleted incidence "
00558 << e->summary() << " to the palm" << endl;
00559 return;
00560 }
00561
00562 PilotRecord *r = recordFromIncidence( de, e );
00563
00564
00565 if ( r )
00566 {
00567 recordid_t id=fDatabase->writeRecord(r);
00568 r->setID(id);
00569
00570 fLocalDatabase->writeRecord( r );
00571
00572 e->setPilotId( id );
00573
00574
00575
00576
00577 e->setSyncStatus(KCal::Incidence::SYNCNONE);
00578 KPILOT_DELETE( r );
00579 }
00580 }
00581
00582 const QString VCalConduitBase::dbname()
00583 {
00584 return QString::null;
00585 }
00586
00587 PilotRecord *VCalConduitBase::readRecordByIndex( int index )
00588 {
00589 FUNCTIONSETUP;
00590 return fDatabase->readRecordByIndex( index );
00591 }
00592
00593 KCal::Incidence *VCalConduitBase::incidenceFromRecord( PilotRecord *r )
00594 {
00595 FUNCTIONSETUP;
00596 PilotRecordBase *pac = newPilotEntry( r );
00597 KCal::Incidence *i = newIncidence();
00598 incidenceFromRecord( i, pac );
00599
00600 KPILOT_DELETE( pac );
00601 return i;
00602 }
00603
00604 void VCalConduitBase::setState( ConduitState *s )
00605 {
00606 KPILOT_DELETE( fState );
00607 fState = s;
00608 }
00609
00610 void VCalConduitBase::postSync( )
00611 {
00612 FUNCTIONSETUP;
00613 if (fCtrPC && fP)
00614 fCtrPC->setEndCount(fP->count());
00615 }
00616
00617 void VCalConduitBase::preSync( )
00618 {
00619 FUNCTIONSETUP;
00620 if (fCtrPC && fP)
00621 fCtrPC->setStartCount(fP->count());
00622 }