diff options
| -rw-r--r-- | debian/changelog | 92 | ||||
| -rw-r--r-- | debian/compat | 1 | ||||
| -rw-r--r-- | debian/control | 108 | ||||
| -rw-r--r-- | debian/copyright | 24 | ||||
| -rw-r--r-- | debian/libqmf-dev.install | 3 | ||||
| -rw-r--r-- | debian/libqmf-doc.install | 1 | ||||
| -rw-r--r-- | debian/libqmf-plugins.install | 3 | ||||
| -rw-r--r-- | debian/libqmf-tests.install | 1 | ||||
| -rw-r--r-- | debian/libqmf0.install | 3 | ||||
| -rw-r--r-- | debian/patches/0001-maemo_changes.diff | 7050 | ||||
| -rw-r--r-- | debian/patches/series | 1 | ||||
| -rw-r--r-- | debian/qmfmail.install | 5 | ||||
| -rw-r--r-- | debian/qmfserver.install | 1 | ||||
| -rwxr-xr-x | debian/rules | 64 | ||||
| -rwxr-xr-x | debian/runtests.sh | 5 | ||||
| -rwxr-xr-x | debian/test_script.sh | 79 |
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<QStringList>"/> ++ ++ * 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<QStringList>"/> ++ ++ 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<QStringList>"/> ++ <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 |
