You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
394 lines
15 KiB
394 lines
15 KiB
/* |
|
Copyright (c) 2007 Volker Krause <vkrause@kde.org> |
|
Copyright (c) 2009 Sebastian Kügler <sebas@kde.org> |
|
|
|
This library is free software; you can redistribute it and/or modify it |
|
under the terms of the GNU Library General Public License as published by |
|
the Free Software Foundation; either version 2 of the License, or (at your |
|
option) any later version. |
|
|
|
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 Library General Public |
|
License for more details. |
|
|
|
You should have received a copy of the GNU Library General Public License |
|
along with this library; see the file COPYING.LIB. If not, write to the |
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
02110-1301, USA. |
|
*/ |
|
|
|
|
|
#include "akonadiengine.h" |
|
|
|
|
|
#include <Akonadi/CollectionFetchJob> |
|
#include <Akonadi/ItemFetchJob> |
|
#include <Akonadi/ItemFetchScope> |
|
#include <Akonadi/Monitor> |
|
#include <akonadi/kmime/messageparts.h> |
|
|
|
#include <kabc/addressee.h> |
|
#include <kabc/phonenumber.h> |
|
#include <kabc/picture.h> |
|
#include <kabc/key.h> |
|
|
|
using namespace Akonadi; |
|
|
|
AkonadiEngine::AkonadiEngine(QObject* parent, const QVariantList& args) |
|
: Plasma::DataEngine(parent), |
|
m_emailMonitor(0), |
|
m_contactMonitor(0) |
|
{ |
|
Q_UNUSED(args); |
|
setMaxSourceCount( 512 ); // Guard against loading thousands of emails |
|
} |
|
|
|
void AkonadiEngine::initEmailMonitor() |
|
{ |
|
m_emailMonitor = new Monitor( this ); |
|
m_emailMonitor->setMimeTypeMonitored("message/rfc822"); |
|
//m_emailMonitor->setCollectionMonitored(Collection::root(), false); |
|
m_emailMonitor->itemFetchScope().fetchFullPayload( true ); |
|
connect(m_emailMonitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), |
|
SLOT(emailItemAdded(Akonadi::Item)) ); |
|
connect(m_emailMonitor, SIGNAL(itemChanged(Akonadi::Item,QSet<QByteArray>)), |
|
SLOT(emailItemAdded(Akonadi::Item)) ); |
|
// remove the monitor on a source that's not used |
|
connect(this, SIGNAL(sourceRemoved(QString)), SLOT(stopMonitor(QString))); |
|
} |
|
|
|
void AkonadiEngine::initContactMonitor() |
|
{ |
|
m_contactMonitor = new Monitor( this ); |
|
m_contactMonitor->setMimeTypeMonitored("text/directory"); |
|
m_contactMonitor->setCollectionMonitored(Collection::root(), false); |
|
m_contactMonitor->itemFetchScope().fetchFullPayload(); |
|
connect(m_contactMonitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)), |
|
SLOT(contactItemAdded(Akonadi::Item)) ); |
|
connect(m_contactMonitor, SIGNAL(itemChanged(Akonadi::Item,QSet<QByteArray>)), |
|
SLOT(contactItemAdded(Akonadi::Item)) ); |
|
// remove the monitor on a source that's not used |
|
connect(this, SIGNAL(sourceRemoved(QString)), SLOT(stopMonitor(QString))); |
|
} |
|
|
|
|
|
AkonadiEngine::~AkonadiEngine() |
|
{ |
|
} |
|
|
|
QStringList AkonadiEngine::sources() const |
|
{ |
|
return QStringList() << "EmailCollections" << "ContactCollections"; |
|
} |
|
|
|
void AkonadiEngine::fetchEmailCollectionsDone(KJob* job) |
|
{ |
|
// called when the job fetching email collections from Akonadi emits result() |
|
if ( job->error() ) { |
|
qDebug() << "Job Error:" << job->errorString(); |
|
} else { |
|
CollectionFetchJob* cjob = static_cast<CollectionFetchJob*>( job ); |
|
int i = 0; |
|
foreach( const Collection &collection, cjob->collections() ) { |
|
if (collection.contentMimeTypes().contains("message/rfc822")) { |
|
//qDebug() << "EmailCollection setting data:" << collection.name() << collection.url() << collection.contentMimeTypes(); |
|
i++; |
|
setData("EmailCollections", QString("EmailCollection-%1").arg(collection.id()), collection.name()); |
|
} |
|
} |
|
qDebug() << i << "Email collections are in now"; |
|
scheduleSourcesUpdated(); |
|
} |
|
} |
|
|
|
void AkonadiEngine::fetchContactCollectionsDone(KJob* job) |
|
{ |
|
// called when the job fetching contact collections from Akonadi emits result() |
|
if ( job->error() ) { |
|
qDebug() << "Job Error:" << job->errorString(); |
|
} else { |
|
CollectionFetchJob* cjob = static_cast<CollectionFetchJob*>( job ); |
|
int i = 0; |
|
foreach( const Collection &collection, cjob->collections() ) { |
|
if (collection.contentMimeTypes().contains("text/directory")) { |
|
//qDebug() << "ContactCollection setting data:" << collection.name() << collection.url() << collection.contentMimeTypes(); |
|
i++; |
|
setData("ContactCollections", QString("ContactCollection-%1").arg(collection.id()), collection.name()); |
|
} |
|
} |
|
qDebug() << i << "Contact collections are in now"; |
|
scheduleSourcesUpdated(); |
|
} |
|
} |
|
|
|
bool AkonadiEngine::sourceRequestEvent(const QString &name) |
|
{ |
|
qDebug() << "Source requested:" << name << sources(); |
|
|
|
if (name == "EmailCollections") { |
|
Collection emailCollection(Collection::root()); |
|
emailCollection.setContentMimeTypes(QStringList() << "message/rfc822"); |
|
CollectionFetchJob *fetch = new CollectionFetchJob( emailCollection, CollectionFetchJob::Recursive); |
|
connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchEmailCollectionsDone(KJob*)) ); |
|
// For async data fetching, it's mandatory to set the data source to empty before returning true |
|
setData(name, DataEngine::Data()); |
|
return true; |
|
|
|
} else if (name.startsWith(QString("EmailCollection-"))) { |
|
qlonglong id = name.split('-')[1].toLongLong(); |
|
ItemFetchJob* fetch = new ItemFetchJob( Collection( id ), this ); |
|
if (!m_emailMonitor) { |
|
initEmailMonitor(); |
|
} |
|
m_emailMonitor->setCollectionMonitored(Collection( id ), true); |
|
fetch->fetchScope().fetchPayloadPart( MessagePart::Envelope ); |
|
connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchEmailCollectionDone(KJob*)) ); |
|
connect( fetch, SIGNAL(itemsReceived(Akonadi::Item::List)), SLOT(emailItemsReceived(Akonadi::Item::List)) ); |
|
m_jobCollections[fetch] = name; |
|
setData(name, DataEngine::Data()); |
|
return true; |
|
|
|
} else if (name.startsWith(QString("Email-"))) { |
|
qlonglong id = name.split('-')[1].toLongLong(); |
|
ItemFetchJob* fetch = new ItemFetchJob( Item( id ), this ); |
|
if (!m_emailMonitor) { |
|
initEmailMonitor(); |
|
} |
|
m_emailMonitor->setItemMonitored(Item( id ), true); |
|
fetch->fetchScope().fetchFullPayload( true ); |
|
connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchEmailCollectionDone(KJob*)) ); |
|
connect( fetch, SIGNAL(itemsReceived(Akonadi::Item::List)), SLOT(emailItemsReceived(Akonadi::Item::List)) ); |
|
m_jobCollections[fetch] = name; |
|
setData(name, DataEngine::Data()); |
|
return true; |
|
|
|
} else if (name == "ContactCollections") { |
|
Collection contactCollection(Collection::root()); |
|
contactCollection.setContentMimeTypes(QStringList() << "text/directory"); |
|
|
|
CollectionFetchJob* fetch = new CollectionFetchJob( contactCollection, CollectionFetchJob::Recursive); |
|
connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchContactCollectionsDone(KJob*)) ); |
|
setData(name, DataEngine::Data()); |
|
return true; |
|
|
|
} else if (name.startsWith(QString("ContactCollection-"))) { |
|
qlonglong id = name.split('-')[1].toLongLong(); |
|
ItemFetchJob *fetch = new ItemFetchJob( Collection( id ), this ); |
|
if (!m_contactMonitor) { |
|
initContactMonitor(); |
|
} |
|
m_contactMonitor->setCollectionMonitored(Collection( id ), true); // FIXME: should be contacts monitor |
|
fetch->fetchScope().fetchFullPayload(); |
|
connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchContactCollectionDone(KJob*)) ); |
|
setData(name, DataEngine::Data()); |
|
return true; |
|
|
|
} else if (name.startsWith(QString("Contact-"))) { |
|
qDebug() << "Fetching contact" << name; |
|
qlonglong id = name.split('-')[1].toLongLong(); |
|
ItemFetchJob *fetch = new ItemFetchJob( Item( id ), this ); |
|
if (!m_contactMonitor) { |
|
initContactMonitor(); |
|
} |
|
m_contactMonitor->setItemMonitored(Item( id ), true); // FIXME: should be contacts monitor |
|
fetch->fetchScope().fetchFullPayload(); |
|
connect( fetch, SIGNAL(result(KJob*)), SLOT(fetchContactCollectionDone(KJob*)) ); |
|
setData(name, DataEngine::Data()); |
|
return true; |
|
|
|
// We don't understand the request. |
|
qDebug() << "Don't know what to do with:" << name; |
|
return false; |
|
} |
|
|
|
void AkonadiEngine::stopMonitor(const QString &name) |
|
{ |
|
if (name.startsWith(QString("EmailCollection-"))) { |
|
// Stop monitoring this one |
|
qlonglong id = name.split('-')[1].toLongLong(); |
|
m_emailMonitor->setCollectionMonitored( Collection( id ), false); |
|
qDebug() << "Removed monitor from:" << name << id; |
|
} |
|
} |
|
|
|
void AkonadiEngine::emailItemsReceived(const Akonadi::Item::List &items) |
|
{ |
|
foreach (const Akonadi::Item &item, items) { |
|
emailItemAdded(item); |
|
} |
|
} |
|
|
|
void AkonadiEngine::emailItemAdded(const Akonadi::Item &item, const QString &collection) |
|
{ |
|
if ( !item.hasPayload<MessagePtr>() ) { |
|
return; |
|
} |
|
MessagePtr msg = item.payload<MessagePtr>(); |
|
if (msg) { |
|
QString source = QString::number( item.id() ); |
|
source = "Email-" + source; |
|
//qDebug() << "new source adding:" << source << item.url() << msg->subject()->asUnicodeString(); |
|
|
|
setData( source, "Id", item.id() ); |
|
setData( source, "Collection", collection); |
|
setData( source, "Url", item.url().url() ); |
|
setData( source, "Subject", msg->subject()->asUnicodeString() ); |
|
setData( source, "From", msg->from()->asUnicodeString() ); |
|
setData( source, "DateTime", msg->date()->dateTime().date() ); |
|
setData( source, "To", msg->to()->asUnicodeString() ); |
|
setData( source, "Cc", msg->cc()->asUnicodeString() ); |
|
setData( source, "Bcc", msg->bcc()->asUnicodeString() ); |
|
setData( source, "Body", QString(msg->mainBodyPart()->body())); |
|
// Flags |
|
//qDebug() << item.flags(); |
|
setData( source, "Flag-New", !item.hasFlag("\\Seen") ); |
|
setData( source, "Flag-Task", item.hasFlag("\\Task") ); // not in Akonadi! |
|
setData( source, "Flag-Important", item.hasFlag("important") ); |
|
setData( source, "Flag-Attachment", item.hasFlag("has_attachment") ); |
|
setData( source, "Flag-Spam", item.hasFlag("spam") ); |
|
setData( source, "Flag-Draft", item.hasFlag("\\Draft") ); |
|
setData( source, "Flag-Answered", item.hasFlag("\\Answered") ); |
|
setData( source, "Flag-Deleted", item.hasFlag("\\Deleted") ); |
|
setData( source, "Flag-Flagged", item.hasFlag("\\Flagged") ); |
|
|
|
if (!collection.isEmpty()) { |
|
setData( collection, source, msg->subject()->asUnicodeString()); |
|
} |
|
printMessage(msg); |
|
scheduleSourcesUpdated(); |
|
} |
|
} |
|
|
|
void AkonadiEngine::printMessage(const MessagePtr msg) |
|
{ |
|
return; |
|
qDebug() << "sub" << msg->subject()->asUnicodeString(); |
|
return; |
|
qDebug() << "=============== New Item" << msg->from()->asUnicodeString() << msg->subject()->asUnicodeString(); |
|
qDebug() << "sub" << msg->subject()->asUnicodeString(); |
|
qDebug() << "from" << msg->from()->asUnicodeString(); |
|
qDebug() << "date" << msg->date()->dateTime().date(); |
|
qDebug() << "to" << msg->to()->asUnicodeString(); |
|
qDebug() << "cc" << msg->cc()->asUnicodeString(); |
|
qDebug() << "bcc" << msg->bcc()->asUnicodeString(); |
|
qDebug() << "body" << msg->mainBodyPart()->body(); |
|
} |
|
|
|
void AkonadiEngine::fetchEmailCollectionDone(KJob* job) |
|
{ |
|
if ( job->error() ) { |
|
qDebug() << "Job Error:" << job->errorString(); |
|
return; |
|
} |
|
const QString col = m_jobCollections[job]; |
|
Item::List items = static_cast<ItemFetchJob*>( job )->items(); |
|
foreach ( const Item &item, items ) { |
|
emailItemAdded(item, col); |
|
} |
|
m_jobCollections.remove(job); |
|
scheduleSourcesUpdated(); |
|
} |
|
|
|
void AkonadiEngine::fetchContactCollectionDone(KJob* job) |
|
{ |
|
if ( job->error() ) { |
|
return; |
|
} |
|
Item::List items = static_cast<ItemFetchJob*>( job )->items(); |
|
foreach ( const Item &item, items ) { |
|
contactItemAdded( item ); |
|
} |
|
} |
|
|
|
|
|
void AkonadiEngine::printContact(const QString &source, const KABC::Addressee &a) |
|
{ |
|
qDebug() << "-----------------------------------"; |
|
qDebug() << source; |
|
qDebug() << "name" << a.name(); |
|
qDebug() << "formattedName" << a.formattedName(); |
|
qDebug() << "nameLabel" << a.nameLabel(); |
|
qDebug() << "given" << a.givenName(); |
|
qDebug() << "familyName" << a.familyName(); |
|
qDebug() << "realName" << a.realName(); |
|
qDebug() << "organization" << a.organization(); |
|
qDebug() << "department" << a.department(); |
|
qDebug() << "role" << a.role(); |
|
qDebug() << "emails" << a.emails(); |
|
qDebug() << "fullEmail" << a.fullEmail(); |
|
qDebug() << "photoUrl" << a.photo().url(); |
|
qDebug() << "note" << a.note(); |
|
|
|
QStringList phoneNumbers; |
|
foreach (const KABC::PhoneNumber &pn, a.phoneNumbers()) { |
|
const QString key = QString("Phone-%1").arg(pn.typeLabel()); |
|
qDebug() << key << a.phoneNumber(pn.type()).number(); |
|
phoneNumbers << a.phoneNumber(pn.type()).number(); |
|
} |
|
qDebug() << "phoneNumbers" << phoneNumbers; |
|
|
|
qDebug() << "additionalName" << a.additionalName(); |
|
|
|
} |
|
|
|
void AkonadiEngine::contactItemAdded( const Akonadi::Item &item ) |
|
{ |
|
if (item.hasPayload<KABC::Addressee>()) { |
|
//qDebug() << item.id() << "item has payload ..."; |
|
KABC::Addressee a = item.payload<KABC::Addressee>(); |
|
if (!a.isEmpty()) { |
|
const QString source = QString("Contact-%1").arg(item.id()); |
|
setData(source, "Id", item.id()); |
|
setData(source, "Url", item.url().url()); |
|
|
|
// Name and related |
|
setData(source, "Name", a.formattedName()); |
|
setData(source, "GivenName", a.givenName()); |
|
setData(source, "FamilyName", a.familyName()); |
|
setData(source, "NickName", a.nickName()); |
|
setData(source, "RealName", a.realName()); |
|
setData(source, "AdditionalName", a.additionalName()); |
|
|
|
// Organization and related |
|
setData(source, "Organization", a.organization()); |
|
setData(source, "Department", a.department()); |
|
setData(source, "Role", a.role()); |
|
|
|
// EMail and related |
|
setData(source, "Emails", a.emails()); |
|
setData(source, "FullEmail", a.fullEmail()); |
|
|
|
// Phone and related |
|
QStringList phoneNumbers; |
|
foreach (const KABC::PhoneNumber &pn, a.phoneNumbers()) { |
|
const QString key = QString("Phone-%1").arg(pn.typeLabel()); |
|
setData(source, key, a.phoneNumber(pn.type()).number()); |
|
phoneNumbers << a.phoneNumber(pn.type()).number(); |
|
} |
|
setData(source, "PhoneNumbers", phoneNumbers); |
|
|
|
// Personal |
|
setData(source, "Birthday", a.birthday()); |
|
setData(source, "Photo", a.photo().data()); |
|
setData(source, "PhotoUrl", a.photo().url()); |
|
setData(source, "Latitude", a.geo().latitude()); |
|
setData(source, "Longitude", a.geo().longitude()); |
|
|
|
// addresses |
|
|
|
// categories |
|
|
|
// note, |
|
setData(source, "Note", a.note()); |
|
// prefix |
|
|
|
// ... |
|
//printContact(source, a); |
|
|
|
scheduleSourcesUpdated(); |
|
} |
|
} |
|
} |
|
|
|
|
|
|