00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kabcclient.h"
00022 #include "formatfactory.h"
00023 #include "inputformat.h"
00024 #include "outputformat.h"
00025
00026
00027 #include <iostream>
00028 #include <set>
00029 #include <string>
00030
00031
00032 #include <QtCore/QTextCodec>
00033 #include <QtCore/QTimer>
00034
00035
00036 #include <kapplication.h>
00037 #include <klocale.h>
00038 #include <krandom.h>
00039
00040
00041 #include <kabc/addressee.h>
00042 #include <kabc/addresseelist.h>
00043 #include <kabc/stdaddressbook.h>
00044
00045 using namespace KABC;
00046
00047
00048 static const char saveError[] = I18N_NOOP("Saving modifications to addressbook failed");
00049 static const char ambiguousMatch[] = I18N_NOOP("Input number %1 matches more than one contact. "
00050 "Skipping it to avoid undesired results");
00051
00053
00054 KABCClient::KABCClient(Operation operation, FormatFactory* factory)
00055 : QObject(0),
00056 m_operation(operation),
00057 m_formatFactory(factory),
00058 m_inputFormat(0),
00059 m_outputFormat(0),
00060 m_inputCodec(0),
00061 m_outputCodec(0),
00062 m_addressBook(0),
00063 m_inputStream(0),
00064 m_matchCaseSensitivity(Qt::CaseInsensitive),
00065 m_allowSaving(true)
00066 {
00067 }
00068
00070
00071 KABCClient::~KABCClient()
00072 {
00073 delete m_inputFormat;
00074 delete m_outputFormat;
00075 }
00076
00078
00079 bool KABCClient::setInputFormat(const QByteArray& name)
00080 {
00081 switch (m_operation)
00082 {
00083
00084 case List:
00085 return true;
00086
00087 case Add:
00088 case Merge:
00089 if (name == "uid" || name == "search" || name == "dialog")
00090 {
00091 QString operation = QString::fromUtf8(m_operation == Add ? "add" : "merge");
00092 QString error = i18n("Input format '%1' not usable with operation '%2'",
00093 QString::fromLocal8Bit(name), operation);
00094 std::cerr << error.toLocal8Bit().data();
00095 std::cerr << std::endl;
00096 return false;
00097 }
00098
00099 default:
00100 break;
00101 }
00102
00103 m_inputFormat = m_formatFactory->inputFormat(name);
00104
00105 return m_inputFormat != 0;
00106 }
00107
00109
00110 bool KABCClient::setOutputFormat(const QByteArray& name)
00111 {
00112 m_outputFormat = m_formatFactory->outputFormat(name);
00113
00114 return m_outputFormat != 0;
00115 }
00116
00118
00119 bool KABCClient::setInputOptions(const QByteArray& options)
00120 {
00121 if (m_operation == List) return true;
00122
00123 if (m_inputFormat == 0) return false;
00124
00125 return m_inputFormat->setOptions(options);
00126 }
00127
00129
00130 bool KABCClient::setOutputOptions(const QByteArray& options)
00131 {
00132 if (m_outputFormat == 0) return false;
00133
00134 return m_outputFormat->setOptions(options);
00135 }
00136
00138
00139 bool KABCClient::setInputCodec(const QByteArray& name)
00140 {
00141 if (m_operation == List) return true;
00142
00143 if (m_inputFormat == 0) return false;
00144
00145 m_inputCodec = codecForName(name);
00146
00147 if (m_inputCodec == 0) return false;
00148
00149 return m_inputFormat->setCodec(m_inputCodec);
00150 }
00151
00153
00154 bool KABCClient::setOutputCodec(const QByteArray& name)
00155 {
00156 if (m_outputFormat == 0) return false;
00157
00158 m_outputCodec = codecForName(name);
00159
00160 if (m_outputCodec == 0) return false;
00161
00162 return m_outputFormat->setCodec(m_outputCodec);
00163 }
00164
00166
00167 void KABCClient::setInputStream(std::istream* stream)
00168 {
00169 m_inputStream = stream;
00170 }
00171
00173
00174 bool KABCClient::initOperation()
00175 {
00176 if (m_inputStream == 0 && m_operation != List) return false;
00177
00178
00179
00180
00181
00182
00183
00184
00185 m_addressBook = KABC::StdAddressBook::self(false);
00186 if (m_addressBook == 0) return false;
00187
00188 KABC::StdAddressBook::setAutomaticSave(false);
00189
00190
00191
00192 QTimer::singleShot(0, this, SLOT(slotAddressBookLoaded()));
00193
00194 return true;
00195 }
00196
00198
00199 int KABCClient::performAdd()
00200 {
00201
00202 std::set<QString> uids;
00203 AddressBook::ConstIterator it = m_addressBook->begin();
00204 AddressBook::ConstIterator endIt = m_addressBook->end();
00205 for (; it != endIt; ++it)
00206 {
00207 uids.insert((*it).uid());
00208 }
00209
00210 bool wantSave = false;
00211 while (!m_inputStream->bad() && !m_inputStream->eof())
00212 {
00213 Addressee addressee = m_inputFormat->readAddressee(*m_inputStream);
00214 if (addressee.isEmpty()) continue;
00215
00216
00217 if (addressee.uid().isEmpty() || uids.find(addressee.uid()) != uids.end())
00218 {
00219 addressee.setUid(KRandom::randomString(10));
00220 uids.insert(addressee.uid());
00221 }
00222
00223 m_addressBook->insertAddressee(addressee);
00224 wantSave = true;
00225
00226 m_outputFormat->writeAddressee(addressee, std::cout);
00227 std::cout << std::endl;
00228 }
00229
00230 if (!wantSave) return 2;
00231
00232 if (m_allowSaving)
00233 {
00234 Ticket* saveTicket = m_addressBook->requestSaveTicket();
00235 if (saveTicket == 0)
00236 {
00237 std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00238 return 3;
00239 }
00240
00241 bool saved = m_addressBook->save(saveTicket);
00242
00243 if (!saved)
00244 {
00245 std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00246 return 3;
00247 }
00248 }
00249
00250 return (m_inputStream->bad() ? 1 : 0);
00251 }
00252
00254
00255 int KABCClient::performRemove()
00256 {
00257 bool wantSave = false;
00258
00259 uint count = 0;
00260 while (!m_inputStream->bad() && !m_inputStream->eof())
00261 {
00262 Addressee search = m_inputFormat->readAddressee(*m_inputStream);
00263 if (search.isEmpty()) continue;
00264
00265 count++;
00266
00267 AddresseeList result;
00268
00269 AddressBook::ConstIterator it = m_addressBook->begin();
00270 AddressBook::ConstIterator endIt = m_addressBook->end();
00271 for (; it != endIt; ++it)
00272 {
00273 if (!search.uid().isEmpty() && (*it).uid() == search.uid())
00274 {
00275 result.append(*it);
00276 }
00277 else if (!search.realName().isEmpty() &&
00278 (*it).realName().indexOf(search.realName(), 0, m_matchCaseSensitivity) != -1)
00279 {
00280 result.append(*it);
00281 }
00282 else if (!search.familyName().isEmpty() &&
00283 (*it).realName().indexOf(search.familyName(), 0, m_matchCaseSensitivity) != -1)
00284 {
00285 if (!search.givenName().isEmpty())
00286 {
00287 if ((*it).realName().indexOf(search.givenName(), 0, m_matchCaseSensitivity) != -1)
00288 {
00289 result.append(*it);
00290 }
00291 }
00292 else
00293 result.append(*it);
00294 }
00295 else if (!search.givenName().isEmpty() &&
00296 (*it).realName().indexOf(search.givenName(), 0, m_matchCaseSensitivity) != -1)
00297 {
00298 result.append(*it);
00299 }
00300 else if (!search.preferredEmail().isEmpty())
00301 {
00302 QStringList matches =
00303 (*it).emails().filter(search.preferredEmail(), m_matchCaseSensitivity);
00304 if (matches.count() > 0)
00305 {
00306 result.append(*it);
00307 }
00308 }
00309
00310 if (result.count() > 1) break;
00311 }
00312
00313
00314 if (result.count() == 1)
00315 {
00316 m_addressBook->removeAddressee(result[0]);
00317 wantSave = true;
00318
00319 m_outputFormat->writeAddressee(result[0], std::cout);
00320 std::cout << std::endl;
00321 }
00322 else if (result.count() > 1)
00323 {
00324 std::cerr << i18n(ambiguousMatch).arg(count).toLocal8Bit().data() << std::endl;
00325 }
00326 }
00327
00328 if (!wantSave) return 2;
00329
00330 if (m_allowSaving)
00331 {
00332 Ticket* saveTicket = m_addressBook->requestSaveTicket();
00333 if (saveTicket == 0)
00334 {
00335 std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00336 return 3;
00337 }
00338
00339 bool saved = m_addressBook->save(saveTicket);
00340
00341 if (!saved)
00342 {
00343 std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00344 return 3;
00345 }
00346 }
00347
00348 return (m_inputStream->bad() ? 1 : 0);
00349 }
00350
00352
00353 int KABCClient::performMerge()
00354 {
00355 bool wantSave = false;
00356
00357 uint count = 0;
00358 while (!m_inputStream->bad() && !m_inputStream->eof())
00359 {
00360 Addressee addressee = m_inputFormat->readAddressee(*m_inputStream);
00361 if (addressee.isEmpty()) continue;
00362
00363 count++;
00364
00365 AddresseeList result;
00366
00367 AddressBook::ConstIterator it = m_addressBook->begin();
00368 AddressBook::ConstIterator endIt = m_addressBook->end();
00369 for (; it != endIt; ++it)
00370 {
00371 if (!addressee.uid().isEmpty() && (*it).uid() == addressee.uid())
00372 {
00373 result.append(*it);
00374 }
00375 else if (!addressee.realName().isEmpty() &&
00376 (*it).realName().indexOf(addressee.realName(), 0, m_matchCaseSensitivity) != -1)
00377 {
00378 result.append(*it);
00379 }
00380 else if (!addressee.familyName().isEmpty() &&
00381 (*it).realName().indexOf(addressee.familyName(), 0, m_matchCaseSensitivity) != -1)
00382 {
00383 if (!addressee.givenName().isEmpty())
00384 {
00385 if ((*it).realName().indexOf(addressee.givenName(),
00386 0, m_matchCaseSensitivity) != -1)
00387 {
00388 result.append(*it);
00389 }
00390 }
00391 else
00392 result.append(*it);
00393 }
00394 else if (!addressee.givenName().isEmpty() &&
00395 (*it).realName().indexOf(addressee.givenName(), 0, m_matchCaseSensitivity) != -1)
00396 {
00397 result.append(*it);
00398 }
00399 else if (!addressee.preferredEmail().isEmpty())
00400 {
00401 QStringList matches =
00402 (*it).emails().filter(addressee.preferredEmail(), m_matchCaseSensitivity);
00403 if (matches.count() > 0)
00404 {
00405 result.append(*it);
00406 }
00407 }
00408
00409 if (result.count() > 1) break;
00410 }
00411
00412
00413 if (result.count() == 1)
00414 {
00415 Addressee master = result[0];
00416 mergeAddressees(master, addressee);
00417
00418 m_addressBook->insertAddressee(master);
00419 wantSave = true;
00420
00421 m_outputFormat->writeAddressee(master, std::cout);
00422 std::cout << std::endl;
00423 }
00424 else if (result.count() > 1)
00425 {
00426 std::cerr << i18n(ambiguousMatch).arg(count).toLocal8Bit().data() << std::endl;
00427 }
00428 }
00429
00430 if (!wantSave) return 2;
00431
00432 if (m_allowSaving)
00433 {
00434 Ticket* saveTicket = m_addressBook->requestSaveTicket();
00435 if (saveTicket == 0)
00436 {
00437 std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00438 return 3;
00439 }
00440
00441 bool saved = m_addressBook->save(saveTicket);
00442
00443 if (!saved)
00444 {
00445 std::cerr << i18n(saveError).toLocal8Bit().data() << std::endl;
00446 return 3;
00447 }
00448 }
00449
00450 return (m_inputStream->bad() ? 1 : 0);
00451 }
00452
00454
00455 int KABCClient::performList()
00456 {
00457 AddresseeList list = m_addressBook->allAddressees();
00458
00459 return m_outputFormat->writeAddresseeList(list, std::cout) ? 0 : 1;
00460 }
00461
00463
00464 int KABCClient::performSearch()
00465 {
00466 int resultValue = 2;
00467
00468 AddressBook::ConstIterator endIt = m_addressBook->end();
00469
00470 while (!m_inputStream->bad() && !m_inputStream->eof())
00471 {
00472 Addressee search = m_inputFormat->readAddressee(*m_inputStream);
00473 if (search.isEmpty()) continue;
00474
00475 AddresseeList result;
00476
00477 AddressBook::ConstIterator it = m_addressBook->begin();
00478 for (; it != endIt; ++it)
00479 {
00480 if (!search.uid().isEmpty() && (*it).uid() == search.uid())
00481 {
00482 result.append(*it);
00483 }
00484 else if (!search.realName().isEmpty() &&
00485 (*it).realName().indexOf(search.realName(), 0, m_matchCaseSensitivity) != -1)
00486 {
00487 result.append(*it);
00488 }
00489 else if (!search.familyName().isEmpty() &&
00490 (*it).realName().indexOf(search.familyName(), 0, m_matchCaseSensitivity) != -1)
00491 {
00492 if (!search.givenName().isEmpty())
00493 {
00494 if ((*it).realName().indexOf(search.givenName(), 0, m_matchCaseSensitivity) != -1)
00495 {
00496 result.append(*it);
00497 }
00498 }
00499 else
00500 result.append(*it);
00501 }
00502 else if (!search.givenName().isEmpty() &&
00503 (*it).realName().indexOf(search.givenName(), 0, m_matchCaseSensitivity) != -1)
00504 {
00505 result.append(*it);
00506 }
00507 else if (!search.preferredEmail().isEmpty())
00508 {
00509 QStringList matches =
00510 (*it).emails().filter(search.preferredEmail(), m_matchCaseSensitivity);
00511 if (matches.count() > 0)
00512 {
00513 result.append(*it);
00514 }
00515 }
00516 }
00517
00518 if (result.count() > 0)
00519 {
00520 resultValue = 0;
00521
00522 if (!m_outputFormat->writeAddresseeList(result, std::cout))
00523 {
00524 return 1;
00525 }
00526 }
00527 }
00528
00529 return resultValue;
00530 }
00531
00533
00534
00535 void KABCClient::mergePictures(KABC::Picture& master, const KABC::Picture slave)
00536 {
00537 if (master.isIntern())
00538 {
00539 if (master.data().isNull())
00540 {
00541 if (slave.isIntern() && !slave.data().isNull())
00542 master.setData(slave.data());
00543 else if (!slave.isIntern() && !slave.url().isEmpty())
00544 master.setUrl(slave.url());
00545 }
00546 }
00547 else
00548 {
00549 if (master.url().isEmpty())
00550 {
00551 if (slave.isIntern() && !slave.data().isNull())
00552 master.setData( slave.data() );
00553 else if (!slave.isIntern() && !slave.url().isEmpty())
00554 master.setUrl(slave.url());
00555 }
00556 }
00557 }
00558
00560
00561
00562 void KABCClient::mergeAddressees(KABC::Addressee& master, const KABC::Addressee& slave)
00563 {
00564 if (slave.isEmpty()) return;
00565
00566
00567 const KABC::Address::List addresses = slave.addresses();
00568 KABC::Address::List masterAddresses = master.addresses();
00569 KABC::Address::List::ConstIterator addrIt ;
00570 for (addrIt = addresses.begin(); addrIt != addresses.end(); ++addrIt)
00571 {
00572 if (!masterAddresses.contains(*addrIt))
00573 master.insertAddress(*addrIt);
00574 }
00575
00576
00577 if (master.birthday().isNull() && !slave.birthday().isNull())
00578 master.setBirthday(slave.birthday());
00579
00580
00581 const QStringList categories = slave.categories();
00582 const QStringList masterCategories = master.categories();
00583
00584 QStringList newCategories = masterCategories;
00585 QStringList::ConstIterator it;
00586 for (it = categories.begin(); it != categories.end(); ++it)
00587 {
00588 if (!masterCategories.contains(*it))
00589 newCategories.append(*it);
00590 }
00591 master.setCategories(newCategories);
00592
00593
00594 if (!master.secrecy().isValid() && slave.secrecy().isValid())
00595 master.setSecrecy(slave.secrecy());
00596
00597
00598 const QStringList emails = slave.emails();
00599 const QStringList masterEmails = master.emails();
00600
00601 for (it = emails.begin(); it != emails.end(); ++it)
00602 {
00603 if (!masterEmails.contains(*it))
00604 master.insertEmail(*it, false);
00605 }
00606
00607
00608 if (master.formattedName().isEmpty() && !slave.formattedName().isEmpty())
00609 master.setFormattedName(slave.formattedName());
00610
00611
00612 if (!master.geo().isValid() && slave.geo().isValid())
00613 master.setGeo(slave.geo());
00614
00615
00616
00617
00618
00619 KABC::Picture logo = master.logo();
00620 mergePictures(logo, slave.logo());
00621 master.setLogo(logo);
00622
00623
00624 if (master.mailer().isEmpty() && !slave.mailer().isEmpty())
00625 master.setMailer(slave.mailer());
00626
00627
00628 if (master.assembledName().isEmpty() && !slave.assembledName().isEmpty())
00629 master.setNameFromString(slave.assembledName());
00630
00631
00632 if (master.nickName().isEmpty() && !slave.nickName().isEmpty())
00633 master.setNickName(slave.nickName());
00634
00635
00636 if (master.note().isEmpty() && !slave.note().isEmpty())
00637 master.setNote(slave.note());
00638
00639
00640 if (master.organization().isEmpty() && !slave.organization().isEmpty())
00641 master.setOrganization(slave.organization());
00642
00643
00644 KABC::Picture photo = master.photo();
00645 mergePictures(photo, slave.photo());
00646 master.setPhoto( photo );
00647
00648
00649 if (master.productId().isEmpty() && !slave.productId().isEmpty())
00650 master.setProductId(slave.productId());
00651
00652
00653 if (master.revision().isNull() && !slave.revision().isNull())
00654 master.setRevision(slave.revision());
00655
00656
00657 if (master.role().isEmpty() && !slave.role().isEmpty())
00658 master.setRole(slave.role());
00659
00660
00661 if (master.sortString().isEmpty() && !slave.sortString().isEmpty())
00662 master.setSortString(slave.sortString());
00663
00664
00665
00666
00667
00668
00669 const KABC::PhoneNumber::List phones = slave.phoneNumbers();
00670 const KABC::PhoneNumber::List masterPhones = master.phoneNumbers();
00671
00672 KABC::PhoneNumber::List::ConstIterator phoneIt;
00673 for (phoneIt = phones.begin(); phoneIt != phones.end(); ++phoneIt)
00674 {
00675 if (!masterPhones.contains(*phoneIt))
00676 master.insertPhoneNumber(*phoneIt);
00677 }
00678
00679
00680 if (master.title().isEmpty() && !slave.title().isEmpty())
00681 master.setTitle(slave.title());
00682
00683
00684 if (!master.timeZone().isValid() && slave.timeZone().isValid())
00685 master.setTimeZone(slave.timeZone());
00686
00687
00688
00689
00690 if (master.url().isEmpty() && !slave.url().isEmpty())
00691 master.setUrl(slave.url());
00692
00693
00694 const QStringList customs = slave.customs();
00695 const QStringList masterCustoms = master.customs();
00696
00697 QStringList newCustoms = masterCustoms;
00698 for (it = customs.begin(); it != customs.end(); ++it)
00699 {
00700 if (!masterCustoms.contains(*it))
00701 newCustoms.append(*it);
00702 }
00703 master.setCustoms(newCustoms);
00704 }
00705
00707
00708 QTextCodec* KABCClient::codecForName(const QByteArray& name)
00709 {
00710 if (name.isEmpty()) return 0;
00711
00712 if (name.toLower() == "utf-8" || name.toLower() == "utf8" || name == "utf")
00713 {
00714 return QTextCodec::codecForName("UTF-8");
00715 }
00716
00717 if (name.toLower() == "local" || name.toLower() == "locale")
00718 {
00719 return QTextCodec::codecForLocale();
00720 }
00721
00722 return QTextCodec::codecForName(name.toUpper());
00723 }
00724
00726
00727 void KABCClient::slotAddressBookLoaded()
00728 {
00729
00730 QObject::disconnect(m_addressBook, SIGNAL(addressBookChanged(AddressBook*)),
00731 this, SLOT(slotAddressBookLoaded()));
00732
00733 int result = 1;
00734
00735 switch (m_operation)
00736 {
00737 case Add:
00738 result = performAdd();
00739 break;
00740
00741 case Remove:
00742 result = performRemove();
00743 break;
00744
00745 case Merge:
00746 result = performMerge();
00747 break;
00748
00749 case List:
00750 result = performList();
00751 break;
00752
00753 case Search:
00754 result = performSearch();
00755 break;
00756
00757 default:
00758 break;
00759 }
00760
00761 KApplication::kApplication()->exit(result);
00762 }
00763
00764
00765
00766 #include "kabcclient.moc"