Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117754321
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
12 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/pim/agent/emailindexer.cpp b/src/pim/agent/emailindexer.cpp
index cbb63da4..83a4f958 100644
--- a/src/pim/agent/emailindexer.cpp
+++ b/src/pim/agent/emailindexer.cpp
@@ -1,386 +1,386 @@
/*
* This file is part of the KDE Baloo Project
* Copyright (C) 2013 Vishesh Handa <me@vhanda.in>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3, or any
* later version accepted by the membership of KDE e.V. (or its
* successor approved by the membership of KDE e.V.), which shall
* act as a proxy defined in Section 6 of version 3 of the license.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "emailindexer.h"
#include <Collection>
#include <Akonadi/KMime/MessageFlags>
#include <QTextDocument>
-#include <KPIMUtils/email.h>
+#include <kpimutils/email.h>
EmailIndexer::EmailIndexer(const QString& path, const QString& contactDbPath):
AbstractIndexer(), m_doc( 0 ), m_termGen( 0 )
{
m_db = new Xapian::WritableDatabase(path.toUtf8().constData(), Xapian::DB_CREATE_OR_OPEN);
m_contactDb = new Xapian::WritableDatabase(contactDbPath.toUtf8().constData(), Xapian::DB_CREATE_OR_OPEN);
}
EmailIndexer::~EmailIndexer()
{
m_db->commit();
delete m_db;
m_contactDb->commit();
delete m_contactDb;
}
QStringList EmailIndexer::mimeTypes() const
{
return QStringList() << KMime::Message::mimeType();
}
void EmailIndexer::index(const Akonadi::Item& item)
{
Akonadi::MessageStatus status;
status.setStatusFromFlags(item.flags());
if (status.isSpam())
return;
KMime::Message::Ptr msg;
try {
msg = item.payload<KMime::Message::Ptr>();
} catch (const Akonadi::PayloadException&) {
return;
}
m_doc = new Xapian::Document();
m_termGen = new Xapian::TermGenerator();
m_termGen->set_document(*m_doc);
m_termGen->set_database(*m_db);
processMessageStatus(status);
process(msg);
// Size
m_doc->add_value(1, QString::number(item.size()).toStdString());
// Parent collection
Q_ASSERT_X(item.parentCollection().isValid(), "Baloo::EmailIndexer::index",
"Item does not have a valid parent collection");
Akonadi::Entity::Id colId = item.parentCollection().id();
QByteArray term = 'C' + QByteArray::number(colId);
m_doc->add_boolean_term(term.data());
m_db->replace_document(item.id(), *m_doc);
delete m_doc;
delete m_termGen;
m_doc = 0;
m_termGen = 0;
}
void EmailIndexer::insert(const QByteArray& key, KMime::Headers::Base* unstructured)
{
if (unstructured) {
m_termGen->index_text_without_positions(unstructured->asUnicodeString().toUtf8().constData(), 1, key.data());
}
}
void EmailIndexer::insert(const QByteArray& key, KMime::Headers::Generics::MailboxList* mlist)
{
if (mlist)
insert(key, mlist->mailboxes());
}
void EmailIndexer::insert(const QByteArray& key, KMime::Headers::Generics::AddressList* alist)
{
if (alist)
insert(key, alist->mailboxes());
}
namespace {
// Does some extra stuff such as lower casing the email, removing all quotes
// and removing extra spaces
// TODO: Move this into KMime?
// TODO: If name is all upper/lower then try to captialize it?
QString prettyAddress(const KMime::Types::Mailbox& mbox) {
const QString name = mbox.name().simplified();
const QByteArray email = mbox.address().simplified().toLower();
return KPIMUtils::normalizedAddress(name, QString::fromUtf8(email));
}
}
// Add once with a prefix and once without
void EmailIndexer::insert(const QByteArray& key, const KMime::Types::Mailbox::List& list)
{
Q_FOREACH (const KMime::Types::Mailbox& mbox, list) {
std::string name(mbox.name().toUtf8().constData());
m_termGen->index_text_without_positions(name, 1, key.data());
m_termGen->index_text_without_positions(name, 1);
m_termGen->index_text_without_positions(mbox.address().data(), 1, key.data());
m_termGen->index_text_without_positions(mbox.address().data(), 1);
m_doc->add_term((key + mbox.address()).data());
m_doc->add_term(mbox.address().data());
//
// Add emails for email auto-completion
//
const QString pa = prettyAddress(mbox);
int id = qHash(pa);
try {
Xapian::Document doc = m_contactDb->get_document(id);
continue;
}
catch (const Xapian::DocNotFoundError&) {
Xapian::Document doc;
std::string pretty(pa.toUtf8().constData());
doc.set_data(pretty);
Xapian::TermGenerator termGen;
termGen.set_document(doc);
termGen.index_text(pretty);
doc.add_term(mbox.address().data());
m_contactDb->replace_document(id, doc);
}
}
}
// FIXME: Only index properties that are actually searched!
void EmailIndexer::process(const KMime::Message::Ptr& msg)
{
//
// Process Headers
// (Give the subject a higher priority)
KMime::Headers::Subject* subject = msg->subject(false);
if (subject) {
std::string str(subject->asUnicodeString().toUtf8().constData());
qDebug() << "Indexing" << str.c_str();
m_termGen->index_text_without_positions(str, 1, "SU");
m_termGen->index_text_without_positions(str, 100);
m_doc->set_data(str);
}
KMime::Headers::Date* date = msg->date(false);
if (date) {
const QString str = QString::number(date->dateTime().toTime_t());
m_doc->add_value(0, str.toStdString());
const QString julianDay = QString::number(date->dateTime().date().toJulianDay());
m_doc->add_value(2, julianDay.toStdString());
}
insert("F", msg->from(false));
insert("T", msg->to(false));
insert("CC", msg->cc(false));
insert("BC", msg->bcc(false));
insert("O", msg->organization(false));
insert("RT", msg->replyTo(false));
insert("RF", msg->headerByType("Resent-From"));
insert("LI", msg->headerByType("List-Id"));
insert("XL", msg->headerByType("X-Loop"));
insert("XML", msg->headerByType("X-Mailing-List"));
insert("XSF", msg->headerByType("X-Spam-Flag"));
//
// Process Plain Text Content
//
//Index all headers
m_termGen->index_text_without_positions(std::string(msg->head().constData()), 1, "HE");
KMime::Content* mainBody = msg->mainBodyPart("text/plain");
if (mainBody) {
const std::string text(mainBody->decodedText().toUtf8().constData());
m_termGen->index_text_without_positions(text);
m_termGen->index_text_without_positions(text, 1, "BO");
}
else {
processPart(msg.get(), 0);
}
}
void EmailIndexer::processPart(KMime::Content* content, KMime::Content* mainContent)
{
if (content == mainContent) {
return;
}
KMime::Headers::ContentType* type = content->contentType(false);
if (type) {
if (type->isMultipart()) {
if (type->isSubtype("encrypted"))
return;
Q_FOREACH (KMime::Content* c, content->contents()) {
processPart(c, mainContent);
}
}
// Only get HTML content, if no plain text content
if (!mainContent && type->isHTMLText()) {
QTextDocument doc;
doc.setHtml(content->decodedText());
const std::string text(doc.toPlainText().toUtf8().constData());
m_termGen->index_text_without_positions(text);
}
}
// FIXME: Handle attachments?
}
void EmailIndexer::processMessageStatus(const Akonadi::MessageStatus& status)
{
insertBool('R', status.isRead());
insertBool('A', status.hasAttachment());
insertBool('I', status.isImportant());
insertBool('W', status.isWatched());
insertBool('T', status.isToAct());
insertBool('D', status.isDeleted());
insertBool('S', status.isSpam());
insertBool('E', status.isReplied());
insertBool('G', status.isIgnored());
insertBool('F', status.isForwarded());
insertBool('N', status.isSent());
insertBool('Q', status.isQueued());
insertBool('H', status.isHam());
insertBool('C', status.isEncrypted());
insertBool('V', status.hasInvitation());
}
void EmailIndexer::insertBool(char key, bool value)
{
QByteArray term("B");
if (value) {
term.append(key);
}
else {
term.append('N');
term.append(key);
}
m_doc->add_boolean_term(term.data());
}
void EmailIndexer::toggleFlag(Xapian::Document& doc, const char* remove, const char* add)
{
try {
doc.remove_term(remove);
}
catch (const Xapian::InvalidArgumentError &e) {
// The previous flag state was not indexed, continue
}
doc.add_term(add);
}
void EmailIndexer::updateFlags(const Akonadi::Item& item,
const QSet<QByteArray>& added,
const QSet<QByteArray>& removed)
{
Xapian::Document doc;
try {
doc = m_db->get_document(item.id());
}
catch (const Xapian::DocNotFoundError&) {
return;
}
Q_FOREACH (const QByteArray& flag, removed) {
if (flag == Akonadi::MessageFlags::Seen) {
toggleFlag(doc, "BR", "BNR");
}
else if (flag == Akonadi::MessageFlags::Flagged) {
toggleFlag(doc, "BI", "BNI");
}
else if (flag == Akonadi::MessageFlags::Watched) {
toggleFlag(doc, "BW", "BNW");
}
}
Q_FOREACH (const QByteArray& flag, added) {
if (flag == Akonadi::MessageFlags::Seen) {
toggleFlag(doc, "BNR", "BR");
}
else if (flag == Akonadi::MessageFlags::Flagged) {
toggleFlag(doc, "BNI", "BI");
}
else if (flag == Akonadi::MessageFlags::Watched) {
toggleFlag(doc, "BNW", "BW");
}
}
m_db->replace_document(doc.get_docid(), doc);
}
void EmailIndexer::remove(const Akonadi::Item& item)
{
try {
m_db->delete_document(item.id());
//TODO remove contacts from contact db?
}
catch (const Xapian::DocNotFoundError&) {
return;
}
}
void EmailIndexer::remove(const Akonadi::Collection& collection)
{
try {
Xapian::Query query('C'+ QString::number(collection.id()).toStdString());
Xapian::Enquire enquire(*m_db);
enquire.set_query(query);
Xapian::MSet mset = enquire.get_mset(0, m_db->get_doccount());
Xapian::MSetIterator end = mset.end();
for (Xapian::MSetIterator it = mset.begin(); it != end; ++it) {
const qint64 id = *it;
remove(Akonadi::Item(id));
}
}
catch (const Xapian::DocNotFoundError&) {
return;
}
}
void EmailIndexer::move(const Akonadi::Item::Id& itemId,
const Akonadi::Entity::Id& from,
const Akonadi::Entity::Id& to)
{
Xapian::Document doc;
try {
doc = m_db->get_document(itemId);
}
catch (const Xapian::DocNotFoundError&) {
return;
}
const QByteArray ft = 'C' + QByteArray::number(from);
const QByteArray tt = 'C' + QByteArray::number(to);
doc.remove_term(ft.data());
doc.add_boolean_term(tt.data());
m_db->replace_document(doc.get_docid(), doc);
}
void EmailIndexer::commit()
{
m_db->commit();
m_contactDb->commit();
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Apr 4, 6:49 AM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18822918
Default Alt Text
(12 KB)
Attached To
Mode
rKB baloo
Attached
Detach File
Event Timeline