File indexing completed on 2024-05-19 05:11:52
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 <xapian.h> 0010 0011 #include "akonadi_search_pim_debug.h" 0012 #include "contactquery.h" 0013 #include "resultiterator_p.h" 0014 0015 #include <QFile> 0016 #include <QList> 0017 #include <QStandardPaths> 0018 0019 using namespace Akonadi::Search::PIM; 0020 0021 class Akonadi::Search::PIM::ContactQueryPrivate 0022 { 0023 public: 0024 QString name; 0025 QString nick; 0026 QString email; 0027 QString uid; 0028 QString any; 0029 0030 int limit; 0031 ContactQuery::MatchCriteria criteria; 0032 }; 0033 0034 ContactQuery::ContactQuery() 0035 : Query() 0036 , d(new ContactQueryPrivate) 0037 { 0038 d->criteria = StartsWithMatch; 0039 } 0040 0041 ContactQuery::~ContactQuery() = default; 0042 0043 void ContactQuery::matchName(const QString &name) 0044 { 0045 d->name = name; 0046 } 0047 0048 void ContactQuery::matchNickname(const QString &nick) 0049 { 0050 d->nick = nick; 0051 } 0052 0053 void ContactQuery::matchEmail(const QString &email) 0054 { 0055 d->email = email; 0056 } 0057 0058 void ContactQuery::matchUID(const QString &uid) 0059 { 0060 d->uid = uid; 0061 } 0062 0063 void ContactQuery::match(const QString &str) 0064 { 0065 d->any = str; 0066 } 0067 0068 int ContactQuery::limit() const 0069 { 0070 return d->limit; 0071 } 0072 0073 void ContactQuery::setLimit(int limit) 0074 { 0075 d->limit = limit; 0076 } 0077 0078 ContactQuery::MatchCriteria ContactQuery::matchCriteria() const 0079 { 0080 return d->criteria; 0081 } 0082 0083 void ContactQuery::setMatchCriteria(ContactQuery::MatchCriteria m) 0084 { 0085 d->criteria = m; 0086 } 0087 0088 ResultIterator ContactQuery::exec() 0089 { 0090 const QString dir = defaultLocation(QStringLiteral("contacts")); 0091 Xapian::Database db; 0092 0093 try { 0094 db = Xapian::Database(QFile::encodeName(dir).toStdString()); 0095 } catch (const Xapian::DatabaseOpeningError &) { 0096 qCWarning(AKONADI_SEARCH_PIM_LOG) << "Xapian Database does not exist at " << dir; 0097 return {}; 0098 } catch (const Xapian::DatabaseCorruptError &) { 0099 qCWarning(AKONADI_SEARCH_PIM_LOG) << "Xapian Database corrupted"; 0100 return {}; 0101 } catch (const Xapian::DatabaseError &e) { 0102 qCWarning(AKONADI_SEARCH_PIM_LOG) << "Failed to open Xapian database:" << QString::fromStdString(e.get_error_string()); 0103 return {}; 0104 } catch (...) { 0105 qCWarning(AKONADI_SEARCH_PIM_LOG) << "Random exception, but we do not want to crash"; 0106 return {}; 0107 } 0108 0109 QList<Xapian::Query> m_queries; 0110 0111 if (d->criteria == ExactMatch) { 0112 if (!d->any.isEmpty()) { 0113 const QByteArray ba = d->any.toUtf8(); 0114 m_queries << Xapian::Query(ba.constData()); 0115 } 0116 0117 if (!d->name.isEmpty()) { 0118 const QByteArray ba = "NA" + d->name.toUtf8(); 0119 m_queries << Xapian::Query(ba.constData()); 0120 } 0121 0122 if (!d->nick.isEmpty()) { 0123 const QByteArray ba = "NI" + d->nick.toUtf8(); 0124 m_queries << Xapian::Query(ba.constData()); 0125 } 0126 0127 if (!d->email.isEmpty()) { 0128 const QByteArray ba = d->email.toUtf8(); 0129 m_queries << Xapian::Query(ba.constData()); 0130 } 0131 0132 if (!d->uid.isEmpty()) { 0133 const QByteArray ba = "UID" + d->uid.toUtf8(); 0134 m_queries << Xapian::Query(ba.constData()); 0135 } 0136 } else if (d->criteria == StartsWithMatch) { 0137 if (!d->any.isEmpty()) { 0138 Xapian::QueryParser parser; 0139 parser.set_database(db); 0140 const QByteArray ba = d->any.toUtf8(); 0141 m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL); 0142 } 0143 0144 if (!d->name.isEmpty()) { 0145 Xapian::QueryParser parser; 0146 parser.set_database(db); 0147 parser.add_prefix("", "NA"); 0148 const QByteArray ba = d->name.toUtf8(); 0149 m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL); 0150 } 0151 0152 if (!d->nick.isEmpty()) { 0153 Xapian::QueryParser parser; 0154 parser.set_database(db); 0155 parser.add_prefix("", "NI"); 0156 const QByteArray ba = d->nick.toUtf8(); 0157 m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL); 0158 } 0159 0160 // FIXME: Check for exact match? 0161 if (!d->email.isEmpty()) { 0162 Xapian::QueryParser parser; 0163 parser.set_database(db); 0164 const QByteArray ba = d->email.toUtf8(); 0165 m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL); 0166 } 0167 0168 if (!d->uid.isEmpty()) { 0169 Xapian::QueryParser parser; 0170 parser.set_database(db); 0171 parser.add_prefix("", "UID"); 0172 const QByteArray ba = d->uid.toUtf8(); 0173 m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL); 0174 } 0175 } 0176 try { 0177 Xapian::Query query(Xapian::Query::OP_OR, m_queries.begin(), m_queries.end()); 0178 qCDebug(AKONADI_SEARCH_PIM_LOG) << query.get_description().c_str(); 0179 0180 Xapian::Enquire enquire(db); 0181 enquire.set_query(query); 0182 0183 if (d->limit == 0) { 0184 d->limit = 10000; 0185 } 0186 0187 Xapian::MSet matches = enquire.get_mset(0, d->limit); 0188 0189 ResultIterator iter; 0190 iter.d->init(matches); 0191 return iter; 0192 } catch (const Xapian::Error &e) { 0193 qCWarning(AKONADI_SEARCH_PIM_LOG) << QString::fromStdString(e.get_type()) << QString::fromStdString(e.get_description()); 0194 return {}; 0195 } 0196 }