Warning, file /pim/akonadi-search/agent/contactindexer.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * This file is part of the KDE Akonadi Search Project
0003  * SPDX-FileCopyrightText: 2013 Vishesh Handa <me@vhanda.in>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006  *
0007  */
0008 
0009 #include "contactindexer.h"
0010 #include "akonadi_indexer_agent_debug.h"
0011 #include "xapiandocument.h"
0012 
0013 #include <Akonadi/Collection>
0014 #include <KContacts/Addressee>
0015 #include <KContacts/ContactGroup>
0016 
0017 ContactIndexer::ContactIndexer(const QString &path)
0018     : AbstractIndexer()
0019 {
0020     try {
0021         m_db = new Akonadi::Search::XapianDatabase(path, true);
0022     } catch (const Xapian::DatabaseCorruptError &err) {
0023         qCWarning(AKONADI_INDEXER_AGENT_LOG) << "Database Corrupted - What did you do?";
0024         qCWarning(AKONADI_INDEXER_AGENT_LOG) << err.get_error_string();
0025         m_db = nullptr;
0026     } catch (const Xapian::Error &e) {
0027         qCWarning(AKONADI_INDEXER_AGENT_LOG) << QString::fromStdString(e.get_type()) << QString::fromStdString(e.get_description());
0028         m_db = nullptr;
0029     }
0030 }
0031 
0032 ContactIndexer::~ContactIndexer()
0033 {
0034     commit();
0035     delete m_db;
0036 }
0037 
0038 QStringList ContactIndexer::mimeTypes() const
0039 {
0040     return QStringList() << KContacts::Addressee::mimeType() << KContacts::ContactGroup::mimeType();
0041 }
0042 
0043 bool ContactIndexer::indexContact(const Akonadi::Item &item)
0044 {
0045     if (!m_db) {
0046         return false;
0047     }
0048     KContacts::Addressee addressee;
0049     try {
0050         addressee = item.payload<KContacts::Addressee>();
0051     } catch (const Akonadi::PayloadException &) {
0052         return false;
0053     }
0054 
0055     Akonadi::Search::XapianDocument doc;
0056 
0057     QString name;
0058     if (!addressee.formattedName().isEmpty()) {
0059         name = addressee.formattedName();
0060     } else if (!addressee.assembledName().isEmpty()) {
0061         name = addressee.assembledName();
0062     } else {
0063         name = addressee.name();
0064     }
0065 
0066     qCDebug(AKONADI_INDEXER_AGENT_LOG) << "Indexing" << name << addressee.nickName();
0067 
0068     doc.indexText(name);
0069     doc.indexText(addressee.nickName());
0070     doc.indexText(addressee.uid(), QStringLiteral("UID"));
0071 
0072     doc.indexText(name, QStringLiteral("NA"));
0073     doc.indexText(addressee.nickName(), QStringLiteral("NI"));
0074 
0075     const QStringList lstEmails = addressee.emails();
0076     for (const QString &email : lstEmails) {
0077         doc.addTerm(email);
0078         doc.indexText(email);
0079     }
0080 
0081     // Parent collection
0082     Q_ASSERT_X(item.parentCollection().isValid(), "Akonadi::Search::ContactIndexer::index", "Item does not have a valid parent collection");
0083 
0084     const Akonadi::Collection::Id colId = item.parentCollection().id();
0085     doc.addBoolTerm(colId, QStringLiteral("C"));
0086 
0087     if (addressee.birthday().isValid()) {
0088         const QString julianDay = QString::number(addressee.birthday().date().toJulianDay());
0089         doc.addValue(0, julianDay);
0090     }
0091     // TODO index anniversary ?
0092 
0093     m_db->replaceDocument(item.id(), doc);
0094     return true;
0095 }
0096 
0097 void ContactIndexer::indexContactGroup(const Akonadi::Item &item)
0098 {
0099     if (!m_db) {
0100         return;
0101     }
0102     KContacts::ContactGroup group;
0103     try {
0104         group = item.payload<KContacts::ContactGroup>();
0105     } catch (const Akonadi::PayloadException &) {
0106         return;
0107     }
0108 
0109     Akonadi::Search::XapianDocument doc;
0110 
0111     const QString name = group.name();
0112     doc.indexText(name);
0113     doc.indexText(name, QStringLiteral("NA"));
0114 
0115     // Parent collection
0116     Q_ASSERT_X(item.parentCollection().isValid(), "Akonadi::Search::ContactIndexer::index", "Item does not have a valid parent collection");
0117 
0118     const Akonadi::Collection::Id colId = item.parentCollection().id();
0119     doc.addBoolTerm(colId, QStringLiteral("C"));
0120     m_db->replaceDocument(item.id(), doc);
0121 }
0122 
0123 void ContactIndexer::index(const Akonadi::Item &item)
0124 {
0125     if (!indexContact(item)) {
0126         indexContactGroup(item);
0127     }
0128 }
0129 
0130 void ContactIndexer::remove(const Akonadi::Item &item)
0131 {
0132     if (m_db) {
0133         m_db->deleteDocument(item.id());
0134     }
0135 }
0136 
0137 void ContactIndexer::remove(const Akonadi::Collection &collection)
0138 {
0139     if (!m_db) {
0140         return;
0141     }
0142     try {
0143         Xapian::Database *db = m_db->db();
0144         Xapian::Query query('C' + QString::number(collection.id()).toStdString());
0145         Xapian::Enquire enquire(*db);
0146         enquire.set_query(query);
0147 
0148         Xapian::MSet mset = enquire.get_mset(0, db->get_doccount());
0149         Xapian::MSetIterator end(mset.end());
0150         for (Xapian::MSetIterator it = mset.begin(); it != end; ++it) {
0151             const qint64 id = *it;
0152             remove(Akonadi::Item(id));
0153         }
0154     } catch (const Xapian::DocNotFoundError &) {
0155         return;
0156     }
0157 }
0158 
0159 void ContactIndexer::commit()
0160 {
0161     if (!m_db) {
0162         return;
0163     }
0164 
0165     try {
0166         m_db->commit();
0167     } catch (const Xapian::Error &err) {
0168         qCWarning(AKONADI_INDEXER_AGENT_LOG) << err.get_error_string();
0169     }
0170     qCDebug(AKONADI_INDEXER_AGENT_LOG) << "Xapian Committed";
0171 }
0172 
0173 void ContactIndexer::move(Akonadi::Item::Id itemId, Akonadi::Collection::Id from, Akonadi::Collection::Id to)
0174 {
0175     if (!m_db) {
0176         return;
0177     }
0178 
0179     Akonadi::Search::XapianDocument doc;
0180     try {
0181         doc = m_db->document(itemId);
0182     } catch (const Xapian::DocNotFoundError &) {
0183         return;
0184     }
0185 
0186     const QByteArray ft = 'C' + QByteArray::number(from);
0187     const QByteArray tt = 'C' + QByteArray::number(to);
0188 
0189     doc.removeTermStartsWith(ft.data());
0190     doc.addBoolTerm(QString::fromLatin1(tt.data()));
0191     m_db->replaceDocument(doc.doc().get_docid(), doc);
0192 }