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 <qtextcodec.h>
00038 #include <qfile.h>
00039 #include <qregexp.h>
00040
00041 #include <kabc/stdaddressbook.h>
00042 #include <kabc/resourcefile.h>
00043 #include <kio/netaccess.h>
00044 #include <ksavefile.h>
00045
00046 #include <pilotSerialDatabase.h>
00047 #include <pilotLocalDatabase.h>
00048
00049 #include "resolutionDialog.h"
00050 #include "resolutionTable.h"
00051 #include "abbrowserSettings.h"
00052 #include "kabcRecord.h"
00053
00054 #include "abbrowser-conduit.moc"
00055
00056
00057
00058
00059
00060 extern "C"
00061 {
00062 unsigned long version_conduit_address = Pilot::PLUGIN_API;
00063 }
00064
00065
00066
00067
00068
00069
00070
00071
00072 template<bool> struct EnumerationMismatch;
00073 template<> struct EnumerationMismatch<true>{};
00074
00075 #define CHECK_ENUM(a) (void)sizeof(EnumerationMismatch<((int)KABCSync::a)==((int)AbbrowserSettings::a)>)
00076
00077 static inline void compile_time_check()
00078 {
00079
00080 CHECK_ENUM(eOtherPhone);
00081 CHECK_ENUM(eOtherPhone);
00082 CHECK_ENUM(eAssistant);
00083 CHECK_ENUM(eBusinessFax);
00084 CHECK_ENUM(eCarPhone);
00085 CHECK_ENUM(eEmail2);
00086 CHECK_ENUM(eHomeFax);
00087 CHECK_ENUM(eTelex);
00088 CHECK_ENUM(eTTYTTDPhone);
00089
00090
00091 CHECK_ENUM(eCustomField);
00092 CHECK_ENUM(eCustomBirthdate);
00093 CHECK_ENUM(eCustomURL);
00094 CHECK_ENUM(eCustomIM);
00095 }
00096
00097 inline int faxTypeOnPC()
00098 {
00099 return KABC::PhoneNumber::Fax |
00100 ( (AbbrowserSettings::pilotFax()==0) ?
00101 KABC::PhoneNumber::Home :
00102 KABC::PhoneNumber::Work );
00103 }
00104
00105
00106 using namespace KABC;
00107
00108
00109
00110
00111
00112
00113 AbbrowserConduit::AbbrowserConduit(KPilotLink * o, const char *n, const QStringList & a):
00114 ConduitAction(o, n, a),
00115 aBook(0L),
00116 fAddressAppInfo(0L),
00117 addresseeMap(),
00118 syncedIds(),
00119 abiter(),
00120 fTicket(0L),
00121 fCreatedBook(false),
00122 fBookResource(0L)
00123 {
00124 FUNCTIONSETUP;
00125 fConduitName=i18n("Addressbook");
00126 }
00127
00128
00129
00130 AbbrowserConduit::~AbbrowserConduit()
00131 {
00132 FUNCTIONSETUP;
00133
00134 if (fTicket)
00135 {
00136 DEBUGKPILOT << fname << ": Releasing ticket" << endl;
00137 aBook->releaseSaveTicket(fTicket);
00138 fTicket=0L;
00139 }
00140
00141 _cleanupAddressBookPointer();
00142
00143 compile_time_check();
00144 }
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 void AbbrowserConduit::_mapContactsToPilot(QMap < recordid_t, QString > &idContactMap)
00157 {
00158 FUNCTIONSETUP;
00159
00160 idContactMap.clear();
00161
00162 for(AddressBook::Iterator contactIter = aBook->begin();
00163 contactIter != aBook->end(); ++contactIter)
00164 {
00165 Addressee aContact = *contactIter;
00166 QString recid = aContact.custom(KABCSync::appString, KABCSync::idString);
00167 if(!recid.isEmpty())
00168 {
00169 recordid_t id = recid.toULong();
00170
00171
00172
00173
00174 if (!idContactMap.contains(id))
00175 {
00176 idContactMap.insert(id, aContact.uid());
00177 }
00178 else
00179 {
00180 DEBUGKPILOT << fname << ": found duplicate pilot key: ["
00181 << id << "], removing pilot id from addressee: ["
00182 << aContact.realName() << "]" << endl;
00183 aContact.removeCustom(KABCSync::appString, KABCSync::idString);
00184 aBook->insertAddressee(aContact);
00185 abChanged = true;
00186 }
00187 }
00188 }
00189 DEBUGKPILOT << fname << ": Loaded " << idContactMap.size() <<
00190 " addresses from the addressbook. " << endl;
00191 }
00192
00193
00194
00195 bool AbbrowserConduit::_prepare()
00196 {
00197 FUNCTIONSETUP;
00198
00199 readConfig();
00200 syncedIds.clear();
00201 pilotindex = 0;
00202
00203 return true;
00204 }
00205
00206
00207
00208 void AbbrowserConduit::readConfig()
00209 {
00210 FUNCTIONSETUP;
00211 AbbrowserSettings::self()->readConfig();
00212
00213
00214 SyncAction::ConflictResolution res = (SyncAction::ConflictResolution)AbbrowserSettings::conflictResolution();
00215 setConflictResolution(res);
00216
00217 DEBUGKPILOT << fname
00218 << ": Reading addressbook "
00219 << ( AbbrowserSettings::addressbookType() == AbbrowserSettings::eAbookFile ?
00220 AbbrowserSettings::fileName() : CSL1("Standard") )
00221 << endl;
00222 DEBUGKPILOT << fname
00223 << ": "
00224 << " fConflictResolution=" << getConflictResolution()
00225 << " fArchive=" << AbbrowserSettings::archiveDeleted()
00226 << " fFirstTime=" << isFirstSync()
00227 << endl;
00228 DEBUGKPILOT << fname
00229 << ": "
00230 << " fPilotStreetHome=" << AbbrowserSettings::pilotStreet()
00231 << " fPilotFaxHome=" << AbbrowserSettings::pilotFax()
00232 << " eCustom[0]=" << AbbrowserSettings::custom0()
00233 << " eCustom[1]=" << AbbrowserSettings::custom1()
00234 << " eCustom[2]=" << AbbrowserSettings::custom2()
00235 << " eCustom[3]=" << AbbrowserSettings::custom3()
00236 << endl;
00237 }
00238
00239
00240
00241 bool isDeleted(const PilotAddress *addr)
00242 {
00243 if (!addr)
00244 {
00245 return true;
00246 }
00247 if (addr->isDeleted() && !addr->isArchived())
00248 {
00249 return true;
00250 }
00251 if (addr->isArchived())
00252 {
00253 return !AbbrowserSettings::archiveDeleted();
00254 }
00255 return false;
00256 }
00257
00258 bool isArchived(const PilotAddress *addr)
00259 {
00260 if (addr && addr->isArchived())
00261 {
00262 return AbbrowserSettings::archiveDeleted();
00263 }
00264 else
00265 {
00266 return false;
00267 }
00268 }
00269
00270
00271
00272 bool AbbrowserConduit::_loadAddressBook()
00273 {
00274 FUNCTIONSETUP;
00275
00276 startTickle();
00277 switch ( AbbrowserSettings::addressbookType() )
00278 {
00279 case AbbrowserSettings::eAbookResource:
00280 DEBUGKPILOT<<"Loading standard addressbook"<<endl;
00281 aBook = StdAddressBook::self( true );
00282 fCreatedBook=false;
00283 break;
00284 case AbbrowserSettings::eAbookFile:
00285 {
00286 DEBUGKPILOT<<"Loading custom addressbook"<<endl;
00287 KURL kurl(AbbrowserSettings::fileName());
00288 if(!KIO::NetAccess::download(AbbrowserSettings::fileName(), fABookFile, 0L) &&
00289 !kurl.isLocalFile())
00290 {
00291 emit logError(i18n("You chose to sync with the file \"%1\", which "
00292 "cannot be opened. Please make sure to supply a "
00293 "valid file name in the conduit's configuration dialog. "
00294 "Aborting the conduit.").arg(AbbrowserSettings::fileName()));
00295 KIO::NetAccess::removeTempFile(fABookFile);
00296 stopTickle();
00297 return false;
00298 }
00299
00300 aBook = new AddressBook();
00301 if (!aBook)
00302 {
00303 stopTickle();
00304 return false;
00305 }
00306 fBookResource = new ResourceFile(fABookFile, CSL1("vcard") );
00307
00308 bool r = aBook->addResource( fBookResource );
00309 if ( !r )
00310 {
00311 DEBUGKPILOT << "Unable to open resource for file " << fABookFile << endl;
00312 KPILOT_DELETE( aBook );
00313 stopTickle();
00314 return false;
00315 }
00316 fCreatedBook=true;
00317 break;
00318 }
00319 default: break;
00320 }
00321
00322
00323
00324 if ( !aBook || !aBook->load() )
00325 {
00326
00327 emit logError(i18n("Unable to initialize and load the addressbook for the sync.") );
00328 addSyncLogEntry(i18n("Unable to initialize and load the addressbook for the sync.") );
00329 WARNINGKPILOT << "Unable to initialize the addressbook for the sync." << endl;
00330 _cleanupAddressBookPointer();
00331 stopTickle();
00332 return false;
00333 }
00334 abChanged = false;
00335
00336 fTicket=aBook->requestSaveTicket();
00337 if (!fTicket)
00338 {
00339 WARNINGKPILOT << "Unable to lock addressbook for writing " << endl;
00340 emit logError(i18n("Unable to lock addressbook for writing. Can't sync!"));
00341 addSyncLogEntry(i18n("Unable to lock addressbook for writing. Can't sync!"));
00342 _cleanupAddressBookPointer();
00343 stopTickle();
00344 return false;
00345 }
00346
00347 fCtrPC->setStartCount(aBook->allAddressees().count());
00348
00349
00350
00351 if(aBook->begin() == aBook->end())
00352 {
00353 setFirstSync( true );
00354 }
00355 else
00356 {
00357 _mapContactsToPilot(addresseeMap);
00358 }
00359 stopTickle();
00360 return(aBook != 0L);
00361 }
00362
00363 bool AbbrowserConduit::_saveAddressBook()
00364 {
00365 FUNCTIONSETUP;
00366
00367 bool saveSuccessful = false;
00368
00369 fCtrPC->setEndCount(aBook->allAddressees().count());
00370
00371 Q_ASSERT(fTicket);
00372
00373 if (abChanged)
00374 {
00375 saveSuccessful = aBook->save(fTicket);
00376 }
00377 else
00378 {
00379 DEBUGKPILOT << fname
00380 << "Addressbook not changed, no need to save it" << endl;
00381 }
00382
00383 if ( !saveSuccessful )
00384 {
00385 aBook->releaseSaveTicket(fTicket);
00386 }
00387 fTicket=0L;
00388
00389 if ( AbbrowserSettings::addressbookType()!= AbbrowserSettings::eAbookResource )
00390 {
00391 KURL kurl(AbbrowserSettings::fileName());
00392 if(!kurl.isLocalFile())
00393 {
00394 DEBUGKPILOT << fname << "Deleting local addressbook tempfile" << endl;
00395 if(!KIO::NetAccess::upload(fABookFile, AbbrowserSettings::fileName(), 0L)) {
00396 emit logError(i18n("An error occurred while uploading \"%1\". You can try to upload "
00397 "the temporary local file \"%2\" manually")
00398 .arg(AbbrowserSettings::fileName()).arg(fABookFile));
00399 }
00400 else {
00401 KIO::NetAccess::removeTempFile(fABookFile);
00402 }
00403 QFile backup(fABookFile + CSL1("~"));
00404 backup.remove();
00405 }
00406
00407 }
00408
00409
00410 if (fBookResource)
00411 {
00412 bool r = aBook->removeResource( fBookResource );
00413 if ( !r )
00414 {
00415 DEBUGKPILOT << fname <<": Unable to close resource." << endl;
00416 }
00417 }
00418
00419 return saveSuccessful;
00420 }
00421
00422
00423
00424 void AbbrowserConduit::_getAppInfo()
00425 {
00426 FUNCTIONSETUP;
00427
00428 delete fAddressAppInfo;
00429 fAddressAppInfo = new PilotAddressInfo(fDatabase);
00430 fAddressAppInfo->dump();
00431 }
00432
00433 void AbbrowserConduit::_setAppInfo()
00434 {
00435 FUNCTIONSETUP;
00436 if (fDatabase) fAddressAppInfo->writeTo(fDatabase);
00437 if (fLocalDatabase) fAddressAppInfo->writeTo(fLocalDatabase);
00438 }
00439
00440
00441 void AbbrowserConduit::_cleanupAddressBookPointer()
00442 {
00443 if (fCreatedBook)
00444 {
00445 KPILOT_DELETE(aBook);
00446 fCreatedBook=false;
00447 }
00448 else
00449 {
00450 aBook=0L;
00451 }
00452 }
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 void AbbrowserConduit::showPilotAddress(const PilotAddress *pilotAddress)
00466 {
00467 FUNCTIONSETUPL(3);
00468 if (debug_level < 3)
00469 {
00470 return;
00471 }
00472 if (!pilotAddress)
00473 {
00474 DEBUGKPILOT<< fname << "| EMPTY"<<endl;
00475 return;
00476 }
00477 DEBUGKPILOT << fname << "\n"
00478 << pilotAddress->getTextRepresentation(
00479 fAddressAppInfo,Qt::PlainText) << endl;
00480 }
00481
00482
00483 void AbbrowserConduit::showAddresses(
00484 const Addressee &pcAddr,
00485 const PilotAddress *backupAddr,
00486 const PilotAddress *palmAddr)
00487 {
00488 FUNCTIONSETUPL(3);
00489 if (debug_level >= 3)
00490 {
00491 DEBUGKPILOT << fname << "abEntry:" << endl;
00492 KABCSync::showAddressee(pcAddr);
00493 DEBUGKPILOT << fname << "pilotAddress:" << endl;
00494 showPilotAddress(palmAddr);
00495 DEBUGKPILOT << fname << "backupAddress:" << endl;
00496 showPilotAddress(backupAddr);
00497 DEBUGKPILOT << fname << "------------------------------------------------" << endl;
00498 }
00499 }
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509 bool AbbrowserConduit::exec()
00510 {
00511 FUNCTIONSETUP;
00512
00513 _prepare();
00514
00515 bool retrieved = false;
00516 if(!openDatabases(CSL1("AddressDB"), &retrieved))
00517 {
00518 emit logError(i18n("Unable to open the addressbook databases on the handheld."));
00519 return false;
00520 }
00521 setFirstSync( retrieved );
00522
00523 _getAppInfo();
00524
00525
00526 {
00527 QString dbpath = fLocalDatabase->dbPathName();
00528 DEBUGKPILOT << fname << ": Local database path " << dbpath << endl;
00529 }
00530
00531 if ( syncMode().isTest() )
00532 {
00533 QTimer::singleShot(0, this, SLOT(slotTestRecord()));
00534 return true;
00535 }
00536
00537 if(!_loadAddressBook())
00538 {
00539 emit logError(i18n("Unable to open the addressbook."));
00540 return false;
00541 }
00542 setFirstSync( isFirstSync() || (aBook->begin() == aBook->end()) );
00543
00544 DEBUGKPILOT << fname << ": First sync now " << isFirstSync()
00545 << " and addressbook is "
00546 << ((aBook->begin() == aBook->end()) ? "" : "non-")
00547 << "empty." << endl;
00548
00549
00550
00551
00552 DEBUGKPILOT << fname << ": fullsync=" << isFullSync() << ", firstSync=" << isFirstSync() << endl;
00553 DEBUGKPILOT << fname << ": "
00554 << "syncDirection=" << syncMode().name() << ", "
00555 << "archive = " << AbbrowserSettings::archiveDeleted() << endl;
00556 DEBUGKPILOT << fname << ": conflictRes="<< getConflictResolution() << endl;
00557 DEBUGKPILOT << fname << ": PilotStreetHome=" << AbbrowserSettings::pilotStreet() << ", PilotFaxHOme" << AbbrowserSettings::pilotFax() << endl;
00558
00559 if (!isFirstSync())
00560 {
00561 allIds=fDatabase->idList();
00562 }
00563
00564 QValueVector<int> v(4);
00565 v[0] = AbbrowserSettings::custom0();
00566 v[1] = AbbrowserSettings::custom1();
00567 v[2] = AbbrowserSettings::custom2();
00568 v[3] = AbbrowserSettings::custom3();
00569
00570 fSyncSettings.setCustomMapping(v);
00571 fSyncSettings.setFieldForOtherPhone(AbbrowserSettings::pilotOther());
00572 fSyncSettings.setDateFormat(AbbrowserSettings::customDateFormat());
00573 fSyncSettings.setPreferHome(AbbrowserSettings::pilotStreet()==0);
00574 fSyncSettings.setFaxTypeOnPC(faxTypeOnPC());
00575
00576
00577
00578
00579
00580
00581
00582
00583 QTimer::singleShot(0, this, SLOT(slotPalmRecToPC()));
00584
00585 return true;
00586 }
00587
00588
00589
00590 void AbbrowserConduit::slotPalmRecToPC()
00591 {
00592 FUNCTIONSETUP;
00593 PilotRecord *palmRec = 0L, *backupRec = 0L;
00594
00595 if ( syncMode() == SyncMode::eCopyPCToHH )
00596 {
00597 DEBUGKPILOT << fname << ": Done; change to PCtoHH phase." << endl;
00598 abiter = aBook->begin();
00599 QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
00600 return;
00601 }
00602
00603 if(isFullSync())
00604 {
00605 palmRec = fDatabase->readRecordByIndex(pilotindex++);
00606 }
00607 else
00608 {
00609 palmRec = fDatabase->readNextModifiedRec();
00610 }
00611
00612
00613
00614 if(!palmRec)
00615 {
00616 abiter = aBook->begin();
00617 QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
00618 return;
00619 }
00620
00621
00622 if(syncedIds.contains(palmRec->id()))
00623 {
00624 KPILOT_DELETE(palmRec);
00625 QTimer::singleShot(0, this, SLOT(slotPalmRecToPC()));
00626 return;
00627 }
00628
00629 backupRec = fLocalDatabase->readRecordById(palmRec->id());
00630 PilotRecord*compareRec=(backupRec)?(backupRec):(palmRec);
00631 Addressee e = _findMatch(PilotAddress(compareRec));
00632
00633 PilotAddress*backupAddr=0L;
00634 if (backupRec)
00635 {
00636 backupAddr=new PilotAddress(backupRec);
00637 }
00638
00639 PilotAddress*palmAddr=0L;
00640 if (palmRec)
00641 {
00642 palmAddr=new PilotAddress(palmRec);
00643 }
00644
00645 syncAddressee(e, backupAddr, palmAddr);
00646
00647 syncedIds.append(palmRec->id());
00648 KPILOT_DELETE(palmAddr);
00649 KPILOT_DELETE(backupAddr);
00650 KPILOT_DELETE(palmRec);
00651 KPILOT_DELETE(backupRec);
00652
00653 QTimer::singleShot(0, this, SLOT(slotPalmRecToPC()));
00654 }
00655
00656
00657
00658 void AbbrowserConduit::slotPCRecToPalm()
00659 {
00660 FUNCTIONSETUP;
00661
00662 if ( (syncMode()==SyncMode::eCopyHHToPC) ||
00663 abiter == aBook->end() || (*abiter).isEmpty() )
00664 {
00665 DEBUGKPILOT << fname << ": Done; change to delete records." << endl;
00666 pilotindex = 0;
00667 QTimer::singleShot(0, this, SLOT(slotDeletedRecord()));
00668 return;
00669 }
00670
00671 PilotRecord *palmRec=0L, *backupRec=0L;
00672 Addressee ad = *abiter;
00673
00674 abiter++;
00675
00676
00677 if (KABCSync::isArchived(ad))
00678 {
00679 DEBUGKPILOT << fname << ": address with id " << ad.uid() <<
00680 " marked archived, so don't sync." << endl;
00681 QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
00682 return;
00683 }
00684
00685
00686 QString recID(ad.custom(KABCSync::appString, KABCSync::idString));
00687 bool ok;
00688 recordid_t rid = recID.toLong(&ok);
00689 if (recID.isEmpty() || !ok || !rid)
00690 {
00691 DEBUGKPILOT << fname << ": This is a new record." << endl;
00692
00693 syncAddressee(ad, 0L, 0L);
00694 QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
00695 return;
00696 }
00697
00698
00699 if (syncedIds.contains(rid))
00700 {
00701 DEBUGKPILOT << ": address with id " << rid << " already synced." << endl;
00702 QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
00703 return;
00704 }
00705
00706
00707 backupRec = fLocalDatabase->readRecordById(rid);
00708
00709
00710 PilotAddress*backupAddr=0L;
00711 if (backupRec)
00712 {
00713 backupAddr=new PilotAddress(backupRec);
00714 }
00715 if(!backupRec || isFirstSync() || !_equal(backupAddr, ad) )
00716 {
00717 DEBUGKPILOT << fname << ": Updating entry." << endl;
00718 palmRec = fDatabase->readRecordById(rid);
00719 PilotAddress *palmAddr = 0L;
00720 if (palmRec)
00721 {
00722 palmAddr = new PilotAddress(palmRec);
00723 }
00724 else
00725 {
00726 DEBUGKPILOT << fname << ": No HH record with id " << rid << endl;
00727 }
00728 syncAddressee(ad, backupAddr, palmAddr);
00729
00730 if (palmRec) rid=palmRec->id();
00731 KPILOT_DELETE(palmRec);
00732 KPILOT_DELETE(palmAddr);
00733 }
00734 else
00735 {
00736 DEBUGKPILOT << fname << ": Entry not updated." << endl;
00737 }
00738 KPILOT_DELETE(backupAddr);
00739 KPILOT_DELETE(backupRec);
00740
00741 DEBUGKPILOT << fname << ": adding id:["<< rid << "] to syncedIds." << endl;
00742
00743 syncedIds.append(rid);
00744
00745 QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
00746 }
00747
00748
00749
00750 void AbbrowserConduit::slotDeletedRecord()
00751 {
00752 FUNCTIONSETUP;
00753
00754 PilotRecord *backupRec = fLocalDatabase->readRecordByIndex(pilotindex++);
00755 if(!backupRec || isFirstSync() )
00756 {
00757 KPILOT_DELETE(backupRec);
00758 QTimer::singleShot(0, this, SLOT(slotDeleteUnsyncedPCRecords()));
00759 return;
00760 }
00761
00762 recordid_t id = backupRec->id();
00763
00764 QString uid = addresseeMap[id];
00765 Addressee e = aBook->findByUid(uid);
00766
00767 DEBUGKPILOT << fname << ": now looking at palm id: ["
00768 << id << "], kabc uid: [" << uid << "]." << endl;
00769
00770 PilotAddress*backupAddr=0L;
00771 if (backupRec)
00772 {
00773 backupAddr=new PilotAddress(backupRec);
00774 }
00775 PilotRecord*palmRec=fDatabase->readRecordById(id);
00776
00777 if ( e.isEmpty() )
00778 {
00779 DEBUGKPILOT << fname << ": no Addressee found for this id." << endl;
00780 DEBUGKPILOT << fname << "\n"
00781 << backupAddr->getTextRepresentation(
00782 fAddressAppInfo,Qt::PlainText) << endl;
00783
00784 if (palmRec) {
00785 DEBUGKPILOT << fname << ": deleting from database on palm." << endl;
00786 fDatabase->deleteRecord(id);
00787 fCtrHH->deleted();
00788 }
00789 DEBUGKPILOT << fname << ": deleting from backup database." << endl;
00790 fLocalDatabase->deleteRecord(id);
00791
00792
00793 pilotindex--;
00794 }
00795
00796 KPILOT_DELETE(palmRec);
00797 KPILOT_DELETE(backupAddr);
00798 KPILOT_DELETE(backupRec);
00799 QTimer::singleShot(0, this, SLOT(slotDeletedRecord()));
00800 }
00801
00802
00803
00804 void AbbrowserConduit::slotDeleteUnsyncedPCRecords()
00805 {
00806 FUNCTIONSETUP;
00807 if ( syncMode()==SyncMode::eCopyHHToPC )
00808 {
00809 QStringList uids;
00810 RecordIDList::iterator it;
00811 QString uid;
00812 for ( it = syncedIds.begin(); it != syncedIds.end(); ++it)
00813 {
00814 uid=addresseeMap[*it];
00815 if (!uid.isEmpty()) uids.append(uid);
00816 }
00817
00818
00819 AddressBook::Iterator abit;
00820 for (abit = aBook->begin(); abit != aBook->end(); ++abit)
00821 {
00822 if (!uids.contains((*abit).uid()))
00823 {
00824 DEBUGKPILOT<<"Deleting addressee "<<(*abit).realName()<<" from PC (is not on HH, and syncing with HH->PC direction)"<<endl;
00825 abChanged = true;
00826
00827 aBook->removeAddressee(*abit);
00828 fCtrPC->deleted();
00829 }
00830 }
00831 }
00832 QTimer::singleShot(0, this, SLOT(slotDeleteUnsyncedHHRecords()));
00833 }
00834
00835
00836
00837 void AbbrowserConduit::slotDeleteUnsyncedHHRecords()
00838 {
00839 FUNCTIONSETUP;
00840 if ( syncMode()==SyncMode::eCopyPCToHH )
00841 {
00842 RecordIDList ids=fDatabase->idList();
00843 RecordIDList::iterator it;
00844 for ( it = ids.begin(); it != ids.end(); ++it )
00845 {
00846 if (!syncedIds.contains(*it))
00847 {
00848 DEBUGKPILOT<<"Deleting record with ID "<<*it<<" from handheld (is not on PC, and syncing with PC->HH direction)"<<endl;
00849 fDatabase->deleteRecord(*it);
00850 fCtrHH->deleted();
00851 fLocalDatabase->deleteRecord(*it);
00852 }
00853 }
00854 }
00855 QTimer::singleShot(0, this, SLOT(slotCleanup()));
00856 }
00857
00858
00859 void AbbrowserConduit::slotCleanup()
00860 {
00861 FUNCTIONSETUP;
00862
00863
00864 _setAppInfo();
00865 if(fDatabase)
00866 {
00867 fDatabase->resetSyncFlags();
00868 fDatabase->cleanup();
00869 }
00870 if(fLocalDatabase)
00871 {
00872 fLocalDatabase->resetSyncFlags();
00873 fLocalDatabase->cleanup();
00874 }
00875
00876
00877 QString syncFile = fLocalDatabase->dbPathName() + CSL1(".sync");
00878 DEBUGKPILOT << fname << ": Writing sync map to " << syncFile << endl;
00879 KSaveFile map( syncFile );
00880 if ( map.status() == 0 )
00881 {
00882 DEBUGKPILOT << fname << ": Writing sync map ..." << endl;
00883 (*map.dataStream()) << addresseeMap ;
00884 map.close();
00885 }
00886
00887 if ( map.status() != 0 )
00888 {
00889 WARNINGKPILOT << "Could not make backup of sync map." << endl;
00890 }
00891
00892 _saveAddressBook();
00893 delayDone();
00894 }
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905 bool AbbrowserConduit::syncAddressee(Addressee &pcAddr, PilotAddress*backupAddr,
00906 PilotAddress*palmAddr)
00907 {
00908 FUNCTIONSETUP;
00909 showAddresses(pcAddr, backupAddr, palmAddr);
00910
00911 if ( syncMode() == SyncMode::eCopyPCToHH )
00912 {
00913 if (pcAddr.isEmpty())
00914 {
00915 return _deleteAddressee(pcAddr, backupAddr, palmAddr);
00916 }
00917 else
00918 {
00919 return _copyToHH(pcAddr, backupAddr, palmAddr);
00920 }
00921 }
00922
00923 if ( syncMode() == SyncMode::eCopyHHToPC )
00924 {
00925 if (!palmAddr)
00926 {
00927 return _deleteAddressee(pcAddr, backupAddr, palmAddr);
00928 }
00929 else
00930 {
00931 return _copyToPC(pcAddr, backupAddr, palmAddr);
00932 }
00933 }
00934
00935 if ( !backupAddr || isFirstSync() )
00936 {
00937 DEBUGKPILOT<< fname << ": Special case: no backup." << endl;
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949 if (!palmAddr && KABCSync::isArchived(pcAddr) )
00950 {
00951 return true;
00952 }
00953 else if (!palmAddr && !pcAddr.isEmpty())
00954 {
00955 DEBUGKPILOT << fname << ": case: 1a"<<endl;
00956
00957 bool res=_copyToHH(pcAddr, 0L, 0L);
00958 return res;
00959 }
00960 else if (!palmAddr && pcAddr.isEmpty())
00961 {
00962 DEBUGKPILOT << fname << ": case: 1b"<<endl;
00963
00964 return false;
00965 }
00966 else if ( (isDeleted(palmAddr) || isArchived(palmAddr)) && pcAddr.isEmpty())
00967 {
00968 DEBUGKPILOT << fname << ": case: 1c"<<endl;
00969 if (isArchived(palmAddr))
00970 return _copyToPC(pcAddr, 0L, palmAddr);
00971 else
00972
00973 return _deleteAddressee(pcAddr, 0L, palmAddr);
00974 }
00975 else if ((isDeleted(palmAddr)||isArchived(palmAddr)) && !pcAddr.isEmpty())
00976 {
00977 DEBUGKPILOT << fname << ": case: 1d"<<endl;
00978
00979 return _smartMergeAddressee(pcAddr, 0L, palmAddr);
00980 }
00981 else if (pcAddr.isEmpty())
00982 {
00983 DEBUGKPILOT << fname << ": case: 1e"<<endl;
00984
00985 return _copyToPC(pcAddr, 0L, palmAddr);
00986 }
00987 else
00988 {
00989 DEBUGKPILOT << fname << ": case: 1f"<<endl;
00990
00991 return _smartMergeAddressee(pcAddr, 0L, palmAddr);
00992 }
00993 }
00994 else
00995 {
00996 DEBUGKPILOT << fname << ": case: 2"<<endl;
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009 if (!palmAddr || isDeleted(palmAddr) )
01010 {
01011 DEBUGKPILOT << fname << ": case: 2a"<<endl;
01012 if (_equal(backupAddr, pcAddr) || pcAddr.isEmpty())
01013 {
01014 return _deleteAddressee(pcAddr, backupAddr, 0L);
01015 }
01016 else
01017 {
01018 return _smartMergeAddressee(pcAddr, backupAddr, 0L);
01019 }
01020 }
01021 else if (pcAddr.isEmpty())
01022 {
01023 DEBUGKPILOT << fname << ": case: 2b"<<endl;
01024 if (*palmAddr == *backupAddr)
01025 {
01026 return _deleteAddressee(pcAddr, backupAddr, palmAddr);
01027 }
01028 else
01029 {
01030 return _smartMergeAddressee(pcAddr, backupAddr, palmAddr);
01031 }
01032 }
01033 else if (_equal(palmAddr, pcAddr))
01034 {
01035 DEBUGKPILOT << fname << ": case: 2c"<<endl;
01036
01037 return _writeBackup(palmAddr);
01038 }
01039 else if (_equal(backupAddr, pcAddr))
01040 {
01041 DEBUGKPILOT << fname << ": case: 2d"<<endl;
01042 DEBUGKPILOT << fname << ": Flags: "<<palmAddr->attributes()<<", isDeleted="<<
01043 isDeleted(palmAddr)<<", isArchived="<<isArchived(palmAddr)<<endl;
01044 if (isDeleted(palmAddr))
01045 return _deleteAddressee(pcAddr, backupAddr, palmAddr);
01046 else
01047 return _copyToPC(pcAddr, backupAddr, palmAddr);
01048 }
01049 else if (*palmAddr == *backupAddr)
01050 {
01051 DEBUGKPILOT << fname << ": case: 2e"<<endl;
01052 return _copyToHH(pcAddr, backupAddr, palmAddr);
01053 }
01054 else
01055 {
01056 DEBUGKPILOT << fname << ": case: 2f"<<endl;
01057
01058 return _smartMergeAddressee(pcAddr, backupAddr, palmAddr);
01059 }
01060 }
01061 return false;
01062 }
01063
01064
01065
01066 bool AbbrowserConduit::_copyToHH(Addressee &pcAddr, PilotAddress*backupAddr,
01067 PilotAddress*palmAddr)
01068 {
01069 FUNCTIONSETUP;
01070
01071 if (pcAddr.isEmpty()) return false;
01072 PilotAddress*paddr=palmAddr;
01073 bool paddrcreated=false;
01074 if (!paddr)
01075 {
01076 paddr=new PilotAddress();
01077 paddrcreated=true;
01078 fCtrHH->created();
01079 }
01080 else
01081 {
01082 fCtrHH->updated();
01083 }
01084 KABCSync::copy(*paddr, pcAddr, *fAddressAppInfo, fSyncSettings);
01085
01086 DEBUGKPILOT << fname << "palmAddr->id=" << paddr->id()
01087 << ", pcAddr.ID=" << pcAddr.custom(KABCSync::appString, KABCSync::idString) << endl;
01088
01089 if(_savePalmAddr(paddr, pcAddr))
01090 {
01091 _savePCAddr(pcAddr, backupAddr, paddr);
01092 }
01093 if (paddrcreated) KPILOT_DELETE(paddr);
01094 return true;
01095 }
01096
01097
01098
01099 bool AbbrowserConduit::_copyToPC(Addressee &pcAddr, PilotAddress*backupAddr,
01100 PilotAddress*palmAddr)
01101 {
01102 FUNCTIONSETUP;
01103 if (!palmAddr)
01104 {
01105 return false;
01106 }
01107
01108 if (pcAddr.isEmpty())
01109 {
01110 fCtrPC->created();
01111 }
01112 else
01113 {
01114 fCtrPC->updated();
01115 }
01116 showPilotAddress(palmAddr);
01117
01118 KABCSync::copy(pcAddr, *palmAddr, *fAddressAppInfo, fSyncSettings);
01119 if (isArchived(palmAddr))
01120 {
01121 KABCSync::makeArchived(pcAddr);
01122 }
01123
01124 _savePCAddr(pcAddr, backupAddr, palmAddr);
01125 _writeBackup(palmAddr);
01126 return true;
01127 }
01128
01129
01130
01131 bool AbbrowserConduit::_writeBackup(PilotAddress *backup)
01132 {
01133 FUNCTIONSETUP;
01134 if (!backup) return false;
01135
01136 showPilotAddress(backup);
01137
01138 PilotRecord *pilotRec = backup->pack();
01139 fLocalDatabase->writeRecord(pilotRec);
01140 KPILOT_DELETE(pilotRec);
01141 return true;
01142 }
01143
01144
01145
01146 bool AbbrowserConduit::_deleteAddressee(Addressee &pcAddr, PilotAddress*backupAddr,
01147 PilotAddress*palmAddr)
01148 {
01149 FUNCTIONSETUP;
01150
01151 if (palmAddr)
01152 {
01153 if (!syncedIds.contains(palmAddr->id())) {
01154 DEBUGKPILOT << fname << ": adding id:["<< palmAddr->id() << "] to syncedIds." << endl;
01155 syncedIds.append(palmAddr->id());
01156 }
01157 fDatabase->deleteRecord(palmAddr->id());
01158 fCtrHH->deleted();
01159 fLocalDatabase->deleteRecord(palmAddr->id());
01160 }
01161 else if (backupAddr)
01162 {
01163 if (!syncedIds.contains(backupAddr->id())) {
01164 DEBUGKPILOT << fname << ": adding id:["<< backupAddr->id() << "] to syncedIds." << endl;
01165 syncedIds.append(backupAddr->id());
01166 }
01167 fLocalDatabase->deleteRecord(backupAddr->id());
01168 }
01169 if (!pcAddr.isEmpty())
01170 {
01171 DEBUGKPILOT << fname << " removing " << pcAddr.formattedName() << endl;
01172 abChanged = true;
01173 aBook->removeAddressee(pcAddr);
01174 fCtrPC->deleted();
01175 }
01176 return true;
01177 }
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188 bool AbbrowserConduit::_savePalmAddr(PilotAddress *palmAddr, Addressee &pcAddr)
01189 {
01190 FUNCTIONSETUP;
01191
01192 DEBUGKPILOT << fname << ": Saving to pilot " << palmAddr->id()
01193 << " " << palmAddr->getField(entryFirstname)
01194 << " " << palmAddr->getField(entryLastname)<< endl;
01195
01196 PilotRecord *pilotRec = palmAddr->pack();
01197 DEBUGKPILOT << fname << ": record with id=" << pilotRec->id()
01198 << " len=" << pilotRec->size() << endl;
01199 recordid_t pilotId = fDatabase->writeRecord(pilotRec);
01200 DEBUGKPILOT << fname << ": Wrote "<<pilotId<<": ID="<<pilotRec->id()<<endl;
01201 fLocalDatabase->writeRecord(pilotRec);
01202 KPILOT_DELETE(pilotRec);
01203
01204
01205 if(pilotId != 0)
01206 {
01207 palmAddr->setID(pilotId);
01208 if (!syncedIds.contains(pilotId)) {
01209 DEBUGKPILOT << fname << ": adding id:["<< pilotId << "] to syncedIds." << endl;
01210 syncedIds.append(pilotId);
01211 }
01212 }
01213
01214 recordid_t abId = 0;
01215 abId = pcAddr.custom(KABCSync::appString, KABCSync::idString).toUInt();
01216 if(abId != pilotId)
01217 {
01218 pcAddr.insertCustom(KABCSync::appString, KABCSync::idString, QString::number(pilotId));
01219 return true;
01220 }
01221
01222 return false;
01223 }
01224
01225
01226
01227 bool AbbrowserConduit::_savePCAddr(Addressee &pcAddr, PilotAddress*,
01228 PilotAddress*)
01229 {
01230 FUNCTIONSETUP;
01231
01232 DEBUGKPILOT<<"Before _savePCAddr, pcAddr.custom="<<pcAddr.custom(KABCSync::appString, KABCSync::idString)<<endl;
01233 QString pilotId = pcAddr.custom(KABCSync::appString, KABCSync::idString);
01234 long pilotIdL = pilotId.toLong();
01235 if(!pilotId.isEmpty())
01236 {
01237
01238
01239
01240 QMap < recordid_t, QString>::iterator it;
01241 for ( it = addresseeMap.begin(); it != addresseeMap.end(); ++it ) {
01242 QString kabcUid = it.data();
01243 if (kabcUid == pcAddr.uid()) {
01244 addresseeMap.remove(it);
01245 break;
01246 }
01247 }
01248
01249
01250 addresseeMap.insert(pilotIdL, pcAddr.uid());
01251 }
01252
01253 aBook->insertAddressee(pcAddr);
01254
01255 abChanged = true;
01256 return true;
01257 }
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268 bool AbbrowserConduit::_equal(const PilotAddress *piAddress, const Addressee &abEntry,
01269 enum eqFlagsType flags) const
01270 {
01271 FUNCTIONSETUP;
01272
01273
01274 if (!piAddress) {
01275 DEBUGKPILOT << fname << ": no pilot address passed" << endl;
01276 return false;
01277 }
01278 if (abEntry.isEmpty()) {
01279 DEBUGKPILOT << fname << ":abEntry.isEmpty()" << endl;
01280 return false;
01281 }
01282
01283 if (flags & eqFlagsFlags)
01284 if (isArchived(piAddress) && KABCSync::isArchived(abEntry) ) return true;
01285
01286 if (flags & eqFlagsName)
01287 {
01288 if(!_equal(abEntry.familyName(), piAddress->getField(entryLastname)))
01289 {
01290 DEBUGKPILOT << fname << ": last name not equal" << endl;
01291 return false;
01292 }
01293 if(!_equal(abEntry.givenName(), piAddress->getField(entryFirstname)))
01294 {
01295 DEBUGKPILOT << fname << ": first name not equal" << endl;
01296 return false;
01297 }
01298 if(!_equal(abEntry.prefix(), piAddress->getField(entryTitle)))
01299 {
01300 DEBUGKPILOT << fname << ": title/prefix not equal" << endl;
01301 return false;
01302 }
01303 if(!_equal(abEntry.organization(), piAddress->getField(entryCompany)))
01304 {
01305 DEBUGKPILOT << fname << ": company/organization not equal" << endl;
01306 return false;
01307 }
01308 }
01309 if (flags & eqFlagsNote)
01310 if(!_equal(abEntry.note(), piAddress->getField(entryNote)))
01311 {
01312 DEBUGKPILOT << fname << ": note not equal" << endl;
01313 return false;
01314 }
01315
01316 if (flags & eqFlagsCategory)
01317 {
01318
01319
01320 QString addressCategoryLabel = fAddressAppInfo->categoryName(piAddress->category());
01321 QString cat = KABCSync::bestMatchedCategoryName(abEntry.categories(),
01322 *fAddressAppInfo, piAddress->category());
01323 if(!_equal(cat, addressCategoryLabel))
01324 {
01325 DEBUGKPILOT << fname << ": category not equal" << endl;
01326 return false;
01327 }
01328 }
01329
01330 if (flags & eqFlagsPhones)
01331 {
01332
01333 QStringList abEmails(abEntry.emails());
01334 QStringList piEmails(piAddress->getEmails());
01335
01336 if (abEmails.count() != piEmails.count())
01337 {
01338 DEBUGKPILOT << fname << ": email count not equal" << endl;
01339 return false;
01340 }
01341 for (QStringList::Iterator it = abEmails.begin(); it != abEmails.end(); it++) {
01342 if (!piEmails.contains(*it))
01343 {
01344 DEBUGKPILOT << fname << ": pilot e-mail missing" << endl;
01345 return false;
01346 }
01347 }
01348 for (QStringList::Iterator it = piEmails.begin(); it != piEmails.end(); it++) {
01349 if (!abEmails.contains(*it))
01350 {
01351 DEBUGKPILOT << fname << ": kabc e-mail missing" << endl;
01352 return false;
01353 }
01354 }
01355
01356
01357
01358
01359
01360 PhoneNumber::List abPhones(abEntry.phoneNumbers());
01361 PhoneNumber::List piPhones = KABCSync::getPhoneNumbers(*piAddress);
01362
01363 for (PhoneNumber::List::Iterator it = piPhones.begin(); it != piPhones.end(); it++) {
01364 PhoneNumber piPhone = *it;
01365 bool found=false;
01366 for (PhoneNumber::List::Iterator it = abPhones.begin(); it != abPhones.end(); it++) {
01367 PhoneNumber abPhone = *it;
01368
01369
01370
01371
01372 if ( _equal(piPhone.number(), abPhone.number()) ) {
01373 found = true;
01374 break;
01375 }
01376 }
01377 if (!found) {
01378 DEBUGKPILOT << fname << ": not equal because kabc phone not found." << endl;
01379 return false;
01380 }
01381 }
01382
01383
01384 for (PhoneNumber::List::Iterator it = abPhones.begin(); it != abPhones.end(); it++) {
01385 PhoneNumber abPhone = *it;
01386 bool found=false;
01387 for (PhoneNumber::List::Iterator it = piPhones.begin(); it != piPhones.end(); it++) {
01388 PhoneNumber piPhone = *it;
01389 if ( _equal(piPhone.number(), abPhone.number()) ) {
01390 found = true;
01391 break;
01392 }
01393 }
01394 if (!found)
01395 {
01396 DEBUGKPILOT << fname << ": not equal because pilot phone not found." << endl;
01397 return false;
01398 }
01399 }
01400
01401 if(!_equal(KABCSync::getFieldForHHOtherPhone(abEntry,fSyncSettings),
01402 piAddress->getPhoneField(PilotAddressInfo::eOther)))
01403 {
01404 DEBUGKPILOT << fname << ": not equal because of other phone field." << endl;
01405 return false;
01406 }
01407 }
01408
01409 if (flags & eqFlagsAdress)
01410 {
01411 KABC::Address address = KABCSync::getAddress(abEntry,fSyncSettings);
01412 if(!_equal(address.street(), piAddress->getField(entryAddress)))
01413 {
01414 DEBUGKPILOT << fname << ": address not equal" << endl;
01415 return false;
01416 }
01417 if(!_equal(address.locality(), piAddress->getField(entryCity)))
01418 {
01419 DEBUGKPILOT << fname << ": city not equal" << endl;
01420 return false;
01421 }
01422 if(!_equal(address.region(), piAddress->getField(entryState)))
01423 {
01424 DEBUGKPILOT << fname << ": state not equal" << endl;
01425 return false;
01426 }
01427 if(!_equal(address.postalCode(), piAddress->getField(entryZip)))
01428 {
01429 DEBUGKPILOT << fname << ": zip not equal" << endl;
01430 return false;
01431 }
01432 if(!_equal(address.country(), piAddress->getField(entryCountry)))
01433 {
01434 DEBUGKPILOT << fname << ": country not equal" << endl;
01435 return false;
01436 }
01437 }
01438
01439 if (flags & eqFlagsCustom)
01440 {
01441 unsigned int customIndex = 0;
01442 unsigned int hhField = entryCustom1;
01443
01444 for ( ; customIndex<4; ++customIndex,++hhField )
01445 {
01446 if (!_equal(KABCSync::getFieldForHHCustom(customIndex, abEntry, fSyncSettings),
01447 piAddress->getField(hhField)))
01448 {
01449 DEBUGKPILOT << fname << ": Custom field " << customIndex
01450 << " (HH field " << hhField << ") differs." << endl;
01451 return false;
01452 }
01453 }
01454 }
01455
01456
01457
01458 if ( (flags & eqFlagsFlags) && (isArchived(piAddress) || KABCSync::isArchived(abEntry) ) )
01459 {
01460 DEBUGKPILOT << fname << ": archived flags don't match" << endl;
01461 return false;
01462 }
01463
01464 return true;
01465 }
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01486 QString AbbrowserConduit::_smartMergeString(const QString &pc, const QString & backup,
01487 const QString & palm, ConflictResolution confRes)
01488 {
01489 FUNCTIONSETUP;
01490
01491
01492 if(pc == palm) return pc;
01493
01494
01495 if(isFirstSync() || backup.isEmpty()) {
01496 if (pc.isEmpty() && palm.isEmpty() ) return QString::null;
01497 if(pc.isEmpty()) return palm;
01498 if(palm.isEmpty()) return pc;
01499 } else {
01500
01501 if(palm == backup) return pc;
01502 if(pc == backup) return palm;
01503 }
01504
01505 DEBUGKPILOT<<"pc="<<pc<<", backup="<<backup<<", palm="<<
01506 palm<<", ConfRes="<<confRes<<endl;
01507 DEBUGKPILOT<<"Use conflict resolution :"<<confRes<<
01508 ", PC="<<SyncAction::ePCOverrides<<endl;
01509 switch(confRes) {
01510 case SyncAction::ePCOverrides: return pc; break;
01511 case SyncAction::eHHOverrides: return palm; break;
01512 case SyncAction::ePreviousSyncOverrides: return backup; break;
01513 default: break;
01514 }
01515 return QString::null;
01516 }
01517
01518
01519
01520 bool AbbrowserConduit::_buildResolutionTable(ResolutionTable*tab, const Addressee &pcAddr,
01521 PilotAddress *backupAddr, PilotAddress *palmAddr)
01522 {
01523 FUNCTIONSETUP;
01524 if (!tab) return false;
01525 tab->setAutoDelete( TRUE );
01526 tab->labels[0]=i18n("Item on PC");
01527 tab->labels[1]=i18n("Handheld");
01528 tab->labels[2]=i18n("Last sync");
01529 if (!pcAddr.isEmpty())
01530 tab->fExistItems=(eExistItems)(tab->fExistItems|eExistsPC);
01531 if (backupAddr)
01532 tab->fExistItems=(eExistItems)(tab->fExistItems|eExistsBackup);
01533 if (palmAddr)
01534 tab->fExistItems=(eExistItems)(tab->fExistItems|eExistsPalm);
01535
01536 #define appendGen(desc, abfield, palmfield) \
01537 tab->append(new ResolutionItem(desc, tab->fExistItems, \
01538 (!pcAddr.isEmpty())?(abfield):(QString::null), \
01539 (palmAddr)?(palmAddr->palmfield):(QString::null), \
01540 (backupAddr)?(backupAddr->palmfield):(QString::null) ))
01541 #define appendAddr(desc, abfield, palmfield) \
01542 appendGen(desc, abfield, getField(palmfield))
01543 #define appendGenPhone(desc, abfield, palmfield) \
01544 appendGen(desc, abfield, getPhoneField(PilotAddressInfo::palmfield))
01545 #define appendPhone(desc, abfield, palmfield) \
01546 appendGenPhone(desc, pcAddr.phoneNumber(PhoneNumber::abfield).number(), palmfield)
01547
01548
01549 appendAddr(i18n("Last name"), pcAddr.familyName(), entryLastname);
01550 appendAddr(i18n("First name"), pcAddr.givenName(), entryFirstname);
01551 appendAddr(i18n("Organization"), pcAddr.organization(), entryCompany);
01552 appendAddr(i18n("Title"), pcAddr.prefix(), entryTitle);
01553 appendAddr(i18n("Note"), pcAddr.note(), entryNote);
01554
01555 appendAddr(i18n("Custom 1"), KABCSync::getFieldForHHCustom(0, pcAddr, fSyncSettings), entryCustom1);
01556 appendAddr(i18n("Custom 2"), KABCSync::getFieldForHHCustom(1, pcAddr, fSyncSettings), entryCustom2);
01557 appendAddr(i18n("Custom 3"), KABCSync::getFieldForHHCustom(2, pcAddr, fSyncSettings), entryCustom3);
01558 appendAddr(i18n("Custom 4"), KABCSync::getFieldForHHCustom(3, pcAddr, fSyncSettings), entryCustom4);
01559
01560 appendPhone(i18n("Work Phone"), Work, eWork);
01561 appendPhone(i18n("Home Phone"), Home, eHome);
01562 appendPhone(i18n("Mobile Phone"), Cell, eMobile);
01563 appendGenPhone(i18n("Fax"), pcAddr.phoneNumber(faxTypeOnPC()).number(), eFax);
01564 appendPhone(i18n("Pager"), Pager, ePager);
01565 appendGenPhone(i18n("Other"), KABCSync::getFieldForHHOtherPhone(pcAddr,fSyncSettings), eOther);
01566 appendGenPhone(i18n("Email"), pcAddr.preferredEmail(), eEmail);
01567
01568 KABC::Address abAddress = KABCSync::getAddress(pcAddr,fSyncSettings);
01569 appendAddr(i18n("Address"), abAddress.street(), entryAddress);
01570 appendAddr(i18n("City"), abAddress.locality(), entryCity);
01571 appendAddr(i18n("Region"), abAddress.region(), entryState);
01572 appendAddr(i18n("Postal code"), abAddress.postalCode(), entryZip);
01573 appendAddr(i18n("Country"), abAddress.country(), entryCountry);
01574
01575 QString palmAddrCategoryLabel;
01576 if (palmAddr)
01577 {
01578 palmAddrCategoryLabel = fAddressAppInfo->categoryName(palmAddr->category());
01579 }
01580 QString backupAddrCategoryLabel;
01581 if (backupAddr)
01582 {
01583 backupAddrCategoryLabel = fAddressAppInfo->categoryName(backupAddr->category());
01584 }
01585 int category = palmAddr ? palmAddr->category() : 0;
01586 tab->append(new ResolutionItem(
01587 i18n("Category"),
01588 tab->fExistItems,
01589 !pcAddr.isEmpty() ?
01590 KABCSync::bestMatchedCategoryName(pcAddr.categories(), *fAddressAppInfo, category) :
01591 QString::null,
01592 palmAddrCategoryLabel,
01593 backupAddrCategoryLabel));
01594 #undef appendGen
01595 #undef appendAddr
01596 #undef appendGenPhone
01597 #undef appendPhone
01598
01599 return true;
01600 }
01601
01602
01604 static inline void setPhoneNumber(Addressee &abEntry, int type, const QString &nr)
01605 {
01606 PhoneNumber phone = abEntry.phoneNumber(type);
01607 phone.setNumber(nr);
01608 abEntry.insertPhoneNumber(phone);
01609 }
01610
01611
01612 bool AbbrowserConduit::_applyResolutionTable(ResolutionTable*tab, Addressee &pcAddr,
01613 PilotAddress *backupAddr, PilotAddress *palmAddr)
01614 {
01615 FUNCTIONSETUP;
01616 if (!tab) return false;
01617 if (!palmAddr) {
01618 WARNINGKPILOT << "Empty palmAddr after conflict resolution." << endl;
01619 return false;
01620 }
01621
01622 ResolutionItem*item=tab->first();
01623 #define SETGENFIELD(abfield, palmfield) \
01624 if (item) {\
01625 abfield; \
01626 palmAddr->setField(palmfield, item->fResolved); \
01627 }\
01628 item=tab->next();
01629 #define SETFIELD(abfield, palmfield) \
01630 SETGENFIELD(pcAddr.set##abfield(item->fResolved), palmfield)
01631 #define SETCUSTOMFIELD(abfield, palmfield) \
01632 SETGENFIELD(KABCSync::setFieldFromHHCustom(abfield, pcAddr, item->fResolved, fSyncSettings), palmfield)
01633 #define SETGENPHONE(abfield, palmfield) \
01634 if (item) { \
01635 abfield; \
01636 palmAddr->setPhoneField(PilotAddressInfo::palmfield, item->fResolved, PilotAddress::Replace); \
01637 }\
01638 item=tab->next();
01639 #define SETPHONEFIELD(abfield, palmfield) \
01640 SETGENPHONE(setPhoneNumber(pcAddr, PhoneNumber::abfield, item->fResolved), palmfield)
01641 #define SETADDRESSFIELD(abfield, palmfield) \
01642 SETGENFIELD(abAddress.abfield(item->fResolved), palmfield)
01643
01644 SETFIELD(FamilyName, entryLastname);
01645 SETFIELD(GivenName, entryFirstname);
01646 SETFIELD(Organization, entryCompany);
01647 SETFIELD(Prefix, entryTitle);
01648 SETFIELD(Note, entryNote);
01649
01650 SETCUSTOMFIELD(0, entryCustom1);
01651 SETCUSTOMFIELD(1, entryCustom2);
01652 SETCUSTOMFIELD(2, entryCustom3);
01653 SETCUSTOMFIELD(3, entryCustom4);
01654
01655 SETPHONEFIELD(Work, eWork);
01656 SETPHONEFIELD(Home, eHome);
01657 SETPHONEFIELD(Cell, eMobile);
01658 SETGENPHONE(setPhoneNumber(pcAddr, faxTypeOnPC(), item->fResolved), eFax);
01659 SETPHONEFIELD(Pager, ePager);
01660 SETGENPHONE(KABCSync::setFieldFromHHOtherPhone(pcAddr, item->fResolved, fSyncSettings), eOther);
01661
01662
01663 if (item)
01664 {
01665 palmAddr->setPhoneField(PilotAddressInfo::eEmail, item->fResolved, PilotAddress::Replace);
01666 if (backupAddr)
01667 {
01668 pcAddr.removeEmail(backupAddr->getPhoneField(PilotAddressInfo::eEmail));
01669 }
01670 pcAddr.removeEmail(palmAddr->getPhoneField(PilotAddressInfo::eEmail));
01671 pcAddr.insertEmail(item->fResolved, true);
01672 }
01673 item=tab->next();
01674
01675 KABC::Address abAddress = KABCSync::getAddress(pcAddr, fSyncSettings);
01676 SETADDRESSFIELD(setStreet, entryAddress);
01677 SETADDRESSFIELD(setLocality, entryCity);
01678 SETADDRESSFIELD(setRegion, entryState);
01679 SETADDRESSFIELD(setPostalCode, entryZip);
01680 SETADDRESSFIELD(setCountry, entryCountry);
01681 pcAddr.insertAddress(abAddress);
01682
01683
01684 if (item)
01685 {
01686 palmAddr->setCategory( fAddressAppInfo->findCategory(item->fResolved) );
01687 KABCSync::setCategory(pcAddr, item->fResolved);
01688 }
01689
01690
01691 #undef SETGENFIELD
01692 #undef SETFIELD
01693 #undef SETCUSTOMFIELD
01694 #undef SETGENPHONE
01695 #undef SETPHONEFIELD
01696 #undef SETADDRESSFIELD
01697
01698 return true;
01699 }
01700
01701
01702
01703 bool AbbrowserConduit::_smartMergeTable(ResolutionTable*tab)
01704 {
01705 FUNCTIONSETUP;
01706 if (!tab) return false;
01707 bool noconflict=true;
01708 ResolutionItem*item;
01709 for ( item = tab->first(); item; item = tab->next() )
01710 {
01711
01712 item->fResolved=_smartMergeString(item->fEntries[0],
01713 item->fEntries[2], item->fEntries[1], getConflictResolution());
01714
01715 if (item->fResolved.isNull() && !(item->fEntries[0].isEmpty() &&
01716 item->fEntries[1].isEmpty() && item->fEntries[2].isEmpty() ) )
01717 {
01718 item->fResolved=item->fEntries[0];
01719 noconflict=false;
01720 }
01721 if (item->fResolved.isNull()) item->fResolved=item->fEntries[1];
01722 if (item->fResolved.isNull()) item->fResolved=item->fEntries[2];
01723 }
01724 return noconflict;
01725 }
01726
01727
01728
01733 bool AbbrowserConduit::_smartMergeAddressee(Addressee &pcAddr,
01734 PilotAddress *backupAddr, PilotAddress *palmAddr)
01735 {
01736 FUNCTIONSETUP;
01737
01738
01739 int res = SyncAction::eAskUser;
01740 bool result=true;
01741 ResolutionTable tab;
01742
01743 result &= _buildResolutionTable(&tab, pcAddr, backupAddr, palmAddr);
01744
01745 bool mergeOk=_smartMergeTable(&tab);
01746
01747 if (!mergeOk)
01748 {
01749 QString dlgText;
01750 if (!palmAddr)
01751 {
01752 dlgText=i18n("The following address entry was changed, but does no longer exist on the handheld. Please resolve this conflict:");
01753 }
01754 else if (pcAddr.isEmpty())
01755 {
01756 dlgText=i18n("The following address entry was changed, but does no longer exist on the PC. Please resolve this conflict:");
01757 }
01758 else
01759 {
01760 dlgText=i18n("The following address entry was changed on the handheld as well as on the PC side. The changes could not be merged automatically, so please resolve the conflict yourself:");
01761 }
01762 ResolutionDlg*resdlg=new ResolutionDlg(0L, fHandle, i18n("Address conflict"), dlgText, &tab);
01763 resdlg->exec();
01764 KPILOT_DELETE(resdlg);
01765 }
01766 res=tab.fResolution;
01767
01768
01769 switch (res) {
01770 case SyncAction::eHHOverrides:
01771 if (!palmAddr) res=SyncAction::eDelete;
01772 break;
01773 case SyncAction::ePCOverrides:
01774 if (pcAddr.isEmpty()) res=SyncAction::eDelete;
01775 break;
01776 case SyncAction::ePreviousSyncOverrides:
01777 if (!backupAddr) res=SyncAction::eDoNothing;
01778 break;
01779 }
01780
01781 PilotAddress*pAddr=palmAddr;
01782 bool pAddrCreated=false;
01783
01784 switch (res) {
01785 case SyncAction::eDuplicate:
01786
01787 pcAddr.removeCustom(KABCSync::appString, KABCSync::idString);
01788 result &= _copyToHH(pcAddr, 0L, 0L);
01789 {
01790 Addressee pcadr;
01791 result &= _copyToPC(pcadr, backupAddr, palmAddr);
01792 }
01793 break;
01794 case SyncAction::eDoNothing:
01795 break;
01796 case SyncAction::eHHOverrides:
01797 result &= _copyToPC(pcAddr, backupAddr, palmAddr);
01798 break;
01799 case SyncAction::ePCOverrides:
01800 result &= _copyToHH(pcAddr, backupAddr, pAddr);
01801 break;
01802 case SyncAction::ePreviousSyncOverrides:
01803 KABCSync::copy(pcAddr, *backupAddr, *fAddressAppInfo, fSyncSettings);
01804 if (palmAddr && backupAddr) *palmAddr=*backupAddr;
01805 result &= _savePalmAddr(backupAddr, pcAddr);
01806 result &= _savePCAddr(pcAddr, backupAddr, backupAddr);
01807 break;
01808 case SyncAction::eDelete:
01809 result &= _deleteAddressee(pcAddr, backupAddr, palmAddr);
01810 break;
01811 case SyncAction::eAskUser:
01812 default:
01813 if (!pAddr)
01814 {
01815 pAddr=new PilotAddress();
01816 pAddrCreated=true;
01817 }
01818 result &= _applyResolutionTable(&tab, pcAddr, backupAddr, pAddr);
01819 showAddresses(pcAddr, backupAddr, pAddr);
01820
01821 result &= _savePalmAddr(pAddr, pcAddr);
01822 result &= _savePCAddr(pcAddr, backupAddr, pAddr);
01823 if (pAddrCreated) KPILOT_DELETE(pAddr);
01824 break;
01825 }
01826
01827 return result;
01828 }
01829
01830
01831
01832
01833
01834
01835 Addressee AbbrowserConduit::_findMatch(const PilotAddress & pilotAddress) const
01836 {
01837 FUNCTIONSETUP;
01838
01839
01840 if( !isFirstSync() && (pilotAddress.id() > 0) )
01841 {
01842 QString id(addresseeMap[pilotAddress.id()]);
01843 DEBUGKPILOT << fname << ": PilotRecord has id " << pilotAddress.id() << ", mapped to " << id << endl;
01844 if(!id.isEmpty())
01845 {
01846 Addressee res(aBook->findByUid(id));
01847 if(!res.isEmpty()) return res;
01848 DEBUGKPILOT << fname << ": PilotRecord has id " << pilotAddress.id() << ", but could not be found in the addressbook" << endl;
01849 }
01850 }
01851
01852 for(AddressBook::Iterator iter = aBook->begin(); iter != aBook->end(); ++iter)
01853 {
01854 Addressee abEntry = *iter;
01855 QString recID(abEntry.custom(KABCSync::appString, KABCSync::idString));
01856 bool ok;
01857 if (!recID.isEmpty() )
01858 {
01859 recordid_t rid = recID.toLong(&ok);
01860 if (ok && rid)
01861 {
01862 if (rid==pilotAddress.id()) return abEntry;
01863
01864 if (allIds.contains(rid)) continue;
01865 }
01866 }
01867
01868 if (_equal(&pilotAddress, abEntry, eqFlagsAlmostAll))
01869 {
01870 return abEntry;
01871 }
01872 }
01873 DEBUGKPILOT << fname << ": Could not find any addressbook enty matching " << pilotAddress.getField(entryLastname) << endl;
01874 return Addressee();
01875 }
01876
01877 void AbbrowserConduit::slotTestRecord()
01878 {
01879 FUNCTIONSETUP;
01880
01881
01882 PilotRecord *r = fDatabase->readRecordByIndex( pilotindex );
01883 if (!r)
01884 {
01885 delayDone();
01886 return;
01887 }
01888 PilotAddress a(r);
01889 KPILOT_DELETE(r);
01890
01891
01892 showPilotAddress(&a);
01893
01894
01895 ++pilotindex;
01896 QTimer::singleShot(0, this, SLOT(slotTestRecord()));
01897 }