diff --git a/src/file/autotest/fileindexingjob/extractor.cpp b/src/file/autotest/fileindexingjob/extractor.cpp index d2d71080..1d2f4f53 100644 --- a/src/file/autotest/fileindexingjob/extractor.cpp +++ b/src/file/autotest/fileindexingjob/extractor.cpp @@ -1,83 +1,83 @@ /* * This file is part of the KDE Baloo Project * Copyright (C) 2014 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include #include #include #include #include #include #include #include #include #include int main(int argc, char* argv[]) { KAboutData aboutData("baloo_file_extractor_dummy", 0, KLocalizedString(), "0.1", KLocalizedString()); KCmdLineArgs::init(argc, argv, &aboutData); KCmdLineOptions options; options.add("+[url]", KLocalizedString()); KCmdLineArgs::addCmdLineOptions(options); const KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); int argCount = args->count(); if (argCount == 0) { QTextStream err(stderr); err << "Must input url/id of the file to be indexed"; return 1; } KComponentData data(aboutData, KComponentData::RegisterAsMainComponent); QByteArray failArr = qgetenv("BALOO_EXTRACTOR_FAIL_FILE"); QByteArray timeoutArr = qgetenv("BALOO_EXTRACTOR_TIMEOUT_FILE"); if (failArr.isEmpty() && timeoutArr.isEmpty()) { return 0; } QStringList failFiles = QString::fromUtf8(failArr).split(QLatin1String(","), QString::SkipEmptyParts); QStringList timeoutFiles = QString::fromUtf8(timeoutArr).split(QLatin1String(","), QString::SkipEmptyParts); for (int i = 0; i < args->count(); ++i) { QString fid = args->arg(i); if (failFiles.contains(fid)) { // kill oneself raise(SIGKILL); return -1; } if (timeoutFiles.contains(fid)) { // 100 msecs - usleep(100 * 1000); + sleep(100); } } return 0; } diff --git a/src/pim/agent/autotests/CMakeLists.txt b/src/pim/agent/autotests/CMakeLists.txt index 88c67284..0c54ee8e 100644 --- a/src/pim/agent/autotests/CMakeLists.txt +++ b/src/pim/agent/autotests/CMakeLists.txt @@ -1,72 +1,75 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ) set(indexer_SRCS ../emailindexer.cpp ../contactindexer.cpp ../akonotesindexer.cpp ../calendarindexer.cpp ../abstractindexer.cpp ../collectionindexer.cpp ../../search/pimsearchstore.cpp ../../search/email/emailsearchstore.cpp ../../search/email/agepostingsource.cpp ../../search/contact/contactsearchstore.cpp ) set(indexer_LIBS ${QT_QTTEST_LIBRARY} ${KDE4_KDECORE_LIBS} ${KDEPIMLIBS_AKONADI_LIBS} ${KDEPIMLIBS_AKONADI_KMIME_LIBS} ${KDEPIMLIBS_KMIME_LIBS} ${KDEPIMLIBS_KABC_LIBS} ${KDEPIMLIBS_KCALCORE_LIBS} ${XAPIAN_LIBRARIES} ${KDEPIMLIBS_KPIMUTILS_LIBS} baloocore balooxapian ) set(indexertest_SRCS indexertest.cpp ${indexer_SRCS} ) add_definitions(-DBALOO_NO_PLUGINS=TRUE) kde4_add_unit_test(indexertest NOGUI ${indexertest_SRCS}) target_link_libraries(indexertest ${indexer_LIBS} ) set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) include(AkonadiMacros) set(KDEPIMLIBS_RUN_ISOLATED_TESTS TRUE) set(KDEPIMLIBS_RUN_SQLITE_ISOLATED_TESTS TRUE) set(scheduler_SRCS ../scheduler.cpp ../index.cpp ../collectionindexingjob.cpp ${indexer_SRCS} ) add_akonadi_isolated_test_advanced(schedulertest.cpp "${scheduler_SRCS}" "${indexer_LIBS}") add_akonadi_isolated_test_advanced(collectionindexingjobtest.cpp "${scheduler_SRCS}" "${indexer_LIBS}") set(query_SRCS ../../lib/query.cpp ../../lib/collectionquery.cpp ../../lib/contactquery.cpp ../../lib/resultiterator.cpp ) +if(NOT WIN32) kde4_add_unit_test(collectionquerytest NOGUI collectionquerytest.cpp ../../lib/collectionquery.cpp ${query_SRCS} ${indexer_SRCS} ${scheduler_SRCS}) target_link_libraries(collectionquerytest ${indexer_LIBS} ${QJSON_LIBRARIES} ) +endif() + diff --git a/src/pim/agent/index.cpp b/src/pim/agent/index.cpp index dd57135b..f8334e3e 100644 --- a/src/pim/agent/index.cpp +++ b/src/pim/agent/index.cpp @@ -1,426 +1,426 @@ /* * Copyright 2014 Christian Mollekopf * * 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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. If not, see . * */ #include "index.h" #include "emailindexer.h" #include "contactindexer.h" #include "akonotesindexer.h" #include "calendarindexer.h" #include #include #include #include #include #include #include #include Index::Index(QObject* parent) : QObject(parent), m_collectionIndexer(0) { m_commitTimer.setInterval(1000); m_commitTimer.setSingleShot(true); connect(&m_commitTimer, SIGNAL(timeout()), this, SLOT(commit())); } Index::~Index() { delete m_collectionIndexer; m_collectionIndexer = 0; qDeleteAll(m_indexer.values().toSet()); m_indexer.clear(); } static void removeDir(const QString& dirName) { QDir dir(dirName); if (dir.exists(dirName)) { Q_FOREACH(const QFileInfo &info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) { if (info.isDir()) { removeDir(info.absoluteFilePath()); } else { QFile::remove(info.absoluteFilePath()); } } dir.rmdir(dirName); } } void Index::removeDatabase() { delete m_collectionIndexer; m_collectionIndexer = 0; qDeleteAll(m_indexer.values().toSet()); m_indexer.clear(); kDebug() << "Removing database"; removeDir(emailIndexingPath()); removeDir(contactIndexingPath()); removeDir(emailContactsIndexingPath()); removeDir(akonotesIndexingPath()); removeDir(calendarIndexingPath()); removeDir(collectionIndexingPath()); } AbstractIndexer* Index::indexerForItem(const Akonadi::Item& item) const { return m_indexer.value(item.mimeType()); } QList Index::indexersForMimetypes(const QStringList& mimeTypes) const { QList indexers; Q_FOREACH (const QString& mimeType, mimeTypes) { AbstractIndexer *i = m_indexer.value(mimeType); if (i) { indexers.append(i); } } return indexers; } bool Index::haveIndexerForMimeTypes(const QStringList &mimeTypes) { return !indexersForMimetypes(mimeTypes).isEmpty(); } void Index::index(const Akonadi::Item& item) { AbstractIndexer *indexer = indexerForItem(item); if (!indexer) { return; } try { indexer->index(item); } catch (const Xapian::Error &e) { kWarning() << "Xapian error in indexer" << indexer << ":" << e.get_msg().c_str(); } } void Index::move(const Akonadi::Item::List& items, const Akonadi::Collection& from, const Akonadi::Collection& to) { //We always get items of the same type AbstractIndexer *indexer = indexerForItem(items.first()); if (!indexer) { return; } Q_FOREACH (const Akonadi::Item& item, items) { try { indexer->move(item.id(), from.id(), to.id()); } catch (const Xapian::Error &e) { kWarning() << "Xapian error in indexer" << indexer << ":" << e.get_msg().c_str(); } } } void Index::updateFlags(const Akonadi::Item::List& items, const QSet& addedFlags, const QSet& removedFlags) { //We always get items of the same type AbstractIndexer *indexer = indexerForItem(items.first()); if (!indexer) { return; } Q_FOREACH (const Akonadi::Item& item, items) { try { indexer->updateFlags(item, addedFlags, removedFlags); } catch (const Xapian::Error &e) { kWarning() << "Xapian error in indexer" << indexer << ":" << e.get_msg().c_str(); } } } void Index::remove(const QSet< Akonadi::Entity::Id >& ids, const QStringList& mimeTypes) { - const QList indexer = indexersForMimetypes(mimeTypes); + const QList indexers = indexersForMimetypes(mimeTypes); Q_FOREACH (const Akonadi::Item::Id& id, ids) { - Q_FOREACH (AbstractIndexer *indexer, indexer) { + Q_FOREACH (AbstractIndexer *indexer, indexers) { try { indexer->remove(Akonadi::Item(id)); } catch (const Xapian::Error &e) { kWarning() << "Xapian error in indexer" << indexer << ":" << e.get_msg().c_str(); } } } } void Index::remove(const Akonadi::Item::List& items) { AbstractIndexer *indexer = indexerForItem(items.first()); if (!indexer) { return; } Q_FOREACH (const Akonadi::Item& item, items) { try { indexer->remove(item); } catch (const Xapian::Error &e) { kWarning() << "Xapian error in indexer" << indexer << ":" << e.get_msg().c_str(); } } } void Index::index(const Akonadi::Collection& collection) { if (m_collectionIndexer) { m_collectionIndexer->index(collection); m_collectionIndexer->commit(); } kDebug() << "indexed " << collection.id(); } void Index::change(const Akonadi::Collection& col) { if (m_collectionIndexer) { m_collectionIndexer->change(col); m_collectionIndexer->commit(); } } void Index::remove(const Akonadi::Collection& col) { //Remove items Q_FOREACH (AbstractIndexer *indexer, indexersForMimetypes(col.contentMimeTypes())) { try { indexer->remove(col); } catch (const Xapian::Error &e) { kWarning() << "Xapian error in indexer" << indexer << ":" << e.get_msg().c_str(); } } if (m_collectionIndexer) { m_collectionIndexer->remove(col); m_collectionIndexer->commit(); } } void Index::move(const Akonadi::Collection& collection, const Akonadi::Collection& from, const Akonadi::Collection& to) { if (m_collectionIndexer) { m_collectionIndexer->move(collection, from, to); m_collectionIndexer->commit(); } } void Index::addIndexer(AbstractIndexer* indexer) { Q_FOREACH (const QString& mimeType, indexer->mimeTypes()) { m_indexer.insert(mimeType, indexer); } } bool Index::createIndexers() { AbstractIndexer *indexer = 0; try { QDir().mkpath(emailIndexingPath()); QDir().mkpath(emailContactsIndexingPath()); indexer = new EmailIndexer(emailIndexingPath(), emailContactsIndexingPath()); addIndexer(indexer); } catch (const Xapian::DatabaseError &e) { delete indexer; kError() << "Failed to create email indexer:" << QString::fromStdString(e.get_msg()); } catch (...) { delete indexer; kError() << "Random exception, but we do not want to crash"; } try { QDir().mkpath(contactIndexingPath()); indexer = new ContactIndexer(contactIndexingPath()); addIndexer(indexer); } catch (const Xapian::DatabaseError &e) { delete indexer; kError() << "Failed to create contact indexer:" << QString::fromStdString(e.get_msg()); } catch (...) { delete indexer; kError() << "Random exception, but we do not want to crash"; } try { QDir().mkpath(akonotesIndexingPath()); indexer = new AkonotesIndexer(akonotesIndexingPath()); addIndexer(indexer); } catch (const Xapian::DatabaseError &e) { delete indexer; kError() << "Failed to create akonotes indexer:" << QString::fromStdString(e.get_msg()); } catch (...) { delete indexer; kError() << "Random exception, but we do not want to crash"; } try { QDir().mkpath(calendarIndexingPath()); indexer = new CalendarIndexer(calendarIndexingPath()); addIndexer(indexer); } catch (const Xapian::DatabaseError &e) { delete indexer; kError() << "Failed to create collection indexer:" << QString::fromStdString(e.get_msg()); } catch (...) { delete indexer; kError() << "Random exception, but we do not want to crash"; } try { QDir().mkpath(collectionIndexingPath()); m_collectionIndexer = new CollectionIndexer(collectionIndexingPath()); } catch (const Xapian::DatabaseError &e) { delete m_collectionIndexer; m_collectionIndexer = 0; kError() << "Failed to create akonotes indexer:" << QString::fromStdString(e.get_msg()); } catch (...) { delete m_collectionIndexer; m_collectionIndexer = 0; kError() << "Random exception, but we do not want to crash"; } return !m_indexer.isEmpty(); } void Index::scheduleCommit() { if (!m_commitTimer.isActive()) { m_commitTimer.start(); } } void Index::commit() { m_commitTimer.stop(); Q_FOREACH (AbstractIndexer *indexer, m_indexer) { try { indexer->commit(); } catch (const Xapian::Error &e) { kWarning() << "Xapian error in indexer" << indexer << ":" << e.get_msg().c_str(); } } } void Index::findIndexedInDatabase(QSet &indexed, Akonadi::Entity::Id collectionId, const QString& dbPath) { Xapian::Database db; try { db = Xapian::Database(QFile::encodeName(dbPath).constData()); } catch (const Xapian::DatabaseError& e) { kError() << "Failed to open database" << dbPath << ":" << QString::fromStdString(e.get_msg()); return; } const std::string term = QString::fromLatin1("C%1").arg(collectionId).toStdString(); Xapian::Query query(term); Xapian::Enquire enquire(db); enquire.set_query(query); Xapian::MSet mset = enquire.get_mset(0, UINT_MAX); Xapian::MSetIterator it = mset.begin(); for (;it != mset.end(); it++) { indexed << *it; } } void Index::findIndexed(QSet& indexed, Akonadi::Entity::Id collectionId) { findIndexedInDatabase(indexed, collectionId, emailIndexingPath()); findIndexedInDatabase(indexed, collectionId, contactIndexingPath()); findIndexedInDatabase(indexed, collectionId, akonotesIndexingPath()); findIndexedInDatabase(indexed, collectionId, calendarIndexingPath()); } qlonglong Index::indexedItems(const qlonglong id) { const std::string term = QString::fromLatin1("C%1").arg(id).toStdString(); return indexedItemsInDatabase(term, emailIndexingPath()) + indexedItemsInDatabase(term, contactIndexingPath()) + indexedItemsInDatabase(term, akonotesIndexingPath()) + indexedItemsInDatabase(term, calendarIndexingPath()); } qlonglong Index::indexedItemsInDatabase(const std::string& term, const QString& dbPath) const { Xapian::Database db; try { db = Xapian::Database(QFile::encodeName(dbPath).constData()); } catch (const Xapian::DatabaseError& e) { kError() << "Failed to open database" << dbPath << ":" << QString::fromStdString(e.get_msg()); return 0; } return db.get_termfreq(term); } void Index::setOverrideDbPrefixPath(const QString& path) { m_overridePrefixPath = path; } QString Index::dbPath(const QString& dbName) const { if (!m_overridePrefixPath.isEmpty()) { return QString::fromLatin1("%1/%2/").arg(m_overridePrefixPath, dbName); } QString basePath = QLatin1String("baloo"); if (Akonadi::ServerManager::hasInstanceIdentifier()) { basePath = QString::fromLatin1("baloo/instances/%1").arg(Akonadi::ServerManager::instanceIdentifier()); } return KGlobal::dirs()->localxdgdatadir() + QString::fromLatin1("%1/%2/").arg(basePath, dbName); } QString Index::emailIndexingPath() const { return dbPath(QLatin1String("email")); } QString Index::contactIndexingPath() const { return dbPath(QLatin1String("contacts")); } QString Index::emailContactsIndexingPath() const { return dbPath(QLatin1String("emailContacts")); } QString Index::akonotesIndexingPath() const { return dbPath(QLatin1String("notes")); } QString Index::calendarIndexingPath() const { return dbPath(QLatin1String("calendars")); } QString Index::collectionIndexingPath() const { return dbPath(QLatin1String("collections")); } diff --git a/src/pim/akonadiplugin/searchplugin.cpp b/src/pim/akonadiplugin/searchplugin.cpp index 5a59ef0f..eec5be7e 100644 --- a/src/pim/akonadiplugin/searchplugin.cpp +++ b/src/pim/akonadiplugin/searchplugin.cpp @@ -1,353 +1,353 @@ /* * This file is part of the KDE Baloo Project * Copyright (C) 2014 Christian Mollekopf * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "searchplugin.h" #include "query.h" #include "term.h" #include "resultiterator.h" #include #include #include #include #include #include #include static Baloo::Term::Operation mapRelation(Akonadi::SearchTerm::Relation relation) { if (relation == Akonadi::SearchTerm::RelAnd){ return Baloo::Term::And; } return Baloo::Term::Or; } static Baloo::Term::Comparator mapComparator(Akonadi::SearchTerm::Condition comparator) { if (comparator == Akonadi::SearchTerm::CondContains){ return Baloo::Term::Contains; } if (comparator == Akonadi::SearchTerm::CondGreaterOrEqual){ return Baloo::Term::GreaterEqual; } if (comparator == Akonadi::SearchTerm::CondGreaterThan){ return Baloo::Term::Greater; } if (comparator == Akonadi::SearchTerm::CondEqual){ return Baloo::Term::Equal; } if (comparator == Akonadi::SearchTerm::CondLessOrEqual){ return Baloo::Term::LessEqual; } if (comparator == Akonadi::SearchTerm::CondLessThan){ return Baloo::Term::Less; } return Baloo::Term::Auto; } static Baloo::Term getTerm(const Akonadi::SearchTerm &term, const QString &property) { Baloo::Term t(property, term.value().toString(), mapComparator(term.condition())); t.setNegation(term.isNegated()); return t; } Baloo::Term recursiveEmailTermMapping(const Akonadi::SearchTerm &term) { if (!term.subTerms().isEmpty()) { Baloo::Term t(mapRelation(term.relation())); Q_FOREACH (const Akonadi::SearchTerm &subterm, term.subTerms()) { const Baloo::Term newTerm = recursiveEmailTermMapping(subterm); if (newTerm.isValid()) { t.addSubTerm(newTerm); } } return t; } else { - kDebug() << term.key() << term.value(); + // kDebug() << term.key() << term.value(); const Akonadi::EmailSearchTerm::EmailSearchField field = Akonadi::EmailSearchTerm::fromKey(term.key()); switch (field) { case Akonadi::EmailSearchTerm::Message: { Baloo::Term s(Baloo::Term::Or); s.setNegation(term.isNegated()); s.addSubTerm(Baloo::Term(QLatin1String("body"), term.value(), mapComparator(term.condition()))); s.addSubTerm(Baloo::Term(QLatin1String("headers"), term.value(), mapComparator(term.condition()))); return s; } case Akonadi::EmailSearchTerm::Body: return getTerm(term, QLatin1String("body")); case Akonadi::EmailSearchTerm::Headers: return getTerm(term, QLatin1String("headers")); case Akonadi::EmailSearchTerm::ByteSize: return getTerm(term, QLatin1String("size")); case Akonadi::EmailSearchTerm::HeaderDate: { Baloo::Term s(QLatin1String("date"), QString::number(term.value().toDateTime().toTime_t()), mapComparator(term.condition())); s.setNegation(term.isNegated()); return s; } case Akonadi::EmailSearchTerm::HeaderOnlyDate: { Baloo::Term s(QLatin1String("onlydate"), QString::number(term.value().toDate().toJulianDay()), mapComparator(term.condition())); s.setNegation(term.isNegated()); return s; } case Akonadi::EmailSearchTerm::Subject: return getTerm(term, QLatin1String("subject")); case Akonadi::EmailSearchTerm::HeaderFrom: return getTerm(term, QLatin1String("from")); case Akonadi::EmailSearchTerm::HeaderTo: return getTerm(term, QLatin1String("to")); case Akonadi::EmailSearchTerm::HeaderCC: return getTerm(term, QLatin1String("cc")); case Akonadi::EmailSearchTerm::HeaderBCC: return getTerm(term, QLatin1String("bcc")); case Akonadi::EmailSearchTerm::MessageStatus: if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Flagged)) { return Baloo::Term(QLatin1String("isimportant"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::ToAct)) { return Baloo::Term(QLatin1String("istoact"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Watched)) { return Baloo::Term(QLatin1String("iswatched"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Deleted)) { return Baloo::Term(QLatin1String("isdeleted"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Spam)) { return Baloo::Term(QLatin1String("isspam"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Replied)) { return Baloo::Term(QLatin1String("isreplied"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Ignored)) { return Baloo::Term(QLatin1String("isignored"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Forwarded)) { return Baloo::Term(QLatin1String("isforwarded"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Sent)) { return Baloo::Term(QLatin1String("issent"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Queued)) { return Baloo::Term(QLatin1String("isqueued"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Ham)) { return Baloo::Term(QLatin1String("isham"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Seen)) { return Baloo::Term(QLatin1String("isread"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::HasAttachment)) { return Baloo::Term(QLatin1String("hasattachment"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::Encrypted)) { return Baloo::Term(QLatin1String("isencrypted"), !term.isNegated()); } if (term.value().toString() == QString::fromLatin1(Akonadi::MessageFlags::HasInvitation)) { return Baloo::Term(QLatin1String("hasinvitation"), !term.isNegated()); } break; case Akonadi::EmailSearchTerm::MessageTag: //search directly in akonadi? or index tags. break; case Akonadi::EmailSearchTerm::HeaderReplyTo: return getTerm(term, QLatin1String("replyto")); case Akonadi::EmailSearchTerm::HeaderOrganization: return getTerm(term, QLatin1String("organization")); case Akonadi::EmailSearchTerm::HeaderListId: return getTerm(term, QLatin1String("listid")); case Akonadi::EmailSearchTerm::HeaderResentFrom: return getTerm(term, QLatin1String("resentfrom")); case Akonadi::EmailSearchTerm::HeaderXLoop: return getTerm(term, QLatin1String("xloop")); case Akonadi::EmailSearchTerm::HeaderXMailingList: return getTerm(term, QLatin1String("xmailinglist")); case Akonadi::EmailSearchTerm::HeaderXSpamFlag: return getTerm(term, QLatin1String("xspamflag")); case Akonadi::EmailSearchTerm::Unknown: default: kWarning() << "unknown term " << term.key(); } } return Baloo::Term(); } Baloo::Term recursiveCalendarTermMapping(const Akonadi::SearchTerm &term) { if (!term.subTerms().isEmpty()) { Baloo::Term t(mapRelation(term.relation())); Q_FOREACH (const Akonadi::SearchTerm &subterm, term.subTerms()) { const Baloo::Term newTerm = recursiveCalendarTermMapping(subterm); if (newTerm.isValid()) { t.addSubTerm(newTerm); } } return t; } else { - kDebug() << term.key() << term.value(); + // kDebug() << term.key() << term.value(); const Akonadi::IncidenceSearchTerm::IncidenceSearchField field = Akonadi::IncidenceSearchTerm::fromKey(term.key()); switch (field) { case Akonadi::IncidenceSearchTerm::Organizer: return getTerm(term, QLatin1String("organizer")); case Akonadi::IncidenceSearchTerm::Summary: return getTerm(term, QLatin1String("summary")); case Akonadi::IncidenceSearchTerm::Location: return getTerm(term, QLatin1String("location")); case Akonadi::IncidenceSearchTerm::PartStatus: { Baloo::Term t(QLatin1String("partstatus"), term.value().toString(), Baloo::Term::Equal); t.setNegation(term.isNegated()); return t; } default: kWarning() << "unknown term " << term.key(); } } return Baloo::Term(); } Baloo::Term recursiveNoteTermMapping(const Akonadi::SearchTerm &term) { if (!term.subTerms().isEmpty()) { Baloo::Term t(mapRelation(term.relation())); Q_FOREACH (const Akonadi::SearchTerm &subterm, term.subTerms()) { const Baloo::Term newTerm = recursiveNoteTermMapping(subterm); if (newTerm.isValid()) { t.addSubTerm(newTerm); } } return t; } else { - kDebug() << term.key() << term.value(); + // kDebug() << term.key() << term.value(); const Akonadi::EmailSearchTerm::EmailSearchField field = Akonadi::EmailSearchTerm::fromKey(term.key()); switch (field) { case Akonadi::EmailSearchTerm::Subject: return getTerm(term, QLatin1String("subject")); case Akonadi::EmailSearchTerm::Body: return getTerm(term, QLatin1String("body")); default: kWarning() << "unknown term " << term.key(); } } return Baloo::Term(); } Baloo::Term recursiveContactTermMapping(const Akonadi::SearchTerm &term) { if (!term.subTerms().isEmpty()) { Baloo::Term t(mapRelation(term.relation())); Q_FOREACH (const Akonadi::SearchTerm &subterm, term.subTerms()) { const Baloo::Term newTerm = recursiveContactTermMapping(subterm); if (newTerm.isValid()) { t.addSubTerm(newTerm); } } return t; } else { - kDebug() << term.key() << term.value(); + // kDebug() << term.key() << term.value(); const Akonadi::ContactSearchTerm::ContactSearchField field = Akonadi::ContactSearchTerm::fromKey(term.key()); switch (field) { case Akonadi::ContactSearchTerm::Name: return getTerm(term, QLatin1String("name")); case Akonadi::ContactSearchTerm::Email: return getTerm(term, QLatin1String("email")); case Akonadi::ContactSearchTerm::Nickname: return getTerm(term, QLatin1String("nick")); case Akonadi::ContactSearchTerm::Uid: return getTerm(term, QLatin1String("uid")); case Akonadi::ContactSearchTerm::Unknown: default: kWarning() << "unknown term " << term.key(); } } return Baloo::Term(); } QSet SearchPlugin::search(const QString &akonadiQuery, const QList &collections, const QStringList &mimeTypes) { const Akonadi::SearchQuery searchQuery = Akonadi::SearchQuery::fromJSON(akonadiQuery.toLatin1()); if (searchQuery.isNull()) { kWarning() << "invalid query " << akonadiQuery; return QSet(); } const Akonadi::SearchTerm term = searchQuery.term(); Baloo::Query query; if (term.subTerms().isEmpty()) { kWarning() << "empty query"; return QSet(); } Baloo::Term t; if (mimeTypes.contains(QLatin1String("message/rfc822"))) { - kDebug() << "mail query"; + // kDebug() << "mail query"; query.setType(QLatin1String("Email")); t = recursiveEmailTermMapping(term); } else if (mimeTypes.contains(KABC::Addressee::mimeType()) || mimeTypes.contains(KABC::ContactGroup::mimeType())) { query.setType(QLatin1String("Contact")); t = recursiveContactTermMapping(term); } else if (mimeTypes.contains(QLatin1String("text/x-vnd.akonadi.note"))) { query.setType(QLatin1String("Note")); t = recursiveNoteTermMapping(term); } else if (mimeTypes.contains(QLatin1String("application/x-vnd.akonadi.calendar.event")) || mimeTypes.contains(QLatin1String("application/x-vnd.akonadi.calendar.todo")) || mimeTypes.contains(QLatin1String("application/x-vnd.akonadi.calendar.journal")) || mimeTypes.contains(QLatin1String("application/x-vnd.akonadi.calendar.freebusy"))) { query.setType(QLatin1String("Calendar")); t = recursiveCalendarTermMapping(term); } if (t.subTerms().isEmpty()) { kWarning() << "no terms added"; return QSet(); } if (searchQuery.limit() > 0) { query.setLimit(searchQuery.limit()); } //Filter by collection if not empty if (!collections.isEmpty()) { Baloo::Term parentTerm(Baloo::Term::And); Baloo::Term collectionTerm(Baloo::Term::Or); Q_FOREACH (const qint64 col, collections) { collectionTerm.addSubTerm(Baloo::Term(QLatin1String("collection"), QString::number(col), Baloo::Term::Equal)); } parentTerm.addSubTerm(collectionTerm); parentTerm.addSubTerm(t); query.setTerm(parentTerm); } else { query.setTerm(t); } QSet resultSet; - kDebug() << query.toJSON(); + // kDebug() << query.toJSON(); Baloo::ResultIterator iter = query.exec(); while (iter.next()) { const QByteArray id = iter.id(); const int fid = Baloo::deserialize("akonadi", id); resultSet << fid; } kDebug() << "Got" << resultSet.count() << "results"; return resultSet; } Q_EXPORT_PLUGIN2(akonadi_baloo_searchplugin, SearchPlugin) diff --git a/src/xapian/xapiandatabase.cpp b/src/xapian/xapiandatabase.cpp index 123285b7..ec04b913 100644 --- a/src/xapian/xapiandatabase.cpp +++ b/src/xapian/xapiandatabase.cpp @@ -1,209 +1,210 @@ /* * Copyright (C) 2014 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include "xapiandatabase.h" #include "xapiandocument.h" #include #include #include #if defined(HAVE_MALLOC_H) #include -#include #else #include #endif +#include + using namespace Baloo; XapianDatabase::XapianDatabase(const QString& path, bool writeOnly) : m_db(0) , m_writeOnly(writeOnly) { QDir().mkpath(path); m_path = path.toUtf8().constData(); if (!writeOnly) { try { createWritableDb(); m_db = new Xapian::Database(m_path); } catch (const Xapian::DatabaseError& err) { kError() << "Serious Error: " << err.get_error_string(); kError() << err.get_msg().c_str() << err.get_context().c_str() << err.get_description().c_str(); } // Possible errors - DatabaseLock error // Corrupt and InvalidID error } else { m_wDb = createWritableDb(); } } XapianDatabase::~XapianDatabase() { delete m_db; } void XapianDatabase::replaceDocument(uint id, const XapianDocument& doc) { replaceDocument(id, doc.doc()); } void XapianDatabase::replaceDocument(uint id, const Xapian::Document& doc) { if (m_writeOnly) { try { m_wDb.replace_document(id, doc); } catch (const Xapian::Error&) { } return; } m_docsToAdd << qMakePair(id, doc); } void XapianDatabase::deleteDocument(uint id) { if (m_writeOnly) { try { m_wDb.delete_document(id); } catch (const Xapian::Error&) { } return; } m_docsToRemove << id; } void XapianDatabase::commit() { if (m_writeOnly) { try { m_wDb.commit(); } catch (const Xapian::Error& err) { kError() << err.get_error_string(); } return; } if (m_docsToAdd.isEmpty() && m_docsToRemove.isEmpty()) { return; } Xapian::WritableDatabase wdb = createWritableDb(); kDebug() << "Adding:" << m_docsToAdd.size() << "docs"; Q_FOREACH (const DocIdPair& doc, m_docsToAdd) { try { wdb.replace_document(doc.first, doc.second); } catch (const Xapian::Error&) { } } kDebug() << "Removing:" << m_docsToRemove.size() << "docs"; Q_FOREACH (Xapian::docid id, m_docsToRemove) { try { wdb.delete_document(id); } catch (const Xapian::Error&) { } } try { wdb.commit(); m_db->reopen(); } catch (const Xapian::Error& err) { kError() << err.get_error_string(); } kDebug() << "Xapian Committed"; m_docsToAdd.clear(); m_docsToRemove.clear(); #if defined(HAVE_MALLOC_TRIM) malloc_trim(0); #endif } XapianDocument XapianDatabase::document(uint id) { try { Xapian::Document xdoc; if (m_writeOnly) { xdoc = m_wDb.get_document(id); } else { xdoc = m_db->get_document(id); } return XapianDocument(xdoc); } catch (const Xapian::DatabaseModifiedError&) { m_db->reopen(); return document(id); } catch (const Xapian::Error&) { return XapianDocument(); } } Xapian::WritableDatabase XapianDatabase::createWritableDb() { // We need to keep sleeping for a required amount, until we reach // a threshold. That's when we decide to abort? for (int i = 1; i <= 20; ++i) { try { Xapian::WritableDatabase wdb(m_path, Xapian::DB_CREATE_OR_OPEN); return wdb; } catch (const Xapian::DatabaseLockError&) { - usleep(i * 50 * 1000); + sleep(i * 50 ); } catch (const Xapian::DatabaseModifiedError&) { - usleep(i * 50 * 1000); + sleep(i * 50 ); } catch (const Xapian::DatabaseCreateError& err) { kDebug() << err.get_error_string(); return Xapian::WritableDatabase(); } catch (const Xapian::DatabaseCorruptError& err) { kError() << "Database Corrupted - What did you do?"; kError() << err.get_error_string(); return Xapian::WritableDatabase(); } catch (const std::exception& err) { kError() << "Unknown exception: " << err.what(); return Xapian::WritableDatabase(); } catch (...) { kError() << "Bananana Error"; return Xapian::WritableDatabase(); } } kError() << "Could not obtain lock for Xapian Database. This is bad"; return Xapian::WritableDatabase(); }