diff options
Diffstat (limited to 'kpilot/conduits/abbrowserconduit/abbrowser-conduit.cc')
-rw-r--r-- | kpilot/conduits/abbrowserconduit/abbrowser-conduit.cc | 1897 |
1 files changed, 0 insertions, 1897 deletions
diff --git a/kpilot/conduits/abbrowserconduit/abbrowser-conduit.cc b/kpilot/conduits/abbrowserconduit/abbrowser-conduit.cc deleted file mode 100644 index 11e25f2dd..000000000 --- a/kpilot/conduits/abbrowserconduit/abbrowser-conduit.cc +++ /dev/null @@ -1,1897 +0,0 @@ -/* KPilot -** -** Copyright (C) 2000,2001 by Dan Pilone -** Copyright (C) 2002-2003 by Reinhold Kainhofer -** Copyright (C) 2007 by Adriaan de Groot <[email protected]> -** -** The abbrowser conduit copies addresses from the Pilot's address book to -** the KDE addressbook maintained via the kabc library. -*/ - -/* -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program in a file called COPYING; if not, write to -** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -** MA 02110-1301, USA. -*/ - -/* -** Bug reports and questions can be sent to [email protected]. -*/ - - - -#include "options.h" - -#include <tqtimer.h> -#include <tqtextcodec.h> -#include <tqfile.h> -#include <tqregexp.h> - -#include <kabc/stdaddressbook.h> -#include <kabc/resourcefile.h> -#include <kio/netaccess.h> -#include <ksavefile.h> - -#include <pilotSerialDatabase.h> -#include <pilotLocalDatabase.h> - -#include "resolutionDialog.h" -#include "resolutionTable.h" -#include "abbrowserSettings.h" -#include "kabcRecord.h" - -#include "abbrowser-conduit.moc" - -// Something to allow us to check what revision -// the modules are that make up a binary distribution. -// -// -extern "C" -{ -unsigned long version_conduit_address = Pilot::PLUGIN_API; -} - - -/* This is partly stolen from the boost libraries, partly from -* "Modern C++ design" for doing compile time checks; we need -* to make sure that the enum values in KABCSync:: and in the -* AbbrowserSettings class are the same so that both interpret -* configuration values the same way. -*/ -template<bool> struct EnumerationMismatch; -template<> struct EnumerationMismatch<true>{}; - -#define CHECK_ENUM(a) (void)sizeof(EnumerationMismatch<((int)KABCSync::a)==((int)AbbrowserSettings::a)>) - -static inline void compile_time_check() -{ - // Mappings for other phone - CHECK_ENUM(eOtherPhone); - CHECK_ENUM(eOtherPhone); - CHECK_ENUM(eAssistant); - CHECK_ENUM(eBusinessFax); - CHECK_ENUM(eCarPhone); - CHECK_ENUM(eEmail2); - CHECK_ENUM(eHomeFax); - CHECK_ENUM(eTelex); - CHECK_ENUM(eTTYTTDPhone); - - // Mappings for custom fields - CHECK_ENUM(eCustomField); - CHECK_ENUM(eCustomBirthdate); - CHECK_ENUM(eCustomURL); - CHECK_ENUM(eCustomIM); -} - -inline int faxTypeOnPC() -{ - return KABC::PhoneNumber::Fax | - ( (AbbrowserSettings::pilotFax()==0) ? - KABC::PhoneNumber::Home : - KABC::PhoneNumber::Work ); -} - - -using namespace KABC; - -/********************************************************************* - C O N S T R U C T O R - *********************************************************************/ - - -AbbrowserConduit::AbbrowserConduit(KPilotLink * o, const char *n, const TQStringList & a): - ConduitAction(o, n, a), - aBook(0L), - fAddressAppInfo(0L), - addresseeMap(), - syncedIds(), - abiter(), - fTicket(0L), - fCreatedBook(false), - fBookResource(0L) -{ - FUNCTIONSETUP; - fConduitName=i18n("Addressbook"); -} - - - -AbbrowserConduit::~AbbrowserConduit() -{ - FUNCTIONSETUP; - - if (fTicket) - { - DEBUGKPILOT << fname << ": Releasing ticket" << endl; - aBook->releaseSaveTicket(fTicket); - fTicket=0L; - } - - _cleanupAddressBookPointer(); - // unused function warnings. - compile_time_check(); -} - - - -/********************************************************************* - L O A D I N G T H E D A T A - *********************************************************************/ - - - -/* Builds the map which links record ids to uid's of Addressee -*/ -void AbbrowserConduit::_mapContactsToPilot(TQMap < recordid_t, TQString > &idContactMap) -{ - FUNCTIONSETUP; - - idContactMap.clear(); - - for(AddressBook::Iterator contactIter = aBook->begin(); - contactIter != aBook->end(); ++contactIter) - { - Addressee aContact = *contactIter; - TQString recid = aContact.custom(KABCSync::appString, KABCSync::idString); - if(!recid.isEmpty()) - { - recordid_t id = recid.toULong(); - // safety check: make sure that we don't already have a map for this pilot id. - // if we do (this can come from a copy/paste in kaddressbook, etc.), then we need - // to reset our Addressee so that we can assign him a new pilot Id later and sync - // him properly. if we don't do this, we'll lose one of these on the pilot. - if (!idContactMap.contains(id)) - { - idContactMap.insert(id, aContact.uid()); - } - else - { - DEBUGKPILOT << fname << ": found duplicate pilot key: [" - << id << "], removing pilot id from addressee: [" - << aContact.realName() << "]" << endl; - aContact.removeCustom(KABCSync::appString, KABCSync::idString); - aBook->insertAddressee(aContact); - abChanged = true; - } - } - } - DEBUGKPILOT << fname << ": Loaded " << idContactMap.size() << - " addresses from the addressbook. " << endl; -} - - - -bool AbbrowserConduit::_prepare() -{ - FUNCTIONSETUP; - - readConfig(); - syncedIds.clear(); - pilotindex = 0; - - return true; -} - - - -void AbbrowserConduit::readConfig() -{ - FUNCTIONSETUP; - AbbrowserSettings::self()->readConfig(); - - // Conflict page - SyncAction::ConflictResolution res = (SyncAction::ConflictResolution)AbbrowserSettings::conflictResolution(); - setConflictResolution(res); - - DEBUGKPILOT << fname - << ": Reading addressbook " - << ( AbbrowserSettings::addressbookType() == AbbrowserSettings::eAbookFile ? - AbbrowserSettings::fileName() : CSL1("Standard") ) - << endl; - DEBUGKPILOT << fname - << ": " - << " fConflictResolution=" << getConflictResolution() - << " fArchive=" << AbbrowserSettings::archiveDeleted() - << " fFirstTime=" << isFirstSync() - << endl; - DEBUGKPILOT << fname - << ": " - << " fPilotStreetHome=" << AbbrowserSettings::pilotStreet() - << " fPilotFaxHome=" << AbbrowserSettings::pilotFax() - << " eCustom[0]=" << AbbrowserSettings::custom0() - << " eCustom[1]=" << AbbrowserSettings::custom1() - << " eCustom[2]=" << AbbrowserSettings::custom2() - << " eCustom[3]=" << AbbrowserSettings::custom3() - << endl; -} - - - -bool isDeleted(const PilotAddress *addr) -{ - if (!addr) - { - return true; - } - if (addr->isDeleted() && !addr->isArchived()) - { - return true; - } - if (addr->isArchived()) - { - return !AbbrowserSettings::archiveDeleted(); - } - return false; -} - -bool isArchived(const PilotAddress *addr) -{ - if (addr && addr->isArchived()) - { - return AbbrowserSettings::archiveDeleted(); - } - else - { - return false; - } -} - - - -bool AbbrowserConduit::_loadAddressBook() -{ - FUNCTIONSETUP; - - startTickle(); - switch ( AbbrowserSettings::addressbookType() ) - { - case AbbrowserSettings::eAbookResource: - DEBUGKPILOT<<"Loading standard addressbook"<<endl; - aBook = StdAddressBook::self( true ); - fCreatedBook=false; - break; - case AbbrowserSettings::eAbookFile: - { // initialize the abook with the given file - DEBUGKPILOT<<"Loading custom addressbook"<<endl; - KURL kurl(AbbrowserSettings::fileName()); - if(!KIO::NetAccess::download(AbbrowserSettings::fileName(), fABookFile, 0L) && - !kurl.isLocalFile()) - { - emit logError(i18n("You chose to sync with the file \"%1\", which " - "cannot be opened. Please make sure to supply a " - "valid file name in the conduit's configuration dialog. " - "Aborting the conduit.").arg(AbbrowserSettings::fileName())); - KIO::NetAccess::removeTempFile(fABookFile); - stopTickle(); - return false; - } - - aBook = new AddressBook(); - if (!aBook) - { - stopTickle(); - return false; - } - fBookResource = new ResourceFile(fABookFile, CSL1("vcard") ); - - bool r = aBook->addResource( fBookResource ); - if ( !r ) - { - DEBUGKPILOT << "Unable to open resource for file " << fABookFile << endl; - KPILOT_DELETE( aBook ); - stopTickle(); - return false; - } - fCreatedBook=true; - break; - } - default: break; - } - // find out if this can fail for reasons other than a non-existent - // vcf file. If so, how can I determine if the missing file was the problem - // or something more serious: - if ( !aBook || !aBook->load() ) - { - // Something went wrong, so tell the user and return false to exit the conduit - emit logError(i18n("Unable to initialize and load the addressbook for the sync.") ); - addSyncLogEntry(i18n("Unable to initialize and load the addressbook for the sync.") ); - WARNINGKPILOT << "Unable to initialize the addressbook for the sync." << endl; - _cleanupAddressBookPointer(); - stopTickle(); - return false; - } - abChanged = false; - - fTicket=aBook->requestSaveTicket(); - if (!fTicket) - { - WARNINGKPILOT << "Unable to lock addressbook for writing " << endl; - emit logError(i18n("Unable to lock addressbook for writing. Can't sync!")); - addSyncLogEntry(i18n("Unable to lock addressbook for writing. Can't sync!")); - _cleanupAddressBookPointer(); - stopTickle(); - return false; - } - - fCtrPC->setStartCount(aBook->allAddressees().count()); - - // get the addresseMap which maps Pilot unique record(address) id's to - // a Abbrowser Addressee; allows for easy lookup and comparisons - if(aBook->begin() == aBook->end()) - { - setFirstSync( true ); - } - else - { - _mapContactsToPilot(addresseeMap); - } - stopTickle(); - return(aBook != 0L); -} - -bool AbbrowserConduit::_saveAddressBook() -{ - FUNCTIONSETUP; - - bool saveSuccessful = false; - - fCtrPC->setEndCount(aBook->allAddressees().count()); - - Q_ASSERT(fTicket); - - if (abChanged) - { - saveSuccessful = aBook->save(fTicket); - } - else - { - DEBUGKPILOT << fname - << "Addressbook not changed, no need to save it" << endl; - } - // XXX: KDE4: release ticket in all cases (save no longer releases it) - if ( !saveSuccessful ) // didn't save, delete ticket manually - { - aBook->releaseSaveTicket(fTicket); - } - fTicket=0L; - - if ( AbbrowserSettings::addressbookType()!= AbbrowserSettings::eAbookResource ) - { - KURL kurl(AbbrowserSettings::fileName()); - if(!kurl.isLocalFile()) - { - DEBUGKPILOT << fname << "Deleting local addressbook tempfile" << endl; - if(!KIO::NetAccess::upload(fABookFile, AbbrowserSettings::fileName(), 0L)) { - emit logError(i18n("An error occurred while uploading \"%1\". You can try to upload " - "the temporary local file \"%2\" manually") - .arg(AbbrowserSettings::fileName()).arg(fABookFile)); - } - else { - KIO::NetAccess::removeTempFile(fABookFile); - } - TQFile backup(fABookFile + CSL1("~")); - backup.remove(); - } - - } - - // now try to remove the resource from the addressbook... - if (fBookResource) - { - bool r = aBook->removeResource( fBookResource ); - if ( !r ) - { - DEBUGKPILOT << fname <<": Unable to close resource." << endl; - } - } - - return saveSuccessful; -} - - - -void AbbrowserConduit::_getAppInfo() -{ - FUNCTIONSETUP; - - delete fAddressAppInfo; - fAddressAppInfo = new PilotAddressInfo(fDatabase); - fAddressAppInfo->dump(); -} - -void AbbrowserConduit::_setAppInfo() -{ - FUNCTIONSETUP; - if (fDatabase) fAddressAppInfo->writeTo(fDatabase); - if (fLocalDatabase) fAddressAppInfo->writeTo(fLocalDatabase); -} - - -void AbbrowserConduit::_cleanupAddressBookPointer() -{ - if (fCreatedBook) - { - KPILOT_DELETE(aBook); - fCreatedBook=false; - } - else - { - aBook=0L; - } -} - - - - -/********************************************************************* - D E B U G O U T P U T - *********************************************************************/ - - - - - -void AbbrowserConduit::showPilotAddress(const PilotAddress *pilotAddress) -{ - FUNCTIONSETUPL(3); - if (debug_level < 3) - { - return; - } - if (!pilotAddress) - { - DEBUGKPILOT<< fname << "| EMPTY"<<endl; - return; - } - DEBUGKPILOT << fname << "\n" - << pilotAddress->getTextRepresentation( - fAddressAppInfo,Qt::PlainText) << endl; -} - - -void AbbrowserConduit::showAddresses( - const Addressee &pcAddr, - const PilotAddress *backupAddr, - const PilotAddress *palmAddr) -{ - FUNCTIONSETUPL(3); - if (debug_level >= 3) - { - DEBUGKPILOT << fname << "abEntry:" << endl; - KABCSync::showAddressee(pcAddr); - DEBUGKPILOT << fname << "pilotAddress:" << endl; - showPilotAddress(palmAddr); - DEBUGKPILOT << fname << "backupAddress:" << endl; - showPilotAddress(backupAddr); - DEBUGKPILOT << fname << "------------------------------------------------" << endl; - } -} - - - -/********************************************************************* - S Y N C S T R U C T U R E - *********************************************************************/ - - - -/* virtual */ bool AbbrowserConduit::exec() -{ - FUNCTIONSETUP; - - _prepare(); - - bool retrieved = false; - if(!openDatabases(CSL1("AddressDB"), &retrieved)) - { - emit logError(i18n("Unable to open the addressbook databases on the handheld.")); - return false; - } - setFirstSync( retrieved ); - - _getAppInfo(); - - // Local block - { - TQString dbpath = fLocalDatabase->dbPathName(); - DEBUGKPILOT << fname << ": Local database path " << dbpath << endl; - } - - if ( syncMode().isTest() ) - { - TQTimer::singleShot(0, this, TQT_SLOT(slotTestRecord())); - return true; - } - - if(!_loadAddressBook()) - { - emit logError(i18n("Unable to open the addressbook.")); - return false; - } - setFirstSync( isFirstSync() || (aBook->begin() == aBook->end()) ); - - DEBUGKPILOT << fname << ": First sync now " << isFirstSync() - << " and addressbook is " - << ((aBook->begin() == aBook->end()) ? "" : "non-") - << "empty." << endl; - - // perform syncing from palm to abbrowser - // iterate through all records in palm pilot - - DEBUGKPILOT << fname << ": fullsync=" << isFullSync() << ", firstSync=" << isFirstSync() << endl; - DEBUGKPILOT << fname << ": " - << "syncDirection=" << syncMode().name() << ", " - << "archive = " << AbbrowserSettings::archiveDeleted() << endl; - DEBUGKPILOT << fname << ": conflictRes="<< getConflictResolution() << endl; - DEBUGKPILOT << fname << ": PilotStreetHome=" << AbbrowserSettings::pilotStreet() << ", PilotFaxHOme" << AbbrowserSettings::pilotFax() << endl; - - if (!isFirstSync()) - { - allIds=fDatabase->idList(); - } - - TQValueVector<int> v(4); - v[0] = AbbrowserSettings::custom0(); - v[1] = AbbrowserSettings::custom1(); - v[2] = AbbrowserSettings::custom2(); - v[3] = AbbrowserSettings::custom3(); - - fSyncSettings.setCustomMapping(v); - fSyncSettings.setFieldForOtherPhone(AbbrowserSettings::pilotOther()); - fSyncSettings.setDateFormat(AbbrowserSettings::customDateFormat()); - fSyncSettings.setPreferHome(AbbrowserSettings::pilotStreet()==0); - fSyncSettings.setFaxTypeOnPC(faxTypeOnPC()); - - /* Note: - if eCopyPCToHH or eCopyHHToPC, first sync everything, then lookup - those entries on the receiving side that are not yet syncced and delete - them. Use slotDeleteUnsyncedPCRecords and slotDeleteUnsyncedHHRecords - for this, and no longer purge the whole addressbook before the sync to - prevent data loss in case of connection loss. */ - - TQTimer::singleShot(0, this, TQT_SLOT(slotPalmRecToPC())); - - return true; -} - - - -void AbbrowserConduit::slotPalmRecToPC() -{ - FUNCTIONSETUP; - PilotRecord *palmRec = 0L, *backupRec = 0L; - - if ( syncMode() == SyncMode::eCopyPCToHH ) - { - DEBUGKPILOT << fname << ": Done; change to PCtoHH phase." << endl; - abiter = aBook->begin(); - TQTimer::singleShot(0, this, TQT_SLOT(slotPCRecToPalm())); - return; - } - - if(isFullSync()) - { - palmRec = fDatabase->readRecordByIndex(pilotindex++); - } - else - { - palmRec = fDatabase->readNextModifiedRec(); - } - - // no record means we're done going in this direction, so switch to - // PC->Palm - if(!palmRec) - { - abiter = aBook->begin(); - TQTimer::singleShot(0, this, TQT_SLOT(slotPCRecToPalm())); - return; - } - - // already synced, so skip: - if(syncedIds.contains(palmRec->id())) - { - KPILOT_DELETE(palmRec); - TQTimer::singleShot(0, this, TQT_SLOT(slotPalmRecToPC())); - return; - } - - backupRec = fLocalDatabase->readRecordById(palmRec->id()); - PilotRecord*compareRec=(backupRec)?(backupRec):(palmRec); - Addressee e = _findMatch(PilotAddress(compareRec)); - - PilotAddress*backupAddr=0L; - if (backupRec) - { - backupAddr=new PilotAddress(backupRec); - } - - PilotAddress*palmAddr=0L; - if (palmRec) - { - palmAddr=new PilotAddress(palmRec); - } - - syncAddressee(e, backupAddr, palmAddr); - - syncedIds.append(palmRec->id()); - KPILOT_DELETE(palmAddr); - KPILOT_DELETE(backupAddr); - KPILOT_DELETE(palmRec); - KPILOT_DELETE(backupRec); - - TQTimer::singleShot(0, this, TQT_SLOT(slotPalmRecToPC())); -} - - - -void AbbrowserConduit::slotPCRecToPalm() -{ - FUNCTIONSETUP; - - if ( (syncMode()==SyncMode::eCopyHHToPC) || - abiter == aBook->end() || (*abiter).isEmpty() ) - { - DEBUGKPILOT << fname << ": Done; change to delete records." << endl; - pilotindex = 0; - TQTimer::singleShot(0, this, TQT_SLOT(slotDeletedRecord())); - return; - } - - PilotRecord *palmRec=0L, *backupRec=0L; - Addressee ad = *abiter; - - abiter++; - - // If marked as archived, don't sync! - if (KABCSync::isArchived(ad)) - { - DEBUGKPILOT << fname << ": address with id " << ad.uid() << - " marked archived, so don't sync." << endl; - TQTimer::singleShot(0, this, TQT_SLOT(slotPCRecToPalm())); - return; - } - - - TQString recID(ad.custom(KABCSync::appString, KABCSync::idString)); - bool ok; - recordid_t rid = recID.toLong(&ok); - if (recID.isEmpty() || !ok || !rid) - { - DEBUGKPILOT << fname << ": This is a new record." << endl; - // it's a new item(no record ID and not inserted by the Palm -> PC sync), so add it - syncAddressee(ad, 0L, 0L); - TQTimer::singleShot(0, this, TQT_SLOT(slotPCRecToPalm())); - return; - } - - // look into the list of already synced record ids to see if the addressee hasn't already been synced - if (syncedIds.contains(rid)) - { - DEBUGKPILOT << ": address with id " << rid << " already synced." << endl; - TQTimer::singleShot(0, this, TQT_SLOT(slotPCRecToPalm())); - return; - } - - - backupRec = fLocalDatabase->readRecordById(rid); - // only update if no backup record or the backup record is not equal to the addressee - - PilotAddress*backupAddr=0L; - if (backupRec) - { - backupAddr=new PilotAddress(backupRec); - } - if(!backupRec || isFirstSync() || !_equal(backupAddr, ad) ) - { - DEBUGKPILOT << fname << ": Updating entry." << endl; - palmRec = fDatabase->readRecordById(rid); - PilotAddress *palmAddr = 0L; - if (palmRec) - { - palmAddr = new PilotAddress(palmRec); - } - else - { - DEBUGKPILOT << fname << ": No HH record with id " << rid << endl; - } - syncAddressee(ad, backupAddr, palmAddr); - // update the id just in case it changed - if (palmRec) rid=palmRec->id(); - KPILOT_DELETE(palmRec); - KPILOT_DELETE(palmAddr); - } - else - { - DEBUGKPILOT << fname << ": Entry not updated." << endl; - } - KPILOT_DELETE(backupAddr); - KPILOT_DELETE(backupRec); - - DEBUGKPILOT << fname << ": adding id:["<< rid << "] to syncedIds." << endl; - - syncedIds.append(rid); - // done with the sync process, go on with the next one: - TQTimer::singleShot(0, this, TQT_SLOT(slotPCRecToPalm())); -} - - - -void AbbrowserConduit::slotDeletedRecord() -{ - FUNCTIONSETUP; - - PilotRecord *backupRec = fLocalDatabase->readRecordByIndex(pilotindex++); - if(!backupRec || isFirstSync() ) - { - KPILOT_DELETE(backupRec); - TQTimer::singleShot(0, this, TQT_SLOT(slotDeleteUnsyncedPCRecords())); - return; - } - - recordid_t id = backupRec->id(); - - TQString uid = addresseeMap[id]; - Addressee e = aBook->findByUid(uid); - - DEBUGKPILOT << fname << ": now looking at palm id: [" - << id << "], kabc uid: [" << uid << "]." << endl; - - PilotAddress*backupAddr=0L; - if (backupRec) - { - backupAddr=new PilotAddress(backupRec); - } - PilotRecord*palmRec=fDatabase->readRecordById(id); - - if ( e.isEmpty() ) - { - DEBUGKPILOT << fname << ": no Addressee found for this id." << endl; - DEBUGKPILOT << fname << "\n" - << backupAddr->getTextRepresentation( - fAddressAppInfo,Qt::PlainText) << endl; - - if (palmRec) { - DEBUGKPILOT << fname << ": deleting from database on palm." << endl; - fDatabase->deleteRecord(id); - fCtrHH->deleted(); - } - DEBUGKPILOT << fname << ": deleting from backup database." << endl; - fLocalDatabase->deleteRecord(id); - - // because we just deleted a record, we need to go back one - pilotindex--; - } - - KPILOT_DELETE(palmRec); - KPILOT_DELETE(backupAddr); - KPILOT_DELETE(backupRec); - TQTimer::singleShot(0, this, TQT_SLOT(slotDeletedRecord())); -} - - - -void AbbrowserConduit::slotDeleteUnsyncedPCRecords() -{ - FUNCTIONSETUP; - if ( syncMode()==SyncMode::eCopyHHToPC ) - { - TQStringList uids; - RecordIDList::iterator it; - TQString uid; - for ( it = syncedIds.begin(); it != syncedIds.end(); ++it) - { - uid=addresseeMap[*it]; - if (!uid.isEmpty()) uids.append(uid); - } - // TODO: Does this speed up anything? - // qHeapSort( uids ); - AddressBook::Iterator abit; - for (abit = aBook->begin(); abit != aBook->end(); ++abit) - { - if (!uids.contains((*abit).uid())) - { - DEBUGKPILOT<<"Deleting addressee "<<(*abit).realName()<<" from PC (is not on HH, and syncing with HH->PC direction)"<<endl; - abChanged = true; - // TODO: Can I really remove the current iterator??? - aBook->removeAddressee(*abit); - fCtrPC->deleted(); - } - } - } - TQTimer::singleShot(0, this, TQT_SLOT(slotDeleteUnsyncedHHRecords())); -} - - - -void AbbrowserConduit::slotDeleteUnsyncedHHRecords() -{ - FUNCTIONSETUP; - if ( syncMode()==SyncMode::eCopyPCToHH ) - { - RecordIDList ids=fDatabase->idList(); - RecordIDList::iterator it; - for ( it = ids.begin(); it != ids.end(); ++it ) - { - if (!syncedIds.contains(*it)) - { - DEBUGKPILOT<<"Deleting record with ID "<<*it<<" from handheld (is not on PC, and syncing with PC->HH direction)"<<endl; - fDatabase->deleteRecord(*it); - fCtrHH->deleted(); - fLocalDatabase->deleteRecord(*it); - } - } - } - TQTimer::singleShot(0, this, TQT_SLOT(slotCleanup())); -} - - -void AbbrowserConduit::slotCleanup() -{ - FUNCTIONSETUP; - - // Set the appInfoBlock, just in case the category labels changed - _setAppInfo(); - if(fDatabase) - { - fDatabase->resetSyncFlags(); - fDatabase->cleanup(); - } - if(fLocalDatabase) - { - fLocalDatabase->resetSyncFlags(); - fLocalDatabase->cleanup(); - } - - // Write out the sync maps - TQString syncFile = fLocalDatabase->dbPathName() + CSL1(".sync"); - DEBUGKPILOT << fname << ": Writing sync map to " << syncFile << endl; - KSaveFile map( syncFile ); - if ( map.status() == 0 ) - { - DEBUGKPILOT << fname << ": Writing sync map ..." << endl; - (*map.dataStream()) << addresseeMap ; - map.close(); - } - // This also picks up errors from map.close() - if ( map.status() != 0 ) - { - WARNINGKPILOT << "Could not make backup of sync map." << endl; - } - - _saveAddressBook(); - delayDone(); -} - - - -/********************************************************************* - G E N E R A L S Y N C F U N C T I O N - These functions modify the Handheld and the addressbook - *********************************************************************/ - - - -bool AbbrowserConduit::syncAddressee(Addressee &pcAddr, PilotAddress*backupAddr, - PilotAddress*palmAddr) -{ - FUNCTIONSETUP; - showAddresses(pcAddr, backupAddr, palmAddr); - - if ( syncMode() == SyncMode::eCopyPCToHH ) - { - if (pcAddr.isEmpty()) - { - return _deleteAddressee(pcAddr, backupAddr, palmAddr); - } - else - { - return _copyToHH(pcAddr, backupAddr, palmAddr); - } - } - - if ( syncMode() == SyncMode::eCopyHHToPC ) - { - if (!palmAddr) - { - return _deleteAddressee(pcAddr, backupAddr, palmAddr); - } - else - { - return _copyToPC(pcAddr, backupAddr, palmAddr); - } - } - - if ( !backupAddr || isFirstSync() ) - { - DEBUGKPILOT<< fname << ": Special case: no backup." << endl; - /* - Resolution matrix (0..does not exist, E..exists, D..deleted flag set, A..archived): - HH PC | Resolution - ------------------------------------------------------------ - 0 A | - - 0 E | PC -> HH, reset ID if not set correctly - D 0 | delete (error, should never occur!!!) - D E | CR (ERROR) - E/A 0 | HH -> PC - E/A E/A| merge/CR - */ - if (!palmAddr && KABCSync::isArchived(pcAddr) ) - { - return true; - } - else if (!palmAddr && !pcAddr.isEmpty()) - { - DEBUGKPILOT << fname << ": case: 1a"<<endl; - // PC->HH - bool res=_copyToHH(pcAddr, 0L, 0L); - return res; - } - else if (!palmAddr && pcAddr.isEmpty()) - { - DEBUGKPILOT << fname << ": case: 1b"<<endl; - // everything's empty -> ERROR - return false; - } - else if ( (isDeleted(palmAddr) || isArchived(palmAddr)) && pcAddr.isEmpty()) - { - DEBUGKPILOT << fname << ": case: 1c"<<endl; - if (isArchived(palmAddr)) - return _copyToPC(pcAddr, 0L, palmAddr); - else - // this happens if you add a record on the handheld and delete it again before you do the next sync - return _deleteAddressee(pcAddr, 0L, palmAddr); - } - else if ((isDeleted(palmAddr)||isArchived(palmAddr)) && !pcAddr.isEmpty()) - { - DEBUGKPILOT << fname << ": case: 1d"<<endl; - // CR (ERROR) - return _smartMergeAddressee(pcAddr, 0L, palmAddr); - } - else if (pcAddr.isEmpty()) - { - DEBUGKPILOT << fname << ": case: 1e"<<endl; - // HH->PC - return _copyToPC(pcAddr, 0L, palmAddr); - } - else - { - DEBUGKPILOT << fname << ": case: 1f"<<endl; - // Conflict Resolution - return _smartMergeAddressee(pcAddr, 0L, palmAddr); - } - } // !backupAddr - else - { - DEBUGKPILOT << fname << ": case: 2"<<endl; - /* - Resolution matrix: - 1) if HH.(empty| (deleted &! archived) ) -> { if (PC==B) -> delete, else -> CR } - if HH.archied -> {if (PC==B) -> copyToPC, else -> CR } - if PC.empty -> { if (HH==B) -> delete, else -> CR } - if PC.archived -> {if (HH==B) -> delete on HH, else CR } - 2) if PC==HH -> { update B, update ID of PC if needed } - 3) if PC==B -> { HH!=PC, thus HH modified, so copy HH->PC } - if HH==B -> { PC!=HH, thus PC modified, so copy PC->HH } - 4) else: all three addressees are different -> CR - */ - - if (!palmAddr || isDeleted(palmAddr) ) - { - DEBUGKPILOT << fname << ": case: 2a"<<endl; - if (_equal(backupAddr, pcAddr) || pcAddr.isEmpty()) - { - return _deleteAddressee(pcAddr, backupAddr, 0L); - } - else - { - return _smartMergeAddressee(pcAddr, backupAddr, 0L); - } - } - else if (pcAddr.isEmpty()) - { - DEBUGKPILOT << fname << ": case: 2b"<<endl; - if (*palmAddr == *backupAddr) - { - return _deleteAddressee(pcAddr, backupAddr, palmAddr); - } - else - { - return _smartMergeAddressee(pcAddr, backupAddr, palmAddr); - } - } - else if (_equal(palmAddr, pcAddr)) - { - DEBUGKPILOT << fname << ": case: 2c"<<endl; - // update Backup, update ID of PC if neededd - return _writeBackup(palmAddr); - } - else if (_equal(backupAddr, pcAddr)) - { - DEBUGKPILOT << fname << ": case: 2d"<<endl; - DEBUGKPILOT << fname << ": Flags: "<<palmAddr->attributes()<<", isDeleted="<< - isDeleted(palmAddr)<<", isArchived="<<isArchived(palmAddr)<<endl; - if (isDeleted(palmAddr)) - return _deleteAddressee(pcAddr, backupAddr, palmAddr); - else - return _copyToPC(pcAddr, backupAddr, palmAddr); - } - else if (*palmAddr == *backupAddr) - { - DEBUGKPILOT << fname << ": case: 2e"<<endl; - return _copyToHH(pcAddr, backupAddr, palmAddr); - } - else - { - DEBUGKPILOT << fname << ": case: 2f"<<endl; - // CR, since all are different - return _smartMergeAddressee(pcAddr, backupAddr, palmAddr); - } - } // backupAddr - return false; -} - - - -bool AbbrowserConduit::_copyToHH(Addressee &pcAddr, PilotAddress*backupAddr, - PilotAddress*palmAddr) -{ - FUNCTIONSETUP; - - if (pcAddr.isEmpty()) return false; - PilotAddress*paddr=palmAddr; - bool paddrcreated=false; - if (!paddr) - { - paddr=new PilotAddress(); - paddrcreated=true; - fCtrHH->created(); - } - else - { - fCtrHH->updated(); - } - KABCSync::copy(*paddr, pcAddr, *fAddressAppInfo, fSyncSettings); - - DEBUGKPILOT << fname << "palmAddr->id=" << paddr->id() - << ", pcAddr.ID=" << pcAddr.custom(KABCSync::appString, KABCSync::idString) << endl; - - if(_savePalmAddr(paddr, pcAddr)) - { - _savePCAddr(pcAddr, backupAddr, paddr); - } - if (paddrcreated) KPILOT_DELETE(paddr); - return true; -} - - - -bool AbbrowserConduit::_copyToPC(Addressee &pcAddr, PilotAddress*backupAddr, - PilotAddress*palmAddr) -{ - FUNCTIONSETUP; - if (!palmAddr) - { - return false; - } - // keep track of CUD's... - if (pcAddr.isEmpty()) - { - fCtrPC->created(); - } - else - { - fCtrPC->updated(); - } - showPilotAddress(palmAddr); - - KABCSync::copy(pcAddr, *palmAddr, *fAddressAppInfo, fSyncSettings); - if (isArchived(palmAddr)) - { - KABCSync::makeArchived(pcAddr); - } - - _savePCAddr(pcAddr, backupAddr, palmAddr); - _writeBackup(palmAddr); - return true; -} - - - -bool AbbrowserConduit::_writeBackup(PilotAddress *backup) -{ - FUNCTIONSETUP; - if (!backup) return false; - - showPilotAddress(backup); - - PilotRecord *pilotRec = backup->pack(); - fLocalDatabase->writeRecord(pilotRec); - KPILOT_DELETE(pilotRec); - return true; -} - - - -bool AbbrowserConduit::_deleteAddressee(Addressee &pcAddr, PilotAddress*backupAddr, - PilotAddress*palmAddr) -{ - FUNCTIONSETUP; - - if (palmAddr) - { - if (!syncedIds.contains(palmAddr->id())) { - DEBUGKPILOT << fname << ": adding id:["<< palmAddr->id() << "] to syncedIds." << endl; - syncedIds.append(palmAddr->id()); - } - fDatabase->deleteRecord(palmAddr->id()); - fCtrHH->deleted(); - fLocalDatabase->deleteRecord(palmAddr->id()); - } - else if (backupAddr) - { - if (!syncedIds.contains(backupAddr->id())) { - DEBUGKPILOT << fname << ": adding id:["<< backupAddr->id() << "] to syncedIds." << endl; - syncedIds.append(backupAddr->id()); - } - fLocalDatabase->deleteRecord(backupAddr->id()); - } - if (!pcAddr.isEmpty()) - { - DEBUGKPILOT << fname << " removing " << pcAddr.formattedName() << endl; - abChanged = true; - aBook->removeAddressee(pcAddr); - fCtrPC->deleted(); - } - return true; -} - - - -/********************************************************************* - l o w - l e v e l f u n c t i o n s f o r - adding / removing palm/pc records - *********************************************************************/ - - - -bool AbbrowserConduit::_savePalmAddr(PilotAddress *palmAddr, Addressee &pcAddr) -{ - FUNCTIONSETUP; - - DEBUGKPILOT << fname << ": Saving to pilot " << palmAddr->id() - << " " << palmAddr->getField(entryFirstname) - << " " << palmAddr->getField(entryLastname)<< endl; - - PilotRecord *pilotRec = palmAddr->pack(); - DEBUGKPILOT << fname << ": record with id=" << pilotRec->id() - << " len=" << pilotRec->size() << endl; - recordid_t pilotId = fDatabase->writeRecord(pilotRec); - DEBUGKPILOT << fname << ": Wrote "<<pilotId<<": ID="<<pilotRec->id()<<endl; - fLocalDatabase->writeRecord(pilotRec); - KPILOT_DELETE(pilotRec); - - // pilotId == 0 if using local db, so don't overwrite the valid id - if(pilotId != 0) - { - palmAddr->setID(pilotId); - if (!syncedIds.contains(pilotId)) { - DEBUGKPILOT << fname << ": adding id:["<< pilotId << "] to syncedIds." << endl; - syncedIds.append(pilotId); - } - } - - recordid_t abId = 0; - abId = pcAddr.custom(KABCSync::appString, KABCSync::idString).toUInt(); - if(abId != pilotId) - { - pcAddr.insertCustom(KABCSync::appString, KABCSync::idString, TQString::number(pilotId)); - return true; - } - - return false; -} - - - -bool AbbrowserConduit::_savePCAddr(Addressee &pcAddr, PilotAddress*, - PilotAddress*) -{ - FUNCTIONSETUP; - - DEBUGKPILOT<<"Before _savePCAddr, pcAddr.custom="<<pcAddr.custom(KABCSync::appString, KABCSync::idString)<<endl; - TQString pilotId = pcAddr.custom(KABCSync::appString, KABCSync::idString); - long pilotIdL = pilotId.toLong(); - if(!pilotId.isEmpty()) - { - // because we maintain a mapping between pilotId -> kabc uid, whenever we add - // a new relationship, we have to remove any old mapping that would tie a different - // pilot id -> this kabc uid - TQMap < recordid_t, TQString>::iterator it; - for ( it = addresseeMap.begin(); it != addresseeMap.end(); ++it ) { - TQString kabcUid = it.data(); - if (kabcUid == pcAddr.uid()) { - addresseeMap.remove(it); - break; - } - } - - // now put the new mapping in - addresseeMap.insert(pilotIdL, pcAddr.uid()); - } - - aBook->insertAddressee(pcAddr); - - abChanged = true; - return true; -} - - - - -/********************************************************************* - C O P Y R E C O R D S - *********************************************************************/ - - - -bool AbbrowserConduit::_equal(const PilotAddress *piAddress, const Addressee &abEntry, - enum eqFlagsType flags) const -{ - FUNCTIONSETUP; - - // empty records are never equal! - if (!piAddress) { - DEBUGKPILOT << fname << ": no pilot address passed" << endl; - return false; - } - if (abEntry.isEmpty()) { - DEBUGKPILOT << fname << ":abEntry.isEmpty()" << endl; - return false; - } - // Archived records match anything so they won't be copied to the HH again - if (flags & eqFlagsFlags) - if (isArchived(piAddress) && KABCSync::isArchived(abEntry) ) return true; - - if (flags & eqFlagsName) - { - if(!_equal(abEntry.familyName(), piAddress->getField(entryLastname))) - { - DEBUGKPILOT << fname << ": last name not equal" << endl; - return false; - } - if(!_equal(abEntry.givenName(), piAddress->getField(entryFirstname))) - { - DEBUGKPILOT << fname << ": first name not equal" << endl; - return false; - } - if(!_equal(abEntry.prefix(), piAddress->getField(entryTitle))) - { - DEBUGKPILOT << fname << ": title/prefix not equal" << endl; - return false; - } - if(!_equal(abEntry.organization(), piAddress->getField(entryCompany))) - { - DEBUGKPILOT << fname << ": company/organization not equal" << endl; - return false; - } - } - if (flags & eqFlagsNote) - if(!_equal(abEntry.note(), piAddress->getField(entryNote))) - { - DEBUGKPILOT << fname << ": note not equal" << endl; - return false; - } - - if (flags & eqFlagsCategory) - { - // Check that the name of the category of the HH record - // is one matching the PC record. - TQString addressCategoryLabel = fAddressAppInfo->categoryName(piAddress->category()); - TQString cat = KABCSync::bestMatchedCategoryName(abEntry.categories(), - *fAddressAppInfo, piAddress->category()); - if(!_equal(cat, addressCategoryLabel)) - { - DEBUGKPILOT << fname << ": category not equal" << endl; - return false; - } - } - - if (flags & eqFlagsPhones) - { - // first, look for missing e-mail addresses on either side - TQStringList abEmails(abEntry.emails()); - TQStringList piEmails(piAddress->getEmails()); - - if (abEmails.count() != piEmails.count()) - { - DEBUGKPILOT << fname << ": email count not equal" << endl; - return false; - } - for (TQStringList::Iterator it = abEmails.begin(); it != abEmails.end(); it++) { - if (!piEmails.contains(*it)) - { - DEBUGKPILOT << fname << ": pilot e-mail missing" << endl; - return false; - } - } - for (TQStringList::Iterator it = piEmails.begin(); it != piEmails.end(); it++) { - if (!abEmails.contains(*it)) - { - DEBUGKPILOT << fname << ": kabc e-mail missing" << endl; - return false; - } - } - - // now look for differences in phone numbers. Note: we can't just compare one - // of each kind of phone number, because there's no guarantee that if the user - // has more than one of a given type, we're comparing the correct two. - - PhoneNumber::List abPhones(abEntry.phoneNumbers()); - PhoneNumber::List piPhones = KABCSync::getPhoneNumbers(*piAddress); - // first make sure that all of the pilot phone numbers are in kabc - for (PhoneNumber::List::Iterator it = piPhones.begin(); it != piPhones.end(); it++) { - PhoneNumber piPhone = *it; - bool found=false; - for (PhoneNumber::List::Iterator it = abPhones.begin(); it != abPhones.end(); it++) { - PhoneNumber abPhone = *it; - // see if we have the same number here... - // * Note * We used to check for preferred number matching, but - // this seems to have broke in kdepim 3.5 and I don't have time to - // figure out why, so we won't check to see if preferred number match - if ( _equal(piPhone.number(), abPhone.number()) ) { - found = true; - break; - } - } - if (!found) { - DEBUGKPILOT << fname << ": not equal because kabc phone not found." << endl; - return false; - } - } - // now the other way. *cringe* kabc has the capacity to store way more addresses - // than the Pilot, so this might give false positives more than we'd want.... - for (PhoneNumber::List::Iterator it = abPhones.begin(); it != abPhones.end(); it++) { - PhoneNumber abPhone = *it; - bool found=false; - for (PhoneNumber::List::Iterator it = piPhones.begin(); it != piPhones.end(); it++) { - PhoneNumber piPhone = *it; - if ( _equal(piPhone.number(), abPhone.number()) ) { - found = true; - break; - } - } - if (!found) - { - DEBUGKPILOT << fname << ": not equal because pilot phone not found." << endl; - return false; - } - } - - if(!_equal(KABCSync::getFieldForHHOtherPhone(abEntry,fSyncSettings), - piAddress->getPhoneField(PilotAddressInfo::eOther))) - { - DEBUGKPILOT << fname << ": not equal because of other phone field." << endl; - return false; - } - } - - if (flags & eqFlagsAdress) - { - KABC::Address address = KABCSync::getAddress(abEntry,fSyncSettings); - if(!_equal(address.street(), piAddress->getField(entryAddress))) - { - DEBUGKPILOT << fname << ": address not equal" << endl; - return false; - } - if(!_equal(address.locality(), piAddress->getField(entryCity))) - { - DEBUGKPILOT << fname << ": city not equal" << endl; - return false; - } - if(!_equal(address.region(), piAddress->getField(entryState))) - { - DEBUGKPILOT << fname << ": state not equal" << endl; - return false; - } - if(!_equal(address.postalCode(), piAddress->getField(entryZip))) - { - DEBUGKPILOT << fname << ": zip not equal" << endl; - return false; - } - if(!_equal(address.country(), piAddress->getField(entryCountry))) - { - DEBUGKPILOT << fname << ": country not equal" << endl; - return false; - } - } - - if (flags & eqFlagsCustom) - { - unsigned int customIndex = 0; - unsigned int hhField = entryCustom1; - - for ( ; customIndex<4; ++customIndex,++hhField ) - { - if (!_equal(KABCSync::getFieldForHHCustom(customIndex, abEntry, fSyncSettings), - piAddress->getField(hhField))) - { - DEBUGKPILOT << fname << ": Custom field " << customIndex - << " (HH field " << hhField << ") differs." << endl; - return false; - } - } - } - - // if any side is marked archived, but the other is not, the two - // are not equal. - if ( (flags & eqFlagsFlags) && (isArchived(piAddress) || KABCSync::isArchived(abEntry) ) ) - { - DEBUGKPILOT << fname << ": archived flags don't match" << endl; - return false; - } - - return true; -} - - - - - - - - - - -/********************************************************************* - C O N F L I C T R E S O L U T I O N a n d M E R G I N G - *********************************************************************/ - - - -/** smartly merge the given field for the given entry. use the backup record to determine which record has been modified - @pc, @backup, @palm ... entries of the according databases - @returns string of the merged entries. -*/ -TQString AbbrowserConduit::_smartMergeString(const TQString &pc, const TQString & backup, - const TQString & palm, ConflictResolution confRes) -{ - FUNCTIONSETUP; - - // if both entries are already the same, no need to do anything - if(pc == palm) return pc; - - // If this is a first sync, we don't have a backup record, so - if(isFirstSync() || backup.isEmpty()) { - if (pc.isEmpty() && palm.isEmpty() ) return TQString::null; - if(pc.isEmpty()) return palm; - if(palm.isEmpty()) return pc; - } else { - // only one side modified, so return that string, no conflict - if(palm == backup) return pc; - if(pc == backup) return palm; - } - - DEBUGKPILOT<<"pc="<<pc<<", backup="<<backup<<", palm="<< - palm<<", ConfRes="<<confRes<<endl; - DEBUGKPILOT<<"Use conflict resolution :"<<confRes<< - ", PC="<<SyncAction::ePCOverrides<<endl; - switch(confRes) { - case SyncAction::ePCOverrides: return pc; break; - case SyncAction::eHHOverrides: return palm; break; - case SyncAction::ePreviousSyncOverrides: return backup; break; - default: break; - } - return TQString::null; -} - - - -bool AbbrowserConduit::_buildResolutionTable(ResolutionTable*tab, const Addressee &pcAddr, - PilotAddress *backupAddr, PilotAddress *palmAddr) -{ - FUNCTIONSETUP; - if (!tab) return false; - tab->setAutoDelete( TRUE ); - tab->labels[0]=i18n("Item on PC"); - tab->labels[1]=i18n("Handheld"); - tab->labels[2]=i18n("Last sync"); - if (!pcAddr.isEmpty()) - tab->fExistItems=(eExistItems)(tab->fExistItems|eExistsPC); - if (backupAddr) - tab->fExistItems=(eExistItems)(tab->fExistItems|eExistsBackup); - if (palmAddr) - tab->fExistItems=(eExistItems)(tab->fExistItems|eExistsPalm); - -#define appendGen(desc, abfield, palmfield) \ - tab->append(new ResolutionItem(desc, tab->fExistItems, \ - (!pcAddr.isEmpty())?(abfield):(TQString::null), \ - (palmAddr)?(palmAddr->palmfield):(TQString::null), \ - (backupAddr)?(backupAddr->palmfield):(TQString::null) )) -#define appendAddr(desc, abfield, palmfield) \ - appendGen(desc, abfield, getField(palmfield)) -#define appendGenPhone(desc, abfield, palmfield) \ - appendGen(desc, abfield, getPhoneField(PilotAddressInfo::palmfield)) -#define appendPhone(desc, abfield, palmfield) \ - appendGenPhone(desc, pcAddr.phoneNumber(PhoneNumber::abfield).number(), palmfield) - - - appendAddr(i18n("Last name"), pcAddr.familyName(), entryLastname); - appendAddr(i18n("First name"), pcAddr.givenName(), entryFirstname); - appendAddr(i18n("Organization"), pcAddr.organization(), entryCompany); - appendAddr(i18n("Title"), pcAddr.prefix(), entryTitle); - appendAddr(i18n("Note"), pcAddr.note(), entryNote); - - appendAddr(i18n("Custom 1"), KABCSync::getFieldForHHCustom(0, pcAddr, fSyncSettings), entryCustom1); - appendAddr(i18n("Custom 2"), KABCSync::getFieldForHHCustom(1, pcAddr, fSyncSettings), entryCustom2); - appendAddr(i18n("Custom 3"), KABCSync::getFieldForHHCustom(2, pcAddr, fSyncSettings), entryCustom3); - appendAddr(i18n("Custom 4"), KABCSync::getFieldForHHCustom(3, pcAddr, fSyncSettings), entryCustom4); - - appendPhone(i18n("Work Phone"), Work, eWork); - appendPhone(i18n("Home Phone"), Home, eHome); - appendPhone(i18n("Mobile Phone"), Cell, eMobile); - appendGenPhone(i18n("Fax"), pcAddr.phoneNumber(faxTypeOnPC()).number(), eFax); - appendPhone(i18n("Pager"), Pager, ePager); - appendGenPhone(i18n("Other"), KABCSync::getFieldForHHOtherPhone(pcAddr,fSyncSettings), eOther); - appendGenPhone(i18n("Email"), pcAddr.preferredEmail(), eEmail); - - KABC::Address abAddress = KABCSync::getAddress(pcAddr,fSyncSettings); - appendAddr(i18n("Address"), abAddress.street(), entryAddress); - appendAddr(i18n("City"), abAddress.locality(), entryCity); - appendAddr(i18n("Region"), abAddress.region(), entryState); - appendAddr(i18n("Postal code"), abAddress.postalCode(), entryZip); - appendAddr(i18n("Country"), abAddress.country(), entryCountry); - - TQString palmAddrCategoryLabel; - if (palmAddr) - { - palmAddrCategoryLabel = fAddressAppInfo->categoryName(palmAddr->category()); - } - TQString backupAddrCategoryLabel; - if (backupAddr) - { - backupAddrCategoryLabel = fAddressAppInfo->categoryName(backupAddr->category()); - } - int category = palmAddr ? palmAddr->category() : 0; - tab->append(new ResolutionItem( - i18n("Category"), - tab->fExistItems, - !pcAddr.isEmpty() ? - KABCSync::bestMatchedCategoryName(pcAddr.categories(), *fAddressAppInfo, category) : - TQString::null, - palmAddrCategoryLabel, - backupAddrCategoryLabel)); -#undef appendGen -#undef appendAddr -#undef appendGenPhone -#undef appendPhone - - return true; -} - - -/// This function just sets the phone number of type "type" to "phone" -static inline void setPhoneNumber(Addressee &abEntry, int type, const TQString &nr) -{ - PhoneNumber phone = abEntry.phoneNumber(type); - phone.setNumber(nr); - abEntry.insertPhoneNumber(phone); -} - - -bool AbbrowserConduit::_applyResolutionTable(ResolutionTable*tab, Addressee &pcAddr, - PilotAddress *backupAddr, PilotAddress *palmAddr) -{ - FUNCTIONSETUP; - if (!tab) return false; - if (!palmAddr) { - WARNINGKPILOT << "Empty palmAddr after conflict resolution." << endl; - return false; - } - - ResolutionItem*item=tab->first(); -#define SETGENFIELD(abfield, palmfield) \ - if (item) {\ - abfield; \ - palmAddr->setField(palmfield, item->fResolved); \ - }\ - item=tab->next(); -#define SETFIELD(abfield, palmfield) \ - SETGENFIELD(pcAddr.set##abfield(item->fResolved), palmfield) -#define SETCUSTOMFIELD(abfield, palmfield) \ - SETGENFIELD(KABCSync::setFieldFromHHCustom(abfield, pcAddr, item->fResolved, fSyncSettings), palmfield) -#define SETGENPHONE(abfield, palmfield) \ - if (item) { \ - abfield; \ - palmAddr->setPhoneField(PilotAddressInfo::palmfield, item->fResolved, PilotAddress::Replace); \ - }\ - item=tab->next(); -#define SETPHONEFIELD(abfield, palmfield) \ - SETGENPHONE(setPhoneNumber(pcAddr, PhoneNumber::abfield, item->fResolved), palmfield) -#define SETADDRESSFIELD(abfield, palmfield) \ - SETGENFIELD(abAddress.abfield(item->fResolved), palmfield) - - SETFIELD(FamilyName, entryLastname); - SETFIELD(GivenName, entryFirstname); - SETFIELD(Organization, entryCompany); - SETFIELD(Prefix, entryTitle); - SETFIELD(Note, entryNote); - - SETCUSTOMFIELD(0, entryCustom1); - SETCUSTOMFIELD(1, entryCustom2); - SETCUSTOMFIELD(2, entryCustom3); - SETCUSTOMFIELD(3, entryCustom4); - - SETPHONEFIELD(Work, eWork); - SETPHONEFIELD(Home, eHome); - SETPHONEFIELD(Cell, eMobile); - SETGENPHONE(setPhoneNumber(pcAddr, faxTypeOnPC(), item->fResolved), eFax); - SETPHONEFIELD(Pager, ePager); - SETGENPHONE(KABCSync::setFieldFromHHOtherPhone(pcAddr, item->fResolved, fSyncSettings), eOther); - - // TODO: fix email - if (item) - { - palmAddr->setPhoneField(PilotAddressInfo::eEmail, item->fResolved, PilotAddress::Replace); - if (backupAddr) - { - pcAddr.removeEmail(backupAddr->getPhoneField(PilotAddressInfo::eEmail)); - } - pcAddr.removeEmail(palmAddr->getPhoneField(PilotAddressInfo::eEmail)); - pcAddr.insertEmail(item->fResolved, true); - } - item=tab->next(); - - KABC::Address abAddress = KABCSync::getAddress(pcAddr, fSyncSettings); - SETADDRESSFIELD(setStreet, entryAddress); - SETADDRESSFIELD(setLocality, entryCity); - SETADDRESSFIELD(setRegion, entryState); - SETADDRESSFIELD(setPostalCode, entryZip); - SETADDRESSFIELD(setCountry, entryCountry); - pcAddr.insertAddress(abAddress); - - // TODO: Is this correct? - if (item) - { - palmAddr->setCategory( fAddressAppInfo->findCategory(item->fResolved) ); - KABCSync::setCategory(pcAddr, item->fResolved); - } - - -#undef SETGENFIELD -#undef SETFIELD -#undef SETCUSTOMFIELD -#undef SETGENPHONE -#undef SETPHONEFIELD -#undef SETADDRESSFIELD - - return true; -} - - - -bool AbbrowserConduit::_smartMergeTable(ResolutionTable*tab) -{ - FUNCTIONSETUP; - if (!tab) return false; - bool noconflict=true; - ResolutionItem*item; - for ( item = tab->first(); item; item = tab->next() ) - { - // try to merge the three strings - item->fResolved=_smartMergeString(item->fEntries[0], - item->fEntries[2], item->fEntries[1], getConflictResolution()); - // if a conflict occurred, set the default to something sensitive: - if (item->fResolved.isNull() && !(item->fEntries[0].isEmpty() && - item->fEntries[1].isEmpty() && item->fEntries[2].isEmpty() ) ) - { - item->fResolved=item->fEntries[0]; - noconflict=false; - } - if (item->fResolved.isNull()) item->fResolved=item->fEntries[1]; - if (item->fResolved.isNull()) item->fResolved=item->fEntries[2]; - } - return noconflict; -} - - - -/** Merge the palm and the pc entries with the additional information of - * the backup. - * return value: no meaning yet - */ -bool AbbrowserConduit::_smartMergeAddressee(Addressee &pcAddr, - PilotAddress *backupAddr, PilotAddress *palmAddr) -{ - FUNCTIONSETUP; - - // Merge them, then look which records have to be written to device or abook - int res = SyncAction::eAskUser; - bool result=true; - ResolutionTable tab; - - result &= _buildResolutionTable(&tab, pcAddr, backupAddr, palmAddr); - // Now attempt a smart merge. If that fails, let conflict resolution do the job - bool mergeOk=_smartMergeTable(&tab); - - if (!mergeOk) - { - TQString dlgText; - if (!palmAddr) - { - dlgText=i18n("The following address entry was changed, but does no longer exist on the handheld. Please resolve this conflict:"); - } - else if (pcAddr.isEmpty()) - { - dlgText=i18n("The following address entry was changed, but does no longer exist on the PC. Please resolve this conflict:"); - } - else - { - 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:"); - } - ResolutionDlg*resdlg=new ResolutionDlg(0L, fHandle, i18n("Address conflict"), dlgText, &tab); - resdlg->exec(); - KPILOT_DELETE(resdlg); - } - res=tab.fResolution; - - // Disallow some resolution under certain conditions, fix wrong values: - switch (res) { - case SyncAction::eHHOverrides: - if (!palmAddr) res=SyncAction::eDelete; - break; - case SyncAction::ePCOverrides: - if (pcAddr.isEmpty()) res=SyncAction::eDelete; - break; - case SyncAction::ePreviousSyncOverrides: - if (!backupAddr) res=SyncAction::eDoNothing; - break; - } - - PilotAddress*pAddr=palmAddr; - bool pAddrCreated=false; - // Now that we have done a possible conflict resolution, apply the changes - switch (res) { - case SyncAction::eDuplicate: - // Set the Palm ID to 0 so we don't overwrite the existing record. - pcAddr.removeCustom(KABCSync::appString, KABCSync::idString); - result &= _copyToHH(pcAddr, 0L, 0L); - { - Addressee pcadr; - result &= _copyToPC(pcadr, backupAddr, palmAddr); - } - break; - case SyncAction::eDoNothing: - break; - case SyncAction::eHHOverrides: - result &= _copyToPC(pcAddr, backupAddr, palmAddr); - break; - case SyncAction::ePCOverrides: - result &= _copyToHH(pcAddr, backupAddr, pAddr); - break; - case SyncAction::ePreviousSyncOverrides: - KABCSync::copy(pcAddr, *backupAddr, *fAddressAppInfo, fSyncSettings); - if (palmAddr && backupAddr) *palmAddr=*backupAddr; - result &= _savePalmAddr(backupAddr, pcAddr); - result &= _savePCAddr(pcAddr, backupAddr, backupAddr); - break; - case SyncAction::eDelete: - result &= _deleteAddressee(pcAddr, backupAddr, palmAddr); - break; - case SyncAction::eAskUser: - default: - if (!pAddr) - { - pAddr=new PilotAddress(); - pAddrCreated=true; - } - result &= _applyResolutionTable(&tab, pcAddr, backupAddr, pAddr); -showAddresses(pcAddr, backupAddr, pAddr); - // savePalmAddr sets the RecordID custom field already - result &= _savePalmAddr(pAddr, pcAddr); - result &= _savePCAddr(pcAddr, backupAddr, pAddr); - if (pAddrCreated) KPILOT_DELETE(pAddr); - break; - } - - return result; -} - - - -// TODO: right now entries are equal if both first/last name and organization are -// equal. This rules out two entries for the same person(e.g. real home and weekend home) -// or two persons with the same name where you don't know the organization.!!! -Addressee AbbrowserConduit::_findMatch(const PilotAddress & pilotAddress) const -{ - FUNCTIONSETUP; - // TODO: also search with the pilotID - // first, use the pilotID to UID map to find the appropriate record - if( !isFirstSync() && (pilotAddress.id() > 0) ) - { - TQString id(addresseeMap[pilotAddress.id()]); - DEBUGKPILOT << fname << ": PilotRecord has id " << pilotAddress.id() << ", mapped to " << id << endl; - if(!id.isEmpty()) - { - Addressee res(aBook->findByUid(id)); - if(!res.isEmpty()) return res; - DEBUGKPILOT << fname << ": PilotRecord has id " << pilotAddress.id() << ", but could not be found in the addressbook" << endl; - } - } - - for(AddressBook::Iterator iter = aBook->begin(); iter != aBook->end(); ++iter) - { - Addressee abEntry = *iter; - TQString recID(abEntry.custom(KABCSync::appString, KABCSync::idString)); - bool ok; - if (!recID.isEmpty() ) - { - recordid_t rid = recID.toLong(&ok); - if (ok && rid) - { - if (rid==pilotAddress.id()) return abEntry;// yes, we found it - // skip this addressee, as it can an other corresponding address on the handheld - if (allIds.contains(rid)) continue; - } - } - - if (_equal(&pilotAddress, abEntry, eqFlagsAlmostAll)) - { - return abEntry; - } - } - DEBUGKPILOT << fname << ": Could not find any addressbook enty matching " << pilotAddress.getField(entryLastname) << endl; - return Addressee(); -} - -void AbbrowserConduit::slotTestRecord() -{ - FUNCTIONSETUP; - - // Get a record and interpret it as an address. - PilotRecord *r = fDatabase->readRecordByIndex( pilotindex ); - if (!r) - { - delayDone(); - return; - } - PilotAddress a(r); - KPILOT_DELETE(r); - - // Process this record. - showPilotAddress(&a); - - // Schedule more work. - ++pilotindex; - TQTimer::singleShot(0, this, TQT_SLOT(slotTestRecord())); -} |