Akonadi Search

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

KDE's Doxygen guidelines are available online.