Akonadi Search

contactquery.cpp
1/*
2 * This file is part of the KDE Akonadi Search Project
3 * SPDX-FileCopyrightText: 2013 Vishesh Handa <me@vhanda.in>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 *
7 */
8
9#include <xapian.h>
10
11#include "akonadi_search_pim_debug.h"
12#include "contactquery.h"
13#include "resultiterator_p.h"
14
15#include <QFile>
16#include <QList>
17#include <QStandardPaths>
18
19using namespace Akonadi::Search::PIM;
20
21class Akonadi::Search::PIM::ContactQueryPrivate
22{
23public:
24 QString name;
25 QString nick;
26 QString email;
27 QString uid;
28 QString any;
29
30 int limit;
31 ContactQuery::MatchCriteria criteria;
32};
33
34ContactQuery::ContactQuery()
35 : d(new ContactQueryPrivate)
36{
37 d->criteria = StartsWithMatch;
38}
39
40ContactQuery::~ContactQuery() = default;
41
42void ContactQuery::matchName(const QString &name)
43{
44 d->name = name;
45}
46
47void ContactQuery::matchNickname(const QString &nick)
48{
49 d->nick = nick;
50}
51
52void ContactQuery::matchEmail(const QString &email)
53{
54 d->email = email;
55}
56
57void ContactQuery::matchUID(const QString &uid)
58{
59 d->uid = uid;
60}
61
62void ContactQuery::match(const QString &str)
63{
64 d->any = str;
65}
66
67int ContactQuery::limit() const
68{
69 return d->limit;
70}
71
72void ContactQuery::setLimit(int limit)
73{
74 d->limit = limit;
75}
76
77ContactQuery::MatchCriteria ContactQuery::matchCriteria() const
78{
79 return d->criteria;
80}
81
82void ContactQuery::setMatchCriteria(ContactQuery::MatchCriteria m)
83{
84 d->criteria = m;
85}
86
87ResultIterator ContactQuery::exec()
88{
89 const QString dir = defaultLocation(QStringLiteral("contacts"));
90 Xapian::Database db;
91
92 try {
93 db = Xapian::Database(QFile::encodeName(dir).toStdString());
94 } catch (const Xapian::DatabaseOpeningError &) {
95 qCWarning(AKONADI_SEARCH_PIM_LOG) << "Xapian Database does not exist at " << dir;
96 return {};
97 } catch (const Xapian::DatabaseCorruptError &) {
98 qCWarning(AKONADI_SEARCH_PIM_LOG) << "Xapian Database corrupted";
99 return {};
100 } catch (const Xapian::DatabaseError &e) {
101 qCWarning(AKONADI_SEARCH_PIM_LOG) << "Failed to open Xapian database:" << QString::fromStdString(e.get_error_string());
102 return {};
103 } catch (...) {
104 qCWarning(AKONADI_SEARCH_PIM_LOG) << "Random exception, but we do not want to crash";
105 return {};
106 }
107
108 QList<Xapian::Query> m_queries;
109
110 if (d->criteria == ExactMatch) {
111 if (!d->any.isEmpty()) {
112 const QByteArray ba = d->any.toUtf8();
113 m_queries << Xapian::Query(ba.constData());
114 }
115
116 if (!d->name.isEmpty()) {
117 const QByteArray ba = "NA" + d->name.toUtf8();
118 m_queries << Xapian::Query(ba.constData());
119 }
120
121 if (!d->nick.isEmpty()) {
122 const QByteArray ba = "NI" + d->nick.toUtf8();
123 m_queries << Xapian::Query(ba.constData());
124 }
125
126 if (!d->email.isEmpty()) {
127 const QByteArray ba = d->email.toUtf8();
128 m_queries << Xapian::Query(ba.constData());
129 }
130
131 if (!d->uid.isEmpty()) {
132 const QByteArray ba = "UID" + d->uid.toUtf8();
133 m_queries << Xapian::Query(ba.constData());
134 }
135 } else if (d->criteria == StartsWithMatch) {
136 if (!d->any.isEmpty()) {
137 Xapian::QueryParser parser;
138 parser.set_database(db);
139 const QByteArray ba = d->any.toUtf8();
140 m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL);
141 }
142
143 if (!d->name.isEmpty()) {
144 Xapian::QueryParser parser;
145 parser.set_database(db);
146 parser.add_prefix("", "NA");
147 const QByteArray ba = d->name.toUtf8();
148 m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL);
149 }
150
151 if (!d->nick.isEmpty()) {
152 Xapian::QueryParser parser;
153 parser.set_database(db);
154 parser.add_prefix("", "NI");
155 const QByteArray ba = d->nick.toUtf8();
156 m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL);
157 }
158
159 // FIXME: Check for exact match?
160 if (!d->email.isEmpty()) {
161 Xapian::QueryParser parser;
162 parser.set_database(db);
163 const QByteArray ba = d->email.toUtf8();
164 m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL);
165 }
166
167 if (!d->uid.isEmpty()) {
168 Xapian::QueryParser parser;
169 parser.set_database(db);
170 parser.add_prefix("", "UID");
171 const QByteArray ba = d->uid.toUtf8();
172 m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL);
173 }
174 }
175 try {
176 Xapian::Query query(Xapian::Query::OP_OR, m_queries.begin(), m_queries.end());
177 qCDebug(AKONADI_SEARCH_PIM_LOG) << query.get_description().c_str();
178
179 Xapian::Enquire enquire(db);
180 enquire.set_query(query);
181
182 if (d->limit == 0) {
183 d->limit = 10000;
184 }
185
186 Xapian::MSet matches = enquire.get_mset(0, d->limit);
187
188 ResultIterator iter;
189 iter.d->init(matches);
190 return iter;
191 } catch (const Xapian::Error &e) {
192 qCWarning(AKONADI_SEARCH_PIM_LOG) << QString::fromStdString(e.get_type()) << QString::fromStdString(e.get_description());
193 return {};
194 }
195}
PIM specific search API.
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
KIOCORE_EXPORT QString dir(const QString &fileClass)
QString name(StandardAction id)
const char * constData() const const
QByteArray encodeName(const QString &fileName)
iterator begin()
iterator end()
QString fromStdString(const std::string &str)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri May 2 2025 11:55:57 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.