2
* This file is part of the KDE Baloo Project
3
* Copyright (C) 2013 Vishesh Handa <me@vhanda.in>
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) version 3, or any
9
* later version accepted by the membership of KDE e.V. (or its
10
* successor approved by the membership of KDE e.V.), which shall
11
* act as a proxy defined in Section 6 of version 3 of the license.
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
23
#include "emailquery.h"
24
#include "resultiterator_p.h"
26
#include "../search/email/agepostingsource.h"
28
#include <QStandardPaths>
32
using namespace Baloo::PIM;
34
class EmailQuery::Private
45
QList<Akonadi::Collection::Id> collections;
52
QString subjectMatchString;
53
QString bodyMatchString;
55
EmailQuery::OpType opType;
59
EmailQuery::Private::Private():
68
EmailQuery::EmailQuery():
74
EmailQuery::~EmailQuery()
79
void EmailQuery::setSearchType(EmailQuery::OpType op)
84
void EmailQuery::addInvolves(const QString& email)
89
void EmailQuery::setInvolves(const QStringList& involves)
91
d->involves = involves;
94
void EmailQuery::addBcc(const QString& bcc)
99
void EmailQuery::setBcc(const QStringList& bcc)
104
void EmailQuery::setCc(const QStringList& cc)
109
void EmailQuery::setFrom(const QString& from)
114
void EmailQuery::addTo(const QString& to)
119
void EmailQuery::setTo(const QStringList& to)
124
void EmailQuery::addCc(const QString& cc)
129
void EmailQuery::addFrom(const QString& from)
134
void EmailQuery::addCollection(Akonadi::Collection::Id id)
136
d->collections << id;
139
void EmailQuery::setCollection(const QList< Akonadi::Entity::Id >& collections)
141
d->collections = collections;
144
int EmailQuery::limit() const
149
void EmailQuery::setLimit(int limit)
154
void EmailQuery::matches(const QString& match)
156
d->matchString = match;
159
void EmailQuery::subjectMatches(const QString& subjectMatch)
161
d->subjectMatchString = subjectMatch;
164
void EmailQuery::bodyMatches(const QString &bodyMatch)
166
d->bodyMatchString = bodyMatch;
169
void EmailQuery::setAttachment(bool hasAttachment)
171
d->attachment = hasAttachment ? 'T' : 'F';
174
void EmailQuery::setImportant(bool important)
176
d->important = important ? 'T' : 'F';
179
void EmailQuery::setRead(bool read)
181
d->read = read ? 'T' : 'F';
184
ResultIterator EmailQuery::exec()
186
const QString dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/baloo/email/");
189
db = Xapian::Database(QFile::encodeName(dir).constData());
190
} catch (const Xapian::DatabaseOpeningError&) {
191
qWarning() << "Xapian Database does not exist at " << dir;
192
return ResultIterator();
193
} catch (const Xapian::DatabaseCorruptError&) {
194
qWarning() << "Xapian Database corrupted";
195
return ResultIterator();
196
} catch (const Xapian::DatabaseError& e) {
197
qWarning() << "Failed to open Xapian database:" << QString::fromStdString(e.get_error_string());
198
return ResultIterator();
200
qWarning() << "Random exception, but we do not want to crash";
201
return ResultIterator();
204
QList<Xapian::Query> m_queries;
206
if (!d->involves.isEmpty()) {
207
Xapian::QueryParser parser;
208
parser.set_database(db);
209
parser.add_prefix("", "F");
210
parser.add_prefix("", "T");
211
parser.add_prefix("", "CC");
212
parser.add_prefix("", "BCC");
214
// vHanda: Do we really need the query parser over here?
215
Q_FOREACH (const QString& str, d->involves) {
216
const QByteArray ba = str.toUtf8();
217
m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL);
221
if (!d->from.isEmpty()) {
222
Xapian::QueryParser parser;
223
parser.set_database(db);
224
parser.add_prefix("", "F");
225
const QByteArray ba = d->from.toUtf8();
226
m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL);
229
if (!d->to.isEmpty()) {
230
Xapian::QueryParser parser;
231
parser.set_database(db);
232
parser.add_prefix("", "T");
234
Q_FOREACH (const QString& str, d->to) {
235
const QByteArray ba = str.toUtf8();
236
m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL);
240
if (!d->cc.isEmpty()) {
241
Xapian::QueryParser parser;
242
parser.set_database(db);
243
parser.add_prefix("", "CC");
245
Q_FOREACH (const QString& str, d->cc) {
246
const QByteArray ba = str.toUtf8();
247
m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL);
251
if (!d->bcc.isEmpty()) {
252
Xapian::QueryParser parser;
253
parser.set_database(db);
254
parser.add_prefix("", "BC");
256
Q_FOREACH (const QString& str, d->bcc) {
257
const QByteArray ba = str.toUtf8();
258
m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL);
262
if (!d->subjectMatchString.isEmpty()) {
263
Xapian::QueryParser parser;
264
parser.set_database(db);
265
parser.add_prefix("", "SU");
266
parser.set_default_op(Xapian::Query::OP_AND);
267
const QByteArray ba = d->subjectMatchString.toUtf8();
268
m_queries << parser.parse_query(ba.constData(),
269
Xapian::QueryParser::FLAG_PARTIAL);
272
if (!d->collections.isEmpty()) {
274
Q_FOREACH (const Akonadi::Collection::Id& id, d->collections) {
275
QString c = QString::number(id);
276
Xapian::Query q = Xapian::Query('C' + c.toStdString());
278
query = Xapian::Query(Xapian::Query::OP_OR, query, q);
284
if (!d->bodyMatchString.isEmpty()) {
285
Xapian::QueryParser parser;
286
parser.set_database(db);
287
parser.add_prefix("", "BO");
288
parser.set_default_op(Xapian::Query::OP_AND);
289
const QByteArray ba = d->bodyMatchString.toUtf8();
290
m_queries << parser.parse_query(ba.constData(), Xapian::QueryParser::FLAG_PARTIAL);
293
if (d->important == 'T')
294
m_queries << Xapian::Query("BI");
295
else if (d->important == 'F')
296
m_queries << Xapian::Query("BNI");
299
m_queries << Xapian::Query("BR");
300
else if (d->read == 'F')
301
m_queries << Xapian::Query("BNR");
303
if (d->attachment == 'T')
304
m_queries << Xapian::Query("BA");
305
else if (d->attachment == 'F')
306
m_queries << Xapian::Query("BNA");
308
if (!d->matchString.isEmpty()) {
309
Xapian::QueryParser parser;
310
parser.set_database(db);
311
parser.set_default_op(Xapian::Query::OP_AND);
313
const QStringList list = d->matchString.split(QRegExp(QLatin1String("\\s")), QString::SkipEmptyParts);
314
Q_FOREACH (const QString& s, list) {
315
const QByteArray ba = s.toUtf8();
316
m_queries << parser.parse_query(ba.constData(),
317
Xapian::QueryParser::FLAG_PARTIAL);
323
query = Xapian::Query(Xapian::Query::OP_AND, m_queries.begin(), m_queries.end());
326
query = Xapian::Query(Xapian::Query::OP_OR, m_queries.begin(), m_queries.end());
330
AgePostingSource ps(0);
331
query = Xapian::Query(Xapian::Query::OP_AND_MAYBE, query, Xapian::Query(&ps));
334
Xapian::Enquire enquire(db);
335
enquire.set_query(query);
340
Xapian::MSet mset = enquire.get_mset(0, d->limit);
346
catch (const Xapian::Error &e) {
347
qWarning() << QString::fromStdString(e.get_type()) << QString::fromStdString(e.get_description());
348
return ResultIterator();