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