~ubuntu-branches/debian/sid/baloo-kf5/sid

« back to all changes in this revision

Viewing changes to src/pim/lib/emailquery.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2014-07-10 21:13:07 UTC
  • Revision ID: package-import@ubuntu.com-20140710211307-iku0qs6vlplgn06m
Tags: upstream-5.0.0b
ImportĀ upstreamĀ versionĀ 5.0.0b

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of the KDE Baloo Project
 
3
 * Copyright (C) 2013  Vishesh Handa <me@vhanda.in>
 
4
 *
 
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.
 
12
 *
 
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.
 
17
 *
 
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/>.
 
20
 *
 
21
 */
 
22
 
 
23
#include "emailquery.h"
 
24
#include "resultiterator_p.h"
 
25
#include "xapian.h"
 
26
#include "../search/email/agepostingsource.h"
 
27
 
 
28
#include <QStandardPaths>
 
29
 
 
30
#include <QFile>
 
31
 
 
32
using namespace Baloo::PIM;
 
33
 
 
34
class EmailQuery::Private
 
35
{
 
36
  public:
 
37
    Private();
 
38
 
 
39
    QStringList involves;
 
40
    QStringList to;
 
41
    QStringList cc;
 
42
    QStringList bcc;
 
43
    QString from;
 
44
 
 
45
    QList<Akonadi::Collection::Id> collections;
 
46
 
 
47
    char important;
 
48
    char read;
 
49
    char attachment;
 
50
 
 
51
    QString matchString;
 
52
    QString subjectMatchString;
 
53
    QString bodyMatchString;
 
54
 
 
55
    EmailQuery::OpType opType;
 
56
    int limit;
 
57
};
 
58
 
 
59
EmailQuery::Private::Private():
 
60
    important('0'),
 
61
    read('0'),
 
62
    attachment('0'),
 
63
    opType(OpAnd),
 
64
    limit(0)
 
65
{
 
66
}
 
67
 
 
68
EmailQuery::EmailQuery():
 
69
    Query(),
 
70
    d(new Private)
 
71
{
 
72
}
 
73
 
 
74
EmailQuery::~EmailQuery()
 
75
{
 
76
    delete d;
 
77
}
 
78
 
 
79
void EmailQuery::setSearchType(EmailQuery::OpType op)
 
80
{
 
81
    d->opType = op;
 
82
}
 
83
 
 
84
void EmailQuery::addInvolves(const QString& email)
 
85
{
 
86
    d->involves << email;
 
87
}
 
88
 
 
89
void EmailQuery::setInvolves(const QStringList& involves)
 
90
{
 
91
    d->involves = involves;
 
92
}
 
93
 
 
94
void EmailQuery::addBcc(const QString& bcc)
 
95
{
 
96
    d->bcc << bcc;
 
97
}
 
98
 
 
99
void EmailQuery::setBcc(const QStringList& bcc)
 
100
{
 
101
    d->bcc = bcc;
 
102
}
 
103
 
 
104
void EmailQuery::setCc(const QStringList& cc)
 
105
{
 
106
    d->cc = cc;
 
107
}
 
108
 
 
109
void EmailQuery::setFrom(const QString& from)
 
110
{
 
111
    d->from = from;
 
112
}
 
113
 
 
114
void EmailQuery::addTo(const QString& to)
 
115
{
 
116
    d->to << to;
 
117
}
 
118
 
 
119
void EmailQuery::setTo(const QStringList& to)
 
120
{
 
121
    d->to = to;
 
122
}
 
123
 
 
124
void EmailQuery::addCc(const QString& cc)
 
125
{
 
126
    d->cc << cc;
 
127
}
 
128
 
 
129
void EmailQuery::addFrom(const QString& from)
 
130
{
 
131
    d->from = from;
 
132
}
 
133
 
 
134
void EmailQuery::addCollection(Akonadi::Collection::Id id)
 
135
{
 
136
    d->collections << id;
 
137
}
 
138
 
 
139
void EmailQuery::setCollection(const QList< Akonadi::Entity::Id >& collections)
 
140
{
 
141
    d->collections = collections;
 
142
}
 
143
 
 
144
int EmailQuery::limit() const
 
145
{
 
146
    return d->limit;
 
147
}
 
148
 
 
149
void EmailQuery::setLimit(int limit)
 
150
{
 
151
    d->limit = limit;
 
152
}
 
153
 
 
154
void EmailQuery::matches(const QString& match)
 
155
{
 
156
    d->matchString = match;
 
157
}
 
158
 
 
159
void EmailQuery::subjectMatches(const QString& subjectMatch)
 
160
{
 
161
    d->subjectMatchString = subjectMatch;
 
162
}
 
163
 
 
164
void EmailQuery::bodyMatches(const QString &bodyMatch)
 
165
{
 
166
    d->bodyMatchString =  bodyMatch;
 
167
}
 
168
 
 
169
void EmailQuery::setAttachment(bool hasAttachment)
 
170
{
 
171
    d->attachment = hasAttachment ? 'T' : 'F';
 
172
}
 
173
 
 
174
void EmailQuery::setImportant(bool important)
 
175
{
 
176
    d->important = important ? 'T' : 'F';
 
177
}
 
178
 
 
179
void EmailQuery::setRead(bool read)
 
180
{
 
181
    d->read = read ? 'T' : 'F';
 
182
}
 
183
 
 
184
ResultIterator EmailQuery::exec()
 
185
{
 
186
    const QString dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/baloo/email/");
 
187
    Xapian::Database db;
 
188
    try {
 
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();
 
199
    } catch (...) {
 
200
        qWarning() << "Random exception, but we do not want to crash";
 
201
        return ResultIterator();
 
202
    }
 
203
 
 
204
    QList<Xapian::Query> m_queries;
 
205
 
 
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");
 
213
 
 
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);
 
218
        }
 
219
    }
 
220
 
 
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);
 
227
    }
 
228
 
 
229
    if (!d->to.isEmpty()) {
 
230
        Xapian::QueryParser parser;
 
231
        parser.set_database(db);
 
232
        parser.add_prefix("", "T");
 
233
 
 
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);
 
237
        }
 
238
    }
 
239
 
 
240
    if (!d->cc.isEmpty()) {
 
241
        Xapian::QueryParser parser;
 
242
        parser.set_database(db);
 
243
        parser.add_prefix("", "CC");
 
244
 
 
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);
 
248
        }
 
249
    }
 
250
 
 
251
    if (!d->bcc.isEmpty()) {
 
252
        Xapian::QueryParser parser;
 
253
        parser.set_database(db);
 
254
        parser.add_prefix("", "BC");
 
255
 
 
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);
 
259
        }
 
260
    }
 
261
 
 
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);
 
270
    }
 
271
 
 
272
    if (!d->collections.isEmpty()) {
 
273
        Xapian::Query query;
 
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());
 
277
 
 
278
            query = Xapian::Query(Xapian::Query::OP_OR, query, q);
 
279
        }
 
280
 
 
281
        m_queries << query;
 
282
    }
 
283
 
 
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);
 
291
    }
 
292
 
 
293
    if (d->important == 'T')
 
294
        m_queries << Xapian::Query("BI");
 
295
    else if (d->important == 'F')
 
296
        m_queries << Xapian::Query("BNI");
 
297
 
 
298
    if (d->read == 'T')
 
299
        m_queries << Xapian::Query("BR");
 
300
    else if (d->read == 'F')
 
301
        m_queries << Xapian::Query("BNR");
 
302
 
 
303
    if (d->attachment == 'T')
 
304
        m_queries << Xapian::Query("BA");
 
305
    else if (d->attachment == 'F')
 
306
        m_queries << Xapian::Query("BNA");
 
307
 
 
308
    if (!d->matchString.isEmpty()) {
 
309
        Xapian::QueryParser parser;
 
310
        parser.set_database(db);
 
311
        parser.set_default_op(Xapian::Query::OP_AND);
 
312
 
 
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);
 
318
        }
 
319
    }
 
320
    Xapian::Query query;
 
321
    switch(d->opType) {
 
322
    case OpAnd:
 
323
        query = Xapian::Query(Xapian::Query::OP_AND, m_queries.begin(), m_queries.end());
 
324
        break;
 
325
    case OpOr:
 
326
        query = Xapian::Query(Xapian::Query::OP_OR, m_queries.begin(), m_queries.end());
 
327
        break;
 
328
    }
 
329
 
 
330
    AgePostingSource ps(0);
 
331
    query = Xapian::Query(Xapian::Query::OP_AND_MAYBE, query, Xapian::Query(&ps));
 
332
 
 
333
    try {
 
334
        Xapian::Enquire enquire(db);
 
335
        enquire.set_query(query);
 
336
 
 
337
        if (d->limit == 0)
 
338
            d->limit = 1000000;
 
339
 
 
340
        Xapian::MSet mset = enquire.get_mset(0, d->limit);
 
341
 
 
342
        ResultIterator iter;
 
343
        iter.d->init(mset);
 
344
        return iter;
 
345
    }
 
346
    catch (const Xapian::Error &e) {
 
347
        qWarning() << QString::fromStdString(e.get_type()) << QString::fromStdString(e.get_description());
 
348
        return ResultIterator();
 
349
    }
 
350
}