summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debian/changelog92
-rw-r--r--debian/compat1
-rw-r--r--debian/control108
-rw-r--r--debian/copyright24
-rw-r--r--debian/libqmf-dev.install3
-rw-r--r--debian/libqmf-doc.install1
-rw-r--r--debian/libqmf-plugins.install3
-rw-r--r--debian/libqmf-tests.install1
-rw-r--r--debian/libqmf0.install3
-rw-r--r--debian/patches/0001-maemo_changes.diff7050
-rw-r--r--debian/patches/series1
-rw-r--r--debian/qmfmail.install5
-rw-r--r--debian/qmfserver.install1
-rwxr-xr-xdebian/rules64
-rwxr-xr-xdebian/runtests.sh5
-rwxr-xr-xdebian/test_script.sh79
16 files changed, 7441 insertions, 0 deletions
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 00000000..e4886fa3
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,92 @@
+qt4-messagingframework (2009W19-0maemo2) hardy; urgency=low
+
+ * Pull from upstream.
+
+ -- Gareth Pethig <gareth.pethig@nokia.com> Fri, 08 May 2009 18:51:23 +1000
+
+qt4-messagingframework (2009W19-0maemo1) hardy; urgency=low
+
+ * Pull from upstream.
+
+ -- Gareth Pethig <gareth.pethig@nokia.com> Thu, 07 May 2009 19:56:45 +1000
+
+qt4-messagingframework (2009W17-0maemo2) hardy; urgency=low
+
+ * Add SPARQL library to package.
+
+ -- Shane Bradley <shane.bradley@nokia.com> Sun, 26 Apr 2009 09:40:23 +1000
+
+qt4-messagingframework (2009W17-0maemo1) hardy; urgency=low
+
+ * Pull from upstream.
+
+ -- Gareth Pethig <gareth.pethig@nokia.com> Fri, 24 Apr 2009 18:00:47 +1000
+
+qt4-messagingframework (2009W16-0maemo4) hardy; urgency=low
+
+ * Install test scripts into test pkg.
+
+ -- Gareth Pethig <gareth.pethig@nokia.com> Wed, 22 Apr 2009 15:46:39 +1000
+
+qt4-messagingframework (2009W16-0maemo3) hardy; urgency=low
+
+ * Add initial version of the Content Manager Integration.
+
+ -- Shane Bradley <shane.bradley@nokia.com> Wed, 22 Apr 2009 12:03:35 +1000
+
+qt4-messagingframework (2009W16-0maemo2) hardy; urgency=low
+
+ * Add test pkg containing unit tests.
+
+ -- Gareth Pethig <gareth.pethig@nokia.com> Tue, 21 Apr 2009 14:13:28 +1000
+
+qt4-messagingframework (2009W16-0maemo1) hardy; urgency=low
+
+ * Pull from upstream.
+
+ -- Gareth Pethig <gareth.pethig@nokia.com> Tue, 21 Apr 2009 11:08:04 +1000
+
+qt4-messagingframework (2009W14-0maemo1) hardy; urgency=low
+
+ * Pull from upstream.
+
+ -- Shane Bradley <shane.bradley@nokia.com> Fri, 03 Apr 2009 16:39:16 +1000
+
+qt4-messagingframework (2009W13-0maemo1) hardy; urgency=low
+
+ * Pull from upstream.
+
+ -- Shane Bradley <shane.bradley@nokia.com> Mon, 30 Mar 2009 13:13:03 +1000
+
+qt4-messagingframework (2009W12-0maemo4) hardy; urgency=low
+
+ * Fix the changelog format.
+ * Make the rule script clean up *all* generated files.
+ * Fixes: NB#103702 - QMF Message server crashes during mail transmition if Outbox folder is empty.
+ * Fixes: NB#103707 - QMailAddress does not recognize e-mail address in case of domain name is from 1st zone.
+ * Fixes: NB#103923 - Issue with databaseIdentifier() function call order.
+ * Fixes: NB#103716 - QMF: Fail to retrieve messages from MSExchange 2007 server using POP3 protocol plugin.
+ * Fixes: NB#104197 - Common issues with QMF sources.
+ * Fixes: NB#105396 - Messageserver crashes during IMAP mail retrieval.
+
+ -- Shane Bradley <shane.bradley@nokia.com> Mon, 30 Mar 2009 11:32:59 +1000
+
+qt4-messagingframework (2009W12-0maemo3) hardy; urgency=low
+
+ * Move source changes to a separate patch.
+ * Fixes: NB#103702, NB#103707, NB#103923, NB#103716, NB#104197, NB#105396
+
+ -- Shane Bradley <shane.bradley@nokia.com> Thu, 26 Mar 2009 15:57:52 +1000
+
+qt4-messagingframework (2009W12-0maemo2) hardy; urgency=low
+
+ * Development package and QtMail application package were added.
+
+ -- Dmitry Zelenkovsky <ext-Dmitry.Zelenkovskyiy@nokia.com> Tue, 24 Mar 2009 14:34:59 +0200
+
+qt4-messagingframework (2009W12-0maemo1) unstable; urgency=low
+
+ * Initial release
+
+ -- Shane Bradley <shane.bradley@nokia.com> Thu, 19 Mar 2009 16:23:33 +1000
+
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 00000000..7ed6ff82
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 00000000..e16a3a0a
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,108 @@
+Source: qt4-messagingframework
+Section: libs
+Priority: optional
+Maintainer: Shane Bradley <shane.bradley@nokia.com>
+Build-Depends: cdbs, debhelper (>= 5), quilt, libqt4-dev (>= 4.5)
+Standards-Version: 3.7.3
+
+Package: libqmf0
+Section: libs
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+#Recommends: libqmf-plugins
+Description: Qt Messaging Framework library
+ The Qt Messaging Framework Library provides a set of APIs
+ that support the most common operations related
+ to arbitrary messages such as creation, modification,
+ retrieval, storage and display of messages. It
+ defines interfaces which enable the integration
+ of new message types. Therefore multiple applications
+ can access the data independ of their storage and if
+ necessary on a concurrent base.
+
+Package: libqmf-dev
+Section: libdevel
+Architecture: any
+Depends: libqmf0 (= ${binary:Version}), libqt4-dev (>= 4.5)
+Recommends: libqmf-doc
+Description: Qt Messaging Framework Library development files
+ Development files for Qt Messaging Framework Library.
+ .
+ The Qt Messaging Framework Library provides a set of APIs
+ that support the most common operations related
+ to arbitrary messages such as creation, modification,
+ retrieval, storage and display of messages. It
+ defines interfaces which enable the integration
+ of new message types. Therefore multiple applications
+ can access the data independ of their storage and if
+ necessary on a concurrent base.
+
+Package: libqmf-tests
+Section: tests
+Architecture: any
+Depends: libqmf0 (= ${binary:Version}), libqt4-dev (>= 4.5)
+Description: Qt Messaging Framework Library unit tests
+ Unit tests for Qt Messaging Framework Library.
+ .
+ The Qt Messaging Framework Library provides a set of APIs
+ that support the most common operations related
+ to arbitrary messages such as creation, modification,
+ retrieval, storage and display of messages. It
+ defines interfaces which enable the integration
+ of new message types. Therefore multiple applications
+ can access the data independ of their storage and if
+ necessary on a concurrent base.
+
+Package: libqmf0-dbg
+Section: libdevel
+Priority: extra
+Architecture: any
+Depends: libqmf0 (= ${binary:Version})
+Description: Qt Messaging Framework Library debug information.
+ Debug information of the Qt Messaging Framework Library.
+
+#Package: libqmf-doc
+#Section: doc
+#Architecture: any
+#Recommends: libqmf0, libqmf-dev
+#Description: Qt Messaging Framework Library documentation.
+# Documentation for the Qt Messaging Framework Library.
+
+Package: libqmf-plugins
+Section: libs
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Plugins for Qt Messaging Framework Library and Messaging Server
+ Plugins library consist of set of plugins for
+ extending functionality of the Messagins Server.
+ .
+ Following protocols are supported:
+ * POP3
+ * IMAP
+ * SMTP
+ .
+ Default mail content manager is provided as a plugin also.
+
+Package: qmfserver
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Recommends: libqmf-plugins
+Description: The Qt Messaging Server
+ The Message server daemon can send and retrieve
+ messages of various types from multiple sources
+ such as POP and IMAP accounts or a local SIM card.
+ It forms the back-end of the Qtopia Messaging
+ framework.
+
+Package: qmfmail
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, qmfserver (= ${binary:Version}), libqmf-plugins (= ${binary:Version})
+Description: The Qt Mail Application
+ The Messages client application enables the user
+ to receive emails from multiple mail servers as
+ well as SMS and MMS messages from other mobile
+ phone devices. It also provides the ability to send
+ emails, MMS or SMS messages to multiple people
+ with or without attachments.
+
+
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 00000000..1b8d6fea
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,24 @@
+This package was debianized by Dmitry Zelenkovsky <ext-dmitry.zelenkovskiy@nokia.com> on
+Tue, 17 Mar 2009 15:16:59 +0200.
+
+It was downloaded from <url://example.com>
+
+Upstream Author(s):
+
+ <put author's name and email here>
+ <likewise for another author>
+
+Copyright:
+
+ <Copyright (C) YYYY Name OfAuthor>
+ <likewise for another author>
+
+License:
+
+ <Put the license of the package here indented by 4 spaces>
+
+The Debian packaging is (C) 2009, Dmitry Zelenkovsky <ext-dmitry.zelenkovskiy@nokia.com> and
+is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them here.
diff --git a/debian/libqmf-dev.install b/debian/libqmf-dev.install
new file mode 100644
index 00000000..b6a0f17c
--- /dev/null
+++ b/debian/libqmf-dev.install
@@ -0,0 +1,3 @@
+usr/include/qmf/*
+usr/lib/pkgconfig/*
+
diff --git a/debian/libqmf-doc.install b/debian/libqmf-doc.install
new file mode 100644
index 00000000..08dadab1
--- /dev/null
+++ b/debian/libqmf-doc.install
@@ -0,0 +1 @@
+usr/doc/* usr/share/doc/qmf \ No newline at end of file
diff --git a/debian/libqmf-plugins.install b/debian/libqmf-plugins.install
new file mode 100644
index 00000000..fe6f7445
--- /dev/null
+++ b/debian/libqmf-plugins.install
@@ -0,0 +1,3 @@
+usr/plugins/contentmanagers/*.so* usr/lib/qmf/contentmanagers
+usr/plugins/messageservices/*.so* usr/lib/qmf/messageservices
+
diff --git a/debian/libqmf-tests.install b/debian/libqmf-tests.install
new file mode 100644
index 00000000..94da7e7a
--- /dev/null
+++ b/debian/libqmf-tests.install
@@ -0,0 +1 @@
+usr/tests/* usr/tests/qmf/
diff --git a/debian/libqmf0.install b/debian/libqmf0.install
new file mode 100644
index 00000000..877827ec
--- /dev/null
+++ b/debian/libqmf0.install
@@ -0,0 +1,3 @@
+usr/lib/libsparql.so*
+usr/lib/libqtopiamail.so*
+usr/lib/libmessageserver.so*
diff --git a/debian/patches/0001-maemo_changes.diff b/debian/patches/0001-maemo_changes.diff
new file mode 100644
index 00000000..c3337f07
--- /dev/null
+++ b/debian/patches/0001-maemo_changes.diff
@@ -0,0 +1,7050 @@
+diff --git a/qmf.pro b/qmf.pro
+index cd9a51e..3415d8e 100644
+--- a/qmf.pro
++++ b/qmf.pro
+@@ -1,5 +1,6 @@
+ TEMPLATE = subdirs
+-SUBDIRS = src/libraries/qtopiamail \
++SUBDIRS = src/libraries/sparql \
++ src/libraries/qtopiamail \
+ src/libraries/messageserver \
+ src/libraries/qmfutil \
+ src/plugins/messageservices/imap \
+diff --git a/src/applications/qtmail/qtmail.pro b/src/applications/qtmail/qtmail.pro
+index 74c79bc..65be577 100644
+--- a/src/applications/qtmail/qtmail.pro
++++ b/src/applications/qtmail/qtmail.pro
+@@ -11,7 +11,11 @@ INCLUDEPATH += . ../../libraries/qtopiamail \
+ ../../libraries/qmfutil
+
+ LIBS += -L../../libraries/qtopiamail -lqtopiamail \
+- -L../../libraries/qmfutil -lqmfutil
++ -L../../libraries/qmfutil -lqmfutil
++
++QMAKE_LFLAGS += -Wl,-rpath,../../libraries/qtopiamail \
++ -Wl,-rpath,../../libraries/qmfutil \
++ -Wl,-rpath,../../libraries/sparql
+
+ HEADERS += foldermodel.h \
+ folderdelegate.h \
+diff --git a/src/libraries/messageserver/include/QMailAuthenticator b/src/libraries/messageserver/include/QMailAuthenticator
+new file mode 100644
+index 0000000..a1c5ba5
+--- /dev/null
++++ b/src/libraries/messageserver/include/QMailAuthenticator
+@@ -0,0 +1 @@
++#include "qmailauthenticator.h"
+diff --git a/src/libraries/messageserver/include/QMailMessageClassifier b/src/libraries/messageserver/include/QMailMessageClassifier
+new file mode 100644
+index 0000000..285ed1a
+--- /dev/null
++++ b/src/libraries/messageserver/include/QMailMessageClassifier
+@@ -0,0 +1 @@
++#include "qmailmessageclassifier.h"
+diff --git a/src/libraries/messageserver/include/QMailMessageService b/src/libraries/messageserver/include/QMailMessageService
+new file mode 100644
+index 0000000..8df572e
+--- /dev/null
++++ b/src/libraries/messageserver/include/QMailMessageService
+@@ -0,0 +1 @@
++#include "qmailmessageservice.h"
+diff --git a/src/libraries/messageserver/include/QMailMessageServiceConfigurator b/src/libraries/messageserver/include/QMailMessageServiceConfigurator
+new file mode 100644
+index 0000000..8df572e
+--- /dev/null
++++ b/src/libraries/messageserver/include/QMailMessageServiceConfigurator
+@@ -0,0 +1 @@
++#include "qmailmessageservice.h"
+diff --git a/src/libraries/messageserver/include/QMailMessageServiceEditor b/src/libraries/messageserver/include/QMailMessageServiceEditor
+new file mode 100644
+index 0000000..8df572e
+--- /dev/null
++++ b/src/libraries/messageserver/include/QMailMessageServiceEditor
+@@ -0,0 +1 @@
++#include "qmailmessageservice.h"
+diff --git a/src/libraries/messageserver/include/QMailMessageServiceFactory b/src/libraries/messageserver/include/QMailMessageServiceFactory
+new file mode 100644
+index 0000000..8df572e
+--- /dev/null
++++ b/src/libraries/messageserver/include/QMailMessageServiceFactory
+@@ -0,0 +1 @@
++#include "qmailmessageservice.h"
+diff --git a/src/libraries/messageserver/include/QMailMessageServicePlugin b/src/libraries/messageserver/include/QMailMessageServicePlugin
+new file mode 100644
+index 0000000..8df572e
+--- /dev/null
++++ b/src/libraries/messageserver/include/QMailMessageServicePlugin
+@@ -0,0 +1 @@
++#include "qmailmessageservice.h"
+diff --git a/src/libraries/messageserver/include/QMailMessageSink b/src/libraries/messageserver/include/QMailMessageSink
+new file mode 100644
+index 0000000..8df572e
+--- /dev/null
++++ b/src/libraries/messageserver/include/QMailMessageSink
+@@ -0,0 +1 @@
++#include "qmailmessageservice.h"
+diff --git a/src/libraries/messageserver/include/QMailMessageSource b/src/libraries/messageserver/include/QMailMessageSource
+new file mode 100644
+index 0000000..8df572e
+--- /dev/null
++++ b/src/libraries/messageserver/include/QMailMessageSource
+@@ -0,0 +1 @@
++#include "qmailmessageservice.h"
+diff --git a/src/libraries/messageserver/include/QMailServiceConfiguration b/src/libraries/messageserver/include/QMailServiceConfiguration
+new file mode 100644
+index 0000000..c6f8a6c
+--- /dev/null
++++ b/src/libraries/messageserver/include/QMailServiceConfiguration
+@@ -0,0 +1 @@
++#include "qmailserviceconfiguration.h"
+diff --git a/src/libraries/messageserver/include/QMailTransport b/src/libraries/messageserver/include/QMailTransport
+new file mode 100644
+index 0000000..1b390c9
+--- /dev/null
++++ b/src/libraries/messageserver/include/QMailTransport
+@@ -0,0 +1 @@
++#include "qmailtransport.h"
+diff --git a/src/libraries/messageserver/messageserver.pro b/src/libraries/messageserver/messageserver.pro
+index 2b02a7b..1677d4d 100644
+--- a/src/libraries/messageserver/messageserver.pro
++++ b/src/libraries/messageserver/messageserver.pro
+@@ -1,12 +1,10 @@
+ TEMPLATE = lib
+
+ TARGET = messageserver
+-target.path += $$QMF_INSTALL_ROOT/lib
+-INSTALLS += target
+
+ QT *= network
+
+-CONFIG += warn_on
++CONFIG += warn_on create_pc create_prl
+
+ DEPENDPATH += .
+
+@@ -27,3 +25,18 @@ SOURCES += qmailauthenticator.cpp \
+ qmailserviceconfiguration.cpp \
+ qmailstoreaccountfilter.cpp \
+ qmailtransport.cpp
++
++target.path += $$QMF_INSTALL_ROOT/lib
++INSTALLS += target
++
++# Install headers
++headers.files = $$HEADERS include/*
++headers.path = $$QMF_INSTALL_ROOT/include/qmf
++
++INSTALLS += headers
++
++# Install pkgconfig file
++QMAKE_PKGCONFIG_LIBDIR = $$target.path
++QMAKE_PKGCONFIG_INCDIR = $$headers.path
++QMAKE_PKGCONFIG_DESTDIR = pkgconfig
++
+diff --git a/src/libraries/qmfutil/include/QMailComposerFactory b/src/libraries/qmfutil/include/QMailComposerFactory
+new file mode 100644
+index 0000000..23b68f1
+--- /dev/null
++++ b/src/libraries/qmfutil/include/QMailComposerFactory
+@@ -0,0 +1 @@
++#include "qmailcomposer.h"
+\ No newline at end of file
+diff --git a/src/libraries/qmfutil/include/QMailComposerInterface b/src/libraries/qmfutil/include/QMailComposerInterface
+new file mode 100644
+index 0000000..23b68f1
+--- /dev/null
++++ b/src/libraries/qmfutil/include/QMailComposerInterface
+@@ -0,0 +1 @@
++#include "qmailcomposer.h"
+\ No newline at end of file
+diff --git a/src/libraries/qmfutil/include/QMailMessageDelegate b/src/libraries/qmfutil/include/QMailMessageDelegate
+new file mode 100644
+index 0000000..6d19eb2
+--- /dev/null
++++ b/src/libraries/qmfutil/include/QMailMessageDelegate
+@@ -0,0 +1 @@
++#include "qmailmessagedelegate.h"
+\ No newline at end of file
+diff --git a/src/libraries/qmfutil/include/QMailViewerFactory b/src/libraries/qmfutil/include/QMailViewerFactory
+new file mode 100644
+index 0000000..81a8bde
+--- /dev/null
++++ b/src/libraries/qmfutil/include/QMailViewerFactory
+@@ -0,0 +1 @@
++#include "qmailviewer.h"
+diff --git a/src/libraries/qmfutil/include/QMailViewerInterface b/src/libraries/qmfutil/include/QMailViewerInterface
+new file mode 100644
+index 0000000..dc9d052
+--- /dev/null
++++ b/src/libraries/qmfutil/include/QMailViewerInterface
+@@ -0,0 +1 @@
++#include "qmailviewer.h"
+\ No newline at end of file
+diff --git a/src/libraries/qmfutil/include/QtopiaHomeMailMessageDelegate b/src/libraries/qmfutil/include/QtopiaHomeMailMessageDelegate
+new file mode 100644
+index 0000000..6d19eb2
+--- /dev/null
++++ b/src/libraries/qmfutil/include/QtopiaHomeMailMessageDelegate
+@@ -0,0 +1 @@
++#include "qmailmessagedelegate.h"
+\ No newline at end of file
+diff --git a/src/libraries/qmfutil/qmfutil.pro b/src/libraries/qmfutil/qmfutil.pro
+index c58af12..c01a180 100644
+--- a/src/libraries/qmfutil/qmfutil.pro
++++ b/src/libraries/qmfutil/qmfutil.pro
+@@ -1,10 +1,8 @@
+ TEMPLATE = lib
+
+ TARGET = qmfutil
+-target.path += $$QMF_INSTALL_ROOT/lib
+-INSTALLS += target
+
+-CONFIG += warn_on
++CONFIG += warn_on create_pc create_prl
+
+ DEPENDPATH += .
+
+@@ -31,3 +29,18 @@ TRANSLATIONS += libqmfutil-ar.ts \
+ libqmfutil-pt_BR.ts \
+ libqmfutil-zh_CN.ts \
+ libqmfutil-zh_TW.ts
++
++target.path += $$QMF_INSTALL_ROOT/lib
++INSTALLS += target
++
++# Install headers
++headers.files = $$HEADERS include/*
++headers.path = $$QMF_INSTALL_ROOT/include/qmf
++
++INSTALLS += headers
++
++# Install pkgconfig file
++QMAKE_PKGCONFIG_LIBDIR = $$target.path
++QMAKE_PKGCONFIG_INCDIR = $$headers.path
++QMAKE_PKGCONFIG_DESTDIR = pkgconfig
++
+diff --git a/src/libraries/qtopiamail/include/MailId b/src/libraries/qtopiamail/include/MailId
+new file mode 100644
+index 0000000..e2db656
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/MailId
+@@ -0,0 +1 @@
++#include "qmailid.h"
+diff --git a/src/libraries/qtopiamail/include/QMailAccount b/src/libraries/qtopiamail/include/QMailAccount
+new file mode 100644
+index 0000000..e403614
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailAccount
+@@ -0,0 +1 @@
++#include "qmailaccount.h"
+diff --git a/src/libraries/qtopiamail/include/QMailAccountConfiguration b/src/libraries/qtopiamail/include/QMailAccountConfiguration
+new file mode 100644
+index 0000000..0631517
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailAccountConfiguration
+@@ -0,0 +1 @@
++#include "qmailaccountconfiguration.h"
+diff --git a/src/libraries/qtopiamail/include/QMailAccountId b/src/libraries/qtopiamail/include/QMailAccountId
+new file mode 100644
+index 0000000..e2db656
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailAccountId
+@@ -0,0 +1 @@
++#include "qmailid.h"
+diff --git a/src/libraries/qtopiamail/include/QMailAccountKey b/src/libraries/qtopiamail/include/QMailAccountKey
+new file mode 100644
+index 0000000..1c39992
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailAccountKey
+@@ -0,0 +1 @@
++#include "qmailaccountkey.h"
+diff --git a/src/libraries/qtopiamail/include/QMailAccountListModel b/src/libraries/qtopiamail/include/QMailAccountListModel
+new file mode 100644
+index 0000000..a9d6feb
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailAccountListModel
+@@ -0,0 +1 @@
++#include "qmailaccountlistmodel.h"
+diff --git a/src/libraries/qtopiamail/include/QMailAccountMessageSet b/src/libraries/qtopiamail/include/QMailAccountMessageSet
+new file mode 100644
+index 0000000..d8be240
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailAccountMessageSet
+@@ -0,0 +1 @@
++#include "qmailmessageset.h"
+diff --git a/src/libraries/qtopiamail/include/QMailAccountSortKey b/src/libraries/qtopiamail/include/QMailAccountSortKey
+new file mode 100644
+index 0000000..87a88f6
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailAccountSortKey
+@@ -0,0 +1 @@
++#include "qmailaccountsortkey.h"
+diff --git a/src/libraries/qtopiamail/include/QMailAddress b/src/libraries/qtopiamail/include/QMailAddress
+new file mode 100644
+index 0000000..80d6726
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailAddress
+@@ -0,0 +1 @@
++#include "qmailaddress.h"
+diff --git a/src/libraries/qtopiamail/include/QMailBase64Codec b/src/libraries/qtopiamail/include/QMailBase64Codec
+new file mode 100644
+index 0000000..1a908f2
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailBase64Codec
+@@ -0,0 +1 @@
++#include "qmailcodec.h"
+diff --git a/src/libraries/qtopiamail/include/QMailCodec b/src/libraries/qtopiamail/include/QMailCodec
+new file mode 100644
+index 0000000..1a908f2
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailCodec
+@@ -0,0 +1 @@
++#include "qmailcodec.h"
+diff --git a/src/libraries/qtopiamail/include/QMailContentManager b/src/libraries/qtopiamail/include/QMailContentManager
+new file mode 100644
+index 0000000..7c05cb5
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailContentManager
+@@ -0,0 +1 @@
++#include "qmailcontentmanager.h"
+diff --git a/src/libraries/qtopiamail/include/QMailContentManagerFactory b/src/libraries/qtopiamail/include/QMailContentManagerFactory
+new file mode 100644
+index 0000000..7c05cb5
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailContentManagerFactory
+@@ -0,0 +1 @@
++#include "qmailcontentmanager.h"
+diff --git a/src/libraries/qtopiamail/include/QMailContentManagerPlugin b/src/libraries/qtopiamail/include/QMailContentManagerPlugin
+new file mode 100644
+index 0000000..7c05cb5
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailContentManagerPlugin
+@@ -0,0 +1 @@
++#include "qmailcontentmanager.h"
+diff --git a/src/libraries/qtopiamail/include/QMailFilterMessageSet b/src/libraries/qtopiamail/include/QMailFilterMessageSet
+new file mode 100644
+index 0000000..d8be240
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailFilterMessageSet
+@@ -0,0 +1 @@
++#include "qmailmessageset.h"
+diff --git a/src/libraries/qtopiamail/include/QMailFolder b/src/libraries/qtopiamail/include/QMailFolder
+new file mode 100644
+index 0000000..cae2455
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailFolder
+@@ -0,0 +1 @@
++#include "qmailfolder.h"
+diff --git a/src/libraries/qtopiamail/include/QMailFolderId b/src/libraries/qtopiamail/include/QMailFolderId
+new file mode 100644
+index 0000000..e2db656
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailFolderId
+@@ -0,0 +1 @@
++#include "qmailid.h"
+diff --git a/src/libraries/qtopiamail/include/QMailFolderKey b/src/libraries/qtopiamail/include/QMailFolderKey
+new file mode 100644
+index 0000000..5effe63
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailFolderKey
+@@ -0,0 +1 @@
++#include "qmailfolderkey.h"
+diff --git a/src/libraries/qtopiamail/include/QMailFolderMessageSet b/src/libraries/qtopiamail/include/QMailFolderMessageSet
+new file mode 100644
+index 0000000..d8be240
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailFolderMessageSet
+@@ -0,0 +1 @@
++#include "qmailmessageset.h"
+diff --git a/src/libraries/qtopiamail/include/QMailFolderSortKey b/src/libraries/qtopiamail/include/QMailFolderSortKey
+new file mode 100644
+index 0000000..231dba5
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailFolderSortKey
+@@ -0,0 +1 @@
++#include "qmailfoldersortkey.h"
+diff --git a/src/libraries/qtopiamail/include/QMailLineEndingCodec b/src/libraries/qtopiamail/include/QMailLineEndingCodec
+new file mode 100644
+index 0000000..1a908f2
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailLineEndingCodec
+@@ -0,0 +1 @@
++#include "qmailcodec.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessage b/src/libraries/qtopiamail/include/QMailMessage
+new file mode 100644
+index 0000000..1f120e0
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessage
+@@ -0,0 +1 @@
++#include "qmailmessage.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageBody b/src/libraries/qtopiamail/include/QMailMessageBody
+new file mode 100644
+index 0000000..1f120e0
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageBody
+@@ -0,0 +1 @@
++#include "qmailmessage.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageContentDisposition b/src/libraries/qtopiamail/include/QMailMessageContentDisposition
+new file mode 100644
+index 0000000..1f120e0
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageContentDisposition
+@@ -0,0 +1 @@
++#include "qmailmessage.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageContentType b/src/libraries/qtopiamail/include/QMailMessageContentType
+new file mode 100644
+index 0000000..1f120e0
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageContentType
+@@ -0,0 +1 @@
++#include "qmailmessage.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageHeaderField b/src/libraries/qtopiamail/include/QMailMessageHeaderField
+new file mode 100644
+index 0000000..1f120e0
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageHeaderField
+@@ -0,0 +1 @@
++#include "qmailmessage.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageId b/src/libraries/qtopiamail/include/QMailMessageId
+new file mode 100644
+index 0000000..e2db656
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageId
+@@ -0,0 +1 @@
++#include "qmailid.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageKey b/src/libraries/qtopiamail/include/QMailMessageKey
+new file mode 100644
+index 0000000..06211f5
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageKey
+@@ -0,0 +1 @@
++#include "qmailmessagekey.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageListModel b/src/libraries/qtopiamail/include/QMailMessageListModel
+new file mode 100644
+index 0000000..5eb664a
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageListModel
+@@ -0,0 +1 @@
++#include "qmailmessagelistmodel.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageMetaData b/src/libraries/qtopiamail/include/QMailMessageMetaData
+new file mode 100644
+index 0000000..1f120e0
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageMetaData
+@@ -0,0 +1 @@
++#include "qmailmessage.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessagePart b/src/libraries/qtopiamail/include/QMailMessagePart
+new file mode 100644
+index 0000000..1f120e0
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessagePart
+@@ -0,0 +1 @@
++#include "qmailmessage.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessagePartContainer b/src/libraries/qtopiamail/include/QMailMessagePartContainer
+new file mode 100644
+index 0000000..1f120e0
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessagePartContainer
+@@ -0,0 +1 @@
++#include "qmailmessage.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageRemovalRecord b/src/libraries/qtopiamail/include/QMailMessageRemovalRecord
+new file mode 100644
+index 0000000..737bd83
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageRemovalRecord
+@@ -0,0 +1 @@
++#include "qmailmessageremovalrecord.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageServer b/src/libraries/qtopiamail/include/QMailMessageServer
+new file mode 100644
+index 0000000..5398cdc
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageServer
+@@ -0,0 +1 @@
++#include "qmailmessageserver.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageSet b/src/libraries/qtopiamail/include/QMailMessageSet
+new file mode 100644
+index 0000000..d8be240
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageSet
+@@ -0,0 +1 @@
++#include "qmailmessageset.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageSetContainer b/src/libraries/qtopiamail/include/QMailMessageSetContainer
+new file mode 100644
+index 0000000..d8be240
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageSetContainer
+@@ -0,0 +1 @@
++#include "qmailmessageset.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageSetModel b/src/libraries/qtopiamail/include/QMailMessageSetModel
+new file mode 100644
+index 0000000..d8be240
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageSetModel
+@@ -0,0 +1 @@
++#include "qmailmessageset.h"
+diff --git a/src/libraries/qtopiamail/include/QMailMessageSortKey b/src/libraries/qtopiamail/include/QMailMessageSortKey
+new file mode 100644
+index 0000000..b6f0399
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailMessageSortKey
+@@ -0,0 +1 @@
++#include "qmailmessagesortkey.h"
+diff --git a/src/libraries/qtopiamail/include/QMailNewEmailHandler b/src/libraries/qtopiamail/include/QMailNewEmailHandler
+new file mode 100644
+index 0000000..61db895
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailNewEmailHandler
+@@ -0,0 +1 @@
++#include "qmailnewmessagehandler.h"
+diff --git a/src/libraries/qtopiamail/include/QMailNewMessageHandler b/src/libraries/qtopiamail/include/QMailNewMessageHandler
+new file mode 100644
+index 0000000..61db895
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailNewMessageHandler
+@@ -0,0 +1 @@
++#include "qmailnewmessagehandler.h"
+diff --git a/src/libraries/qtopiamail/include/QMailPassThroughCodec b/src/libraries/qtopiamail/include/QMailPassThroughCodec
+new file mode 100644
+index 0000000..1a908f2
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailPassThroughCodec
+@@ -0,0 +1 @@
++#include "qmailcodec.h"
+diff --git a/src/libraries/qtopiamail/include/QMailQuotedPrintableCodec b/src/libraries/qtopiamail/include/QMailQuotedPrintableCodec
+new file mode 100644
+index 0000000..1a908f2
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailQuotedPrintableCodec
+@@ -0,0 +1 @@
++#include "qmailcodec.h"
+diff --git a/src/libraries/qtopiamail/include/QMailRetrievalAction b/src/libraries/qtopiamail/include/QMailRetrievalAction
+new file mode 100644
+index 0000000..cfbd6ca
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailRetrievalAction
+@@ -0,0 +1 @@
++#include "qmailserviceaction.h"
+diff --git a/src/libraries/qtopiamail/include/QMailSearchAction b/src/libraries/qtopiamail/include/QMailSearchAction
+new file mode 100644
+index 0000000..cfbd6ca
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailSearchAction
+@@ -0,0 +1 @@
++#include "qmailserviceaction.h"
+diff --git a/src/libraries/qtopiamail/include/QMailServiceAction b/src/libraries/qtopiamail/include/QMailServiceAction
+new file mode 100644
+index 0000000..cfbd6ca
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailServiceAction
+@@ -0,0 +1 @@
++#include "qmailserviceaction.h"
+diff --git a/src/libraries/qtopiamail/include/QMailStorageAction b/src/libraries/qtopiamail/include/QMailStorageAction
+new file mode 100644
+index 0000000..cfbd6ca
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailStorageAction
+@@ -0,0 +1 @@
++#include "qmailserviceaction.h"
+diff --git a/src/libraries/qtopiamail/include/QMailStore b/src/libraries/qtopiamail/include/QMailStore
+new file mode 100644
+index 0000000..217a7a7
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailStore
+@@ -0,0 +1 @@
++#include "qmailstore.h"
+diff --git a/src/libraries/qtopiamail/include/QMailTimeStamp b/src/libraries/qtopiamail/include/QMailTimeStamp
+new file mode 100644
+index 0000000..07bfe99
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailTimeStamp
+@@ -0,0 +1 @@
++#include "qmailtimestamp.h"
+diff --git a/src/libraries/qtopiamail/include/QMailTransmitAction b/src/libraries/qtopiamail/include/QMailTransmitAction
+new file mode 100644
+index 0000000..cfbd6ca
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QMailTransmitAction
+@@ -0,0 +1 @@
++#include "qmailserviceaction.h"
+diff --git a/src/libraries/qtopiamail/include/QPrivatelyImplemented b/src/libraries/qtopiamail/include/QPrivatelyImplemented
+new file mode 100644
+index 0000000..0b73b3b
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QPrivatelyImplemented
+@@ -0,0 +1 @@
++#include "qprivateimplementation.h"
+diff --git a/src/libraries/qtopiamail/include/QPrivatelyNoncopyable b/src/libraries/qtopiamail/include/QPrivatelyNoncopyable
+new file mode 100644
+index 0000000..0b73b3b
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/QPrivatelyNoncopyable
+@@ -0,0 +1 @@
++#include "qprivateimplementation.h"
+diff --git a/src/libraries/qtopiamail/include/ServiceConfiguration b/src/libraries/qtopiamail/include/ServiceConfiguration
+new file mode 100644
+index 0000000..0631517
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/ServiceConfiguration
+@@ -0,0 +1 @@
++#include "qmailaccountconfiguration.h"
+diff --git a/src/libraries/qtopiamail/include/Status b/src/libraries/qtopiamail/include/Status
+new file mode 100644
+index 0000000..cfbd6ca
+--- /dev/null
++++ b/src/libraries/qtopiamail/include/Status
+@@ -0,0 +1 @@
++#include "qmailserviceaction.h"
+diff --git a/src/libraries/qtopiamail/qmailstore.cpp b/src/libraries/qtopiamail/qmailstore.cpp
+index bc5fecc..992cafc 100644
+--- a/src/libraries/qtopiamail/qmailstore.cpp
++++ b/src/libraries/qtopiamail/qmailstore.cpp
+@@ -11,7 +11,12 @@
+ // Needed to give friend access to the function defined by Q_GLOBAL_STATIC
+ #define QMAILSTOREINSTANCE_DEFINED_HERE
+ #include "qmailstore.h"
++
++#ifndef SPARQL_STORE
+ #include "qmailstore_p.h"
++#else
++#include "qmailstore_sparql.h"
++#endif
+
+ /*!
+ \class QMailStore
+diff --git a/src/libraries/qtopiamail/qmailstore_sparql.cpp b/src/libraries/qtopiamail/qmailstore_sparql.cpp
+new file mode 100644
+index 0000000..132f0a7
+--- /dev/null
++++ b/src/libraries/qtopiamail/qmailstore_sparql.cpp
+@@ -0,0 +1,3314 @@
++/****************************************************************************
++**
++** This file is part of the $PACKAGE_NAME$.
++**
++** Copyright (C) $THISYEAR$ $COMPANY_NAME$.
++**
++** $QT_EXTENDED_DUAL_LICENSE$
++**
++****************************************************************************/
++
++#include "qmailstore_sparql.h"
++#include "qmailcontentmanager.h"
++#include "qmailmessageremovalrecord.h"
++#include "qmailtimestamp.h"
++#include "semaphore_p.h"
++#include "qmailnamespace.h"
++#include "qmaillog.h"
++#include <QTextCodec>
++#include <sys/types.h>
++#include <sys/ipc.h>
++#include <unistd.h>
++#include <time.h>
++#include <QFile>
++#include <QCoreApplication>
++#include <QDir>
++
++#include "sparqlquery.h"
++#include "sparqlresult.h"
++#include "sparqluri.h"
++
++
++#define Q_USE_SQLITE
++
++// When using GCC 4.1.1 on ARM, TR1 functional cannot be included when RTTI
++// is disabled, since it automatically instantiates some code using typeid().
++//#include <tr1/functional>
++//using std::tr1::bind;
++//using std::tr1::cref;
++#include "bind_p.h"
++
++using nonstd::tr1::bind;
++using nonstd::tr1::cref;
++
++
++namespace { // none of this code is externally visible:
++
++//using namespace QMailDataComparator;
++using namespace QMailKey;
++
++// We allow queries to be specified by supplying a list of message IDs against
++// which candidates will be matched; this list can become too large to be
++// expressed directly in SQL. Instead, we will build a temporary table to
++// match against when required...
++// The most IDs we can include in a query is currently 999; set an upper limit
++// below this to allow for other variables in the same query, bearing in mind
++// that there may be more than one clause containing this number of IDs in the
++// same query...
++const int IdLookupThreshold = 256;
++
++// Note on retry logic - it appears that SQLite3 will return a SQLITE_BUSY error (5)
++// whenever there is contention on file locks or mutexes, and that these occurrences
++// are not handled by the handler installed by either sqlite3_busy_timeout or
++// sqlite3_busy_handler. Furthermore, the comments for sqlite3_step state that if
++// the SQLITE_BUSY error is returned whilst in a transaction, the transaction should
++// be rolled back. Therefore, it appears that we must handle this error by retrying
++// at the QMailStore level, since this is the level where we perform transactions.
++const int Sqlite3BusyErrorNumber = 5;
++
++const int Sqlite3ConstraintErrorNumber = 19;
++
++
++// Helper class for automatic unlocking
++template<typename Mutex>
++class Guard
++{
++ Mutex &mutex;
++ bool locked;
++
++public:
++ enum { DefaultTimeout = 1000 };
++
++ Guard(Mutex& m)
++ : mutex(m),
++ locked(false)
++ {
++ }
++
++ ~Guard()
++ {
++ unlock();
++ }
++
++ bool lock(int timeout = DefaultTimeout)
++ {
++ return (locked = mutex.lock(timeout));
++ }
++
++ void unlock()
++ {
++ if (locked) {
++ mutex.unlock();
++ locked = false;
++ }
++ }
++};
++
++typedef Guard<ProcessMutex> MutexGuard;
++
++template <typename IdType>
++QVariantList idValueList(const QList<IdType>& ids)
++{
++ QVariantList values;
++
++ foreach (const IdType& id, ids)
++ values.append(QVariant(id.toULongLong()));
++
++ return values;
++}
++
++
++QString escape(const QString &original, const QChar &escapee, const QChar &escaper = '\\')
++{
++ QString result(original);
++ return result.replace(escapee, QString(escaper) + escapee);
++}
++
++QString unescape(const QString &original, const QChar &escapee, const QChar &escaper = '\\')
++{
++ QString result(original);
++ return result.replace(QString(escaper) + escapee, escapee);
++}
++
++QString contentUri(const QString &scheme, const QString &identifier)
++{
++ if (scheme.isEmpty())
++ return QString();
++
++ // Formulate a URI from the content scheme and identifier
++ return escape(scheme, ':') + ':' + escape(identifier, ':');
++}
++
++QString contentUri(const QMailMessageMetaData &message)
++{
++ return contentUri(message.contentScheme(), message.contentIdentifier());
++}
++
++QPair<QString, QString> uriElements(const QString &uri)
++{
++ int index = uri.indexOf(':');
++ while ((index != -1) && (uri.at(index - 1) == '\\'))
++ index = uri.indexOf(':', index + 1);
++
++ return qMakePair(unescape(uri.mid(0, index), ':'), unescape(uri.mid(index + 1), ':'));
++}
++
++const char *WellKnownUris[] = {
++ "qmf://groove.harmattan.com/email#",
++ "qmf://groove.nokia.com/folder#",
++ "qmf://groove.nokia.com/accounts#" };
++
++template <class T, int INDEX>
++class WellKnownUri : public SparqlUri
++{
++public:
++ WellKnownUri() : SparqlUri(WellKnownUris[INDEX]) {}
++ WellKnownUri(const T& id) : SparqlUri(WellKnownUris[INDEX], id.toULongLong()) {}
++ T id() const { return T(id()); }
++ operator T () { return id(); }
++};
++
++typedef WellKnownUri<QMailMessageId, 0> MailMessageUri;
++typedef WellKnownUri<QMailFolderId, 1> MailFolderUri;
++typedef WellKnownUri<QMailAccountId, 2> MailAccountUri;
++
++QString combineOperatorString(QMailKey::Combiner op)
++{
++ switch (op)
++ {
++ case And:
++ return " && ";
++ break;
++
++ case Or:
++ return " || ";
++ break;
++
++ case None:
++ break;
++ }
++
++ return QString();
++}
++
++QString operatorStringPattern(int argNumber, const QString& op, const QString& comp)
++{
++ QStringList pattern;
++ for (int i = 0; i<argNumber; i++)
++ pattern << "(%1 " + op + " %" + QString::number(i+2) + ")";
++
++ if (argNumber > 1)
++ return "(" + pattern.join(comp) + ")";
++ else
++ return pattern.join(comp);
++}
++
++template <class Comparator>
++QString operatorString(Comparator op, int argsNumber = 1);
++
++template <>
++QString operatorString<QMailKey::Comparator>(QMailKey::Comparator op, int argsNumber)
++{
++ switch (op)
++ {
++ case Equal:
++ // "(%1 = \"%2\")" : "(%1 = \"%2\") || (%1 = \"%3\")"
++ return (argsNumber == 1 ? operatorStringPattern(argsNumber, "=", "") : operatorStringPattern(argsNumber, "=", " || "));
++ break;
++
++ case NotEqual:
++ // "(%1 != \"%2\")" : "(%1 != \"%2\") && (%1 != \"%3\")"
++ return (argsNumber == 1 ? operatorStringPattern(argsNumber, "!=", "") : operatorStringPattern(argsNumber, "!=", " && "));
++ break;
++
++ case LessThan:
++ return "(%1 < %2)";
++ break;
++
++ case LessThanEqual:
++ return "(%1 <= %2)";
++ break;
++
++ case GreaterThan:
++ return "(%1 > %2)";
++ break;
++
++ case GreaterThanEqual:
++ return "(%1 >= %2)";
++ break;
++
++ case Includes:
++ case Present:
++ // "(%1 & \"%2\")" : "(%1 = \"%2\") || (%1 = \"%3\")"
++ return (argsNumber == 1 ? operatorStringPattern(argsNumber, "&", "") : operatorStringPattern(argsNumber, "=", " || "));
++ break;
++
++ case Excludes:
++ case Absent:
++ // "!(%1 & \"%2\")" : "(%1 != \"%2\") && (%1 != \"%3\")"
++ return (argsNumber == 1 ? "(!" + operatorStringPattern(argsNumber, "&", "") + ")": operatorStringPattern(argsNumber, "!=", " && "));
++ break;
++ }
++
++ return QString();
++}
++
++template <class Property>
++QString propertyNameString(Property property);
++
++template <>
++QString propertyNameString<QMailMessageKey::Property>(QMailMessageKey::Property property)
++{
++ switch (property)
++ {
++ case QMailMessageKey::Id:
++ return "?mail";
++
++ case QMailMessageKey::Type:
++ return "?type";
++
++ case QMailMessageKey::ParentFolderId:
++ return "?parentFolderId";
++
++ case QMailMessageKey::Sender:
++ return "?sender";
++
++ case QMailMessageKey::Recipients:
++ return "?recipients";
++
++ case QMailMessageKey::Subject:
++ return "?subject";
++
++ case QMailMessageKey::TimeStamp:
++ return "?timestamp";
++
++ case QMailMessageKey::Status:
++ return "?status";
++
++ case QMailMessageKey::Conversation:
++ return "?conversation";
++
++ case QMailMessageKey::ReceptionTimeStamp:
++ return "?receptionTimeStamp";
++
++ case QMailMessageKey::ServerUid:
++ return "?serverUid";
++
++ case QMailMessageKey::Size:
++ return "?size";
++
++ case QMailMessageKey::ParentAccountId:
++ return "?parentAccountId";
++
++ case QMailMessageKey::AncestorFolderIds:
++ return "?ancestorFolderIds";
++
++ case QMailMessageKey::ContentType:
++ return "?contentType";
++
++ case QMailMessageKey::PreviousParentFolderId:
++ return "?previousParentFolderId";
++
++ case QMailMessageKey::ContentScheme:
++ return "?contentScheme";
++
++ case QMailMessageKey::ContentIdentifier:
++ return "?contentIdentifier";
++
++ case QMailMessageKey::InResponseTo:
++ return "?inResponseTo";
++
++ case QMailMessageKey::ResponseType:
++ return "?responseType";
++
++ case QMailMessageKey::Custom:
++ return "?custom";
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString propertyNameString<QMailFolderKey::Property>(QMailFolderKey::Property property)
++{
++ switch (property)
++ {
++ case QMailFolderKey::Id:
++ return "?folder";
++
++ case QMailFolderKey::Path:
++ return "?path";
++
++ case QMailFolderKey::ParentFolderId:
++ return "?parentFolderId";
++
++ case QMailFolderKey::ParentAccountId:
++ return "?parentAccountId";
++
++ case QMailFolderKey::DisplayName:
++ return "?displayName";
++
++ case QMailFolderKey::Status:
++ return "?status";
++
++ case QMailFolderKey::AncestorFolderIds:
++ return "?ancestorFolderIds";
++
++ case QMailFolderKey::ServerCount:
++ return "?serverCount";
++
++ case QMailFolderKey::ServerUnreadCount:
++ return "?serverUnreadCount";
++
++ case QMailFolderKey::Custom:
++ return "?custom";
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString propertyNameString<QMailAccountKey::Property>(QMailAccountKey::Property property)
++{
++ switch (property)
++ {
++ case QMailAccountKey::Id:
++ return "?account";
++
++ case QMailAccountKey::Name:
++ return "?name";
++
++ case QMailAccountKey::MessageType:
++ return "?messageType";
++
++ case QMailAccountKey::FromAddress:
++ return "?fromAddress";
++
++ case QMailAccountKey::Status:
++ return "?status";
++
++ case QMailAccountKey::Custom:
++ return "?custom";
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString propertyNameString<QMailMessageSortKey::Property>(QMailMessageSortKey::Property property)
++{
++ switch (property)
++ {
++ case QMailMessageSortKey::Id:
++ return propertyNameString(QMailMessageKey::Id);
++
++ case QMailMessageSortKey::Type:
++ return propertyNameString(QMailMessageKey::Type);
++
++ case QMailMessageSortKey::ParentFolderId:
++ return propertyNameString(QMailMessageKey::ParentFolderId);
++
++ case QMailMessageSortKey::Sender:
++ return propertyNameString(QMailMessageKey::Sender);
++
++ case QMailMessageSortKey::Recipients:
++ return propertyNameString(QMailMessageKey::Recipients);
++
++ case QMailMessageSortKey::Subject:
++ return propertyNameString(QMailMessageKey::Subject);
++
++ case QMailMessageSortKey::TimeStamp:
++ return propertyNameString(QMailMessageKey::TimeStamp);
++
++ case QMailMessageSortKey::Status:
++ return propertyNameString(QMailMessageKey::Status);
++
++ case QMailMessageSortKey::ReceptionTimeStamp:
++ return propertyNameString(QMailMessageKey::ReceptionTimeStamp);
++
++ case QMailMessageSortKey::ServerUid:
++ return propertyNameString(QMailMessageKey::ServerUid);
++
++ case QMailMessageSortKey::Size:
++ return propertyNameString(QMailMessageKey::Size);
++
++ case QMailMessageSortKey::ParentAccountId:
++ return propertyNameString(QMailMessageKey::ParentAccountId);
++
++ case QMailMessageSortKey::ContentType:
++ return propertyNameString(QMailMessageKey::ContentType);
++
++ case QMailMessageSortKey::PreviousParentFolderId:
++ return propertyNameString(QMailMessageKey::PreviousParentFolderId);
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString propertyNameString<QMailFolderSortKey::Property>(QMailFolderSortKey::Property property)
++{
++ switch (property)
++ {
++ case QMailFolderSortKey::Id:
++ return propertyNameString(QMailFolderKey::Id);
++
++ case QMailFolderSortKey::Path:
++ return propertyNameString(QMailFolderKey::Path);
++
++ case QMailFolderSortKey::ParentFolderId:
++ return propertyNameString(QMailFolderKey::ParentFolderId);
++
++ case QMailFolderSortKey::ParentAccountId:
++ return propertyNameString(QMailFolderKey::ParentAccountId);
++
++ case QMailFolderSortKey::DisplayName:
++ return propertyNameString(QMailFolderKey::DisplayName);
++
++ case QMailFolderSortKey::Status:
++ return propertyNameString(QMailFolderKey::Status);
++
++ case QMailFolderSortKey::ServerCount:
++ return propertyNameString(QMailFolderKey::ServerCount);
++
++ case QMailFolderSortKey::ServerUnreadCount:
++ return propertyNameString(QMailFolderKey::ServerUnreadCount);
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString propertyNameString<QMailAccountSortKey::Property>(QMailAccountSortKey::Property property)
++{
++ switch (property)
++ {
++ case QMailAccountSortKey::Id:
++ return propertyNameString(QMailAccountKey::Id);
++
++ case QMailAccountSortKey::Name:
++ return propertyNameString(QMailAccountKey::Name);
++
++ case QMailAccountSortKey::MessageType:
++ return propertyNameString(QMailAccountKey::MessageType);
++
++ case QMailAccountSortKey::Status:
++ return propertyNameString(QMailAccountKey::Status);
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <class Property>
++QString sparqlPropertyStatmentString(const QString& uri, Property property);
++
++template <>
++QString sparqlPropertyStatmentString<QMailMessageKey::Property>(const QString& uri, QMailMessageKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailMessageKey::Id:
++ return QString();
++
++ case QMailMessageKey::Type:
++ return QString();
++
++ case QMailMessageKey::ParentFolderId:
++ return QString("%1 nie:isLogicalPartOf %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Sender:
++ return QString("%1 nmo:sender [ rdf:type nco:Contact ; nco:hasEmailAddress %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Recipients:
++ return QString("%1 nmo:recipient [ rdf:type nco:Contact ; nco:hasEmailAddress %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Subject:
++ return QString("%1 nmo:messageSubject %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::TimeStamp:
++ return QString("%1 nmo:sentDate %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Conversation:
++ return QString();
++
++ case QMailMessageKey::ReceptionTimeStamp:
++ return QString();
++
++ case QMailMessageKey::ServerUid:
++ return QString("%1 nmo:messageId %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Size:
++ return QString("%1 nie:contentSize %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::ParentAccountId:
++ return QString("%1 nie:relatedTo %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::AncestorFolderIds:
++ return QString();
++
++ case QMailMessageKey::ContentType:
++ return QString();
++
++ case QMailMessageKey::PreviousParentFolderId:
++ return QString();
++
++ case QMailMessageKey::ContentScheme:
++ return QString();
++
++ case QMailMessageKey::ContentIdentifier:
++ return QString("%1 nie:isStoredAs [ rdf:type nie:DataObject ; nie:dataSource %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::InResponseTo:
++ return QString("%1 nmo:inReplyTo %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::ResponseType:
++ return QString();
++
++ case QMailMessageKey::Custom:
++ return QString();
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString sparqlPropertyStatmentString<QMailFolderKey::Property>(const QString& uri, QMailFolderKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailFolderKey::Id:
++ return QString();
++
++ case QMailFolderKey::Path:
++ return QString("%1 nmo:folderName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::ParentFolderId:
++ return QString("%1 nie:isLogicalPartOf %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::ParentAccountId:
++ return QString("%1 nie:relatedTo %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::DisplayName:
++ return QString("%1 nmo:folderDisplayName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::AncestorFolderIds:
++ return QString();
++
++ case QMailFolderKey::ServerCount:
++ return QString("%1 nmo:serverCount %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::ServerUnreadCount:
++ return QString("%1 nmo:serverUnreadCount %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::Custom:
++ return QString();
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString sparqlPropertyStatmentString<QMailAccountKey::Property>(const QString& uri, QMailAccountKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailAccountKey::Id:
++ return QString("%1 rdf:type %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailAccountKey::Name:
++ return QString("%1 nmo:accountName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailAccountKey::MessageType:
++ return QString();
++
++ case QMailAccountKey::FromAddress:
++ return QString("%1 nmo:fromAddress [ rdf:type nco:EmailAddress ; nco:emailAddress %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailAccountKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailAccountKey::Custom:
++ return QString();
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString sparqlPropertyStatmentString<QMailMessageSortKey::Property>(const QString& uri, QMailMessageSortKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailMessageSortKey::Id:
++ return QString();
++
++ case QMailMessageSortKey::Type:
++ return QString();
++
++ case QMailMessageSortKey::ParentFolderId:
++ return QString("%1 nie:isLogicalPartOf %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::Sender:
++ return QString("%1 nmo:sender [ rdf:type nco:Contact ; nco:hasEmailAddress %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::Recipients:
++ return QString("%1 nmo:recipient [ rdf:type nco:Contact ; nco:hasEmailAddress %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::Subject:
++ return QString("%1 nmo:messageSubject %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::TimeStamp:
++ return QString("%1 nmo:sentDate %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::ReceptionTimeStamp:
++ return QString();
++
++ case QMailMessageSortKey::ServerUid:
++ return QString("%1 nmo:messageId %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::Size:
++ return QString("%1 nie:contentSize %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::ParentAccountId:
++ return QString("%1 nie:relatedTo %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::ContentType:
++ return QString();
++
++ case QMailMessageSortKey::PreviousParentFolderId:
++ return QString();
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString sparqlPropertyStatmentString<QMailFolderSortKey::Property>(const QString& uri, QMailFolderSortKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailFolderSortKey::Id:
++ return "id";
++
++ case QMailFolderSortKey::Path:
++ return QString("%1 nmo:folderName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::ParentFolderId:
++ return QString("%1 nie:isLogicalPartOf %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::ParentAccountId:
++ return QString("%1 nie:relatedTo %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::DisplayName:
++ return QString("%1 nmo:folderDisplayName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::ServerCount:
++ return QString("%1 nmo:serverCount %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::ServerUnreadCount:
++ return QString("%1 nmo:serverUnreadCount %2 .").arg(uri).arg(propertyNameString(property));
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString sparqlPropertyStatmentString<QMailAccountSortKey::Property>(const QString& uri, QMailAccountSortKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailAccountSortKey::Id:
++ return QString();
++
++ case QMailAccountSortKey::Name:
++ return QString("%1 nmo:accountName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailAccountSortKey::MessageType:
++ return QString();
++
++ case QMailAccountSortKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <class Key, class SortKey>
++QString keyStatment(const QString& uri, const Key& key, const SortKey& sort = SortKey())
++{
++ typedef typename Key::ArgumentType ArgumentType;
++ typedef typename SortKey::ArgumentType SortArgumentType;
++
++ QStringList arguments;
++ foreach (SortArgumentType argument, sort.arguments())
++ {
++ QString statement = sparqlPropertyStatmentString(uri, argument.first);
++ if (!statement.isEmpty() && !arguments.contains(statement))
++ arguments << statement;
++ }
++
++ foreach (ArgumentType argument, key.arguments())
++ {
++ QString statement = sparqlPropertyStatmentString(uri, argument.property);
++ if (!statement.isEmpty() && !arguments.contains(statement))
++ arguments << statement;
++ }
++
++ foreach (const Key& subkey, key.subKeys())
++ arguments << keyStatment(uri, subkey, SortKey());
++
++ return arguments.join("\n");
++}
++
++QString argumentValue(const QVariant& value)
++{
++ if (qVariantCanConvert<QMailAccountId>(value))
++ return MailAccountUri(qVariantValue<QMailAccountId>(value));
++ else if (qVariantCanConvert<QMailFolderId>(value))
++ return MailFolderUri(qVariantValue<QMailFolderId>(value));
++ else if (qVariantCanConvert<QMailMessageId>(value))
++ return MailMessageUri(qVariantValue<QMailMessageId>(value));
++ else if (qVariantCanConvert<QString>(value))
++ return qVariantValue<QString>(value);
++ else if (qVariantCanConvert<int>(value))
++ return QString::number(qVariantValue<int>(value));
++ else {
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <class ArgumentType>
++QString keyArgument(const ArgumentType& argument)
++{
++ typedef typename ArgumentType::Property Property;
++ typedef typename ArgumentType::Comparator Comparator;
++
++ QString pattern = operatorString(argument.op, argument.valueList.count());
++ pattern = pattern.arg(propertyNameString(argument.property));
++
++ foreach (QVariant value, argument.valueList)
++ pattern = pattern.arg(argumentValue(value));
++
++ return pattern;
++}
++
++template <class Key>
++QString keyFilter(const Key& key)
++{
++ typedef typename Key::ArgumentType ArgumentType;
++
++ QStringList arguments;
++ foreach (ArgumentType argument, key.arguments())
++ arguments << keyArgument<ArgumentType>(argument);
++
++ foreach (const Key& subkey, key.subKeys())
++ arguments << keyFilter<Key>(subkey);
++
++ QString filter = arguments.size() > 1 ? QString(key.isNegated() ? "!(%1)" : "(%1)") :
++ QString(key.isNegated() ? "!(%1)" : "%1");
++ return filter.arg(arguments.join(combineOperatorString(key.combiner())));
++}
++
++template <class SortKey>
++QString sortKey(const SortKey& sortKey)
++{
++ typedef typename SortKey::ArgumentType ArgumentType;
++
++ QString orderCondition;
++ foreach (ArgumentType argument, sortKey.arguments())
++ if (argument.second == Qt::AscendingOrder)
++ orderCondition += QString(" ASC(%1)").arg(propertyNameString(argument.first));
++ else
++ orderCondition += QString(" DESC(%1)").arg(propertyNameString(argument.first));
++
++ if (!orderCondition.isEmpty())
++ return QString("ORDER BY %1").arg(orderCondition);
++
++ return QString();
++}
++
++QString keyQuery(const QMailMessageKey& key, const QMailMessageSortKey& sort = QMailMessageSortKey())
++{
++ QString query = QString("SELECT %1 \n"
++ "WHERE { \n"
++ "%1 rdf:type nmo:Email . \n"
++ "%2"
++ "%3"
++ "} %4\n").arg(propertyNameString(QMailMessageKey::Id));
++
++ QString statement = keyStatment(propertyNameString(QMailMessageKey::Id), key, sort);
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter).arg(sortKey(sort));
++}
++
++QString keyQuery(const QMailFolderKey& key, const QMailFolderSortKey& sort = QMailFolderSortKey())
++{
++ QString query = QString("SELECT %1 \n"
++ "WHERE { \n"
++ "%1 rdf:type nmo:MailFolder . \n"
++ "%2"
++ "%3"
++ "} %4\n").arg(propertyNameString(QMailFolderKey::Id));
++
++ QString statement = keyStatment(propertyNameString(QMailFolderKey::Id), key, sort);
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter).arg(sortKey(sort));
++}
++
++QString keyQuery(const QMailAccountKey& key, const QMailAccountSortKey& sort = QMailAccountSortKey())
++{
++ QString query = QString("SELECT %1 \n"
++ "WHERE { \n"
++ "%1 rdf:type nmo:Mailbox . \n"
++ "%2"
++ "%3"
++ "} %4\n").arg(propertyNameString(QMailAccountKey::Id));
++
++ QString statement = keyStatment(propertyNameString(QMailAccountKey::Id), key, sort);
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter).arg(sortKey(sort));
++}
++
++QString keyCount(const QMailMessageKey& key)
++{
++ QString query("SELECT COUNT(?mail) AS count \n"
++ "WHERE { \n"
++ "?mail rdf:type nmo:Email . \n"
++ "%1"
++ "%2"
++ "}\n");
++
++ QString statement = keyStatment("?mail", key, QMailAccountSortKey());
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter);
++}
++
++QString keyCount(const QMailFolderKey& key)
++{
++ QString query("SELECT COUNT(?folder) AS count \n"
++ "WHERE { \n"
++ "?folder rdf:type nmo:MailFolder . \n"
++ "%1"
++ "%2"
++ "}\n");
++
++ QString statement = keyStatment("?folder", key, QMailAccountSortKey());
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter);
++}
++
++QString keyCount(const QMailAccountKey& key)
++{
++ QString query("SELECT COUNT(?account) AS count \n"
++ "WHERE { \n"
++ "?account rdf:type nmo:Mailbox . \n"
++ "%1"
++ "%2"
++ "}\n");
++
++ QString statement = keyStatment("?account", key, QMailAccountSortKey());
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter);
++}
++
++template <class Key>
++void debugKey(const Key& key)
++{
++ typedef typename Key::ArgumentType ArgumentType;
++
++ qDebug() << "Key Combiner:" << key.combiner();
++ qDebug() << "Key Is empty:" << key.isEmpty();
++ qDebug() << "Key Non Matching:" << key.isNonMatching();
++ qDebug() << "Key Is Negated:" << key.isNegated();
++
++ foreach (ArgumentType argument, key.arguments())
++ {
++ qDebug() << "Argument Property:" << argument.property;
++ qDebug() << "Argument Comparator:" << argument.op;
++ foreach (QVariant value, argument.valueList)
++ qDebug() << "Argument Value List:" << value;
++ }
++
++ foreach (const Key& subkey, key.subKeys())
++ debugKey(subkey);
++}
++
++QString nmoRecipients(const QList<QMailAddress>& recipients)
++{
++ QString result;
++ foreach (const QMailAddress& address, recipients)
++ {
++ QString triplet(QString(
++ " nmo:recipient [\n"
++ " rdf:type nco:Contact ;\n"
++ " nco:fullname \"%1\" ; \n"
++ " nco:hasEmailAddress <mailto:%2> ] ;\n")
++ .arg(address.name())
++ .arg(address.address()));
++ result.append(triplet);
++ }
++ return result;
++}
++
++template <class T>
++T IdFromUri(const QString& uri)
++{
++ int pos = uri.indexOf('#');
++ if (pos >= 0)
++ {
++ bool ok = false;
++ quint64 postfix = uri.right(uri.length() - pos-1).toULongLong(&ok);
++
++ if (ok)
++ return T(postfix);
++ }
++
++ return T();
++}
++
++} // namespace
++
++// We need to support recursive locking, per-process
++static volatile int mutexLockCount = 0;
++static volatile int readLockCount = 0;
++
++class QMailStorePrivate::Transaction
++{
++ QMailStorePrivate *m_d;
++ bool m_initted;
++ bool m_committed;
++
++public:
++ Transaction(QMailStorePrivate *);
++ ~Transaction();
++
++ bool commit();
++
++ bool committed() const;
++};
++
++QMailStorePrivate::Transaction::Transaction(QMailStorePrivate* d)
++ : m_d(d),
++ m_initted(false),
++ m_committed(false)
++{
++ if (mutexLockCount > 0) {
++ // Increase lock recursion depth
++ ++mutexLockCount;
++ m_initted = true;
++ } else {
++ // This process does not yet have a mutex lock
++ if (m_d->databaseMutex().lock(10000)) {
++ // Wait for any readers to complete
++ if (m_d->databaseReadLock().wait(10000)) {
++ ++mutexLockCount;
++ m_initted = true;
++ } else {
++ qWarning() << "Unable to wait for database read lock to reach zero!";
++ }
++
++ if (!m_initted) {
++ m_d->databaseMutex().unlock();
++ }
++ } else {
++ qWarning() << "Unable to lock database mutex for transaction!";
++ }
++ }
++}
++
++QMailStorePrivate::Transaction::~Transaction()
++{
++ if (m_initted && !m_committed) {
++
++ --mutexLockCount;
++ if (mutexLockCount == 0)
++ m_d->databaseMutex().unlock();
++ }
++}
++
++bool QMailStorePrivate::Transaction::commit()
++{
++ if (m_initted && !m_committed) {
++ // TBD: Pretend that we've
++ // commited that already.
++ m_committed = true;
++ --mutexLockCount;
++ if (mutexLockCount == 0)
++ m_d->databaseMutex().unlock();
++ }
++
++ return m_committed;
++}
++
++bool QMailStorePrivate::Transaction::committed() const
++{
++ return m_committed;
++}
++
++class QMailStorePrivate::ReadLock
++{
++ QMailStorePrivate *m_d;
++ bool m_locked;
++
++public:
++ ReadLock(QMailStorePrivate *);
++ ~ReadLock();
++};
++
++QMailStorePrivate::ReadLock::ReadLock(QMailStorePrivate* d)
++ : m_d(d),
++ m_locked(false)
++{
++ if (readLockCount > 0) {
++ // Increase lock recursion depth
++ ++readLockCount;
++ m_locked = true;
++ } else {
++ // This process does not yet have a read lock
++ // Lock the mutex to ensure no writers are active or waiting (unless we have already locked it)
++ if ((mutexLockCount > 0) || m_d->databaseMutex().lock(10000)) {
++ m_d->databaseReadLock().lock();
++ ++readLockCount;
++ m_locked = true;
++
++ if (mutexLockCount == 0)
++ m_d->databaseMutex().unlock();
++ } else {
++ qWarning() << "Unable to lock database mutex for read lock!";
++ }
++ }
++}
++
++QMailStorePrivate::ReadLock::~ReadLock()
++{
++ if (m_locked) {
++ --readLockCount;
++ if (readLockCount == 0)
++ m_d->databaseReadLock().unlock();
++ }
++}
++
++template<typename FunctionType>
++QMailStorePrivate::AttemptResult evaluate(QMailStorePrivate::WriteAccess, FunctionType func, const QString& description, QMailStorePrivate* d)
++{
++ QMailStorePrivate::Transaction t(d);
++
++ QMailStorePrivate::AttemptResult result = func(t);
++
++ // Ensure that the transaction was committed
++ if ((result == QMailStorePrivate::Success) && !t.committed()) {
++ qMailLog(Messaging) << ::getpid() << "Failed to commit successful" << qPrintable(description) << "!";
++ }
++
++ return result;
++}
++
++template<typename FunctionType>
++QMailStorePrivate::AttemptResult evaluate(QMailStorePrivate::ReadAccess, FunctionType func, const QString&, QMailStorePrivate* d)
++{
++ QMailStorePrivate::ReadLock l(d);
++
++ return func(l);
++}
++
++QMailStore::ErrorCode errorType(QMailStorePrivate::ReadAccess)
++{
++ return QMailStore::InvalidId;
++}
++
++QMailStore::ErrorCode errorType(QMailStorePrivate::WriteAccess)
++{
++ return QMailStore::ConstraintFailure;
++}
++
++// Properties of the mailmessages table
++static QMailStorePrivate::MessagePropertyMap messagePropertyMap()
++{
++ QMailStorePrivate::MessagePropertyMap map;
++
++ map.insert(QMailMessageKey::Id,"id");
++ map.insert(QMailMessageKey::Type,"type");
++ map.insert(QMailMessageKey::ParentFolderId,"parentfolderid");
++ map.insert(QMailMessageKey::Sender,"sender");
++ map.insert(QMailMessageKey::Recipients,"recipients");
++ map.insert(QMailMessageKey::Subject,"subject");
++ map.insert(QMailMessageKey::TimeStamp,"stamp");
++ map.insert(QMailMessageKey::ReceptionTimeStamp,"receivedstamp");
++ map.insert(QMailMessageKey::Status,"status");
++ map.insert(QMailMessageKey::ParentAccountId,"parentaccountid");
++ map.insert(QMailMessageKey::ServerUid,"serveruid");
++ map.insert(QMailMessageKey::Size,"size");
++ map.insert(QMailMessageKey::ContentType,"contenttype");
++ map.insert(QMailMessageKey::PreviousParentFolderId,"previousparentfolderid");
++ map.insert(QMailMessageKey::ContentScheme,"mailfile");
++ map.insert(QMailMessageKey::ContentIdentifier,"mailfile");
++ map.insert(QMailMessageKey::InResponseTo,"responseid");
++ map.insert(QMailMessageKey::ResponseType,"responsetype");
++
++ return map;
++}
++
++const QMailMessageKey::Properties &QMailStorePrivate::updatableMessageProperties()
++{
++ static QMailMessageKey::Properties p = QMailMessageKey::ParentFolderId |
++ QMailMessageKey::Type |
++ QMailMessageKey::Sender |
++ QMailMessageKey::Recipients |
++ QMailMessageKey::Subject |
++ QMailMessageKey::TimeStamp |
++ QMailMessageKey::ReceptionTimeStamp |
++ QMailMessageKey::Status |
++ QMailMessageKey::ParentAccountId |
++ QMailMessageKey::ServerUid |
++ QMailMessageKey::Size |
++ QMailMessageKey::ContentType |
++ QMailMessageKey::PreviousParentFolderId |
++ QMailMessageKey::ContentScheme |
++ QMailMessageKey::ContentIdentifier |
++ QMailMessageKey::InResponseTo |
++ QMailMessageKey::ResponseType;
++ return p;
++}
++
++const QMailMessageKey::Properties &QMailStorePrivate::allMessageProperties()
++{
++ static QMailMessageKey::Properties p = QMailMessageKey::Id | updatableMessageProperties();
++ return p;
++}
++
++const QMailStorePrivate::MessagePropertyMap& QMailStorePrivate::messagePropertyMap()
++{
++ static const MessagePropertyMap map(::messagePropertyMap());
++ return map;
++}
++
++const QMailStorePrivate::MessagePropertyList& QMailStorePrivate::messagePropertyList()
++{
++ static const MessagePropertyList list(messagePropertyMap().keys());
++ return list;
++}
++
++const QString &QMailStorePrivate::defaultContentScheme()
++{
++ static QString scheme(QMailContentManagerFactory::defaultScheme());
++ return scheme;
++}
++
++int QMailStorePrivate::pathIdentifier(const QString &filePath)
++{
++ return static_cast<int>(::ftok(filePath.toAscii(), 1));
++}
++
++int QMailStorePrivate::databaseIdentifier(int n) const
++{
++ // TBD: Find good file name for the SPARQL database
++ QString databasePath = QDir::homePath() + "/.cache/tracker/contents.db";
++ int result = static_cast<int>(::ftok(databasePath.toAscii(), n));
++ if (result == -1)
++ qFatal("Could not create database semaphore. Database could not be found.");
++ return result;
++}
++
++
++ProcessMutex* QMailStorePrivate::contentMutex = 0;
++
++QMailStorePrivate::QMailStorePrivate(QMailStore* parent)
++ : QMailStoreImplementation(parent),
++ headerCache(headerCacheSize),
++ folderCache(folderCacheSize),
++ accountCache(accountCacheSize),
++ inTransaction(false),
++ lastQueryError(0),
++ mutex(0)
++{
++ qDebug() << "QMailStorePrivate::QMailStorePrivate";
++ ProcessMutex creationMutex(pathIdentifier(QDir::rootPath()));
++ MutexGuard guard(creationMutex);
++ mutex = new ProcessMutex(databaseIdentifier(1));
++ readLock = new ProcessReadLock(databaseIdentifier(2));
++ if (contentMutex == 0) {
++ contentMutex = new ProcessMutex(databaseIdentifier(3));
++ }
++}
++
++QMailStorePrivate::~QMailStorePrivate()
++{
++ delete mutex;
++ delete readLock;
++}
++
++ProcessMutex& QMailStorePrivate::databaseMutex(void) const
++{
++ return *mutex;
++}
++
++ProcessReadLock& QMailStorePrivate::databaseReadLock(void) const
++{
++ return *readLock;
++}
++
++ProcessMutex& QMailStorePrivate::contentManagerMutex(void)
++{
++ return *contentMutex;
++}
++
++bool QMailStorePrivate::initStore()
++{
++ ProcessMutex creationMutex(pathIdentifier(QDir::rootPath()));
++ MutexGuard guard(creationMutex);
++ if (!guard.lock(1000)) {
++ return init;
++ }
++
++ if (sparqlDatabase.isOpenError()) {
++ qMailLog(Messaging) << "Unable to open database in initStore!";
++ return false;
++ }
++
++ if (!setupStandardFolder(QMailFolder::InboxFolder, tr("Inbox")) ||
++ !setupStandardFolder(QMailFolder::OutboxFolder, tr("Outbox")) ||
++ !setupStandardFolder(QMailFolder::DraftsFolder, tr("Drafts")) ||
++ !setupStandardFolder(QMailFolder::SentFolder, tr("Sent")) ||
++ !setupStandardFolder(QMailFolder::TrashFolder, tr("Trash"))) {
++ return false;
++ }
++
++ QMailAccount::initStore();
++ QMailFolder::initStore();
++ QMailMessage::initStore();
++
++ if (!QMailContentManagerFactory::init()) {
++ qMailLog(Messaging) << "Could not initialize content manager factory";
++ return false;
++ }
++
++ // We are now correctly initialized
++ init = true;
++ return true;
++}
++
++void QMailStorePrivate::clearContent()
++{
++ // Clear all caches
++ accountCache.clear();
++ folderCache.clear();
++ headerCache.clear();
++
++ // TBD: Drop all data
++
++ // Remove all content
++ QMailContentManagerFactory::clearContent();
++}
++
++void QMailStorePrivate::setQueryError(const SparqlQuery& query, const QString &description)
++{
++ QString s;
++ QTextStream ts(&s);
++
++ lastQueryError = query.error();
++
++ ts << qPrintable(description) << "; error:\"" << query.query() << '"';
++ qMailLog(Messaging) << "(" << ::getpid() << ")" << qPrintable(s);
++ qWarning() << qPrintable(s);
++}
++
++QString QMailStorePrivate::queryError() const
++{
++ return lastQueryError;
++}
++
++void QMailStorePrivate::clearQueryError(void)
++{
++ lastQueryError.clear();
++}
++
++bool QMailStorePrivate::uriExists(const QString& uri)
++{
++ // TBD: Check whether value exists already
++ Q_UNUSED(uri);
++ return false;
++}
++
++bool QMailStorePrivate::setupStandardFolder(enum QMailFolder::StandardFolder folder, const QString& name)
++{
++ MailFolderUri folderUri(QMailFolderId((int)folder));
++ MailFolderUri parentFolderUri(QMailFolderId(0));
++ MailAccountUri parentAccountUri(QMailAccountId(0));
++
++ SparqlQuery query(SparqlQuery::UpdateQuery);
++ query.prepare(QString(
++ "INSERT { \n"
++ "%1 rdf:type nmo:MailFolder ; \n"
++ " nmo:folderName \"%2\" ; \n"
++ " nie:isLogicalPartOf %3 ; \n"
++ " nie:relatedTo %4 ; \n"
++ " nmo:folderDisplayName \"%5\" ; \n"
++ " nmo:status \"%6\"^^xsd:integer ; \n"
++ " nmo:serverCount \"%7\"^^xsd:integer ; \n"
++ " nmo:serverUnreadCount \"%8\"^^xsd:integet . \n"
++ "}").arg(folderUri.uri())
++ .arg(name)
++ .arg(parentFolderUri.uri())
++ .arg(parentAccountUri.uri())
++ .arg(0)
++ .arg(0)
++ .arg(0)
++ .arg(0));
++
++ // TBD: Add custom fields later
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return false;
++ }
++
++ qDebug() << "Query succeeded";
++
++ // TBD: Update folder links also
++ return true;
++}
++
++QMailAccount QMailStorePrivate::extractAccount(const QMailAccountId& id, const QStringList& list)
++{
++ QMailAccount account;
++
++ // Load account data
++ account.setId(id);
++ account.setName(list.at(0));
++ /* account.setStatus(list.at(1).toULongLong()); */
++ account.setSignature(list.at(1));
++ account.setFromAddress(QMailAddress(list.at(2)));
++
++ return account;
++}
++
++QMailFolder QMailStorePrivate::extractFolder(const QMailFolderId& id, const QStringList& list)
++{
++ // Load folder data
++ QMailFolder folder(list.at(0), IdFromUri<QMailFolderId>(list.at(1)), IdFromUri<QMailAccountId>(list.at(2)));
++
++ folder.setId(id);
++ folder.setDisplayName(list.at(3));
++// folder.setStatus(list.at(4).toULongLong());
++// folder.setServerCount(list.at(5).toUInt());
++// folder.setServerUnreadCount(list.at(6).toUInt());
++
++ return folder;
++}
++
++void QMailStorePrivate::extractMessageMetaData(const QStringList& list, QMailMessageMetaData* metaData)
++{
++ // Load message properties
++
++ metaData->setParentFolderId(IdFromUri<QMailFolderId>(list.at(0)));
++ metaData->setFrom(QMailAddress(list.at(1), list.at(2)));
++ metaData->setSubject(list.at(3));
++ metaData->setDate(QMailTimeStamp(list.at(4)));
++ metaData->setStatus(list.at(5).toULongLong());
++ metaData->setParentAccountId(IdFromUri<QMailAccountId>(list.at(6)));
++ metaData->setServerUid(list.at(10));
++ metaData->setSize(list.at(9).toUInt());
++ metaData->setContent((QMailMessageMetaDataFwd::ContentType)list.at(10).toInt());
++ metaData->setInResponseTo(QMailMessageId(IdFromUri<QMailMessageId>(list.at(11))));
++ metaData->setResponseType((QMailMessageMetaDataFwd::ResponseType)list.at(12).toInt());
++ metaData->setReceivedDate(QMailTimeStamp(list.at(13)));
++
++ metaData->setUnmodified();
++}
++
++bool QMailStorePrivate::addAccount(QMailAccount *account, QMailAccountConfiguration *config,
++ QMailAccountIdList *addedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptAddAccount, this,
++ account, config,
++ addedAccountIds),
++ "addAccount");
++}
++
++bool QMailStorePrivate::addFolder(QMailFolder *folder,
++ QMailFolderIdList *addedFolderIds, QMailAccountIdList *modifiedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptAddFolder, this,
++ folder,
++ addedFolderIds, modifiedAccountIds),
++ "addFolder");
++}
++
++bool QMailStorePrivate::addMessage(QMailMessage *message,
++ QMailMessageIdList *addedMessageIds, QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds)
++{
++ if (!message->parentAccountId().isValid()) {
++ // Require a parent account - possibly relax this later
++ qMailLog(Messaging) << "Unable to add message without parent account";
++ return false;
++ }
++
++ if (message->contentScheme().isEmpty()) {
++ // Use the default storage scheme
++ message->setContentScheme(defaultContentScheme());
++ }
++
++ MutexGuard lock(contentManagerMutex());
++ if (!lock.lock(1000)) {
++ qMailLog(Messaging) << "Unable to acquire message body mutex in addMessage!";
++ return false;
++ }
++
++ if (QMailContentManager *contentManager = QMailContentManagerFactory::create(message->contentScheme())) {
++ QMailStore::ErrorCode code = contentManager->add(message);
++ if (code != QMailStore::NoError) {
++ setLastError(code);
++ qMailLog(Messaging) << "Unable to add message content to URI:" << ::contentUri(*message);
++ return false;
++ }
++
++ if (!addMessage(static_cast<QMailMessageMetaData*>(message), updatedMessageIds, addedMessageIds, modifiedFolderIds, modifiedAccountIds)) {
++ QMailStore::ErrorCode code = contentManager->remove(message->contentIdentifier());
++ if (code != QMailStore::NoError) {
++ setLastError(code);
++ qMailLog(Messaging) << "Could not remove extraneous message content:" << ::contentUri(*message);
++ }
++
++ return false;
++ }
++ } else {
++ qMailLog(Messaging) << "Unable to create content manager for scheme:" << message->contentScheme();
++ return false;
++ }
++
++ return true;
++}
++
++bool QMailStorePrivate::addMessage(QMailMessageMetaData *metaData,
++ QMailMessageIdList *addedMessageIds, QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptAddMessage, this,
++ metaData,
++ addedMessageIds, modifiedFolderIds, modifiedAccountIds),
++ "addMessage");
++}
++
++bool QMailStorePrivate::removeAccounts(const QMailAccountKey &key,
++ QMailAccountIdList *deletedAccounts, QMailFolderIdList *deletedFolders, QMailMessageIdList *deletedMessages, QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptRemoveAccounts, this,
++ cref(key),
++ deletedAccounts, deletedFolders, deletedMessages),
++ "removeAccounts");
++}
++
++bool QMailStorePrivate::removeFolders(const QMailFolderKey &key, QMailStore::MessageRemovalOption option,
++ QMailFolderIdList *deletedFolders, QMailMessageIdList *deletedMessages, QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptRemoveFolders, this,
++ cref(key), option,
++ deletedFolders, deletedMessages, modifiedAccountIds),
++ "removeFolders");
++}
++
++bool QMailStorePrivate::removeMessages(const QMailMessageKey &key, QMailStore::MessageRemovalOption option,
++ QMailMessageIdList *deletedMessages, QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptRemoveMessages, this,
++ cref(key), option,
++ deletedMessages, modifiedAccountIds, modifiedFolderIds),
++ "removeMessages");
++}
++
++bool QMailStorePrivate::updateAccount(QMailAccount *account, QMailAccountConfiguration *config,
++ QMailAccountIdList *updatedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptUpdateAccount, this,
++ account, config,
++ updatedAccountIds),
++ "updateAccount");
++}
++
++bool QMailStorePrivate::updateAccountConfiguration(QMailAccountConfiguration *config,
++ QMailAccountIdList *updatedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptUpdateAccount, this,
++ reinterpret_cast<QMailAccount*>(0), config,
++ updatedAccountIds),
++ "updateAccount");
++}
++
++bool QMailStorePrivate::updateFolder(QMailFolder *folder,
++ QMailFolderIdList *updatedFolderIds, QMailAccountIdList *modifiedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptUpdateFolder, this,
++ folder,
++ updatedFolderIds, modifiedAccountIds),
++ "updateFolder");
++}
++
++bool QMailStorePrivate::updateMessage(QMailMessageMetaData *metaData, QMailMessage *message,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds, bool *modifiedContent)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptUpdateMessage, this,
++ metaData, message,
++ updatedMessageIds, modifiedFolderIds, modifiedAccountIds, modifiedContent),
++ "updateMessage");
++}
++
++bool QMailStorePrivate::updateMessagesMetaData(const QMailMessageKey &key, const QMailMessageKey::Properties &properties, const QMailMessageMetaData &data,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptUpdateMessagesMetaData, this,
++ cref(key), cref(properties), cref(data),
++ updatedMessageIds, modifiedFolderIds, modifiedAccountIds),
++ "updateMessagesMetaData");
++}
++
++bool QMailStorePrivate::updateMessagesMetaData(const QMailMessageKey &key, quint64 status, bool set,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptUpdateMessagesStatus, this,
++ cref(key), status, set,
++ updatedMessageIds, modifiedFolderIds, modifiedAccountIds),
++ "updateMessagesMetaData"); // not 'updateMessagesStatus', due to function name exported by QMailStore
++}
++
++bool QMailStorePrivate::restoreToPreviousFolder(const QMailMessageKey &key,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptRestoreToPreviousFolder, this,
++ cref(key),
++ updatedMessageIds, modifiedFolderIds, modifiedAccountIds),
++ "restoreToPreviousFolder");
++}
++
++bool QMailStorePrivate::purgeMessageRemovalRecords(const QMailAccountId &accountId, const QStringList &serverUids)
++{
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptPurgeMessageRemovalRecords, this,
++ cref(accountId), cref(serverUids)),
++ "purgeMessageRemovalRecords");
++}
++
++int QMailStorePrivate::countAccounts(const QMailAccountKey &key) const
++{
++ int result(0);
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptCountAccounts, const_cast<QMailStorePrivate*>(this),
++ cref(key), &result),
++ "countAccounts");
++ return result;
++}
++
++int QMailStorePrivate::countFolders(const QMailFolderKey &key) const
++{
++ int result(0);
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptCountFolders, const_cast<QMailStorePrivate*>(this),
++ cref(key), &result),
++ "countFolders");
++ return result;
++}
++
++int QMailStorePrivate::countMessages(const QMailMessageKey &key) const
++{
++ int result(0);
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptCountMessages, const_cast<QMailStorePrivate*>(this),
++ cref(key), &result),
++ "countMessages");
++ return result;
++}
++
++int QMailStorePrivate::sizeOfMessages(const QMailMessageKey &key) const
++{
++ int result(0);
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptSizeOfMessages, const_cast<QMailStorePrivate*>(this),
++ cref(key), &result),
++ "sizeOfMessages");
++ return result;
++}
++
++QMailAccountIdList QMailStorePrivate::queryAccounts(const QMailAccountKey &key, const QMailAccountSortKey &sortKey) const
++{
++ QMailAccountIdList ids;
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptQueryAccounts, const_cast<QMailStorePrivate*>(this),
++ cref(key), cref(sortKey), &ids),
++ "queryAccounts");
++ return ids;
++}
++
++QMailFolderIdList QMailStorePrivate::queryFolders(const QMailFolderKey &key, const QMailFolderSortKey &sortKey) const
++{
++ QMailFolderIdList ids;
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptQueryFolders, const_cast<QMailStorePrivate*>(this),
++ cref(key), cref(sortKey), &ids),
++ "queryFolders");
++ return ids;
++}
++
++QMailMessageIdList QMailStorePrivate::queryMessages(const QMailMessageKey &key, const QMailMessageSortKey &sortKey) const
++{
++ QMailMessageIdList ids;
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptQueryMessages, const_cast<QMailStorePrivate*>(this),
++ cref(key), cref(sortKey), &ids),
++ "queryMessages");
++ return ids;
++}
++
++QMailAccount QMailStorePrivate::account(const QMailAccountId &id) const
++{
++ if (accountCache.contains(id))
++ return accountCache.lookup(id);
++
++ QMailAccount account;
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptAccount, const_cast<QMailStorePrivate*>(this),
++ cref(id), &account),
++ "account");
++ return account;
++}
++
++QMailAccountConfiguration QMailStorePrivate::accountConfiguration(const QMailAccountId &id) const
++{
++ QMailAccountConfiguration config;
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptAccountConfiguration, const_cast<QMailStorePrivate*>(this),
++ cref(id), &config),
++ "accountConfiguration");
++ return config;
++}
++
++QMailFolder QMailStorePrivate::folder(const QMailFolderId &id) const
++{
++ if (folderCache.contains(id))
++ return folderCache.lookup(id);
++
++ QMailFolder folder;
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptFolder, const_cast<QMailStorePrivate*>(this),
++ cref(id), &folder),
++ "folder");
++ return folder;
++}
++
++QMailMessage QMailStorePrivate::message(const QMailMessageId &id) const
++{
++ // Resolve from overloaded member functions:
++ AttemptResult (QMailStorePrivate::*func)(const QMailMessageId&, QMailMessage*, ReadLock&) = &QMailStorePrivate::attemptMessage;
++
++ QMailMessage msg;
++ repeatedly<ReadAccess>(bind(func, const_cast<QMailStorePrivate*>(this),
++ cref(id), &msg),
++ "message(id)");
++ return msg;
++}
++
++QMailMessage QMailStorePrivate::message(const QString &uid, const QMailAccountId &accountId) const
++{
++ // Resolve from overloaded member functions:
++ AttemptResult (QMailStorePrivate::*func)(const QString&, const QMailAccountId&, QMailMessage*, ReadLock&) = &QMailStorePrivate::attemptMessage;
++
++ QMailMessage msg;
++ repeatedly<ReadAccess>(bind(func, const_cast<QMailStorePrivate*>(this),
++ cref(uid), cref(accountId), &msg),
++ "message(uid, accountId)");
++ return msg;
++}
++
++QMailMessageMetaData QMailStorePrivate::messageMetaData(const QMailMessageId &id) const
++{
++ if (headerCache.contains(id))
++ return headerCache.lookup(id);
++
++ //if not in the cache, then preload the cache with the id and its most likely requested siblings
++ preloadHeaderCache(id);
++
++ return headerCache.lookup(id);
++}
++
++QMailMessageMetaData QMailStorePrivate::messageMetaData(const QString &uid, const QMailAccountId &accountId) const
++{
++ QMailMessageKey uidKey(QMailMessageKey::serverUid(uid));
++ QMailMessageKey accountKey(QMailMessageKey::parentAccountId(accountId));
++
++ QMailMessageMetaDataList results = messagesMetaData(uidKey & accountKey, allMessageProperties(), QMailStore::ReturnAll);
++ if (!results.isEmpty()) {
++ if (results.count() > 1){
++ qMailLog(Messaging) << "Warning, messageMetaData by uid returned more than 1 result";
++ }
++
++ headerCache.insert(results.first());
++ return results.first();
++ }
++
++ return QMailMessageMetaData();
++}
++
++QMailMessageMetaDataList QMailStorePrivate::messagesMetaData(const QMailMessageKey &key, const QMailMessageKey::Properties &properties, QMailStore::ReturnOption option) const
++{
++ QMailMessageMetaDataList metaData;
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptMessagesMetaData, const_cast<QMailStorePrivate*>(this),
++ cref(key), cref(properties), option, &metaData),
++ "messagesMetaData");
++ return metaData;
++}
++
++QMailMessageRemovalRecordList QMailStorePrivate::messageRemovalRecords(const QMailAccountId &accountId, const QMailFolderId &folderId) const
++{
++ QMailMessageRemovalRecordList removalRecords;
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptMessageRemovalRecords, const_cast<QMailStorePrivate*>(this),
++ cref(accountId), cref(folderId), &removalRecords),
++ "messageRemovalRecords(accountId, folderId)");
++ return removalRecords;
++}
++
++bool QMailStorePrivate::registerAccountStatusFlag(const QString &name)
++{
++ if (accountStatusMask(name) != 0)
++ return true;
++
++ static const QString context("accountstatus");
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptRegisterStatusBit, this,
++ cref(name), cref(context), 64),
++ "registerAccountStatusBit");
++}
++
++quint64 QMailStorePrivate::accountStatusMask(const QString &name) const
++{
++ static QMap<QString, quint64> statusMap;
++ static const QString context("accountstatus");
++
++ return queryStatusMap(name, context, statusMap);
++}
++
++bool QMailStorePrivate::registerFolderStatusFlag(const QString &name)
++{
++ if (folderStatusMask(name) != 0)
++ return true;
++
++ static const QString context("folderstatus");
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptRegisterStatusBit, this,
++ cref(name), cref(context), 64),
++ "registerFolderStatusBit");
++}
++
++quint64 QMailStorePrivate::folderStatusMask(const QString &name) const
++{
++ static QMap<QString, quint64> statusMap;
++ static const QString context("folderstatus");
++
++ return queryStatusMap(name, context, statusMap);
++}
++
++bool QMailStorePrivate::registerMessageStatusFlag(const QString &name)
++{
++ if (messageStatusMask(name) != 0)
++ return true;
++
++ static const QString context("messagestatus");
++ return repeatedly<WriteAccess>(bind(&QMailStorePrivate::attemptRegisterStatusBit, this,
++ cref(name), cref(context), 64),
++ "registerMessageStatusBit");
++}
++
++quint64 QMailStorePrivate::messageStatusMask(const QString &name) const
++{
++ static QMap<QString, quint64> statusMap;
++ static const QString context("messagestatus");
++
++ return queryStatusMap(name, context, statusMap);
++}
++
++quint64 QMailStorePrivate::queryStatusMap(const QString &name, const QString &context, QMap<QString, quint64> &map) const
++{
++ QMap<QString, quint64>::const_iterator it = map.find(name);
++ if (it != map.end())
++ return it.value();
++
++ int result(0);
++ repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptStatusBit, const_cast<QMailStorePrivate*>(this),
++ cref(name), cref(context), &result),
++ "folderStatusMask");
++ if (result == 0)
++ return 0;
++
++ quint64 maskValue = (1 << (result - 1));
++ map[name] = maskValue;
++ return maskValue;
++}
++
++QMailFolderIdList QMailStorePrivate::folderAncestorIds(const QMailFolderIdList& ids, bool inTransaction, AttemptResult *result) const
++{
++ QMailFolderIdList ancestorIds;
++
++ QMailStorePrivate *self(const_cast<QMailStorePrivate*>(this));
++ if (inTransaction) {
++ // We can't retry this query after a busy error if we're in a transaction
++ ReadLock l(self);
++ *result = self->attemptFolderAncestorIds(ids, &ancestorIds, l);
++ } else {
++ bool ok = repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptFolderAncestorIds, self,
++ cref(ids), &ancestorIds),
++ "folderAncestorIds");
++ if (result)
++ *result = ok ? Success : Failure;
++ }
++
++ return ancestorIds;
++}
++
++void QMailStorePrivate::removeExpiredData(const QMailMessageIdList& messageIds, const QStringList& contentUris, const QMailFolderIdList& folderIds, const QMailAccountIdList& accountIds)
++{
++ foreach (const QMailMessageId& id, messageIds) {
++ headerCache.remove(id);
++ }
++
++ {
++ MutexGuard lock(contentManagerMutex());
++ if (!lock.lock(1000)) {
++ qMailLog(Messaging) << "Unable to acquire message body mutex in removeExpiredData!";
++ } else {
++ foreach (const QString& contentUri, contentUris) {
++ QPair<QString, QString> elements(::uriElements(contentUri));
++
++ if (QMailContentManager *contentManager = QMailContentManagerFactory::create(elements.first)) {
++ QMailStore::ErrorCode code = contentManager->remove(elements.second);
++ if (code != QMailStore::NoError) {
++ setLastError(code);
++ qMailLog(Messaging) << "Unable to remove expired message content:" << contentUri;
++ continue;
++ }
++ } else {
++ qMailLog(Messaging) << "Unable to create content manager for scheme:" << elements.first;
++ continue;
++ }
++ }
++ }
++ }
++
++ foreach (const QMailFolderId& id, folderIds) {
++ folderCache.remove(id);
++ }
++
++ foreach (const QMailAccountId& id, accountIds) {
++ accountCache.remove(id);
++ }
++}
++
++template<typename AccessType, typename FunctionType>
++bool QMailStorePrivate::repeatedly(FunctionType func, const QString &description) const
++{
++ static const unsigned int MinRetryDelay = 64;
++ static const unsigned int MaxRetryDelay = 2048;
++ static const unsigned int MaxAttempts = 10;
++
++ // This function calls the supplied function repeatedly, retrying whenever it
++ // returns the DatabaseFailure result and the database's last error is SQLITE_BUSY.
++ // It sleeps between repeated attempts, for increasing amounts of time.
++ // The argument should be an object allowing nullary invocation returning an
++ // AttemptResult value, created with tr1::bind if necessary.
++
++ unsigned int attemptCount = 0;
++ unsigned int delay = MinRetryDelay;
++
++ while (true) {
++ AttemptResult result = evaluate(AccessType(), func, description, const_cast<QMailStorePrivate*>(this));
++
++ if (result == Success) {
++ if (attemptCount > 0) {
++ qMailLog(Messaging) << ::getpid() << "Able to" << qPrintable(description) << "after" << attemptCount << "failed attempts";
++ }
++ return true;
++ } else if (result == Failure) {
++ qMailLog(Messaging) << ::getpid() << "Unable to" << qPrintable(description);
++ if (lastError() == QMailStore::NoError) {
++ setLastError(errorType(AccessType()));
++ }
++ return false;
++ } else {
++ // result == DatabaseFailure
++ if (queryError() == "Sqlite3BusyErrorNumber") {
++ if (attemptCount < MaxAttempts) {
++ qMailLog(Messaging) << ::getpid() << "Failed to" << qPrintable(description) << "- busy, pausing to retry";
++
++ // Pause before we retry
++ QMail::usleep(delay * 1000);
++ if (delay < MaxRetryDelay)
++ delay *= 2;
++
++ ++attemptCount;
++ } else {
++ qMailLog(Messaging) << ::getpid() << "Retry count exceeded - failed to" << qPrintable(description);
++ break;
++ }
++ } else if (queryError() == "Sqlite3ConstraintErrorNumber") {
++ qMailLog(Messaging) << ::getpid() << "Unable to" << qPrintable(description) << "- constraint failure";
++ setLastError(QMailStore::ConstraintFailure);
++ break;
++ } else {
++ qMailLog(Messaging) << ::getpid() << "Unable to" << qPrintable(description) << "- code:" << queryError();
++ break;
++ }
++ }
++ }
++
++ // We experienced a database-related failure
++ if (lastError() == QMailStore::NoError) {
++ setLastError(QMailStore::FrameworkFault);
++ }
++ return false;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::addCustomFields(quint64 id, const QMap<QString, QString> &fields)
++{
++ if (!fields.isEmpty()) {
++ QVariantList customFields;
++ QVariantList customValues;
++
++ // Insert any custom fields belonging to this account
++ QMap<QString, QString>::const_iterator it = fields.begin(), end = fields.end();
++ for ( ; it != end; ++it) {
++ customFields.append(QVariant(it.key()));
++ customValues.append(QVariant(it.value()));
++ }
++ // TBD: Add custom fields
++ Q_UNUSED(id);
++ }
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::updateCustomFields(quint64 id, const QMap<QString, QString> &fields)
++{
++ QMap<QString, QString> existing;
++
++ {
++ // Find the existing fields
++ // TBD: Put actual code here
++ Q_UNUSED(id);
++ }
++
++ QVariantList obsoleteFields;
++ QVariantList modifiedFields;
++ QVariantList modifiedValues;
++ QVariantList addedFields;
++ QVariantList addedValues;
++
++ // Compare the sets
++ QMap<QString, QString>::const_iterator fend = fields.end(), eend = existing.end();
++ QMap<QString, QString>::const_iterator it = existing.begin();
++ for ( ; it != eend; ++it) {
++ QMap<QString, QString>::const_iterator current = fields.find(it.key());
++ if (current == fend) {
++ obsoleteFields.append(QVariant(it.key()));
++ } else if (*current != *it) {
++ modifiedFields.append(QVariant(current.key()));
++ modifiedValues.append(QVariant(current.value()));
++ }
++ }
++
++ for (it = fields.begin(); it != fend; ++it) {
++ if (existing.find(it.key()) == eend) {
++ addedFields.append(QVariant(it.key()));
++ addedValues.append(QVariant(it.value()));
++ }
++ }
++
++ // TBD: Update custom fields
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::customFields(quint64 id, QMap<QString, QString> *fields)
++{
++ // TBD: Load information about custom fields
++ Q_UNUSED(id);
++ Q_UNUSED(fields);
++
++ return Success;
++}
++
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptRemoveAccounts(const QMailAccountKey &key,
++ QMailAccountIdList *deletedAccounts, QMailFolderIdList *deletedFolders, QMailMessageIdList *deletedMessages,
++ Transaction &t)
++{
++ // TBD: Delete accounts
++ Q_UNUSED(key);
++ Q_UNUSED(deletedAccounts);
++ Q_UNUSED(deletedFolders);
++ Q_UNUSED(deletedMessages);
++ Q_UNUSED(t);
++
++ return DatabaseFailure;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptRemoveFolders(const QMailFolderKey &key, QMailStore::MessageRemovalOption option,
++ QMailFolderIdList *deletedFolders, QMailMessageIdList *deletedMessages, QMailAccountIdList *modifiedAccounts,
++ Transaction &t)
++{
++ // TBD: Remove folders
++ Q_UNUSED(key);
++ Q_UNUSED(option);
++ Q_UNUSED(deletedFolders);
++ Q_UNUSED(deletedMessages);
++ Q_UNUSED(modifiedAccounts);
++ Q_UNUSED(t);
++
++ return DatabaseFailure;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptRemoveMessages(const QMailMessageKey &key, QMailStore::MessageRemovalOption option,
++ QMailMessageIdList *deletedMessages, QMailAccountIdList *modifiedAccounts, QMailFolderIdList *modifiedFolders,
++ Transaction &t)
++{
++ // TBD: Remove messages
++ Q_UNUSED(key);
++ Q_UNUSED(option);
++ Q_UNUSED(deletedMessages);
++ Q_UNUSED(modifiedAccounts);
++ Q_UNUSED(modifiedFolders);
++ Q_UNUSED(t);
++
++ return DatabaseFailure;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptUpdateAccount(QMailAccount *account, QMailAccountConfiguration *config,
++ QMailAccountIdList *updatedAccountIds,
++ Transaction &t)
++{
++ Q_UNUSED(t);
++
++ QMailAccountId id(account ? account->id() : config ? config->id() : QMailAccountId());
++ if (!id.isValid())
++ return Failure;
++
++ if (account) {
++ // Update the account cache
++ if (accountCache.contains(id))
++ accountCache.insert(*account);
++ }
++
++ updatedAccountIds->append(id);
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptUpdateFolder(QMailFolder *folder,
++ QMailFolderIdList *updatedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t)
++{
++ //check that the parent folder actually exists
++ if(!checkPreconditions(*folder, true))
++ return Failure;
++
++ QMailFolderId parentFolderId;
++ QMailAccountId parentAccountId;
++
++ // TBD: Update folder
++ Q_UNUSED(modifiedAccountIds);
++ Q_UNUSED(t);
++
++ //update the folder cache
++ if (folderCache.contains(folder->id()))
++ folderCache.insert(*folder);
++
++ updatedFolderIds->append(folder->id());
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptUpdateMessage(QMailMessageMetaData *metaData, QMailMessage *message,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds, bool *modifiedContent,
++ Transaction &t)
++{
++ if (!metaData->id().isValid())
++ return Failure;
++
++ QMailAccountId parentAccountId;
++ QMailFolderId parentFolderId;
++ QString contentUri;
++ QMailFolderIdList folderIds;
++
++ QMailMessageKey::Properties updateProperties(QMailStorePrivate::updatableMessageProperties());
++ QVariantList extractedValues;
++
++ // Do we actually have an update to perform?
++ bool updateContent(message && message->contentModified());
++ if (metaData->dataModified() || updateContent) {
++ // Find the existing properties
++ {
++ // TBD: Query database
++ Q_UNUSED(t);
++ }
++
++ if (updateContent) {
++ updateProperties |= QMailMessageKey::ContentIdentifier;
++
++ bool addContent(updateContent && contentUri.isEmpty());
++ if (addContent)
++ updateProperties |= QMailMessageKey::ContentScheme;
++
++ // We need to update the content for this message
++ if (metaData->contentScheme().isEmpty()) {
++ // Use the default storage scheme
++ metaData->setContentScheme(defaultContentScheme());
++ }
++
++ MutexGuard lock(contentManagerMutex());
++ if (!lock.lock(1000)) {
++ qMailLog(Messaging) << "Unable to acquire message body mutex in updateMessage!";
++ return Failure;
++ }
++
++ if (QMailContentManager *contentManager = QMailContentManagerFactory::create(metaData->contentScheme())) {
++ if (addContent) {
++ // We need to add this content to the message
++ QMailStore::ErrorCode code = contentManager->add(message);
++ if (code != QMailStore::NoError) {
++ setLastError(code);
++ qMailLog(Messaging) << "Unable to add message content to URI:" << ::contentUri(*metaData);
++ return Failure;
++ }
++ } else {
++ QMailStore::ErrorCode code = contentManager->update(message);
++ if (code != QMailStore::NoError) {
++ setLastError(code);
++ qMailLog(Messaging) << "Unable to update message content:" << contentUri;
++ return Failure;
++ }
++ }
++
++ metaData->setContentIdentifier(message->contentIdentifier());
++ } else {
++ qMailLog(Messaging) << "Unable to create content manager for scheme:" << metaData->contentScheme();
++ return Failure;
++ }
++ }
++
++ // Don't update the previous parent folder if it isn't set
++ if (!metaData->previousParentFolderId().isValid())
++ updateProperties &= ~QMailMessageKey::PreviousParentFolderId;
++
++ extractedValues = messageValues(updateProperties, *metaData);
++
++ {
++ // TBD: update exctracted values
++ }
++
++ if (metaData->customFieldsModified()) {
++ AttemptResult result = updateCustomFields(metaData->id().toULongLong(), metaData->customFields());
++ if (result != Success)
++ return result;
++
++ updateProperties |= QMailMessageKey::Custom;
++ }
++ }
++
++ if (parentAccountId.isValid()) {
++ // The message is now up-to-date with data store
++ metaData->setUnmodified();
++
++ if (headerCache.contains(metaData->id())) {
++ QMailMessageMetaData cachedMetaData = headerCache.lookup(metaData->id());
++ updateMessageValues(updateProperties, extractedValues, metaData->customFields(), cachedMetaData);
++ cachedMetaData.setUnmodified();
++ headerCache.insert(cachedMetaData);
++ }
++
++ updatedMessageIds->append(metaData->id());
++ *modifiedFolderIds = folderIds;
++
++ if (metaData->parentAccountId().isValid())
++ modifiedAccountIds->append(metaData->parentAccountId());
++ if (parentAccountId.isValid()) {
++ if (parentAccountId != metaData->parentAccountId())
++ modifiedAccountIds->append(parentAccountId);
++ }
++ }
++
++ *modifiedContent = updateContent;
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::affectedByMessageIds(const QMailMessageIdList &messages, QMailFolderIdList *folderIds, QMailAccountIdList *accountIds) const
++{
++ AttemptResult result;
++
++ // Find the set of folders whose contents are modified by this update
++ QMailFolderIdList messageFolderIds;
++
++ QMailStorePrivate *self(const_cast<QMailStorePrivate*>(this));
++ {
++ ReadLock l(self);
++ result = self->attemptMessageFolderIds(QMailMessageKey::id(messages), &messageFolderIds, l);
++ }
++
++ if (result != Success)
++ return result;
++
++ return affectedByFolderIds(messageFolderIds, folderIds, accountIds);
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::affectedByFolderIds(const QMailFolderIdList &folders, QMailFolderIdList *folderIds, QMailAccountIdList *accountIds) const
++{
++ AttemptResult result;
++
++ // Any ancestor folders are also modified
++ QMailFolderIdList ancestorIds;
++
++ QMailStorePrivate *self(const_cast<QMailStorePrivate*>(this));
++ {
++ ReadLock l(self);
++ result = self->attemptFolderAncestorIds(folders, &ancestorIds, l);
++ }
++
++ if (result != Success)
++ return result;
++
++ *folderIds = folders + ancestorIds;
++
++ // Find the set of accounts whose contents are modified by this update
++ ReadLock l(self);
++ result = self->attemptFolderAccountIds(QMailFolderKey::id(*folderIds), accountIds, l);
++ return result;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptUpdateMessagesMetaData(const QMailMessageKey &key, const QMailMessageKey::Properties &props, const QMailMessageMetaData &data,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t)
++{
++ //do some checks first
++ if (props & QMailMessageKey::Id) {
++ qMailLog(Messaging) << "Updating of messages IDs is not supported";
++ return Failure;
++ }
++
++ QMailMessageKey::Properties properties(props);
++
++ if (properties & QMailMessageKey::ParentFolderId) {
++ MailFolderUri folderUri(data.parentFolderId());
++ if (!uriExists(folderUri)) {
++ qMailLog(Messaging) << "Update of messages failed. Parent folder does not exist";
++ return Failure;
++ }
++ }
++
++ // TBD: Update message metadata
++ Q_UNUSED(key);
++ Q_UNUSED(modifiedFolderIds);
++ Q_UNUSED(modifiedAccountIds);
++ Q_UNUSED(t);
++
++ QVariantList extractedValues;
++
++ // Update the header cache
++ foreach (const QMailMessageId& id, *updatedMessageIds) {
++ if (headerCache.contains(id)) {
++ QMailMessageMetaData cachedMetaData = headerCache.lookup(id);
++ updateMessageValues(properties, extractedValues, data.customFields(), cachedMetaData);
++ cachedMetaData.setUnmodified();
++ headerCache.insert(cachedMetaData);
++ }
++ }
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptUpdateMessagesStatus(const QMailMessageKey &key, quint64 status, bool set,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t)
++{
++ //get the valid ids
++ *updatedMessageIds = queryMessages(key, QMailMessageSortKey());
++
++ // TBD: Update status
++ Q_UNUSED(modifiedFolderIds);
++ Q_UNUSED(modifiedAccountIds);
++ Q_UNUSED(t);
++
++ // Update the header cache
++ foreach (const QMailMessageId& id, *updatedMessageIds) {
++ if (headerCache.contains(id)) {
++ QMailMessageMetaData cachedMetaData = headerCache.lookup(id);
++ quint64 newStatus = cachedMetaData.status();
++ newStatus = set ? (newStatus | status) : (newStatus & ~status);
++ cachedMetaData.setStatus(newStatus);
++ cachedMetaData.setUnmodified();
++ headerCache.insert(cachedMetaData);
++ }
++ }
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptRestoreToPreviousFolder(const QMailMessageKey &key,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t)
++{
++ // TBD: Restore messages to previous folder
++ Q_UNUSED(key);
++ Q_UNUSED(modifiedFolderIds);
++ Q_UNUSED(modifiedAccountIds);
++ Q_UNUSED(t);
++
++ // Update the header cache
++ foreach (const QMailMessageId &id, *updatedMessageIds) {
++ if (headerCache.contains(id)) {
++ QMailMessageMetaData cachedMetaData = headerCache.lookup(id);
++ cachedMetaData.setParentFolderId(cachedMetaData.previousParentFolderId());
++ cachedMetaData.setPreviousParentFolderId(QMailFolderId());
++ cachedMetaData.setUnmodified();
++ headerCache.insert(cachedMetaData);
++ }
++ }
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptPurgeMessageRemovalRecords(const QMailAccountId &accountId, const QStringList &serverUids,
++ Transaction &t)
++{
++ QMailMessageIdList removalIds;
++
++ // TBD: Purge remove records
++ Q_UNUSED(accountId);
++ Q_UNUSED(serverUids);
++ Q_UNUSED(t);
++
++ return Success;
++}
++
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptSizeOfMessages(const QMailMessageKey &key,
++ int *result,
++ ReadLock &)
++{
++ // TBD: Count overal size of the messages
++ Q_UNUSED(key);
++ Q_UNUSED(result);
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptAccountConfiguration(const QMailAccountId &id,
++ QMailAccountConfiguration *result,
++ ReadLock &)
++{
++ // TBD: Find any configuration fields for this account
++
++ // TBD: Fill account configuration with information
++
++
++ result->setId(id);
++ result->setModified(false);
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptMessage(const QString &uid, const QMailAccountId &accountId,
++ QMailMessage *result,
++ ReadLock &lock)
++{
++ quint64 id(0);
++
++ {
++ // TBD: Search for the message with particular server UID
++ Q_UNUSED(uid);
++ Q_UNUSED(accountId);
++ }
++
++ if (id == 0) {
++ return Failure;
++ }
++
++ return attemptMessage(QMailMessageId(id), result, lock);
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptMessagesMetaData(const QMailMessageKey& key, const QMailMessageKey::Properties &properties, QMailStore::ReturnOption option,
++ QMailMessageMetaDataList *result,
++ ReadLock &)
++{
++ if (properties == QMailMessageKey::Custom) {
++ // We're only selecting custom fields
++
++ // TBD: Search by custom fields
++ QMap<QString, QStringList> fields;
++ int maxLen = 0;
++ Q_UNUSED(key);
++
++ for (int i = 0; i < maxLen; ++i)
++ result->append(QMailMessageMetaData());
++
++ // Add all pairs to the results
++ foreach (const QString &name, fields.keys()) {
++ QMailMessageMetaDataList::iterator it = result->begin();
++ foreach (const QString &value, fields[name]) {
++ (*it).setCustomField(name, value);
++ ++it;
++ }
++ }
++
++ QMailMessageMetaDataList::iterator it = result->begin(), end = result->end();
++ for ( ; it != end; ++it)
++ (*it).setCustomFieldsModified(false);
++ } else {
++ bool includeCustom(properties & QMailMessageKey::Custom);
++ if (includeCustom && (option == QMailStore::ReturnDistinct)) {
++ qWarning() << "Warning: Distinct-ness is not supported with custom fields!";
++ }
++
++ QMailMessageKey::Properties props(properties);
++
++ bool removeId(false);
++ if (includeCustom && !(props & QMailMessageKey::Id)) {
++ // We need the ID to match against the custom table
++ props |= QMailMessageKey::Id;
++ removeId = true;
++ }
++
++ {
++ // TBD: Search messages by fields
++ }
++
++ if (includeCustom) {
++ QMailMessageMetaDataList::iterator it = result->begin(), end = result->end();
++ for ( ; it != end; ++it) {
++ // Add the custom fields to the record
++ QMap<QString, QString> fields;
++ AttemptResult attemptResult = customFields((*it).id().toULongLong(), &fields);
++ if (attemptResult != Success)
++ return attemptResult;
++
++ QMailMessageMetaData &metaData(*it);
++ metaData.setCustomFields(fields);
++ metaData.setCustomFieldsModified(false);
++
++ if (removeId)
++ metaData.setId(QMailMessageId());
++ }
++ }
++ }
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptMessageRemovalRecords(const QMailAccountId &accountId, const QMailFolderId &folderId,
++ QMailMessageRemovalRecordList *result,
++ ReadLock &)
++{
++ // TBD: Search for deleted messages
++ Q_UNUSED(accountId);
++ Q_UNUSED(folderId);
++ Q_UNUSED(result);
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptMessageFolderIds(const QMailMessageKey &key,
++ QMailFolderIdList *result,
++ ReadLock &)
++{
++ // TBD: Look for message ID
++ Q_UNUSED(key);
++ Q_UNUSED(result);
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptFolderAccountIds(const QMailFolderKey &key,
++ QMailAccountIdList *result,
++ ReadLock &)
++{
++ // TBD: Look for message folder ID
++ Q_UNUSED(key);
++ Q_UNUSED(result);
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptFolderAncestorIds(const QMailFolderIdList &ids,
++ QMailFolderIdList *result,
++ ReadLock &)
++{
++ // TBD: Look for ancestor message folder ID
++ Q_UNUSED(ids);
++ Q_UNUSED(result);
++
++ return Success;
++}
++
++void QMailStorePrivate::preloadHeaderCache(const QMailMessageId& id) const
++{
++ QMailMessageIdList idBatch;
++ idBatch.append(id);
++
++ int index = lastQueryMessageResult.indexOf(id);
++ if (index != -1) {
++ // Preload based on result of last call to queryMessages
++ int count = 1;
++
++ QMailMessageIdList::const_iterator begin = lastQueryMessageResult.begin();
++ QMailMessageIdList::const_iterator end = lastQueryMessageResult.end();
++ QMailMessageIdList::const_iterator lowIt = begin + index;
++ QMailMessageIdList::const_iterator highIt = lowIt;
++
++ bool ascend(true);
++ bool descend(lowIt != begin);
++
++ while ((count < (QMailStorePrivate::lookAhead * 2)) && (ascend || descend)) {
++ if (ascend) {
++ ++highIt;
++ if (highIt == end) {
++ ascend = false;
++ } else {
++ if (!headerCache.contains(*highIt)) {
++ idBatch.append(*highIt);
++ ++count;
++ } else {
++ // Most likely, a sequence in the other direction will be more useful
++ ascend = false;
++ }
++ }
++ }
++
++ if (descend) {
++ --lowIt;
++ if (!headerCache.contains(*lowIt)) {
++ idBatch.prepend(*lowIt);
++ ++count;
++
++ if (lowIt == begin) {
++ descend = false;
++ }
++ } else {
++ // Most likely, a sequence in the other direction will be more useful
++ descend = false;
++ }
++ }
++ }
++ } else {
++ // Don't bother preloading - if there is a query result, we have now searched outside it;
++ // we should consider it to have outlived its usefulness
++ if (!lastQueryMessageResult.isEmpty())
++ lastQueryMessageResult = QMailMessageIdList();
++ }
++
++ QMailMessageMetaData result;
++ QMailMessageKey key(QMailMessageKey::id(idBatch));
++ foreach (const QMailMessageMetaData& metaData, messagesMetaData(key, allMessageProperties(), QMailStore::ReturnAll)) {
++ if (metaData.id().isValid()) {
++ headerCache.insert(metaData);
++ if (metaData.id() == id)
++ result = metaData;
++ }
++ }
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptStatusBit(const QString &name, const QString &context,
++ int *result,
++ ReadLock &)
++{
++ // TBD: Find out wheither this status bit is present
++ Q_UNUSED(name);
++ Q_UNUSED(context);
++ Q_UNUSED(result);
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptRegisterStatusBit(const QString &name, const QString &context, int maximum,
++ Transaction &t)
++{
++ int highest = 0;
++
++ // TBD: Find out the highest bit
++ Q_UNUSED(name);
++ Q_UNUSED(context);
++ Q_UNUSED(t);
++
++ if (highest == maximum) {
++ return Failure;
++ } else {
++ // TBD: Add new status bit
++ }
++
++ t.commit();
++
++ return Success;
++}
++
++bool QMailStorePrivate::checkPreconditions(const QMailFolder& folder, bool update)
++{
++ //if the parent is valid, check that it exists
++ //if the account is valid, check that is exists
++
++ if(!update)
++ {
++ if(folder.id().isValid())
++ {
++ qMailLog(Messaging) << "Folder exists, use update instead of add.";
++ return false;
++ }
++ }
++ else
++ {
++ if(!folder.id().isValid())
++ {
++ qMailLog(Messaging) << "Folder does not exist, use add instead of update.";
++ return false;
++ }
++
++ if(folder.parentFolderId().isValid() && folder.parentFolderId() == folder.id())
++ {
++ qMailLog(Messaging) << "A folder cannot be a child to itself";
++ return false;
++ }
++ }
++
++ if(folder.parentFolderId().isValid())
++ {
++ MailFolderUri folderUri(folder.parentFolderId());
++ if(!uriExists(folderUri))
++ {
++ qMailLog(Messaging) << "Parent folder does not exist!";
++ return false;
++ }
++ }
++
++ if(folder.parentAccountId().isValid())
++ {
++ MailAccountUri accountUri(folder.parentAccountId());
++ if(!uriExists(accountUri))
++ {
++ qMailLog(Messaging) << "Parent account does not exist!";
++ return false;
++ }
++ }
++
++ return true;
++}
++
++bool QMailStorePrivate::deleteMessages(const QMailMessageKey& key,
++ QMailStore::MessageRemovalOption option,
++ QMailMessageIdList& deletedMessages,
++ QStringList& expiredContent,
++ QMailAccountIdList& modifiedAccounts,
++ QMailFolderIdList& modifiedFolders)
++{
++ // TBD: Delete messages
++ Q_UNUSED(key);
++ Q_UNUSED(option);
++ Q_UNUSED(deletedMessages);
++ Q_UNUSED(expiredContent);
++ Q_UNUSED(modifiedAccounts);
++ Q_UNUSED(modifiedFolders);
++
++ return true;
++}
++
++bool QMailStorePrivate::deleteFolders(const QMailFolderKey& key,
++ QMailStore::MessageRemovalOption option,
++ QMailFolderIdList& deletedFolders,
++ QMailMessageIdList& deletedMessages,
++ QStringList& expiredContent,
++ QMailAccountIdList& modifiedAccounts)
++{
++ // TBD: Delete folders, subfolders and all messages
++ Q_UNUSED(key);
++ Q_UNUSED(option);
++ Q_UNUSED(deletedFolders);
++ Q_UNUSED(deletedMessages);
++ Q_UNUSED(expiredContent);
++ Q_UNUSED(modifiedAccounts);
++
++ return true;
++}
++
++bool QMailStorePrivate::deleteAccounts(const QMailAccountKey& key,
++ QMailAccountIdList& deletedAccounts,
++ QMailFolderIdList& deletedFolders,
++ QMailMessageIdList& deletedMessages,
++ QStringList& expiredContent)
++{
++ // TBD: Delete accounts, folders, subfolders and all messages
++ Q_UNUSED(key);
++ Q_UNUSED(deletedAccounts);
++ Q_UNUSED(deletedFolders);
++ Q_UNUSED(deletedMessages);
++ Q_UNUSED(expiredContent);
++
++ return true;
++}
++
++void QMailStorePrivate::emitIpcNotification(QMailStoreImplementation::AccountUpdateSignal signal, const QMailAccountIdList &ids)
++{
++ if ((signal == &QMailStore::accountsUpdated) || (signal == &QMailStore::accountsRemoved)) {
++ foreach (const QMailAccountId &id, ids)
++ accountCache.remove(id);
++ }
++
++ QMailStoreImplementation::emitIpcNotification(signal, ids);
++}
++
++void QMailStorePrivate::emitIpcNotification(QMailStoreImplementation::FolderUpdateSignal signal, const QMailFolderIdList &ids)
++{
++ if ((signal == &QMailStore::foldersUpdated) || (signal == &QMailStore::foldersRemoved)) {
++ foreach (const QMailFolderId &id, ids)
++ folderCache.remove(id);
++ }
++
++ QMailStoreImplementation::emitIpcNotification(signal, ids);
++}
++
++void QMailStorePrivate::emitIpcNotification(QMailStoreImplementation::MessageUpdateSignal signal, const QMailMessageIdList &ids)
++{
++ if ((signal == &QMailStore::messagesUpdated) || (signal == &QMailStore::messagesRemoved)) {
++ foreach (const QMailMessageId &id, ids)
++ headerCache.remove(id);
++ }
++
++ QMailStoreImplementation::emitIpcNotification(signal, ids);
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptAddMessage(QMailMessageMetaData *metaData,
++ QMailMessageIdList *addedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t)
++{
++ Q_UNUSED(t);
++
++ if (!metaData->parentFolderId().isValid()) {
++ qMailLog(Messaging) << "Unable to add message. Invalid parent folder id";
++ return Failure;
++ }
++
++ MailMessageUri messageUri;
++ MailFolderUri parentFolderUri(metaData->parentFolderId());
++ MailAccountUri parentAccountUri(metaData->parentAccountId());
++
++ SparqlQuery query(SparqlQuery::UpdateQuery);
++ query.prepare(QString(
++ "INSERT {\n"
++ "%1 rdf:type nmo:Email ;\n"
++ " nie:isLogicalPartOf %2 ;\n"
++ " nmo:sender [\n"
++ " rdf:type nco:Contact ;\n"
++ " nco:fullname \"%3\" ; \n"
++ " nco:hasEmailAddress <mailto:%4> ] ;\n"
++ + nmoRecipients(metaData->to()) +
++ " nmo:messageSubject \"%5\" ;\n"
++ " nmo:sentDate \"%6\"^^xsd:dateTime ;\n"
++ " nmo:status \"%7\"^^xsd:integer ;\n"
++ " nie:relatedTo %8 ;\n"
++ " nie:isStoredAs [\n"
++ " rdf:type nie:DataObject ;\n"
++ " nie:dataSource <%9> ] ;\n"
++ " nmo:messageId \"%10\" ;\n"
++ " nie:contentSize \"%11\"^^xsd:integer ;\n"
++ " nie:mimeType \"%12\" ;\n"
++ " nmo:inReplyTo \"%13\" ;\n"
++ " nmo:messageHeader [\n"
++ " rdf:type nmo:MessageHeader ;\n"
++ " nmo:headerName \"responseType\" ;\n"
++ " nmo:headerValue \"%14\" ] ;\n"
++ " nmo:receivedDate \"%15\"^^xsd:dateTime .\n"
++ "}").arg(messageUri.uri())
++ .arg(parentFolderUri.uri())
++ .arg(metaData->from().name())
++ .arg(metaData->from().address())
++ .arg(metaData->subject())
++ .arg(QMailTimeStamp(metaData->date()).toLocalTime().toString())
++ .arg(static_cast<int>(metaData->status()))
++ .arg(parentAccountUri.uri())
++ .arg(::contentUri(*metaData))
++ .arg(metaData->serverUid())
++ .arg(metaData->size())
++ .arg(static_cast<int>(metaData->content()))
++ .arg(metaData->inResponseTo().toULongLong())
++ .arg(metaData->responseType())
++ .arg(QMailTimeStamp(metaData->receivedDate()).toLocalTime().toString()));
++
++ // TBD: Add custom fields later
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ qDebug() << "Query succeeded";
++ metaData->setId(QMailMessageId(messageUri.id()));
++
++ addedMessageIds->append(metaData->id());
++ *modifiedFolderIds = QMailFolderIdList() << metaData->parentFolderId();
++ if (metaData->parentAccountId().isValid())
++ modifiedAccountIds->append(metaData->parentAccountId());
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptAddFolder(QMailFolder *folder,
++ QMailFolderIdList *addedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t)
++{
++ Q_UNUSED(t);
++
++ //check that the parent folder actually exists
++ if (!checkPreconditions(*folder))
++ return Failure;
++
++ MailFolderUri folderUri;
++ MailFolderUri parentFolderUri(folder->parentFolderId());
++ MailAccountUri parentAccountUri(folder->parentAccountId());
++
++ SparqlQuery query(SparqlQuery::UpdateQuery);
++ query.prepare(QString(
++ "INSERT { \n"
++ "%1 rdf:type nmo:MailFolder ; \n"
++ " nmo:folderName \"%2\" ; \n"
++ " nie:isLogicalPartOf %3 ; \n"
++ " nie:relatedTo %4 ; \n"
++ " nmo:folderDisplayName \"%5\" ; \n"
++ " nmo:status \"%6\"^^xsd:integer ; \n"
++ " nmo:serverCount \"%7\"^^xsd:integer ; \n"
++ " nmo:serverUnreadCount \"%8\"^^xsd:integet . \n"
++ "}").arg(folderUri.uri())
++ .arg(folder->path())
++ .arg(parentFolderUri.uri())
++ .arg(parentAccountUri.uri())
++ .arg(folder->displayName())
++ .arg(folder->status())
++ .arg(folder->serverCount())
++ .arg(folder->serverUnreadCount()));
++
++ // TBD: Add custom fields later
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ qDebug() << "Query succeeded";
++ folder->setId(QMailFolderId(folderUri.id()));
++
++ // TBD: Update folder links also
++
++ addedFolderIds->append(folder->id());
++ if (folder->parentAccountId().isValid())
++ modifiedAccountIds->append(folder->parentAccountId());
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptAddAccount(QMailAccount *account, QMailAccountConfiguration* config,
++ QMailAccountIdList *addedAccountIds,
++ Transaction &t)
++{
++ Q_UNUSED(config);
++ Q_UNUSED(t);
++
++ MailAccountUri accountUri;
++ SparqlQuery query(SparqlQuery::UpdateQuery);
++ query.prepare(QString(
++ "INSERT { \n"
++ "%1 rdf:type nmo:Mailbox ; \n"
++ " nmo:accountName \"%2\" ; \n"
++ " nmo:status \"%3\"^^xsd:integer ; \n"
++ " nmo:signature \"%4\" ; \n"
++ " nmo:fromAddress [ \n"
++ " rdf:type nco:EmailAddress ; \n"
++ " nco:emailAddress \"%5\" ] . \n"
++ "}").arg(accountUri.uri())
++ .arg(account->name())
++ .arg(account->status())
++ .arg(account->signature())
++ .arg(account->fromAddress().toString(true)));
++
++ // TBD: Add custom fields later
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ qDebug() << "Query succeeded";
++ account->setId(QMailAccountId(accountUri.id()));
++
++ addedAccountIds->append(account->id());
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptAccount(const QMailAccountId &id,
++ QMailAccount *result,
++ ReadLock &)
++{
++ MailAccountUri messageUri(id);
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(QString(
++ "SELECT ?name ?signature ?fromAddress \n"
++ "WHERE { \n"
++ "%1 rdf:type nmo:Mailbox ; \n"
++ " nmo:accountName ?name ; \n"
++// " nmo:status ?status ; \n"
++ " nmo:signature ?signature ; \n"
++ " nmo:fromAddress [ \n"
++ " rdf:type nco:EmailAddress ; \n"
++ " nco:emailAddress ?fromAddress ] . \n"
++ "}").arg(messageUri.uri()));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ SparqlResult res = query.result();
++ Q_ASSERT(!res.end());
++
++ *result = extractAccount(id, res.fetchRow());
++
++ // Update cache
++ accountCache.insert(*result);
++ return Success;
++}
++
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptFolder(const QMailFolderId &id,
++ QMailFolder *result,
++ ReadLock &)
++{
++ MailFolderUri folderUri(id);
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(QString(
++ "SELECT ?name ?parentFolder ?parentAccount ?displayName \n"
++ "WHERE { \n"
++ "%1 rdf:type nmo:MailFolder ; \n"
++ " nmo:folderName ?name ; \n"
++ " nie:isLogicalPartOf ?parentFolder ; \n"
++ " nie:relatedTo ?parentAccount ; \n"
++ " nmo:folderDisplayName ?displayName ; \n"
++// " nmo:status ?status ; \n"
++// " nmo:serverCount ?serverCount ; \n"
++// " nmo:serverUnreadCount ?serverUnreadCount . \n"
++ "}").arg(folderUri.uri()));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ SparqlResult res = query.result();
++ Q_ASSERT(!res.end());
++
++ *result = extractFolder(id, res.fetchRow());
++
++ // Update cache
++ folderCache.insert(*result);
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptMessage(const QMailMessageId &id,
++ QMailMessage *result,
++ ReadLock &)
++{
++ if (!id.isValid())
++ return Failure;
++
++ MailMessageUri messageUri(id);
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(QString(
++ "SELECT ?fullName ?mailAddress \n"
++ "WHERE { \n"
++ "%1 rdf:type nmo:Email ; \n"
++ " nmo:recipient [ \n"
++ " rdf:type nco:Contact ; \n"
++ " nco:fullname ?fullName ; \n"
++ " nco:hasEmailAddress ?mailAddress ] \n"
++ "}").arg(messageUri.uri()));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ SparqlResult res = query.result();
++
++ QList<QMailAddress> recipients;
++ while (!res.end())
++ {
++ QStringList row = res.fetchRow();
++ recipients.push_back(QMailAddress(row.at(0), row.at(1)));
++ }
++
++ query.prepare(QString(
++ "SELECT ?folderId ?senderFullName ?senderEmailAddress ?messageSubject ?sentDate ?status ?accountId ?dataSource ?uid ?contentSize ?mimeType ?inReplyTo ?headerValue ?receivedDate \n"
++ "WHERE { \n"
++ "%1 rdf:type nmo:Email ;\n"
++ " nie:isLogicalPartOf ?folderId ;\n"
++ " nmo:sender [\n"
++ " rdf:type nco:Contact ;\n"
++ " nco:fullname ?senderFullName ; \n"
++ " nco:hasEmailAddress ?senderEmailAddress ] ;\n"
++ " nmo:messageSubject ?messageSubject ;\n"
++ " nmo:sentDate ?sentDate ;\n"
++ " nmo:status ?status ;\n"
++ " nie:relatedTo ?accountId ;\n"
++ " nie:isStoredAs [\n"
++ " rdf:type nie:DataObject ;\n"
++ " nie:dataSource ?dataSource ] ;\n"
++ " nmo:messageId ?uid ;\n"
++ " nie:contentSize ?contentSize ;\n"
++ " nie:mimeType ?mimeType ;\n"
++ " nmo:inReplyTo ?inReplyTo ;\n"
++ " nmo:messageHeader [\n"
++ " rdf:type nmo:MessageHeader ;\n"
++ " nmo:headerName \"responseType\" ;\n"
++ " nmo:headerValue ?headerValue ] ;\n"
++ " nmo:receivedDate ?receivedDate .\n"
++ "}").arg(messageUri.uri()));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ res = query.result();
++ Q_ASSERT(!res.end());
++
++ QMailMessage message;
++ message.setId(id);
++ extractMessageMetaData(res.fetchRow(), &message);
++ message.setTo(recipients);
++
++ *result = message;
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptQueryAccounts(const QMailAccountKey &key, const QMailAccountSortKey &sortKey,
++ QMailAccountIdList *ids,
++ ReadLock &)
++{
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyQuery(key, sortKey));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ SparqlResult result = query.result();
++
++ ids->clear();
++
++ while (!result.end())
++ {
++ QStringList row = result.fetchRow();
++ ids->append(IdFromUri<QMailAccountId>(row.first()));
++ }
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptQueryFolders(const QMailFolderKey &key, const QMailFolderSortKey &sortKey,
++ QMailFolderIdList *ids,
++ ReadLock &)
++{
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyQuery(key, sortKey));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ SparqlResult result = query.result();
++
++ ids->clear();
++
++ while (!result.end())
++ {
++ QStringList row = result.fetchRow();
++ ids->append(IdFromUri<QMailFolderId>(row.first()));
++ }
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptQueryMessages(const QMailMessageKey &key, const QMailMessageSortKey &sortKey,
++ QMailMessageIdList *ids,
++ ReadLock &)
++{
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyQuery(key, sortKey));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ SparqlResult result = query.result();
++
++ ids->clear();
++
++ while (!result.end())
++ {
++ QStringList row = result.fetchRow();
++ ids->append(IdFromUri<QMailMessageId>(row.first()));
++ }
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptCountAccounts(const QMailAccountKey &key, int *result,
++ ReadLock &)
++{
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyCount(key));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ SparqlResult res = query.result();
++
++ Q_ASSERT(!res.end());
++
++ *result = res.fetchRow().first().toInt();
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptCountFolders(const QMailFolderKey &key, int *result,
++ ReadLock &)
++{
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyCount(key));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ SparqlResult res = query.result();
++
++ Q_ASSERT(!res.end());
++
++ *result = res.fetchRow().first().toInt();
++
++ return Success;
++}
++
++QMailStorePrivate::AttemptResult QMailStorePrivate::attemptCountMessages(const QMailMessageKey &key,
++ int *result,
++ ReadLock &)
++{
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyCount(key));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return Failure;
++ }
++
++ SparqlResult res = query.result();
++
++ Q_ASSERT(!res.end());
++
++ *result = res.fetchRow().first().toInt();
++
++ return Success;
++}
+diff --git a/src/libraries/qtopiamail/qmailstore_sparql.h b/src/libraries/qtopiamail/qmailstore_sparql.h
+new file mode 100644
+index 0000000..fe05e08
+--- /dev/null
++++ b/src/libraries/qtopiamail/qmailstore_sparql.h
+@@ -0,0 +1,470 @@
++/****************************************************************************
++**
++** This file is part of the $PACKAGE_NAME$.
++**
++** Copyright (C) $THISYEAR$ $COMPANY_NAME$.
++**
++** $QT_EXTENDED_DUAL_LICENSE$
++**
++****************************************************************************/
++
++#ifndef QMAILSTORE_P_H
++#define QMAILSTORE_P_H
++
++//
++// W A R N I N G
++// -------------
++//
++// This file is not part of the Qt Extended API. It exists purely as an
++// implementation detail. This header file may change from version to
++// version without notice, or even be removed.
++//
++// We mean it.
++//
++
++#include "qmailstoreimplementation_p.h"
++#include "sparqldatabase.h"
++
++#include <QCache>
++
++//#define QMAILSTORE_LOG_SQL //define to enable SQL query logging
++//#define QMAILSTORE_USE_RTTI //define if RTTI is available to assist debugging
++
++#ifdef QMAILSTORE_USE_RTTI
++#include <typeinfo>
++#endif
++
++class ProcessMutex;
++class ProcessReadLock;
++class SparqlResult;
++class SparqlQuery;
++
++class QMailStorePrivate : public QMailStoreImplementation
++{
++ Q_OBJECT
++
++public:
++ typedef QMap<QMailMessageKey::Property, QString> MessagePropertyMap;
++ typedef QList<QMailMessageKey::Property> MessagePropertyList;
++
++ class Transaction;
++ class ReadLock;
++ class Key;
++
++ struct ReadAccess {};
++ struct WriteAccess {};
++
++ QMailStorePrivate(QMailStore* parent);
++ ~QMailStorePrivate();
++
++ virtual bool initStore();
++ void clearContent();
++
++ bool addAccount(QMailAccount *account, QMailAccountConfiguration *config,
++ QMailAccountIdList *addedAccountIds);
++
++ bool addFolder(QMailFolder *f,
++ QMailFolderIdList *addedFolderIds, QMailAccountIdList *modifiedAccountIds);
++
++ bool addMessage(QMailMessage *m,
++ QMailMessageIdList *addedMessageIds, QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds);
++
++ bool addMessage(QMailMessageMetaData *m,
++ QMailMessageIdList *addedMessageIds, QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds);
++
++ bool removeAccounts(const QMailAccountKey &key,
++ QMailAccountIdList *deletedAccounts, QMailFolderIdList *deletedFolders, QMailMessageIdList *deletedMessages, QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds);
++
++ bool removeFolders(const QMailFolderKey &key, QMailStore::MessageRemovalOption option,
++ QMailFolderIdList *deletedFolders, QMailMessageIdList *deletedMessages, QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds);
++
++ bool removeMessages(const QMailMessageKey &key, QMailStore::MessageRemovalOption option,
++ QMailMessageIdList *deletedMessages, QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds);
++
++ bool updateAccount(QMailAccount *account, QMailAccountConfiguration* config,
++ QMailAccountIdList *updatedAccountIds);
++
++ bool updateAccountConfiguration(QMailAccountConfiguration* config,
++ QMailAccountIdList *updatedAccountIds);
++
++ bool updateFolder(QMailFolder* f,
++ QMailFolderIdList *updatedFolderIds, QMailAccountIdList *modifiedAccountIds);
++
++ bool updateMessage(QMailMessageMetaData *metaData, QMailMessage *mail,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds, bool *modifiedContent);
++
++ bool updateMessagesMetaData(const QMailMessageKey &key, const QMailMessageKey::Properties &properties, const QMailMessageMetaData &data,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds);
++
++ bool updateMessagesMetaData(const QMailMessageKey &key, quint64 messageStatus, bool set,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds);
++
++ bool restoreToPreviousFolder(const QMailMessageKey &key,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds);
++
++ bool purgeMessageRemovalRecords(const QMailAccountId &accountId, const QStringList &serverUids);
++
++ int countAccounts(const QMailAccountKey &key) const;
++ int countFolders(const QMailFolderKey &key) const;
++ int countMessages(const QMailMessageKey &key) const;
++
++ int sizeOfMessages(const QMailMessageKey &key) const;
++
++ QMailAccountIdList queryAccounts(const QMailAccountKey &key, const QMailAccountSortKey &sortKey) const;
++ QMailFolderIdList queryFolders(const QMailFolderKey &key, const QMailFolderSortKey &sortKey) const;
++ QMailMessageIdList queryMessages(const QMailMessageKey &key, const QMailMessageSortKey &sortKey) const;
++
++ QMailAccount account(const QMailAccountId &id) const;
++ QMailAccountConfiguration accountConfiguration(const QMailAccountId &id) const;
++
++ QMailFolder folder(const QMailFolderId &id) const;
++
++ QMailMessage message(const QMailMessageId &id) const;
++ QMailMessage message(const QString &uid, const QMailAccountId &accountId) const;
++
++ QMailMessageMetaData messageMetaData(const QMailMessageId &id) const;
++ QMailMessageMetaData messageMetaData(const QString &uid, const QMailAccountId &accountId) const;
++ QMailMessageMetaDataList messagesMetaData(const QMailMessageKey &key, const QMailMessageKey::Properties &properties, QMailStore::ReturnOption option) const;
++ QMailMessageRemovalRecordList messageRemovalRecords(const QMailAccountId &parentAccountId, const QMailFolderId &parentFolderId) const;
++
++ bool registerAccountStatusFlag(const QString &name);
++ quint64 accountStatusMask(const QString &name) const;
++
++ bool registerFolderStatusFlag(const QString &name);
++ quint64 folderStatusMask(const QString &name) const;
++
++ bool registerMessageStatusFlag(const QString &name);
++ quint64 messageStatusMask(const QString &name) const;
++
++ static QString expandValueList(const QVariantList& valueList);
++ static QString expandValueList(int valueCount);
++
++ template<typename ValueType>
++ static ValueType extractValue(const QVariant& var, const ValueType &defaultValue = ValueType());
++
++private:
++ friend class ReadLock;
++
++ enum AttemptResult { Success = 0, Failure, DatabaseFailure };
++
++ static ProcessMutex& contentManagerMutex(void);
++
++ ProcessMutex& databaseMutex(void) const;
++ ProcessReadLock& databaseReadLock(void) const;
++
++ static const MessagePropertyMap& messagePropertyMap();
++ static const MessagePropertyList& messagePropertyList();
++
++ static const QMailMessageKey::Properties &updatableMessageProperties();
++ static const QMailMessageKey::Properties &allMessageProperties();
++
++ bool containsProperty(const QMailMessageKey::Property& p, const QMailMessageKey& key) const;
++ bool containsProperty(const QMailMessageSortKey::Property& p, const QMailMessageSortKey& sortkey) const;
++
++ int databaseIdentifier(int n) const;
++
++ bool setupStandardFolder(QMailFolder::StandardFolder folder, const QString& name);
++
++ void setQueryError(const SparqlQuery& query, const QString& description = QString());
++ QString queryError() const;
++ void clearQueryError(void);
++
++ bool uriExists(const QString& uri);
++
++ bool checkPreconditions(const QMailFolder& folder, bool update = false);
++
++ void preloadHeaderCache(const QMailMessageId& id) const;
++
++ QMailFolderIdList folderAncestorIds(const QMailFolderIdList& ids, bool inTransaction, AttemptResult *result) const;
++
++ quint64 queryStatusMap(const QString &name, const QString &context, QMap<QString, quint64> &map) const;
++
++ bool deleteMessages(const QMailMessageKey& key,
++ QMailStore::MessageRemovalOption option,
++ QMailMessageIdList& deletedMessageIds,
++ QStringList& expiredMailfiles,
++ QMailAccountIdList& modifiedAccounts,
++ QMailFolderIdList& modifiedFolders);
++
++ bool deleteFolders(const QMailFolderKey& key,
++ QMailStore::MessageRemovalOption option,
++ QMailFolderIdList& deletedFolders,
++ QMailMessageIdList& deletedMessageIds,
++ QStringList& expiredMailfiles,
++ QMailAccountIdList& modifiedAccounts);
++
++ bool deleteAccounts(const QMailAccountKey& key,
++ QMailAccountIdList& deletedAccounts,
++ QMailFolderIdList& deletedFolders,
++ QMailMessageIdList& deletedMessageIds,
++ QStringList& expiredMailfile);
++
++ void removeExpiredData(const QMailMessageIdList& messageIds,
++ const QStringList& mailfiles,
++ const QMailFolderIdList& folderIds = QMailFolderIdList(),
++ const QMailAccountIdList& accountIds = QMailAccountIdList());
++
++ template<typename AccessType, typename FunctionType>
++ bool repeatedly(FunctionType func, const QString &description) const;
++
++ AttemptResult addCustomFields(quint64 id, const QMap<QString, QString> &fields);
++ AttemptResult updateCustomFields(quint64 id, const QMap<QString, QString> &fields);
++ AttemptResult customFields(quint64 id, QMap<QString, QString> *fields);
++
++ AttemptResult attemptAddAccount(QMailAccount *account, QMailAccountConfiguration* config,
++ QMailAccountIdList *addedAccountIds,
++ Transaction &t);
++
++ AttemptResult attemptAddFolder(QMailFolder *folder,
++ QMailFolderIdList *addedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t);
++
++ AttemptResult attemptAddMessage(QMailMessageMetaData *metaData,
++ QMailMessageIdList *addedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t);
++
++ AttemptResult attemptRemoveAccounts(const QMailAccountKey &key,
++ QMailAccountIdList *deletedAccounts, QMailFolderIdList *deletedFolders, QMailMessageIdList *deletedMessages,
++ Transaction &t);
++
++ AttemptResult attemptRemoveFolders(const QMailFolderKey &key, QMailStore::MessageRemovalOption option,
++ QMailFolderIdList *deletedFolders, QMailMessageIdList *deletedMessages, QMailAccountIdList *modifiedAccounts,
++ Transaction &t);
++
++ AttemptResult attemptRemoveMessages(const QMailMessageKey &key, QMailStore::MessageRemovalOption option,
++ QMailMessageIdList *deletedMessages, QMailAccountIdList *modifiedAccounts, QMailFolderIdList *modifiedFolders,
++ Transaction &t);
++
++ AttemptResult attemptUpdateAccount(QMailAccount *account, QMailAccountConfiguration *config,
++ QMailAccountIdList *updatedAccountIds,
++ Transaction &t);
++
++ AttemptResult attemptUpdateAccountConfiguration(QMailAccountConfiguration *config,
++ QMailAccountIdList *updatedAccountIds,
++ Transaction &t);
++
++ AttemptResult attemptUpdateFolder(QMailFolder *folder,
++ QMailFolderIdList *updatedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t);
++
++ AttemptResult attemptUpdateMessage(QMailMessageMetaData *metaData, QMailMessage *mail,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds, bool *modifiedContent,
++ Transaction &t);
++
++ AttemptResult affectedByMessageIds(const QMailMessageIdList &messages, QMailFolderIdList *folderIds, QMailAccountIdList *accountIds) const;
++
++ AttemptResult affectedByFolderIds(const QMailFolderIdList &folders, QMailFolderIdList *folderIds, QMailAccountIdList *accountIds) const;
++
++ AttemptResult attemptUpdateMessagesMetaData(const QMailMessageKey &key, const QMailMessageKey::Properties &props, const QMailMessageMetaData &data,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t);
++
++ AttemptResult attemptUpdateMessagesStatus(const QMailMessageKey &key, quint64 status, bool set,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t);
++
++ AttemptResult attemptRestoreToPreviousFolder(const QMailMessageKey &key,
++ QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds,
++ Transaction &t);
++
++ AttemptResult attemptPurgeMessageRemovalRecords(const QMailAccountId &accountId, const QStringList &serverUids,
++ Transaction &t);
++
++ AttemptResult attemptCountAccounts(const QMailAccountKey &key, int *result,
++ ReadLock &);
++
++ AttemptResult attemptCountFolders(const QMailFolderKey &key, int *result,
++ ReadLock &);
++
++ AttemptResult attemptCountMessages(const QMailMessageKey &key,
++ int *result,
++ ReadLock &);
++
++ AttemptResult attemptSizeOfMessages(const QMailMessageKey &key,
++ int *result,
++ ReadLock &);
++
++ AttemptResult attemptQueryAccounts(const QMailAccountKey &key, const QMailAccountSortKey &sortKey,
++ QMailAccountIdList *ids,
++ ReadLock &);
++
++ AttemptResult attemptQueryFolders(const QMailFolderKey &key, const QMailFolderSortKey &sortKey,
++ QMailFolderIdList *ids,
++ ReadLock &);
++
++ AttemptResult attemptQueryMessages(const QMailMessageKey &key, const QMailMessageSortKey &sortKey,
++ QMailMessageIdList *ids,
++ ReadLock &);
++
++ AttemptResult attemptAccount(const QMailAccountId &id,
++ QMailAccount *result,
++ ReadLock &);
++
++ AttemptResult attemptAccountConfiguration(const QMailAccountId &id,
++ QMailAccountConfiguration *result,
++ ReadLock &);
++
++ AttemptResult attemptFolder(const QMailFolderId &id,
++ QMailFolder *result,
++ ReadLock &);
++
++ AttemptResult attemptMessage(const QMailMessageId &id,
++ QMailMessage *result,
++ ReadLock &);
++
++ AttemptResult attemptMessage(const QString &uid, const QMailAccountId &accountId,
++ QMailMessage *result,
++ ReadLock &);
++
++ AttemptResult attemptMessagesMetaData(const QMailMessageKey& key, const QMailMessageKey::Properties &properties, QMailStore::ReturnOption option,
++ QMailMessageMetaDataList *result,
++ ReadLock &);
++
++ AttemptResult attemptMessageRemovalRecords(const QMailAccountId &accountId, const QMailFolderId &parentFolderId,
++ QMailMessageRemovalRecordList *result,
++ ReadLock &);
++
++ AttemptResult attemptMessageFolderIds(const QMailMessageKey &key,
++ QMailFolderIdList *result,
++ ReadLock &);
++
++ AttemptResult attemptFolderAccountIds(const QMailFolderKey &key,
++ QMailAccountIdList *result,
++ ReadLock &);
++
++ AttemptResult attemptFolderAncestorIds(const QMailFolderIdList &ids,
++ QMailFolderIdList *result,
++ ReadLock &);
++
++ AttemptResult attemptStatusBit(const QString &name, const QString &context,
++ int *result,
++ ReadLock &);
++
++ AttemptResult attemptRegisterStatusBit(const QString &name, const QString &context, int maximum,
++ Transaction &t);
++
++ QMailAccount extractAccount(const QMailAccountId& id, const QStringList& list);
++ QMailFolder extractFolder(const QMailFolderId& id, const QStringList& list);
++ void extractMessageMetaData(const QStringList& list, QMailMessageMetaData* metaData);
++ QMailMessageRemovalRecord extractMessageRemovalRecord(const QStringList& r);
++
++ virtual void emitIpcNotification(QMailStoreImplementation::AccountUpdateSignal signal, const QMailAccountIdList &ids);
++ virtual void emitIpcNotification(QMailStoreImplementation::FolderUpdateSignal signal, const QMailFolderIdList &ids);
++ virtual void emitIpcNotification(QMailStoreImplementation::MessageUpdateSignal signal, const QMailMessageIdList &ids);
++
++ static const int headerCacheSize = 100;
++ static const int folderCacheSize = 10;
++ static const int accountCacheSize = 10;
++ static const int lookAhead = 5;
++
++ static QVariantList messageValues(const QMailMessageKey::Properties& properties, const QMailMessageMetaData& data);
++ static void updateMessageValues(const QMailMessageKey::Properties& properties, const QVariantList& values, const QMap<QString, QString>& customFields, QMailMessageMetaData& metaData);
++
++ static const QString &defaultContentScheme();
++ static const QString &messagesBodyPath();
++ static QString messageFilePath(const QString &fileName);
++ static int pathIdentifier(const QString &filePath);
++
++private:
++ template <typename T, typename ID>
++ class Cache
++ {
++ public:
++ Cache(unsigned int size = 10);
++ ~Cache();
++
++ T lookup(const ID& id) const;
++ void insert(const T& item);
++ bool contains(const ID& id) const;
++ void remove(const ID& id);
++ void clear();
++
++ private:
++ QCache<quint64,T> mCache;
++ };
++
++ mutable QMailMessageIdList lastQueryMessageResult;
++
++ mutable Cache<QMailMessageMetaData, QMailMessageId> headerCache;
++ mutable Cache<QMailFolder, QMailFolderId> folderCache;
++ mutable Cache<QMailAccount, QMailAccountId> accountCache;
++
++ mutable QList<const QMailMessageKey*> requiredTableKeys;
++ mutable QList<const QMailMessageKey*> temporaryTableKeys;
++ QList<const QMailMessageKey*> expiredTableKeys;
++
++ bool inTransaction;
++ mutable QString lastQueryError;
++
++ ProcessMutex *mutex;
++ ProcessReadLock *readLock;
++
++ static ProcessMutex *contentMutex;
++
++ SparqlDatabase sparqlDatabase;
++};
++
++template <typename ValueType>
++ValueType QMailStorePrivate::extractValue(const QVariant &var, const ValueType &defaultValue)
++{
++ if (!qVariantCanConvert<ValueType>(var)) {
++ qWarning() << "QMailStorePrivate::extractValue - Cannot convert variant to:"
++#ifdef QMAILSTORE_USE_RTTI
++ << typeid(ValueType).name();
++#else
++ << "requested type";
++#endif
++ return defaultValue;
++ }
++
++ return qVariantValue<ValueType>(var);
++}
++
++
++template <typename T, typename ID>
++QMailStorePrivate::Cache<T, ID>::Cache(unsigned int cacheSize)
++ : mCache(cacheSize)
++{
++}
++
++template <typename T, typename ID>
++QMailStorePrivate::Cache<T, ID>::~Cache()
++{
++}
++
++template <typename T, typename ID>
++T QMailStorePrivate::Cache<T, ID>::lookup(const ID& id) const
++{
++ if (id.isValid())
++ if (T* cachedItem = mCache.object(id.toULongLong()))
++ return *cachedItem;
++
++ return T();
++}
++
++template <typename T, typename ID>
++void QMailStorePrivate::Cache<T, ID>::insert(const T& item)
++{
++ if (item.id().isValid())
++ mCache.insert(item.id().toULongLong(),new T(item));
++}
++
++template <typename T, typename ID>
++bool QMailStorePrivate::Cache<T, ID>::contains(const ID& id) const
++{
++ return mCache.contains(id.toULongLong());
++}
++
++template <typename T, typename ID>
++void QMailStorePrivate::Cache<T, ID>::remove(const ID& id)
++{
++ mCache.remove(id.toULongLong());
++}
++
++template <typename T, typename ID>
++void QMailStorePrivate::Cache<T, ID>::clear()
++{
++ mCache.clear();
++}
++
++#endif
+diff --git a/src/libraries/qtopiamail/qtopiamail.pro b/src/libraries/qtopiamail/qtopiamail.pro
+index c715160..7d28130 100644
+--- a/src/libraries/qtopiamail/qtopiamail.pro
++++ b/src/libraries/qtopiamail/qtopiamail.pro
+@@ -1,17 +1,35 @@
+ TEMPLATE = lib
+
+ TARGET = qtopiamail
+-target.path += $$QMF_INSTALL_ROOT/lib
+-INSTALLS += target
+
+ DEFINES += QT_BUILD_QCOP_LIB
+
+ QT *= sql network
+
+-CONFIG += warn_on
++CONFIG += warn_on create_pc create_prl sparql
+
+ INCLUDEPATH += support
+
++sparql {
++
++DEFINES += SPARQL_STORE
++
++HEADERS += qmailstore_sparql.h
++
++SOURCES += qmailstore_sparql.cpp
++
++INCLUDEPATH += ../sparql ../sparql/tracker
++
++LIBS += -L../sparql -lsparql
++
++} else {
++
++HEADERS += qmailstore_p.h
++
++SOURCES += qmailstore_p.cpp
++
++}
++
+ HEADERS += bind_p.h \
+ longstream_p.h \
+ longstring_p.h \
+@@ -46,12 +64,11 @@ HEADERS += bind_p.h \
+ qmailmessagesortkey_p.h \
+ qmailserviceaction.h \
+ qmailstore.h \
+- qmailstore_p.h \
++ semaphore_p.h \
+ qmailstoreimplementation_p.h \
+ qmailtimestamp.h \
+ qprivateimplementation.h \
+ qprivateimplementationdef.h \
+- semaphore_p.h \
+ support/qmailglobal.h \
+ support/qmaillog.h \
+ support/qmailnamespace.h \
+@@ -62,7 +79,8 @@ HEADERS += bind_p.h \
+ support/qcopchannelmonitor.h \
+ support/qcopserver.h \
+ support/qmailpluginmanager.h \
+- support/qringbuffer_p.h
++ support/qringbuffer_p.h \
++ support/qmailipc.h
+
+ SOURCES += longstream.cpp \
+ longstring.cpp \
+@@ -90,7 +108,6 @@ SOURCES += longstream.cpp \
+ qmailmessagesortkey.cpp \
+ qmailserviceaction.cpp \
+ qmailstore.cpp \
+- qmailstore_p.cpp \
+ qmailstoreimplementation_p.cpp \
+ qmailtimestamp.cpp \
+ qprivateimplementation.cpp \
+@@ -120,3 +137,19 @@ TRANSLATIONS += libqtopiamail-ar.ts \
+ libqtopiamail-pt_BR.ts \
+ libqtopiamail-zh_CN.ts \
+ libqtopiamail-zh_TW.ts
++
++
++target.path += $$QMF_INSTALL_ROOT/lib
++INSTALLS += target
++
++# Install headers
++headers.files = $$HEADERS include/*
++headers.path = $$QMF_INSTALL_ROOT/include/qmf
++
++INSTALLS += headers
++
++# Install pkgconfig file
++QMAKE_PKGCONFIG_LIBDIR = $$target.path
++QMAKE_PKGCONFIG_INCDIR = $$headers.path
++QMAKE_PKGCONFIG_DESTDIR = pkgconfig
++
+diff --git a/src/libraries/qtopiamail/support/qmaillog.h b/src/libraries/qtopiamail/support/qmaillog.h
+index 9d61887..81373e8 100644
+--- a/src/libraries/qtopiamail/support/qmaillog.h
++++ b/src/libraries/qtopiamail/support/qmaillog.h
+@@ -86,12 +86,12 @@ public:
+
+ #define qMailLog(dbgcat) if(!dbgcat##_QLog::enabled()); else dbgcat##_QLog::log(#dbgcat)
+
+-QLOG_DISABLE() //uncategorized logging
+-QLOG_DISABLE(Messaging)
+-QLOG_DISABLE(IMAP)
+-QLOG_DISABLE(SMTP)
+-QLOG_DISABLE(POP)
+-QLOG_DISABLE(ImapData)
+-QLOG_DISABLE(MessagingState)
++QLOG_ENABLE() //uncategorized logging
++QLOG_ENABLE(Messaging)
++QLOG_ENABLE(IMAP)
++QLOG_ENABLE(SMTP)
++QLOG_ENABLE(POP)
++QLOG_ENABLE(ImapData)
++QLOG_ENABLE(MessagingState)
+
+ #endif //QMAILLOG_H
+diff --git a/src/libraries/qtopiamail/support/qmailnamespace.cpp b/src/libraries/qtopiamail/support/qmailnamespace.cpp
+index d63acdf..ce4b0a7 100644
+--- a/src/libraries/qtopiamail/support/qmailnamespace.cpp
++++ b/src/libraries/qtopiamail/support/qmailnamespace.cpp
+@@ -178,9 +178,9 @@ QString QMail::pluginsPath()
+ {
+ static QString pluginsEnv(getenv(QMF_PLUGINS_ENV));
+ if(!pluginsEnv.isEmpty())
+- return pluginsEnv + "/";
+- //default to "." if no env set
+- return pluginsEnv;
++ return pluginsEnv;
++ //default to "/usr/lib/qmf/" if no env set
++ return "/usr/lib/qmf/";
+ }
+
+ QString QMail::sslCertsPath()
+diff --git a/src/libraries/sparql/include/SparqlDatabase b/src/libraries/sparql/include/SparqlDatabase
+new file mode 100644
+index 0000000..ac92cb7
+--- /dev/null
++++ b/src/libraries/sparql/include/SparqlDatabase
+@@ -0,0 +1 @@
++#include "sparqldatabase.h"
+diff --git a/src/libraries/sparql/include/SparqlQuery b/src/libraries/sparql/include/SparqlQuery
+new file mode 100644
+index 0000000..bf9b61e
+--- /dev/null
++++ b/src/libraries/sparql/include/SparqlQuery
+@@ -0,0 +1 @@
++#include "sparqlquery.h"
+diff --git a/src/libraries/sparql/include/SparqlResult b/src/libraries/sparql/include/SparqlResult
+new file mode 100644
+index 0000000..8e66d59
+--- /dev/null
++++ b/src/libraries/sparql/include/SparqlResult
+@@ -0,0 +1 @@
++#include "sparqlresult.h"
+diff --git a/src/libraries/sparql/include/SparqlUri b/src/libraries/sparql/include/SparqlUri
+new file mode 100644
+index 0000000..52d7ed8
+--- /dev/null
++++ b/src/libraries/sparql/include/SparqlUri
+@@ -0,0 +1 @@
++#include "sparqluri.h"
+diff --git a/src/libraries/sparql/sparql.pro b/src/libraries/sparql/sparql.pro
+new file mode 100644
+index 0000000..b323449
+--- /dev/null
++++ b/src/libraries/sparql/sparql.pro
+@@ -0,0 +1,39 @@
++TEMPLATE = lib
++
++TARGET = sparql
++
++INCLUDEPATH += . tracker
++
++QT *= dbus
++
++# Input
++DBUS_HEADERS += tracker/registertypes.h \
++ tracker/resourcesproxy.h
++
++SPARQL_HEADERS += sparqldatabase.h \
++ sparqlquery.h \
++ sparqlresult.h \
++ sparqluri.h
++
++HEADERS += $$DBUS_HEADERS $$SPARQL_HEADERS
++
++SOURCES += \
++ sparqldatabase.cpp \
++ sparqlquery.cpp \
++ sparqlresult.cpp \
++ tracker/registertypes.cpp \
++ tracker/resourcesproxy.cpp \
++ sparqluri.cpp
++
++# Install headers
++sparql_headers.files = $$SPARQL_HEADERS include/*
++sparql_headers.path = $$QMF_INSTALL_ROOT/include/qmf
++
++dbus_headers.files = $$DBUS_HEADERS
++dbus_headers.path = $$QMF_INSTALL_ROOT/include/qmf/tracker
++
++INSTALLS += sparql_headers dbus_headers
++
++target.path += $$QMF_INSTALL_ROOT/lib
++
++INSTALLS += target
+diff --git a/src/libraries/sparql/sparqldatabase.cpp b/src/libraries/sparql/sparqldatabase.cpp
+new file mode 100644
+index 0000000..7568a09
+--- /dev/null
++++ b/src/libraries/sparql/sparqldatabase.cpp
+@@ -0,0 +1,44 @@
++#include "sparqldatabase.h"
++
++#include <QDBusConnection>
++
++// Pointer to the default database
++SparqlDatabase* SparqlDatabase::_defaultDatabase = NULL;
++
++
++SparqlDatabase::SparqlDatabase(const QString& databaseName) :
++ _proxy(databaseName, "/org/freedesktop/Tracker/Resources", QDBusConnection::sessionBus()),
++ _databaseName(databaseName)
++{
++ qDebug() << "SparqlDatabase::SparqlDatabase";
++ if (!_defaultDatabase)
++ {
++ // Register Qt types
++ registerTypes();
++
++ _defaultDatabase = this;
++ }
++}
++
++SparqlDatabase::~SparqlDatabase()
++{
++ if (_defaultDatabase == this)
++ _defaultDatabase = NULL;
++}
++
++SparqlDatabase* SparqlDatabase::defaultDatabase()
++{
++ return _defaultDatabase;
++}
++
++QString SparqlDatabase::databaseName() const
++{
++ return _databaseName;
++}
++
++bool SparqlDatabase::isOpenError() const
++{
++ // Check wheither we are connected
++ bool isConnected = _proxy.connection().isConnected();
++ return !isConnected;
++}
+diff --git a/src/libraries/sparql/sparqldatabase.h b/src/libraries/sparql/sparqldatabase.h
+new file mode 100644
+index 0000000..ab1d6b5
+--- /dev/null
++++ b/src/libraries/sparql/sparqldatabase.h
+@@ -0,0 +1,59 @@
++#ifndef SPARQLDATABASE_H
++#define SPARQLDATABASE_H
++
++#include "tracker/resourcesproxy.h"
++
++/**
++ * \brief SparqlDatabase represents connection to the SPARQL data base.
++ *
++ * SparqlDatabase represents connection to the SPARQL data base. It relies on the
++ * proxy implementation. It is possible to keep several databases opened at the same
++ * time, but only one of them will be default. All queries without exact database
++ * specification will be performed with default database.
++ *
++ * \see SparqlQuery
++ */
++class SparqlDatabase
++{
++ friend class SparqlQuery;
++
++public:
++ /**
++ * \brief Creates new database
++ *
++ * \param databaseName Name of the data base.
++ */
++ SparqlDatabase(const QString& databaseName = "org.freedesktop.Tracker");
++
++ /**
++ * \brief Default destructor
++ */
++ ~SparqlDatabase();
++
++ /**
++ * \brief Returns default database
++ *
++ * First created database will become default one.
++ *
++ * \return Pointer to the default database.
++ */
++ static SparqlDatabase* defaultDatabase();
++
++ /**
++ * \brief Returns name of the database
++ */
++ QString databaseName() const;
++
++ /**
++ * \brief Returns true wheither there was an error during opening database.
++ */
++ bool isOpenError() const;
++
++private:
++ static SparqlDatabase* _defaultDatabase;
++
++ ResourcesProxy _proxy;
++ QString _databaseName;
++};
++
++#endif // SPARQLDATABASE_H
+diff --git a/src/libraries/sparql/sparqlquery.cpp b/src/libraries/sparql/sparqlquery.cpp
+new file mode 100644
+index 0000000..8801b79
+--- /dev/null
++++ b/src/libraries/sparql/sparqlquery.cpp
+@@ -0,0 +1,86 @@
++#include "sparqlquery.h"
++#include "sparqldatabase.h"
++#include "sparqlresult.h"
++
++#include <QDBusPendingReply>
++
++SparqlQuery::SparqlQuery(SparqlQuery::QueryType type, const QString& query, SparqlDatabase* database) :
++ _type(type),
++ _query(query),
++ _database(database),
++ _result(NULL)
++{
++ if (!_database)
++ _database = SparqlDatabase::defaultDatabase();
++
++ Q_ASSERT(_database);
++}
++
++SparqlQuery::~SparqlQuery()
++{
++}
++
++bool SparqlQuery::prepare(const QString query)
++{
++ _query = query;
++
++ return true;
++}
++
++bool SparqlQuery::exec()
++{
++ Q_ASSERT(_database);
++
++ // Clear last error status and query result
++ _result.clear();
++ _error.clear();
++
++ qDebug() << _query;
++
++ bool err;
++ if (_type == SearchQuery)
++ {
++ QDBusPendingReply<QueryResultType> reply;
++ reply = _database->_proxy.SparqlQuery(_query);
++
++ reply.waitForFinished();
++
++ err = reply.isError();
++ if (!err)
++ {
++ _result = reply.value();
++
++ foreach (const QStringList& row, _result)
++ qDebug() << row.join(", ");
++
++ } else
++ _error = reply.error().message();
++
++ } else {
++ QDBusPendingReply<> reply;
++ reply = _database->_proxy.SparqlUpdate(_query);
++
++ reply.waitForFinished();
++
++ err = reply.isError();
++ if (err)
++ _error = reply.error().message();
++ }
++
++ return !err;
++}
++
++SparqlResult SparqlQuery::result() const
++{
++ return SparqlResult(this);
++}
++
++QString SparqlQuery::error() const
++{
++ return _error;
++}
++
++QString SparqlQuery::query() const
++{
++ return _query;
++}
+diff --git a/src/libraries/sparql/sparqlquery.h b/src/libraries/sparql/sparqlquery.h
+new file mode 100644
+index 0000000..a030cfb
+--- /dev/null
++++ b/src/libraries/sparql/sparqlquery.h
+@@ -0,0 +1,102 @@
++#ifndef SPARQLQUERY_H
++#define SPARQLQUERY_H
++
++#include <QStringList>
++#include <QVector>
++#include <QString>
++
++class SparqlDatabase;
++class SparqlResult;
++
++/**
++ * \brief SparqlQuery represents SPARQL query.
++ *
++ * There are two different types of queries: search and update queries. Search query uses standard SPARQL syntax
++ * and can only read information from the database. Update queries exploit Advanced SPARQL syntax and allow to
++ * insert, delete and update information in the database.
++ *
++ * Database can be defeined explicitely or default database can be used. In anycase at least one SparqlDatabase
++ * object must be created.
++ *
++ * \see SparqlDatabase
++ */
++class SparqlQuery
++{
++ friend class SparqlResult;
++
++public:
++ /**
++ * \brief Type of the query
++ */
++ enum QueryType
++ {
++ SearchQuery, ///< Query can use SELECT, CONSTRUCT, DESCRIBE or ASK SPARQL statments
++ UpdateQuery ///< Query can use INSERT, DELETE and UPDATE advances SPARQL statments
++ };
++
++ /**
++ * \brief Constructs SPARQL query
++ *
++ * \param type Type of the quey.
++ * \param query Query string, It can be defined later with prepare() method.
++ * \param database Pointer to the database. Default database will be used in case of NULL.
++ */
++ SparqlQuery(QueryType type, const QString& query = QString(), SparqlDatabase* database = NULL);
++
++ /**
++ * \brief Default destructor
++ */
++ ~SparqlQuery();
++
++ /**
++ * \brief Prepare query for execution
++ *
++ * \param SPARQL query to prepare.
++ * \return Status of the application.
++ */
++ bool prepare(const QString query);
++
++ /**
++ * \brief Execute prepared query
++ *
++ * Before executing a query it has to be prepared using prepare() method.
++ * In case of any errors exec() will return false. More detailes information
++ * about source of error can be retrieved using error() method.
++ *
++ * Result of query execution can be retrieved using result() method.
++ * Retult is available only for Search queries.
++ *
++ * \return true in case of success and false in case of failure.
++ */
++ bool exec();
++
++ /**
++ * \brief Returns result of the operation
++ *
++ * \return result can be NULL in case of error or Update query was executed.
++ */
++ SparqlResult result() const;
++
++ /**
++ * \brief Returns textual representation of the error.
++ *
++ * \return Literal error description.
++ */
++ QString error() const;
++
++ /**
++ * \brief Returns prepared SPARQL query to execute.
++ */
++ QString query() const;
++
++private:
++ QueryType _type;
++ QString _query;
++ SparqlDatabase* _database;
++ QString _error;
++
++ typedef QVector<QStringList> QueryResultType;
++ QueryResultType _result;
++};
++
++#endif // SPARQLQUERY_H
+diff --git a/src/libraries/sparql/sparqlresult.cpp b/src/libraries/sparql/sparqlresult.cpp
+new file mode 100644
+index 0000000..de7f2a0
+--- /dev/null
++++ b/src/libraries/sparql/sparqlresult.cpp
+@@ -0,0 +1,31 @@
++#include "sparqlresult.h"
++#include "sparqlquery.h"
++
++SparqlResult::SparqlResult(const SparqlQuery* query) :
++ _query(query),
++ _current(0)
++{
++}
++
++const QStringList& SparqlResult::fetchRow()
++{
++ Q_ASSERT(_query);
++
++ return _query->_result.at(_current++);
++}
++
++bool SparqlResult::begin() const
++{
++ return (_current == 0);
++}
++
++bool SparqlResult::end() const
++{
++ Q_ASSERT(_query);
++ return (_query->_result.count() == _current);
++}
++
++void SparqlResult::reset()
++{
++ _current = 0;
++}
+diff --git a/src/libraries/sparql/sparqlresult.h b/src/libraries/sparql/sparqlresult.h
+new file mode 100644
+index 0000000..2c9be91
+--- /dev/null
++++ b/src/libraries/sparql/sparqlresult.h
+@@ -0,0 +1,56 @@
++#ifndef SPARQLRESULT_H
++#define SPARQLRESULT_H
++
++#include <QVector>
++#include <QStringList>
++
++class SparqlQuery;
++
++/**
++ * \brief SparqlResult provides convenient way to fetch data from the executed query.
++ *
++ * To fetch data from already executed query you have to get instance of that class
++ * with SparqlQuery::result() method and call fetchRow() method till you reach the end().
++ *
++ * It is possible to enumerate result of the query using different instances of the
++ * SparqlResult class at the same time. But you have to know that data itself belongs
++ * to the query and you should not access any methods of this class in case of SparqlQuery
++ * was destroyed.
++ *
++ * \see SparqlQuery
++ */
++class SparqlResult
++{
++ friend class SparqlQuery;
++
++public:
++ /**
++ * \brief Fetch the row with results of the query
++ *
++ * \return List of values of the row.
++ */
++ const QStringList& fetchRow();
++
++ /**
++ * \brief Does the result point to the beginig of data set
++ */
++ bool begin() const;
++
++ /**
++ * \brief Does the result point to the end of the data set
++ */
++ bool end() const;
++
++ /**
++ * \brief Reset result and make it points to the begining again
++ */
++ void reset();
++
++private:
++ SparqlResult(const SparqlQuery* query);
++ const SparqlQuery* _query;
++
++ int _current;
++};
++
++#endif // SPARQLRESULT_H
+diff --git a/src/libraries/sparql/sparqluri.cpp b/src/libraries/sparql/sparqluri.cpp
+new file mode 100644
+index 0000000..6963010
+--- /dev/null
++++ b/src/libraries/sparql/sparqluri.cpp
+@@ -0,0 +1,88 @@
++#include "sparqluri.h"
++#include <QUuid>
++
++SparqlUri::SparqlUri(const QString& base) :
++ _id(generate())
++{
++ bool ret = setBase(base);
++ Q_ASSERT(ret);
++}
++
++SparqlUri::SparqlUri(const QString& base, quint64 id) :
++ _id(id)
++{
++ bool ret = setBase(base);
++ Q_ASSERT(ret);
++}
++
++bool SparqlUri::setBase(const QString& base)
++{
++ _base = base;
++ return true;
++}
++
++QString SparqlUri::base() const
++{
++ return _base;
++}
++
++QString SparqlUri::uri() const
++{
++ return QString("<%1>").arg(base() + QString::number(_id));
++}
++
++void SparqlUri::setId(quint64 id)
++{
++ _id = id;
++}
++
++quint64 SparqlUri::id() const
++{
++ return _id;
++}
++
++quint64 SparqlUri::generate()
++{
++ /*
++ * BUG!BUG!BUG!
++ *
++ * We can't just generate UUID and do not make
++ * sure that it is unique.
++ *
++ * THIS CODE HAS TO BE REWRITTEN.
++ */
++ QUuid uuid = QUuid::createUuid();
++
++ quint64 data1 = uuid.data1;
++ quint64 data2 = uuid.data2;
++ quint64 data3 = uuid.data3;
++ quint64 data4 = *(quint64*)uuid.data4;
++
++ quint64 id = (data1 << 32) ^ (data2 << 16) ^ data3;
++ id |= data4;
++
++ return id;
++}
++
++SparqlUri::operator QString () const
++{
++ return uri();
++}
++
++SparqlUri::operator quint64 () const
++{
++ return id();
++}
++
++QString SparqlUri::operator++ ()
++{
++ _id = generate();
++ return uri();
++}
++
++QString SparqlUri::operator++ (int)
++{
++ QString result(uri());
++ _id = generate();
++ return result;
++}
+diff --git a/src/libraries/sparql/sparqluri.h b/src/libraries/sparql/sparqluri.h
+new file mode 100644
+index 0000000..44aeab1
+--- /dev/null
++++ b/src/libraries/sparql/sparqluri.h
+@@ -0,0 +1,102 @@
++#ifndef SPARQLURI_H
++#define SPARQLURI_H
++
++#include "sparqldatabase.h"
++
++/**
++ * \brief SparqlUri provides automatic URI generation.
++ *
++ * URI is unique identifier in the SPARQL language, it is required
++ * to be able to generate unique identifiers fast and easy. SparqlUri class
++ * provides convenient way to generate such URI.
++ *
++ * Every URI has base part and autogenerated part. Base part can be defined by user.
++ * Autogenerated part will be changed with every increment operation.
++ *
++ * Autogenerate URI will look like http://base.part/is/fixed#nnnnnn, where nnnnnn is 64bit
++ * integer, No any prediction is made about order or number of digits in the nnnnnn.
++ *
++ * \see SparqlQuery
++ */
++class SparqlUri
++{
++public:
++ /**
++ * \brief Constructor of the URI
++ *
++ * Unique id will be autogenerated.
++ *
++ * \param base Fixed part of the URI.
++ */
++ SparqlUri(const QString& base);
++
++ /**
++ * \brief Constructor of the URI generator
++ *
++ * Value of id is passed as a parameter
++ *
++ * \param base Fixed part of the URI.
++ * \param id Pre-defined id is used in this case.
++ */
++ SparqlUri(const QString& base, quint64 id);
++
++ /**
++ * \brief Set new fixed base of the URI
++ */
++ bool setBase(const QString& base);
++
++ /**
++ * \brief Get fixed base part of the URI
++ */
++ QString base() const;
++
++ /**
++ * \brief Get current URI as a string
++ */
++ void setId(quint64 id);
++
++ /**
++ * \brief Set current nnnnnn part as 64-bit integer
++ */
++ quint64 id() const;
++
++ /**
++ * \brief Get current nnnnnn part as 64-bit integer
++ */
++ QString uri() const;
++
++ /**
++ * \brief Generates new nnnnnn.
++ *
++ * Current URI is not updated. To update current URI as well operator++ should be used.
++ *
++ * \return new nnnnnn part of the URI as 64-bit unsigned integer.
++ */
++ quint64 generate();
++
++ /**
++ * \brief Convenience operator returns URI
++ */
++ operator QString () const;
++
++ /**
++ * \brief Convenience operator returns nnnnnn part of the URI
++ */
++ operator quint64 () const;
++
++ /**
++ * \brief Generates new URI and returns new value
++ */
++ QString operator++ ();
++
++ /**
++ * \brief Generates new URI and returns old value
++ */
++ QString operator++ (int);
++
++private:
++ QString _base;
++ quint64 _id;
++};
++
++#endif // #ifndef SPARQLURI_H
+diff --git a/src/libraries/sparql/tracker/README b/src/libraries/sparql/tracker/README
+new file mode 100644
+index 0000000..9b8b88a
+--- /dev/null
++++ b/src/libraries/sparql/tracker/README
+@@ -0,0 +1,20 @@
++
++HOWTO Generate proxy code from DBUSXML interface definition
++
++ Obtain latest version of the .xml files from the tracker repository
++ git://git.codethink.co.uk/git/tracker
++
++ Backup existing .xml files and code of the DBUS proxy classes.
++
++ Update XML interface description with correct annotations for all Qt types:
++ * For every type="aas" direction="out", add following annotation:
++ <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVector&lt;QStringList&gt;"/>
++
++ * For every type="a{sv}" direction="out", add following annotation:
++ <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantList"/>
++
++ * For every signal with type="aas", add following annotation:
++ <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="QVector&lt;QStringList&gt;"/>
++
++ Run genproxy.sh script
++
+diff --git a/src/libraries/sparql/tracker/genproxy.sh b/src/libraries/sparql/tracker/genproxy.sh
+new file mode 100755
+index 0000000..73a960c
+--- /dev/null
++++ b/src/libraries/sparql/tracker/genproxy.sh
+@@ -0,0 +1,2 @@
++#!/bin/bash
++qdbusxml2cpp -c ResourcesProxy -p resourcesproxy -i registertypes.h tracker-resources.xml org.freedesktop.Tracker.Resources
+diff --git a/src/libraries/sparql/tracker/registertypes.cpp b/src/libraries/sparql/tracker/registertypes.cpp
+new file mode 100644
+index 0000000..e8ce4ed
+--- /dev/null
++++ b/src/libraries/sparql/tracker/registertypes.cpp
+@@ -0,0 +1,10 @@
++#include <QDBusMetaType>
++#include <QtDebug>
++
++#include "registertypes.h"
++
++void registerTypes()
++{
++ qRegisterMetaType<QVector<QStringList> >();
++ qDBusRegisterMetaType<QVector<QStringList> >();
++}
+diff --git a/src/libraries/sparql/tracker/registertypes.h b/src/libraries/sparql/tracker/registertypes.h
+new file mode 100644
+index 0000000..5c87c3f
+--- /dev/null
++++ b/src/libraries/sparql/tracker/registertypes.h
+@@ -0,0 +1,12 @@
++#ifndef __REGISTERTYPES_H__
++#define __REGISTERTYPES_H__
++
++#include <QMetaType>
++#include <QVector>
++#include <QStringList>
++
++Q_DECLARE_METATYPE(QVector<QStringList>)
++
++void registerTypes();
++
++#endif // #ifndef __REGISTERTYPES_H__
+diff --git a/src/libraries/sparql/tracker/resourcesproxy.cpp b/src/libraries/sparql/tracker/resourcesproxy.cpp
+new file mode 100644
+index 0000000..96f5d46
+--- /dev/null
++++ b/src/libraries/sparql/tracker/resourcesproxy.cpp
+@@ -0,0 +1,26 @@
++/*
++ * This file was generated by qdbusxml2cpp version 0.7
++ * Command line was: qdbusxml2cpp -c ResourcesProxy -p resourcesproxy -i registertypes.h tracker-resources.xml org.freedesktop.Tracker.Resources
++ *
++ * qdbusxml2cpp is Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
++ *
++ * This is an auto-generated file.
++ * This file may have been hand-edited. Look for HAND-EDIT comments
++ * before re-generating it.
++ */
++
++#include "resourcesproxy.h"
++
++/*
++ * Implementation of interface class ResourcesProxy
++ */
++
++ResourcesProxy::ResourcesProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
++ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
++{
++}
++
++ResourcesProxy::~ResourcesProxy()
++{
++}
++
+diff --git a/src/libraries/sparql/tracker/resourcesproxy.h b/src/libraries/sparql/tracker/resourcesproxy.h
+new file mode 100644
+index 0000000..eafaa2a
+--- /dev/null
++++ b/src/libraries/sparql/tracker/resourcesproxy.h
+@@ -0,0 +1,85 @@
++/*
++ * This file was generated by qdbusxml2cpp version 0.7
++ * Command line was: qdbusxml2cpp -c ResourcesProxy -p resourcesproxy -i registertypes.h tracker-resources.xml org.freedesktop.Tracker.Resources
++ *
++ * qdbusxml2cpp is Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
++ *
++ * This is an auto-generated file.
++ * Do not edit! All changes made to it will be lost.
++ */
++
++#ifndef RESOURCESPROXY_H_1241509742
++#define RESOURCESPROXY_H_1241509742
++
++#include <QtCore/QObject>
++#include <QtCore/QByteArray>
++#include <QtCore/QList>
++#include <QtCore/QMap>
++#include <QtCore/QString>
++#include <QtCore/QStringList>
++#include <QtCore/QVariant>
++#include <QtDBus/QtDBus>
++#include "registertypes.h"
++
++/*
++ * Proxy class for interface org.freedesktop.Tracker.Resources
++ */
++class ResourcesProxy: public QDBusAbstractInterface
++{
++ Q_OBJECT
++public:
++ static inline const char *staticInterfaceName()
++ { return "org.freedesktop.Tracker.Resources"; }
++
++public:
++ ResourcesProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
++
++ ~ResourcesProxy();
++
++public Q_SLOTS: // METHODS
++ inline QDBusPendingReply<> Delete(const QString &subject, const QString &predicate, const QString &object)
++ {
++ QList<QVariant> argumentList;
++ argumentList << qVariantFromValue(subject) << qVariantFromValue(predicate) << qVariantFromValue(object);
++ return asyncCallWithArgumentList(QLatin1String("Delete"), argumentList);
++ }
++
++ inline QDBusPendingReply<> Insert(const QString &subject, const QString &predicate, const QString &object)
++ {
++ QList<QVariant> argumentList;
++ argumentList << qVariantFromValue(subject) << qVariantFromValue(predicate) << qVariantFromValue(object);
++ return asyncCallWithArgumentList(QLatin1String("Insert"), argumentList);
++ }
++
++ inline QDBusPendingReply<> Load(const QString &uri)
++ {
++ QList<QVariant> argumentList;
++ argumentList << qVariantFromValue(uri);
++ return asyncCallWithArgumentList(QLatin1String("Load"), argumentList);
++ }
++
++ inline QDBusPendingReply<QVector<QStringList> > SparqlQuery(const QString &query)
++ {
++ QList<QVariant> argumentList;
++ argumentList << qVariantFromValue(query);
++ return asyncCallWithArgumentList(QLatin1String("SparqlQuery"), argumentList);
++ }
++
++ inline QDBusPendingReply<> SparqlUpdate(const QString &query)
++ {
++ QList<QVariant> argumentList;
++ argumentList << qVariantFromValue(query);
++ return asyncCallWithArgumentList(QLatin1String("SparqlUpdate"), argumentList);
++ }
++
++Q_SIGNALS: // SIGNALS
++};
++
++namespace org {
++ namespace freedesktop {
++ namespace Tracker {
++ typedef ::ResourcesProxy Resources;
++ }
++ }
++}
++#endif
+diff --git a/src/libraries/sparql/tracker/tracker-resources.xml b/src/libraries/sparql/tracker/tracker-resources.xml
+new file mode 100644
+index 0000000..233fc64
+--- /dev/null
++++ b/src/libraries/sparql/tracker/tracker-resources.xml
+@@ -0,0 +1,44 @@
++<?xml version="1.0" encoding="UTF-8"?>
++
++<node name="/org/freedesktop/Tracker">
++ <interface name="org.freedesktop.Tracker.Resources">
++
++ <!-- Insert single statement -->
++ <method name="Insert">
++ <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
++ <arg type="s" name="subject" direction="in" />
++ <arg type="s" name="predicate" direction="in" />
++ <arg type="s" name="object" direction="in" />
++ </method>
++
++ <!-- Delete single statement -->
++ <method name="Delete">
++ <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
++ <arg type="s" name="subject" direction="in" />
++ <arg type="s" name="predicate" direction="in" />
++ <arg type="s" name="object" direction="in" />
++ </method>
++
++ <!-- Load statements from Turtle file -->
++ <method name="Load">
++ <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
++ <arg type="s" name="uri" direction="in" />
++ </method>
++
++ <!-- SPARQL Query without updates -->
++ <method name="SparqlQuery">
++ <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
++ <annotation name="com.trolltech.QtDBus.QtTypeName.Out0"
++ value="QVector&lt;QStringList&gt;"/>
++ <arg type="s" name="query" direction="in" />
++ <arg type="aas" name="result" direction="out" />
++ </method>
++
++ <!-- SPARQL Update extensions, allows bulk insert and delete -->
++ <method name="SparqlUpdate">
++ <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
++ <arg type="s" name="query" direction="in" />
++ </method>
++
++ </interface>
++</node>
+diff --git a/tools/sparql-import/main.cpp b/tools/sparql-import/main.cpp
+new file mode 100644
+index 0000000..4fcdd02
+--- /dev/null
++++ b/tools/sparql-import/main.cpp
+@@ -0,0 +1,82 @@
++#include <QCoreApplication>
++
++#include "sparqluri.h"
++#include "sparqlquery.h"
++#include "sparqlresult.h"
++#include "sparqldatabase.h"
++#include "sparqlmailstore.h"
++
++#include <qmailstore.h>
++
++/**
++ * \brief Export database from the SQLite to SPARQ.
++ *
++ * This utility allows you to export your existing SQL
++ * mailstore to the SPARQL database.
++ */
++int main(int argc, char* argv[])
++{
++ QCoreApplication app(argc, argv);
++
++ SparqlDatabase database;
++ SparqlMailStore sparqlStore;
++
++ QMailStore* sqlStore = QMailStore::instance();
++
++ QMailAccountIdList accountIdList = sqlStore->queryAccounts();
++
++ foreach (QMailAccountId accountId, accountIdList)
++ {
++ QMailAccount account(accountId);
++
++ sparqlStore.addAccount(&account);
++
++ QMailFolderKey folderKey = QMailFolderKey::parentAccountId(accountId);
++
++ QMailFolderIdList folderIdList = sqlStore->queryFolders(folderKey);
++
++ foreach (QMailFolderId folderId, folderIdList)
++ {
++ QMailFolder folder(folderId);
++
++ sparqlStore.addFolder(&folder);
++
++ QMailMessageKey messageKey = QMailMessageKey::parentFolderId(folderId);
++
++ QMailMessageIdList messageIdList = sqlStore->queryMessages(messageKey);
++
++ foreach (QMailMessageId messageId, messageIdList)
++ {
++ QMailMessage message(messageId);
++
++ sparqlStore.addMessage(&message);
++ }
++ }
++ }
++
++ // Add all folders without any accounts
++ QMailFolderKey folderKey = QMailFolderKey::parentAccountId(QMailAccountId());
++ QMailFolderIdList folderIdList = sqlStore->queryFolders(folderKey);
++
++ foreach (QMailFolderId folderId, folderIdList)
++ {
++ QMailFolder folder(folderId);
++
++ sparqlStore.addFolder(&folder);
++
++ QMailMessageKey messageKey = QMailMessageKey::parentFolderId(folderId);
++
++ QMailMessageIdList messageIdList = sqlStore->queryMessages(messageKey);
++
++ foreach (QMailMessageId messageId, messageIdList)
++ {
++ QMailMessage message(messageId);
++
++ sparqlStore.addMessage(&message);
++ }
++ }
++
++ return 0;
++}
++
++
+diff --git a/tools/sparql-import/sparql-import.pro b/tools/sparql-import/sparql-import.pro
+new file mode 100644
+index 0000000..3429430
+--- /dev/null
++++ b/tools/sparql-import/sparql-import.pro
+@@ -0,0 +1,23 @@
++TEMPLATE = app
++
++TARGET = sparql-import
++
++QT += dbus
++
++DEPENDPATH += .
++
++INCLUDEPATH += . \
++ ../../src/libraries/qtopiamail \
++ ../../src/libraries/qtopiamail/support \
++ ../../src/libraries/sparql
++
++LIBS += -L../../src/libraries/qtopiamail -L../../src/libraries/sparql -lqtopiamail -lsparql
++
++QMAKE_LFLAGS += -Wl,-rpath,../../src/libraries/qtopiamail -Wl,-rpath,../../src/libraries/sparql
++
++# Input
++HEADERS += sparqlmailstore.h
++SOURCES += main.cpp sparqlmailstore.cpp
++
++target.path += $$QMF_INSTALL_ROOT/tests
++INSTALLS += target
+diff --git a/tools/sparql-import/sparqlmailstore.cpp b/tools/sparql-import/sparqlmailstore.cpp
+new file mode 100644
+index 0000000..cfa78b7
+--- /dev/null
++++ b/tools/sparql-import/sparqlmailstore.cpp
+@@ -0,0 +1,1404 @@
++#include "sparqlmailstore.h"
++
++#include "sparqluri.h"
++#include "sparqlquery.h"
++#include "sparqlresult.h"
++
++
++#include <QDebug>
++
++namespace {
++
++QString escape(const QString &original, const QChar &escapee, const QChar &escaper = '\\')
++{
++ QString result(original);
++ return result.replace(escapee, QString(escaper) + escapee);
++}
++
++QString contentUri(const QString &scheme, const QString &identifier)
++{
++ if (scheme.isEmpty())
++ return QString();
++
++ // Formulate a URI from the content scheme and identifier
++ return escape(scheme, ':') + ':' + escape(identifier, ':');
++}
++
++QString contentUri(const QMailMessageMetaData &message)
++{
++ return contentUri(message.contentScheme(), message.contentIdentifier());
++}
++
++QString unescape(const QString &original, const QChar &escapee, const QChar &escaper = '\\')
++{
++ QString result(original);
++ return result.replace(QString(escaper) + escapee, escapee);
++}
++
++QPair<QString, QString> uriElements(const QString &uri)
++{
++ int index = uri.indexOf(':');
++ while ((index != -1) && (uri.at(index - 1) == '\\'))
++ index = uri.indexOf(':', index + 1);
++
++ return qMakePair(unescape(uri.mid(0, index), ':'), unescape(uri.mid(index + 1), ':'));
++}
++
++using namespace QMailKey;
++
++const char *WellKnownUris[] = {
++ "qmf://groove.harmattan.com/email#",
++ "qmf://groove.nokia.com/folder#",
++ "qmf://groove.nokia.com/accounts#" };
++
++template <int INDEX>
++class WellKnownUri : public SparqlUri
++{
++public:
++ WellKnownUri() : SparqlUri(WellKnownUris[INDEX]) {}
++ WellKnownUri(quint64 id) : SparqlUri(WellKnownUris[INDEX], id) {}
++};
++
++typedef WellKnownUri<0> MailMessageUri;
++typedef WellKnownUri<1> MailFolderUri;
++typedef WellKnownUri<2> MailAccountUri;
++
++QString combineOperatorString(QMailKey::Combiner op)
++{
++ switch (op)
++ {
++ case And:
++ return " && ";
++ break;
++
++ case Or:
++ return " || ";
++ break;
++
++ case None:
++ break;
++ }
++
++ return QString();
++}
++
++template <class Comparator>
++QString operatorString(Comparator op, int argsNumber = 1);
++
++QString operatorStringPattern(int argNumber, const QString& op, const QString& comp)
++{
++ QStringList pattern;
++ for (int i = 0; i<argNumber; i++)
++ pattern << "(%1 " + op + " %" + QString::number(i+2) + ")";
++
++ if (argNumber > 1)
++ return "(" + pattern.join(comp) + ")";
++ else
++ return pattern.join(comp);
++}
++
++template <>
++QString operatorString<QMailKey::Comparator>(QMailKey::Comparator op, int argsNumber)
++{
++ switch (op)
++ {
++ case Equal:
++ // "(%1 = \"%2\")" : "(%1 = \"%2\") || (%1 = \"%3\")"
++ return (argsNumber == 1 ? operatorStringPattern(argsNumber, "=", "") : operatorStringPattern(argsNumber, "=", " || "));
++ break;
++
++ case NotEqual:
++ // "(%1 != \"%2\")" : "(%1 != \"%2\") && (%1 != \"%3\")"
++ return (argsNumber == 1 ? operatorStringPattern(argsNumber, "!=", "") : operatorStringPattern(argsNumber, "!=", " && "));
++ break;
++
++ case LessThan:
++ return "(%1 < %2)";
++ break;
++
++ case LessThanEqual:
++ return "(%1 <= %2)";
++ break;
++
++ case GreaterThan:
++ return "(%1 > %2)";
++ break;
++
++ case GreaterThanEqual:
++ return "(%1 >= %2)";
++ break;
++
++ case Includes:
++ case Present:
++ // "(%1 & \"%2\")" : "(%1 = \"%2\") || (%1 = \"%3\")"
++ return (argsNumber == 1 ? operatorStringPattern(argsNumber, "&", "") : operatorStringPattern(argsNumber, "=", " || "));
++ break;
++
++ case Excludes:
++ case Absent:
++ // "!(%1 & \"%2\")" : "(%1 != \"%2\") && (%1 != \"%3\")"
++ return (argsNumber == 1 ? "(!" + operatorStringPattern(argsNumber, "&", "") + ")": operatorStringPattern(argsNumber, "!=", " && "));
++ break;
++ }
++
++ return QString();
++}
++
++template <class Property>
++QString propertyNameString(Property property);
++
++template <>
++QString propertyNameString<QMailMessageKey::Property>(QMailMessageKey::Property property)
++{
++ switch (property)
++ {
++ case QMailMessageKey::Id:
++ return "?id";
++
++ case QMailMessageKey::Type:
++ return "?type";
++
++ case QMailMessageKey::ParentFolderId:
++ return "?parentFolderId";
++
++ case QMailMessageKey::Sender:
++ return "?sender";
++
++ case QMailMessageKey::Recipients:
++ return "?recipients";
++
++ case QMailMessageKey::Subject:
++ return "?subject";
++
++ case QMailMessageKey::TimeStamp:
++ return "?timestamp";
++
++ case QMailMessageKey::Status:
++ return "?status";
++
++ case QMailMessageKey::Conversation:
++ return "?conversation";
++
++ case QMailMessageKey::ReceptionTimeStamp:
++ return "?receptionTimeStamp";
++
++ case QMailMessageKey::ServerUid:
++ return "?serverUid";
++
++ case QMailMessageKey::Size:
++ return "?size";
++
++ case QMailMessageKey::ParentAccountId:
++ return "?parentAccountId";
++
++ case QMailMessageKey::AncestorFolderIds:
++ return "?ancestorFolderIds";
++
++ case QMailMessageKey::ContentType:
++ return "?contentType";
++
++ case QMailMessageKey::PreviousParentFolderId:
++ return "?previousParentFolderId";
++
++ case QMailMessageKey::ContentScheme:
++ return "?contentScheme";
++
++ case QMailMessageKey::ContentIdentifier:
++ return "?contentIdentifier";
++
++ case QMailMessageKey::InResponseTo:
++ return "?inResponseTo";
++
++ case QMailMessageKey::ResponseType:
++ return "?responseType";
++
++ case QMailMessageKey::Custom:
++ return "?custom";
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString propertyNameString<QMailFolderKey::Property>(QMailFolderKey::Property property)
++{
++ switch (property)
++ {
++ case QMailFolderKey::Id:
++ return "?id";
++
++ case QMailFolderKey::Path:
++ return "?path";
++
++ case QMailFolderKey::ParentFolderId:
++ return "?parentFolderId";
++
++ case QMailFolderKey::ParentAccountId:
++ return "?parentAccountId";
++
++ case QMailFolderKey::DisplayName:
++ return "?displayName";
++
++ case QMailFolderKey::Status:
++ return "?status";
++
++ case QMailFolderKey::AncestorFolderIds:
++ return "?ancestorFolderIds";
++
++ case QMailFolderKey::ServerCount:
++ return "?serverCount";
++
++ case QMailFolderKey::ServerUnreadCount:
++ return "?serverUnreadCount";
++
++ case QMailFolderKey::Custom:
++ return "?custom";
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString propertyNameString<QMailAccountKey::Property>(QMailAccountKey::Property property)
++{
++ switch (property)
++ {
++ case QMailAccountKey::Id:
++ return "?id";
++
++ case QMailAccountKey::Name:
++ return "?name";
++
++ case QMailAccountKey::MessageType:
++ return "?messageType";
++
++ case QMailAccountKey::FromAddress:
++ return "?fromAddress";
++
++ case QMailAccountKey::Status:
++ return "?status";
++
++ case QMailAccountKey::Custom:
++ return "?custom";
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString propertyNameString<QMailMessageSortKey::Property>(QMailMessageSortKey::Property property)
++{
++ switch (property)
++ {
++ case QMailMessageSortKey::Id:
++ return "?id";
++
++ case QMailMessageSortKey::Type:
++ return "?type";
++
++ case QMailMessageSortKey::ParentFolderId:
++ return "?parentFolderId";
++
++ case QMailMessageSortKey::Sender:
++ return "?sender";
++
++ case QMailMessageSortKey::Recipients:
++ return "?recipients";
++
++ case QMailMessageSortKey::Subject:
++ return "?subject";
++
++ case QMailMessageSortKey::TimeStamp:
++ return "?timestamp";
++
++ case QMailMessageSortKey::Status:
++ return "?status";
++
++ case QMailMessageSortKey::ReceptionTimeStamp:
++ return "?receptionTimeStamp";
++
++ case QMailMessageSortKey::ServerUid:
++ return "?serverUid";
++
++ case QMailMessageSortKey::Size:
++ return "?size";
++
++ case QMailMessageSortKey::ParentAccountId:
++ return "?parentAccountId";
++
++ case QMailMessageSortKey::ContentType:
++ return "?contentType";
++
++ case QMailMessageSortKey::PreviousParentFolderId:
++ return "?previousParentFolderId";
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString propertyNameString<QMailFolderSortKey::Property>(QMailFolderSortKey::Property property)
++{
++ switch (property)
++ {
++ case QMailFolderSortKey::Id:
++ return "?id";
++
++ case QMailFolderSortKey::Path:
++ return "?path";
++
++ case QMailFolderSortKey::ParentFolderId:
++ return "?parentFolderId";
++
++ case QMailFolderSortKey::ParentAccountId:
++ return "?parentAccountId";
++
++ case QMailFolderSortKey::DisplayName:
++ return "?displayName";
++
++ case QMailFolderSortKey::Status:
++ return "?status";
++
++ case QMailFolderSortKey::ServerCount:
++ return "?serverCount";
++
++ case QMailFolderSortKey::ServerUnreadCount:
++ return "?serverUnreadCount";
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString propertyNameString<QMailAccountSortKey::Property>(QMailAccountSortKey::Property property)
++{
++ switch (property)
++ {
++ case QMailAccountSortKey::Id:
++ return "?id";
++
++ case QMailAccountSortKey::Name:
++ return "?name";
++
++ case QMailAccountSortKey::MessageType:
++ return "?messageType";
++
++ case QMailAccountSortKey::Status:
++ return "?status";
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <class Property>
++QString sparqlPropertyStatmentString(const QString& uri, Property property);
++
++template <>
++QString sparqlPropertyStatmentString<QMailMessageKey::Property>(const QString& uri, QMailMessageKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailMessageKey::Id:
++ return QString();
++
++ case QMailMessageKey::Type:
++ return QString();
++
++ case QMailMessageKey::ParentFolderId:
++ return QString("%1 nie:isLogicalPartOf %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Sender:
++ return QString("%1 nmo:sender [ rdf:type nco:Contact ; nco:hasEmailAddress %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Recipients:
++ return QString("%1 nmo:recipient [ rdf:type nco:Contact ; nco:hasEmailAddress %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Subject:
++ return QString("%1 nmo:messageSubject %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::TimeStamp:
++ return QString("%1 nmo:sentDate %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Conversation:
++ return QString();
++
++ case QMailMessageKey::ReceptionTimeStamp:
++ return QString();
++
++ case QMailMessageKey::ServerUid:
++ return QString("%1 nmo:messageId %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::Size:
++ return QString("%1 nie:contentSize %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::ParentAccountId:
++ return QString("%1 nie:relatedTo %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::AncestorFolderIds:
++ return QString();
++
++ case QMailMessageKey::ContentType:
++ return QString();
++
++ case QMailMessageKey::PreviousParentFolderId:
++ return QString();
++
++ case QMailMessageKey::ContentScheme:
++ return QString();
++
++ case QMailMessageKey::ContentIdentifier:
++ return QString("%1 nie:isStoredAs [ rdf:type nie:DataObject ; nie:dataSource %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::InResponseTo:
++ return QString("%1 nmo:inReplyTo %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageKey::ResponseType:
++ return QString();
++
++ case QMailMessageKey::Custom:
++ return QString();
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString sparqlPropertyStatmentString<QMailFolderKey::Property>(const QString& uri, QMailFolderKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailFolderKey::Id:
++ return "id";
++
++ case QMailFolderKey::Path:
++ return QString("%1 nmo:folderName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::ParentFolderId:
++ return QString("%1 nie:isLogicalPartOf %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::ParentAccountId:
++ return QString("%1 nie:relatedTo %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::DisplayName:
++ return QString("%1 nmo:folderDisplayName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::AncestorFolderIds:
++ return QString();
++
++ case QMailFolderKey::ServerCount:
++ return QString("%1 nmo:serverCount %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::ServerUnreadCount:
++ return QString("%1 nmo:serverUnreadCount %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderKey::Custom:
++ return QString();
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString sparqlPropertyStatmentString<QMailAccountKey::Property>(const QString& uri, QMailAccountKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailAccountKey::Id:
++ return QString();
++
++ case QMailAccountKey::Name:
++ return QString("%1 nmo:accountName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailAccountKey::MessageType:
++ return QString();
++
++ case QMailAccountKey::FromAddress:
++ return QString("%1 nmo:fromAddress [ rdf:type nco:EmailAddress ; nco:emailAddress %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailAccountKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailAccountKey::Custom:
++ return QString();
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString sparqlPropertyStatmentString<QMailMessageSortKey::Property>(const QString& uri, QMailMessageSortKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailMessageSortKey::Id:
++ return QString();
++
++ case QMailMessageSortKey::Type:
++ return QString();
++
++ case QMailMessageSortKey::ParentFolderId:
++ return QString("%1 nie:isLogicalPartOf %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::Sender:
++ return QString("%1 nmo:sender [ rdf:type nco:Contact ; nco:hasEmailAddress %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::Recipients:
++ return QString("%1 nmo:recipient [ rdf:type nco:Contact ; nco:hasEmailAddress %2 ] .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::Subject:
++ return QString("%1 nmo:messageSubject %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::TimeStamp:
++ return QString("%1 nmo:sentDate %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::ReceptionTimeStamp:
++ return QString();
++
++ case QMailMessageSortKey::ServerUid:
++ return QString("%1 nmo:messageId %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::Size:
++ return QString("%1 nie:contentSize %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::ParentAccountId:
++ return QString("%1 nie:relatedTo %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailMessageSortKey::ContentType:
++ return QString();
++
++ case QMailMessageSortKey::PreviousParentFolderId:
++ return QString();
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString sparqlPropertyStatmentString<QMailFolderSortKey::Property>(const QString& uri, QMailFolderSortKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailFolderSortKey::Id:
++ return "id";
++
++ case QMailFolderSortKey::Path:
++ return QString("%1 nmo:folderName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::ParentFolderId:
++ return QString("%1 nie:isLogicalPartOf %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::ParentAccountId:
++ return QString("%1 nie:relatedTo %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::DisplayName:
++ return QString("%1 nmo:folderDisplayName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::ServerCount:
++ return QString("%1 nmo:serverCount %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailFolderSortKey::ServerUnreadCount:
++ return QString("%1 nmo:serverUnreadCount %2 .").arg(uri).arg(propertyNameString(property));
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <>
++QString sparqlPropertyStatmentString<QMailAccountSortKey::Property>(const QString& uri, QMailAccountSortKey::Property property)
++{
++ /*
++ * TBD: Complete this function with all properties description.
++ */
++ switch (property)
++ {
++ case QMailAccountSortKey::Id:
++ return QString();
++
++ case QMailAccountSortKey::Name:
++ return QString("%1 nmo:accountName %2 .").arg(uri).arg(propertyNameString(property));
++
++ case QMailAccountSortKey::MessageType:
++ return QString();
++
++ case QMailAccountSortKey::Status:
++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property));
++
++ default:
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <class Key, class SortKey>
++QString keyStatment(const QString& uri, const Key& key, const SortKey& sort = SortKey())
++{
++ typedef typename Key::ArgumentType ArgumentType;
++ typedef typename SortKey::ArgumentType SortArgumentType;
++
++ QStringList arguments;
++ foreach (SortArgumentType argument, sort.arguments())
++ {
++ QString statement = sparqlPropertyStatmentString(uri, argument.first);
++ if (!arguments.contains(statement))
++ arguments << statement;
++ }
++
++ foreach (ArgumentType argument, key.arguments())
++ {
++ QString statement = sparqlPropertyStatmentString(uri, argument.property);
++ if (!arguments.contains(statement))
++ arguments << statement;
++ }
++
++ foreach (const Key& subkey, key.subKeys())
++ arguments << keyStatment(uri, subkey, SortKey());
++
++ return arguments.join("\n");
++}
++
++QString argumentValue(const QVariant& value)
++{
++ if (qVariantCanConvert<QMailAccountId>(value))
++ return MailAccountUri(qVariantValue<QMailAccountId>(value).toULongLong());
++ else if (qVariantCanConvert<QMailFolderId>(value))
++ return MailFolderUri(qVariantValue<QMailFolderId>(value).toULongLong());
++ else if (qVariantCanConvert<QMailMessageId>(value))
++ return MailMessageUri(qVariantValue<QMailMessageId>(value).toULongLong());
++ else if (qVariantCanConvert<QString>(value))
++ return qVariantValue<QString>(value);
++ else if (qVariantCanConvert<int>(value))
++ return QString::number(qVariantValue<int>(value));
++ else {
++ Q_ASSERT(false);
++ }
++ return QString();
++}
++
++template <class ArgumentType>
++QString keyArgument(const ArgumentType& argument)
++{
++ typedef typename ArgumentType::Property Property;
++ typedef typename ArgumentType::Comparator Comparator;
++
++ QString pattern = operatorString(argument.op, argument.valueList.count());
++ pattern = pattern.arg(propertyNameString(argument.property));
++
++ foreach (QVariant value, argument.valueList)
++ pattern = pattern.arg(argumentValue(value));
++
++ return pattern;
++}
++
++template <class Key>
++QString keyFilter(const Key& key)
++{
++ typedef typename Key::ArgumentType ArgumentType;
++
++ QStringList arguments;
++ foreach (ArgumentType argument, key.arguments())
++ arguments << keyArgument<ArgumentType>(argument);
++
++ foreach (const Key& subkey, key.subKeys())
++ arguments << keyFilter<Key>(subkey);
++
++ QString filter = arguments.size() > 1 ? QString(key.isNegated() ? "!(%1)" : "(%1)") :
++ QString(key.isNegated() ? "!(%1)" : "%1");
++ return filter.arg(arguments.join(combineOperatorString(key.combiner())));
++}
++
++template <class SortKey>
++QString sortKey(const SortKey& sortKey)
++{
++ typedef typename SortKey::ArgumentType ArgumentType;
++
++ QString orderCondition;
++ foreach (ArgumentType argument, sortKey.arguments())
++ if (argument.second == Qt::AscendingOrder)
++ orderCondition += QString(" ASC(%1)").arg(propertyNameString(argument.first));
++ else
++ orderCondition += QString(" DESC(%1)").arg(propertyNameString(argument.first));
++
++ if (!orderCondition.isEmpty())
++ return QString("ORDER BY %1").arg(orderCondition);
++
++ return QString();
++}
++
++QString keyQuery(const QMailMessageKey& key, const QMailMessageSortKey& sort = QMailMessageSortKey())
++{
++ QString query("SELECT ?mail \n"
++ "WHERE { \n"
++ "?mail rdf:type nmo:Email . \n"
++ "%1"
++ "%2"
++ "} %3\n");
++
++ QString statement = keyStatment("?mail", key, sort);
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter).arg(sortKey(sort));
++}
++
++QString keyQuery(const QMailFolderKey& key, const QMailFolderSortKey& sort = QMailFolderSortKey())
++{
++ QString query("SELECT ?folder \n"
++ "WHERE { \n"
++ "?folder rdf:type nmo:MailFolder . \n"
++ "%1"
++ "%2"
++ "} %3\n");
++
++ QString statement = keyStatment("?folder", key, sort);
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter).arg(sortKey(sort));
++}
++
++QString keyQuery(const QMailAccountKey& key, const QMailAccountSortKey& sort = QMailAccountSortKey())
++{
++ QString query("SELECT ?account \n"
++ "WHERE { \n"
++ "?account rdf:type nmo:Mailbox . \n"
++ "%1"
++ "%2"
++ "} %3\n");
++
++ QString statement = keyStatment("?account", key, sort);
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter).arg(sortKey(sort));
++}
++
++QString keyCount(const QMailMessageKey& key)
++{
++ QString query("SELECT COUNT(?mail) AS count \n"
++ "WHERE { \n"
++ "?mail rdf:type nmo:Email . \n"
++ "%1"
++ "%2"
++ "}\n");
++
++ QString statement = keyStatment("?mail", key, QMailAccountSortKey());
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter);
++}
++
++QString keyCount(const QMailFolderKey& key)
++{
++ QString query("SELECT COUNT(?folder) AS count \n"
++ "WHERE { \n"
++ "?folder rdf:type nmo:MailFolder . \n"
++ "%1"
++ "%2"
++ "}\n");
++
++ QString statement = keyStatment("?folder", key, QMailAccountSortKey());
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter);
++}
++
++QString keyCount(const QMailAccountKey& key)
++{
++ QString query("SELECT COUNT(?account) AS count \n"
++ "WHERE { \n"
++ "?account rdf:type nmo:Mailbox . \n"
++ "%1"
++ "%2"
++ "}\n");
++
++ QString statement = keyStatment("?account", key, QMailAccountSortKey());
++ if (!statement.isEmpty())
++ statement = QString("%1 \n").arg(statement);
++
++ QString filter;
++ if (!key.isEmpty())
++ filter = QString("FILTER %1 \n").arg(keyFilter(key));
++
++ return query.arg(statement).arg(filter);
++}
++
++template <class Key>
++void debugKey(const Key& key)
++{
++ typedef typename Key::ArgumentType ArgumentType;
++
++ qDebug() << "Key Combiner:" << key.combiner();
++ qDebug() << "Key Is empty:" << key.isEmpty();
++ qDebug() << "Key Non Matching:" << key.isNonMatching();
++ qDebug() << "Key Is Negated:" << key.isNegated();
++
++ foreach (ArgumentType argument, key.arguments())
++ {
++ qDebug() << "Argument Property:" << argument.property;
++ qDebug() << "Argument Comparator:" << argument.op;
++ foreach (QVariant value, argument.valueList)
++ qDebug() << "Argument Value List:" << value;
++ }
++
++ foreach (const Key& subkey, key.subKeys())
++ debugKey(subkey);
++}
++
++QString nmoRecipients(const QList<QMailAddress>& recipients)
++{
++ QString result;
++ foreach (const QMailAddress& address, recipients)
++ {
++ QString triplet(QString(
++ " nmo:recipient [\n"
++ " rdf:type nco:Contact ;\n"
++ " nco:fullname \"%1\" ; \n"
++ " nco:hasEmailAddress <mailto:%2> ] ;\n")
++ .arg(address.name())
++ .arg(address.address()));
++ result.append(triplet);
++ }
++ return result;
++}
++
++template <class T>
++T IdFromUri(const QString& uri)
++{
++ int pos = uri.indexOf('#');
++ if (pos >= 0)
++ {
++ bool ok = false;
++ quint64 postfix = uri.right(uri.length() - pos-1).toULongLong(&ok);
++
++ if (ok)
++ return T(postfix);
++ }
++
++ return T();
++}
++
++} // End of namespace
++
++void SparqlMailStore::addMessage(QMailMessageMetaData* metaData)
++{
++ MailMessageUri messageUri(metaData->id().toULongLong());
++ MailFolderUri parentFolderUri(metaData->parentFolderId().toULongLong());
++ MailAccountUri parentAccountUri(metaData->parentAccountId().toULongLong());
++
++ SparqlQuery query(SparqlQuery::UpdateQuery);
++ query.prepare(QString(
++ "INSERT {\n"
++ "%1 rdf:type nmo:Email ;\n"
++ " nie:isLogicalPartOf %2 ;\n"
++ " nmo:sender [\n"
++ " rdf:type nco:Contact ;\n"
++ " nco:fullname \"%3\" ; \n"
++ " nco:hasEmailAddress <mailto:%4> ] ;\n"
++ + nmoRecipients(metaData->to()) +
++ " nmo:messageSubject \"%5\" ;\n"
++ " nmo:sentDate \"%6\"^^xsd:dateTime ;\n"
++ " nmo:status \"%7\"^^xsd:integer ;\n"
++ " nie:relatedTo %8 ;\n"
++ " nie:isStoredAs [\n"
++ " rdf:type nie:DataObject ;\n"
++ " nie:dataSource <%9> ] ;\n"
++ " nmo:messageId \"%10\" ;\n"
++ " nie:contentSize \"%11\"^^xsd:integer ;\n"
++ " nie:mimeType \"%12\" ;\n"
++ " nmo:inReplyTo \"%13\" ;\n"
++ " nmo:messageHeader [\n"
++ " rdf:type nmo:MessageHeader ;\n"
++ " nmo:headerName \"responseType\" ;\n"
++ " nmo:headerValue \"%14\" ] ;\n"
++ " nmo:receivedDate \"%15\"^^xsd:dateTime .\n"
++ "}").arg(messageUri.uri())
++ .arg(parentFolderUri.uri())
++ .arg(metaData->from().name())
++ .arg(metaData->from().address())
++ .arg(metaData->subject())
++ .arg(QMailTimeStamp(metaData->date()).toLocalTime().toString())
++ .arg(static_cast<int>(metaData->status()))
++ .arg(parentAccountUri.uri())
++ .arg(::contentUri(*metaData))
++ .arg(metaData->serverUid())
++ .arg(metaData->size())
++ .arg(static_cast<int>(metaData->content()))
++ .arg(metaData->inResponseTo().toULongLong())
++ .arg(metaData->responseType())
++ .arg(QMailTimeStamp(metaData->receivedDate()).toLocalTime().toString()));
++
++ // TBD: Add custom fields later
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return;
++ }
++
++ qDebug() << "Query succeeded";
++ metaData->setId(QMailMessageId(messageUri.id()));
++}
++
++void SparqlMailStore::addFolder(QMailFolder* folder)
++{
++ MailFolderUri folderUri(folder->id().toULongLong());
++ MailFolderUri parentFolderUri(folder->parentFolderId().toULongLong());
++ MailAccountUri parentAccountUri(folder->parentAccountId().toULongLong());
++
++ SparqlQuery query(SparqlQuery::UpdateQuery);
++ query.prepare(QString(
++ "INSERT { \n"
++ "%1 rdf:type nmo:MailFolder ; \n"
++ " nmo:folderName \"%2\" ; \n"
++ " nie:isLogicalPartOf %3 ; \n"
++ " nie:relatedTo %4 ; \n"
++ " nmo:folderDisplayName \"%5\" ; \n"
++ " nmo:status \"%6\"^^xsd:integer ; \n"
++ " nmo:serverCount \"%7\"^^xsd:integer ; \n"
++ " nmo:serverUnreadCount \"%8\"^^xsd:integet . \n"
++ "}").arg(folderUri.uri())
++ .arg(folder->path())
++ .arg(parentFolderUri.uri())
++ .arg(parentAccountUri.uri())
++ .arg(folder->displayName())
++ .arg(folder->status())
++ .arg(folder->serverCount())
++ .arg(folder->serverUnreadCount()));
++
++ // TBD: Add custom fields later
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return;
++ }
++
++ qDebug() << "Query succeeded";
++ folder->setId(QMailFolderId(folderUri.id()));
++
++ // TBD: Update folder links also
++}
++
++void SparqlMailStore::addAccount(QMailAccount* account)
++{
++ MailAccountUri accountUri(account->id().toULongLong());
++ SparqlQuery query(SparqlQuery::UpdateQuery);
++ query.prepare(QString(
++ "INSERT { \n"
++ "%1 rdf:type nmo:Mailbox ; \n"
++ " nmo:accountName \"%2\" ; \n"
++ " nmo:status \"%3\"^^xsd:integer ; \n"
++ " nmo:signature \"%4\" ; \n"
++ " nmo:fromAddress [ \n"
++ " rdf:type nco:EmailAddress ; \n"
++ " nco:emailAddress \"%5\" ] . \n"
++ "}").arg(accountUri.uri())
++ .arg(account->name())
++ .arg(account->status())
++ .arg(account->signature())
++ .arg(account->fromAddress().toString(true)));
++
++ // TBD: Add custom fields later
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return;
++ }
++
++ qDebug() << "Query succeeded";
++ account->setId(QMailAccountId(accountUri.id()));
++}
++
++QMailAccount SparqlMailStore::account(const QMailAccountId& id) const
++{
++ QMailAccount account;
++
++ MailMessageUri messageUri(id.toULongLong());
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(QString(
++ "SELECT ?name ?signature ?fromAddress \n"
++ "WHERE { \n"
++ "%1 rdf:type nmo:Mailbox ; \n"
++ " nmo:accountName ?name ; \n"
++ " nmo:status ?status ; \n"
++ " nmo:signature ?signature ; \n"
++ " nmo:fromAddress [ \n"
++ " rdf:type nco:EmailAddress ; \n"
++ " nco:emailAddress ?fromAddress ] . \n"
++ "}").arg(messageUri.uri()));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return account;
++ }
++
++ SparqlResult result = query.result();
++
++ Q_ASSERT(!result.end());
++
++ QStringList list = result.fetchRow();
++
++ account.setId(id);
++ account.setName(list.at(0));
++ account.setStatus(list.at(1).toULongLong());
++ account.setSignature(list.at(1));
++ account.setFromAddress(QMailAddress(list.at(2)));
++
++ return account;
++}
++
++QMailFolder SparqlMailStore::folder(const QMailFolderId& id) const
++{
++ MailFolderUri folderUri(id.toULongLong());
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(QString(
++ "SELECT ?name ?parentFolder ?parentAccount ?displayName \n"
++ "WHERE { \n"
++ "%1 rdf:type nmo:MailFolder ; \n"
++ " nmo:folderName ?name ; \n"
++ " nie:isLogicalPartOf ?parentFolder ; \n"
++ " nie:relatedTo ?parentAccount ; \n"
++ " nmo:folderDisplayName ?displayName ; \n"
++ " nmo:status ?status ; \n"
++ " nmo:serverCount ?serverCount ; \n"
++ " nmo:serverUnreadCount ?serverUnreadCount . \n"
++ "}").arg(folderUri.uri()));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return QMailFolder();
++ }
++
++ SparqlResult result = query.result();
++
++ Q_ASSERT(!result.end());
++
++ QStringList list = result.fetchRow();
++
++ QMailFolder folder(list.at(0), IdFromUri<QMailFolderId>(list.at(1)), IdFromUri<QMailAccountId>(list.at(2)));
++ folder.setId(id);
++ folder.setDisplayName(list.at(3));
++ folder.setStatus(list.at(4).toULongLong());
++ folder.setServerCount(list.at(5).toUInt());
++ folder.setServerUnreadCount(list.at(6).toUInt());
++
++ return folder;
++}
++
++QMailMessage SparqlMailStore::message(const QMailMessageId& id) const
++{
++ MailMessageUri messageUri(id.toULongLong());
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(QString(
++ "SELECT ?fullName ?mailAddress \n"
++ "WHERE { \n"
++ "%1 rdf:type nmo:Email ; \n"
++ " nmo:recipient [ \n"
++ " rdf:type nco:Contact ; \n"
++ " nco:fullname ?fullName ; \n"
++ " nco:hasEmailAddress ?mailAddress ] \n"
++ "}").arg(messageUri.uri()));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return QMailMessage();
++ }
++
++ SparqlResult result = query.result();
++
++ QList<QMailAddress> recipients;
++ while (!result.end())
++ {
++ QStringList row = result.fetchRow();
++ recipients.push_back(QMailAddress(row.at(0), row.at(1)));
++ }
++
++ query.prepare(QString(
++ "SELECT ?folderId ?senderFullName ?senderEmailAddress ?messageSubject ?sentDate ?status ?accountId ?dataSource ?uid ?contentSize ?mimeType ?inReplyTo ?headerValue ?receivedDate \n"
++ "WHERE { \n"
++ "%1 rdf:type nmo:Email ;\n"
++ " nie:isLogicalPartOf ?folderId ;\n"
++ " nmo:sender [\n"
++ " rdf:type nco:Contact ;\n"
++ " nco:fullname ?senderFullName ; \n"
++ " nco:hasEmailAddress ?senderEmailAddress ] ;\n"
++ " nmo:messageSubject ?messageSubject ;\n"
++ " nmo:sentDate ?sentDate ;\n"
++ " nmo:status ?status ;\n"
++ " nie:relatedTo ?accountId ;\n"
++ " nie:isStoredAs [\n"
++ " rdf:type nie:DataObject ;\n"
++ " nie:dataSource ?dataSource ] ;\n"
++ " nmo:messageId ?uid ;\n"
++ " nie:contentSize ?contentSize ;\n"
++ " nie:mimeType ?mimeType ;\n"
++ " nmo:inReplyTo ?inReplyTo ;\n"
++ " nmo:messageHeader [\n"
++ " rdf:type nmo:MessageHeader ;\n"
++ " nmo:headerName \"responseType\" ;\n"
++ " nmo:headerValue ?headerValue ] ;\n"
++ " nmo:receivedDate ?receivedDate .\n"
++ "}").arg(messageUri.uri()));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return QMailMessage();
++ }
++
++ result = query.result();
++
++ Q_ASSERT(!result.end());
++
++ QStringList list = result.fetchRow();
++
++ QMailMessage message;
++ message.setId(id);
++ message.setParentFolderId(IdFromUri<QMailFolderId>(list.at(0)));
++ message.setFrom(QMailAddress(list.at(1), list.at(2)));
++ message.setSubject(list.at(3));
++ message.setDate(QMailTimeStamp(list.at(4)));
++ message.setStatus(list.at(5).toULongLong());
++ message.setParentAccountId(IdFromUri<QMailAccountId>(list.at(6)));
++ message.setServerUid(list.at(10));
++ message.setSize(list.at(9).toUInt());
++ message.setContent((QMailMessageMetaDataFwd::ContentType)list.at(10).toInt());
++ message.setInResponseTo(QMailMessageId(IdFromUri<QMailMessageId>(list.at(11))));
++ message.setResponseType((QMailMessageMetaDataFwd::ResponseType)list.at(12).toInt());
++ message.setReceivedDate(QMailTimeStamp(list.at(13)));
++
++ message.setTo(recipients);
++
++ return message;
++}
++
++int SparqlMailStore::countAccounts(const QMailAccountKey& key) const
++{
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyCount(key));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return 0;
++ }
++
++ SparqlResult result = query.result();
++
++ Q_ASSERT(!result.end());
++
++ return result.fetchRow().first().toInt();
++}
++
++int SparqlMailStore::countFolders(const QMailFolderKey& key) const
++{
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyCount(key));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return 0;
++ }
++
++ SparqlResult result = query.result();
++
++ Q_ASSERT(!result.end());
++
++ return result.fetchRow().first().toInt();
++}
++
++int SparqlMailStore::countMessages(const QMailMessageKey& key) const
++{
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyCount(key));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return 0;
++ }
++
++ SparqlResult result = query.result();
++
++ Q_ASSERT(!result.end());
++
++ return result.fetchRow().first().toInt();
++}
++
++QMailAccountIdList SparqlMailStore::queryAccounts(const QMailAccountKey &key, const QMailAccountSortKey &sortKey) const
++{
++ QMailAccountIdList accountIdList;
++
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyQuery(key, sortKey));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return accountIdList;
++ }
++
++ SparqlResult result = query.result();
++
++ while (!result.end())
++ {
++ QStringList row = result.fetchRow();
++ accountIdList << IdFromUri<QMailAccountId>(row.first());
++ }
++
++ return accountIdList;
++}
++
++QMailFolderIdList SparqlMailStore::queryFolders(const QMailFolderKey &key, const QMailFolderSortKey &sortKey) const
++{
++ QMailFolderIdList folderIdList;
++
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyQuery(key, sortKey));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return folderIdList;
++ }
++
++ SparqlResult result = query.result();
++
++ while (!result.end())
++ {
++ QStringList row = result.fetchRow();
++ folderIdList << IdFromUri<QMailFolderId>(row.first());
++ }
++
++ return folderIdList;
++}
++
++QMailMessageIdList SparqlMailStore::queryMessages(const QMailMessageKey &key, const QMailMessageSortKey &sortKey) const
++{
++ QMailMessageIdList messageIdList;
++
++ SparqlQuery query(SparqlQuery::SearchQuery);
++ query.prepare(keyQuery(key, sortKey));
++
++ if (!query.exec())
++ {
++ qDebug() << "Query failed:" << query.error();
++ return messageIdList;
++ }
++
++ SparqlResult result = query.result();
++
++ while (!result.end())
++ {
++ QStringList row = result.fetchRow();
++ messageIdList << IdFromUri<QMailMessageId>(row.first());
++ }
++
++ return messageIdList;
++}
++
++void SparqlMailStore::updateMessage(const QMailMessageMetaData& metedata)
++{
++ Q_UNUSED(metedata);
++}
++
++void SparqlMailStore::updateFolder(const QMailFolder& folder)
++{
++ Q_UNUSED(folder);
++}
++
++void SparqlMailStore::updateAccount(const QMailAccount& account)
++{
++ Q_UNUSED(account);
++}
++
++void SparqlMailStore::removeMessage(const QMailMessageMetaData& metadata)
++{
++ Q_UNUSED(metadata);
++}
++
++void SparqlMailStore::removeFolder(const QMailFolder& folder)
++{
++ Q_UNUSED(folder);
++}
++
++void SparqlMailStore::removeAccount(const QMailAccount& account)
++{
++ Q_UNUSED(account);
++}
+diff --git a/tools/sparql-import/sparqlmailstore.h b/tools/sparql-import/sparqlmailstore.h
+new file mode 100644
+index 0000000..9bcd838
+--- /dev/null
++++ b/tools/sparql-import/sparqlmailstore.h
+@@ -0,0 +1,42 @@
++#ifndef MAILSTORE_H
++#define MAILSTORE_H
++
++#include <qmailmessage.h>
++#include <qmailfolder.h>
++#include <qmailaccount.h>
++#include <qmailaccountkey.h>
++#include <qmailfolderkey.h>
++#include <qmailmessagekey.h>
++#include <qmailaccountsortkey.h>
++#include <qmailfoldersortkey.h>
++#include <qmailmessagesortkey.h>
++
++class SparqlMailStore
++{
++public:
++ void addMessage(QMailMessageMetaData* metaData);
++ void addFolder(QMailFolder* folder);
++ void addAccount(QMailAccount* account);
++
++ QMailAccount account(const QMailAccountId& id) const;
++ QMailFolder folder(const QMailFolderId& id) const;
++ QMailMessage message(const QMailMessageId& id) const;
++
++ int countAccounts(const QMailAccountKey& key = QMailAccountKey()) const;
++ int countFolders(const QMailFolderKey& key = QMailFolderKey()) const;
++ int countMessages(const QMailMessageKey& key = QMailMessageKey()) const;
++
++ QMailAccountIdList queryAccounts(const QMailAccountKey &key = QMailAccountKey(), const QMailAccountSortKey &sortKey = QMailAccountSortKey()) const;
++ QMailFolderIdList queryFolders(const QMailFolderKey &key = QMailFolderKey(), const QMailFolderSortKey &sortKey = QMailFolderSortKey()) const;
++ QMailMessageIdList queryMessages(const QMailMessageKey &key = QMailMessageKey(), const QMailMessageSortKey &sortKey = QMailMessageSortKey()) const;
++
++ void updateMessage(const QMailMessageMetaData& meteData);
++ void updateFolder(const QMailFolder& folder);
++ void updateAccount(const QMailAccount& account);
++
++ void removeMessage(const QMailMessageMetaData& metaData);
++ void removeFolder(const QMailFolder& folder);
++ void removeAccount(const QMailAccount& account);
++};
++
++#endif // MAILSTORE_H
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 00000000..2ea4a24d
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1 @@
+0001-maemo_changes.diff
diff --git a/debian/qmfmail.install b/debian/qmfmail.install
new file mode 100644
index 00000000..99f4f30a
--- /dev/null
+++ b/debian/qmfmail.install
@@ -0,0 +1,5 @@
+usr/bin/qtmail
+usr/bin/messagingaccounts
+usr/lib/libqmfutil.so*
+usr/plugins/composers/*.so* usr/lib/qmf/composers
+usr/plugins/viewers/*.so* usr/lib/qmf/viewers
diff --git a/debian/qmfserver.install b/debian/qmfserver.install
new file mode 100644
index 00000000..b052e603
--- /dev/null
+++ b/debian/qmfserver.install
@@ -0,0 +1 @@
+usr/bin/messageserver
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 00000000..3c04811b
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,64 @@
+#!/usr/bin/make -f
+
+# Uncomment this to turn on verbose mode.
+export DH_VERBOSE=1
+
+# shared library versions, option 1
+#version=2.0.5
+#major=2
+# option 2, assuming the library is created as src/.libs/libfoo.so.2.0.5 or so
+#version=`ls src/.libs/lib*.so.* | \
+# awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'`
+#major=`ls src/.libs/lib*.so.* | \
+# awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'`
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/makefile.mk
+include /usr/share/cdbs/1/rules/patchsys-quilt.mk
+include /usr/share/cdbs/1/rules/utils.mk
+
+DEB_MAKE_INVOKE := $(MAKE) QMAKE_CFLAGS_DEBUG="-g1 -O0"
+DEB_MAKE_INSTALL_TARGET := INSTALL_ROOT=$(DEB_DESTDIR) install
+DEB_DH_INSTALL_SOURCEDIR := debian/tmp
+
+common-configure-arch:: configure-stamp
+configure-stamp:
+ qmake QMF_INSTALL_ROOT=/usr QMAKE_CXXFLAGS_DEBUG="-g1 -O0"
+ touch $@
+
+clean::
+# Clean extra stuff missed
+
+ # Delete all Makefiles
+ find $(CURDIR) -name Makefile \
+ -print0 | xargs -0 rm -rf
+
+ # Leftover files and all symlinks
+ find \( -false \
+ -o -name \*.so \
+ -o -name \*.so.* \
+ -o -type l \
+ \) -print0 | xargs -0 rm -rf
+
+ # Any remaining executables
+ find $(CURDIR) -type f -exec file -i '{}' \; | grep \
+ -e application/x-executable \
+ | cut -d ':' -f 1 | xargs rm -f
+
+ # Misc. directories
+ rm -rf \
+ src/libraries/messageserver/pkgconfig/ \
+ src/libraries/qmfutil/pkgconfig/ \
+ src/libraries/qtopiamail/pkgconfig/ \
+ ;
+
+ rm -f .qmake.cache
+ rm -f configure-stamp
+ rm -f src/libraries/messageserver/libmessageserver.prl
+ rm -f src/libraries/qmfutil/libqmfutil.prl
+ rm -f src/libraries/qtopiamail/libqtopiamail.prl
+
+install/libqmf-tests::
+ mkdir -p $(CURDIR)/debian/tmp/usr/tests
+ cp $(CURDIR)/debian/runtests.sh $(CURDIR)/debian/tmp/usr/tests/.
+ cp $(CURDIR)/debian/test_script.sh $(CURDIR)/debian/tmp/usr/tests/.
diff --git a/debian/runtests.sh b/debian/runtests.sh
new file mode 100755
index 00000000..e5f8d727
--- /dev/null
+++ b/debian/runtests.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+export DISPLAY=:0
+
+./test_script.sh --unit-tests-path /usr/tests/qmf
diff --git a/debian/test_script.sh b/debian/test_script.sh
new file mode 100755
index 00000000..d31c4a1f
--- /dev/null
+++ b/debian/test_script.sh
@@ -0,0 +1,79 @@
+#!/bin/sh
+# even though -n is compliment of -z it doesn't work as expected hence the !
+usage ()
+{
+ echo -e "\n" \
+ "Purpose: run unit tests unless told not to.\n" \
+ "Usage: [--unit-test-path <path to unit tests>]\n" \
+ " [--excludes-file <path to excludes file>]\n" \
+ " [--help|-h|-?]\n" \
+ "\n" \
+ "*** Following is not yet implemented ***\n" \
+ "Script will exclude tests if 'tst_excludes' file\n" \
+ "is present and the test's name has been added to\n" \
+ "exclude_tests='' in the file. List is space seperated.\n" \
+ "Create excludes file if not present.\n"
+}
+
+while [ $# -ne 0 ]; do
+ case $1 in
+ --unit-tests-path)
+ if [ $# -ge 2 ]; then
+ test_dir_path="$2"
+ shift 1
+ fi
+ ;;
+ --excludes-file)
+ if [ $# -ge 2 ]; then
+ test_excludes_path="$2"
+ shift 1
+ fi
+ ;;
+ --help|-h|-?)
+ usage
+ exit 0
+ ;;
+ *)
+ echo "Unknown option: $1"
+ usage
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+# set -x
+# the following handles different paths being set or not and tests
+current_dir=`pwd`
+# if not set then set to current working dir path
+test_dir_path=${test_dir_path-$current_dir/'tests'}
+# if we can't see the tests dir stop
+[ ! -d $test_dir_path ] && echo "Unit tests path: $test_dir_path does not exist" && exit 1
+# if not set or set but empty assume relative to test_dir_path
+test_excludes_path=${test_excludes_path:-$test_dir_path/tst_excludes}
+
+# see if we have an tst_excludes_file
+[ -f $test_excludes_path ] && . $test_excludes_path || exclude_tests=""
+# run through executing tests
+for each_test in `find $test_dir_path -type f -name "tst_*"`; do
+ # comparison to go here
+# if [ ${#exclude_test[@]} -ne 0 ]; then
+# test_excluded=0
+# else
+# for (( i = 0 ; i < ${#exclude_tests[@]} ; i++ ))
+# do
+# if [ ${exclude_tests[i]} == ${test_name} ]; then
+# test_exlcuded=1
+# break
+# fi
+# echo $test_name
+# done
+# fi
+#done
+# if [ ${test_excluded} -eq 0 ]; then
+ test_exec=$each_test
+ mkdir -p /tmp/libqmf-tests
+ [ -x $test_exec ] && $test_exec > /tmp/libqmf-tests/$test_exec.log
+# fi
+done
+exit 0