2
Copyright (c) 2006 Volker Krause <vkrause@kde.org>
3
Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
5
This library is free software; you can redistribute it and/or modify it
6
under the terms of the GNU Library General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or (at your
8
option) any later version.
10
This library is distributed in the hope that it will be useful, but WITHOUT
11
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13
License for more details.
15
You should have received a copy of the GNU Library General Public License
16
along with this library; see the file COPYING.LIB. If not, write to the
17
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21
#include "nepomukemailfeeder.h"
23
#include "emailaddress.h"
24
#include "personcontact.h"
26
#include <akonadi/changerecorder.h>
27
#include <akonadi/item.h>
28
#include <akonadi/itemfetchscope.h>
29
#include <akonadi/kmime/messageparts.h>
31
#include <kmime/kmime_message.h>
32
#include <kmime/kmime_content.h>
33
#include <boost/shared_ptr.hpp>
35
#include <Nepomuk/Resource>
36
#include <Nepomuk/ResourceManager>
37
#include <Nepomuk/Variant>
40
#include <Soprano/Vocabulary/Xesam>
41
#include <Soprano/Vocabulary/NAO>
42
#include <Soprano/Vocabulary/XMLSchema>
43
#include <Soprano/Model>
44
#include <Soprano/QueryResultIterator>
45
#include <soprano/node.h>
46
#include <soprano/nodeiterator.h>
47
#include <soprano/nrl.h>
49
#define USING_SOPRANO_NRLMODEL_UNSTABLE_API 1
50
#include <soprano/nrlmodel.h>
53
using namespace Akonadi;
54
typedef boost::shared_ptr<KMime::Message> MessagePtr;
56
static void removeItemFromNepomuk( const Akonadi::Item &item )
58
// find the graph that contains our item and delete the complete graph
59
QList<Soprano::Node> list = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery(
60
QString( "select ?g where { ?g <http://www.semanticdesktop.org/ontologies/2007/01/19/nie#dataGraphFor> %1. }")
61
.arg( Soprano::Node::resourceToN3( item.url() ) ),
62
Soprano::Query::QueryLanguageSparql ).iterateBindings( 0 ).allNodes();
64
foreach ( const Soprano::Node &node, list )
65
Nepomuk::ResourceManager::instance()->mainModel()->removeContext( node );
68
Akonadi::NepomukEMailFeeder::NepomukEMailFeeder( const QString &id ) :
71
changeRecorder()->itemFetchScope().fetchPayloadPart( MessagePart::Envelope );
72
changeRecorder()->setMimeTypeMonitored( "message/rfc822" );
73
changeRecorder()->setMimeTypeMonitored( "message/news" );
74
changeRecorder()->setChangeRecordingEnabled( false );
77
Nepomuk::ResourceManager::instance()->init();
79
mNrlModel = new Soprano::NRLModel( Nepomuk::ResourceManager::instance()->mainModel() );
82
NepomukEMailFeeder::~NepomukEMailFeeder()
87
void NepomukEMailFeeder::itemAdded(const Akonadi::Item & item, const Akonadi::Collection & collection)
89
Q_UNUSED( collection );
90
itemChanged( item, QSet<QByteArray>() );
93
void NepomukEMailFeeder::itemChanged(const Akonadi::Item & item, const QSet<QByteArray> & partIdentifiers)
95
Q_UNUSED( partIdentifiers );
96
if ( !item.hasPayload<MessagePtr>() )
99
// first remove the item: since we use a graph that has a reference to all parts
100
// of the item's semantic representation this is a really fast operation
101
removeItemFromNepomuk( item );
103
// create a new graph for the item
104
QUrl metaDataGraphUri;
105
QUrl graphUri = mNrlModel->createGraph( Soprano::Vocabulary::NRL::InstanceBase(), &metaDataGraphUri );
107
// remember to which graph the item belongs to (used in search query in removeItemFromNepomuk())
108
mNrlModel->addStatement( graphUri,
109
QUrl::fromEncoded( "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#dataGraphFor", QUrl::StrictMode ),
110
item.url(), metaDataGraphUri );
112
MessagePtr msg = item.payload<MessagePtr>();
114
// FIXME: make a distinction between email and news
115
NepomukFast::Email r( item.url(), graphUri );
117
if ( msg->subject( false ) ) {
118
r.setMessageSubject( msg->subject()->asUnicodeString() );
121
if ( msg->date( false ) ) {
122
r.setReceivedDate( msg->date()->dateTime().dateTime() );
125
if ( msg->from( false ) ) {
126
r.setSenders( extractContactsFromMailboxes( msg->from()->mailboxes(), graphUri ) );
129
if ( msg->to( false ) ) {
130
r.setTos( extractContactsFromMailboxes( msg->to()->mailboxes(), graphUri ) );
133
if ( msg->cc( false ) ) {
134
r.setCcs( extractContactsFromMailboxes( msg->cc()->mailboxes(), graphUri ) );
137
if ( msg->bcc( false ) ) {
138
r.setBccs( extractContactsFromMailboxes( msg->bcc()->mailboxes(), graphUri ) );
141
KMime::Content* content = msg->mainBodyPart( "text/plain" );
143
// FIXME: simplyfy this text as in: remove all html tags. Is there a quick way to do this?
145
QString text = content->decodedText( true, true );
146
if ( !text.isEmpty() ) {
147
r.addProperty( Soprano::Vocabulary::Xesam::asText(), Soprano::LiteralValue( text ) );
151
// FIXME: is xesam:id the best idea here?
152
if ( msg->messageID( false ) ) {
153
r.addProperty( Soprano::Vocabulary::Xesam::id(), Soprano::LiteralValue( msg->messageID()->asUnicodeString() ) );
156
// IDEA: use Strigi to index the attachments
159
void NepomukEMailFeeder::itemRemoved(const Akonadi::Item & item)
161
removeItemFromNepomuk( item );
164
QList<NepomukFast::Contact> NepomukEMailFeeder::extractContactsFromMailboxes( const KMime::Types::Mailbox::List& mbs,
165
const QUrl &graphUri )
167
QList<NepomukFast::Contact> contacts;
169
foreach( const KMime::Types::Mailbox& mbox, mbs ) {
170
if ( mbox.hasAddress() ) {
172
NepomukFast::Contact c = findContact( mbox.address(), graphUri, &found );
173
if ( !found && mbox.hasName() )
174
c.addFullname( mbox.name() );
182
NepomukFast::PersonContact NepomukEMailFeeder::findContact( const QByteArray& address, const QUrl &graphUri, bool *found )
185
// Querying with the exact address string is not perfect since email addresses
186
// are case insensitive. But for the moment we stick to it and hope Nepomuk
187
// alignment fixes any duplicates
189
Soprano::QueryResultIterator it =
190
Nepomuk::ResourceManager::instance()->mainModel()->executeQuery( QString( "select distinct ?r where { ?r <%1> ?a . ?a <%2> \"%3\"^^<%4> . }" )
191
.arg( NepomukFast::Role::emailAddressUri().toString() )
192
.arg( NepomukFast::EmailAddress::emailAddressUri().toString() )
193
.arg( QString::fromAscii( address ) )
194
.arg( Soprano::Vocabulary::XMLSchema::string().toString() ),
195
Soprano::Query::QueryLanguageSparql );
198
return NepomukFast::PersonContact( it.binding( 0 ).uri(), graphUri );
202
// create a new contact
203
NepomukFast::PersonContact contact( QUrl(), graphUri );
204
NepomukFast::EmailAddress email( QUrl( "mailto:" + address ), graphUri );
205
email.setEmailAddress( QString::fromAscii( address ) );
206
contact.addEmailAddress( email );
211
AKONADI_AGENT_MAIN( NepomukEMailFeeder )
213
#include "nepomukemailfeeder.moc"