diff options
author | Gareth Pethig <gareth.pethig@nokia.com> | 2009-05-07 20:01:44 +1000 |
---|---|---|
committer | Gareth Pethig <gareth.pethig@nokia.com> | 2009-05-07 20:01:44 +1000 |
commit | 27af764b9063d79c28664390702cf8242f07a5a1 (patch) | |
tree | 720eea1da13f210e332f7b9afc1164f013ddd0e9 | |
parent | 5639741f45327422daca4247568963be89499080 (diff) |
Update maemo patch to 2009W17 changes.2009W19-0maemo1
Update Changelog.
-rw-r--r-- | debian/changelog | 6 | ||||
-rw-r--r-- | debian/patches/0001-maemo_changes.diff | 5988 |
2 files changed, 1387 insertions, 4607 deletions
diff --git a/debian/changelog b/debian/changelog index 01c68b1b..bf4fe388 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +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. diff --git a/debian/patches/0001-maemo_changes.diff b/debian/patches/0001-maemo_changes.diff index 50905629..7dcce571 100644 --- a/debian/patches/0001-maemo_changes.diff +++ b/debian/patches/0001-maemo_changes.diff @@ -578,7 +578,7 @@ index 0000000..cfbd6ca @@ -0,0 +1 @@ +#include "qmailserviceaction.h" diff --git a/src/libraries/qtopiamail/qmailstore.cpp b/src/libraries/qtopiamail/qmailstore.cpp -index 814a2dd..504303b 100644 +index bc5fecc..992cafc 100644 --- a/src/libraries/qtopiamail/qmailstore.cpp +++ b/src/libraries/qtopiamail/qmailstore.cpp @@ -11,7 +11,12 @@ @@ -596,10 +596,10 @@ index 814a2dd..504303b 100644 \class QMailStore diff --git a/src/libraries/qtopiamail/qmailstore_sparql.cpp b/src/libraries/qtopiamail/qmailstore_sparql.cpp new file mode 100644 -index 0000000..029ca4e +index 0000000..f596c19 --- /dev/null +++ b/src/libraries/qtopiamail/qmailstore_sparql.cpp -@@ -0,0 +1,6610 @@ +@@ -0,0 +1,3314 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. @@ -617,9 +617,6 @@ index 0000000..029ca4e +#include "semaphore_p.h" +#include "qmailnamespace.h" +#include "qmaillog.h" -+#include <QSqlQuery> -+#include <QSqlError> -+#include <QSqlRecord> +#include <QTextCodec> +#include <sys/types.h> +#include <sys/ipc.h> @@ -647,63 +644,6 @@ index 0000000..029ca4e +using nonstd::tr1::cref; + + -+class QMailStorePrivate::Key -+{ -+ enum Type { -+ Account = 0, -+ AccountSort, -+ Folder, -+ FolderSort, -+ Message, -+ MessageSort, -+ Text -+ }; -+ -+ Type m_type; -+ const void* m_key; -+ const QString* m_alias; -+ -+ template<typename NonKeyType> -+ bool isType(NonKeyType) const { return false; } -+ -+ bool isType(QMailAccountKey*) const { return (m_type == Account); } -+ bool isType(QMailAccountSortKey*) const { return (m_type == AccountSort); } -+ bool isType(QMailFolderKey*) const { return (m_type == Folder); } -+ bool isType(QMailFolderSortKey*) const { return (m_type == FolderSort); } -+ bool isType(QMailMessageKey*) const { return (m_type == Message); } -+ bool isType(QMailMessageSortKey*) const { return (m_type == MessageSort); } -+ bool isType(QString*) const { return (m_type == Text); } -+ -+ const QMailAccountKey &key(QMailAccountKey*) const { return *reinterpret_cast<const QMailAccountKey*>(m_key); } -+ const QMailAccountSortKey &key(QMailAccountSortKey*) const { return *reinterpret_cast<const QMailAccountSortKey*>(m_key); } -+ const QMailFolderKey &key(QMailFolderKey*) const { return *reinterpret_cast<const QMailFolderKey*>(m_key); } -+ const QMailFolderSortKey &key(QMailFolderSortKey*) const { return *reinterpret_cast<const QMailFolderSortKey*>(m_key); } -+ const QMailMessageKey &key(QMailMessageKey*) const { return *reinterpret_cast<const QMailMessageKey*>(m_key); } -+ const QMailMessageSortKey &key(QMailMessageSortKey*) const { return *reinterpret_cast<const QMailMessageSortKey*>(m_key); } -+ const QString &key(QString*) const { return *m_alias; } -+ -+public: -+ explicit Key(const QMailAccountKey &key, const QString &alias = QString()) : m_type(Account), m_key(&key), m_alias(&alias) {} -+ explicit Key(const QMailAccountSortKey &key, const QString &alias = QString()) : m_type(AccountSort), m_key(&key), m_alias(&alias) {} -+ -+ explicit Key(const QMailFolderKey &key, const QString &alias = QString()) : m_type(Folder), m_key(&key), m_alias(&alias) {} -+ explicit Key(const QMailFolderSortKey &key, const QString &alias = QString()) : m_type(FolderSort), m_key(&key), m_alias(&alias) {} -+ -+ explicit Key(const QMailMessageKey &key, const QString &alias = QString()) : m_type(Message), m_key(&key), m_alias(&alias) {} -+ explicit Key(const QMailMessageSortKey &key, const QString &alias = QString()) : m_type(MessageSort), m_key(&key), m_alias(&alias) {} -+ -+ explicit Key(const QString &text) : m_type(Text), m_key(0), m_alias(&text) {} -+ -+ template<typename KeyType> -+ bool isType() const { return isType(reinterpret_cast<KeyType*>(0)); } -+ -+ template<typename KeyType> -+ const KeyType &key() const { return key(reinterpret_cast<KeyType*>(0)); } -+ -+ const QString &alias() const { return *m_alias; } -+}; -+ -+ +namespace { // none of this code is externally visible: + +//using namespace QMailDataComparator; @@ -768,7 +708,6 @@ index 0000000..029ca4e + +typedef Guard<ProcessMutex> MutexGuard; + -+ +template <typename IdType> +QVariantList idValueList(const QList<IdType>& ids) +{ @@ -816,1488 +755,877 @@ index 0000000..029ca4e + 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<typename ValueContainer> -+class MessageValueExtractor; -+ -+// Class to extract QMailMessageMetaData properties to QVariant form -+template<> -+class MessageValueExtractor<QMailMessageMetaData> ++template <class T, int INDEX> ++class WellKnownUri : public SparqlUri +{ -+ const QMailMessageMetaData &_data; -+ +public: -+ MessageValueExtractor(const QMailMessageMetaData &d) : _data(d) {} -+ -+ QVariant id() const { return _data.id().toULongLong(); } -+ -+ QVariant messageType() const { return static_cast<int>(_data.messageType()); } -+ -+ QVariant parentFolderId() const { return _data.parentFolderId().toULongLong(); } -+ -+ QVariant from() const { return _data.from().toString(); } -+ -+ QVariant to() const { return QMailAddress::toStringList(_data.to()).join(","); } -+ -+ QVariant subject() const { return _data.subject(); } -+ -+ QVariant date() const { return _data.date().toLocalTime(); } -+ -+ QVariant receivedDate() const { return _data.receivedDate().toLocalTime(); } -+ -+ // Don't record the value of the UnloadedData flag: -+ QVariant status() const { return (_data.status() & ~QMailMessage::UnloadedData); } -+ -+ QVariant parentAccountId() const { return _data.parentAccountId().toULongLong(); } -+ -+ QVariant serverUid() const { return _data.serverUid(); } -+ -+ QVariant size() const { return _data.size(); } -+ -+ QVariant content() const { return static_cast<int>(_data.content()); } -+ -+ QVariant previousParentFolderId() const { return _data.previousParentFolderId().toULongLong(); } -+ -+ QVariant contentScheme() const { return _data.contentScheme(); } -+ -+ QVariant contentIdentifier() const { return _data.contentIdentifier(); } -+ -+ QVariant inResponseTo() const { return _data.inResponseTo().toULongLong(); } -+ -+ QVariant responseType() const { return static_cast<int>(_data.responseType()); } ++ WellKnownUri() : SparqlUri(WellKnownUris[INDEX]) {} ++ WellKnownUri(const T& id) : SparqlUri(WellKnownUris[INDEX], id.toULongLong()) {} ++ T id() const { return T(id()); } ++ operator T () { return id(); } +}; + -+// Class to extract QMailMessageMetaData properties from QVariant object -+template<> -+class MessageValueExtractor<QVariant> -+{ -+ const QVariant &_value; -+ -+public: -+ MessageValueExtractor(const QVariant &v) : _value(v) {} ++typedef WellKnownUri<QMailMessageId, 0> MailMessageUri; ++typedef WellKnownUri<QMailFolderId, 1> MailFolderUri; ++typedef WellKnownUri<QMailAccountId, 2> MailAccountUri; + -+ QMailMessageId id() const { return QMailMessageId(QMailStorePrivate::extractValue<quint64>(_value)); } -+ -+ QMailMessage::MessageType messageType() const { return QMailMessage::MessageType(QMailStorePrivate::extractValue<int>(_value)); } -+ -+ QMailFolderId parentFolderId() const { return QMailFolderId(QMailStorePrivate::extractValue<quint64>(_value)); } -+ -+ QMailAddress from() const { return QMailAddress(QMailStorePrivate::extractValue<QString>(_value)); } -+ -+ QList<QMailAddress> to() const { return QMailAddress::fromStringList(QMailStorePrivate::extractValue<QString>(_value)); } -+ -+ QString subject() const { return QMailStorePrivate::extractValue<QString>(_value); } -+ -+ QMailTimeStamp date() const { return QMailTimeStamp(QMailStorePrivate::extractValue<QDateTime>(_value)); } -+ -+ QMailTimeStamp receivedDate() const { return QMailTimeStamp(QMailStorePrivate::extractValue<QDateTime>(_value)); } -+ -+ quint64 status() const { return QMailStorePrivate::extractValue<quint64>(_value); } -+ -+ QMailAccountId parentAccountId() const { return QMailAccountId(QMailStorePrivate::extractValue<quint64>(_value)); } -+ -+ QString serverUid() const { return QMailStorePrivate::extractValue<QString>(_value); } -+ -+ int size() const { return QMailStorePrivate::extractValue<int>(_value); } -+ -+ QMailMessage::ContentType content() const { return QMailMessage::ContentType(QMailStorePrivate::extractValue<int>(_value)); } -+ -+ QMailFolderId previousParentFolderId() const { return QMailFolderId(QMailStorePrivate::extractValue<quint64>(_value)); } -+ -+ QString contentUri() const { return QMailStorePrivate::extractValue<QString>(_value); } -+ -+ QMailMessageId inResponseTo() const { return QMailMessageId(QMailStorePrivate::extractValue<quint64>(_value)); } -+ -+ QMailMessage::ResponseType responseType() const { return QMailMessage::ResponseType(QMailStorePrivate::extractValue<int>(_value)); } -+}; -+ -+ -+// Properties of the mailmessages table -+static QMailStorePrivate::MessagePropertyMap messagePropertyMap() ++QString combineOperatorString(QMailKey::Combiner op) +{ -+ 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; -+} ++ switch (op) ++ { ++ case And: ++ return " && "; ++ break; + -+static QString messagePropertyName(QMailMessageKey::Property property) -+{ -+ static const QMailStorePrivate::MessagePropertyMap map(messagePropertyMap()); ++ case Or: ++ return " || "; ++ break; + -+ QMailStorePrivate::MessagePropertyMap::const_iterator it = map.find(property); -+ if (it != map.end()) -+ return it.value(); ++ case None: ++ break; ++ } + -+ if ((property != QMailMessageKey::AncestorFolderIds) && -+ (property != QMailMessageKey::Conversation) && -+ (property != QMailMessageKey::Custom)) -+ qWarning() << "Unknown message property:" << property; -+ + return QString(); +} + -+typedef QMap<QMailAccountKey::Property, QString> AccountPropertyMap; ++template <class Comparator> ++QString operatorString(Comparator op, int argsNumber = 1); + -+// Properties of the mailaccounts table -+static AccountPropertyMap accountPropertyMap() ++QString operatorStringPattern(int argNumber, const QString& op, const QString& comp) +{ -+ AccountPropertyMap map; -+ -+ map.insert(QMailAccountKey::Id,"id"); -+ map.insert(QMailAccountKey::Name,"name"); -+ map.insert(QMailAccountKey::MessageType,"type"); -+ map.insert(QMailAccountKey::FromAddress,"emailaddress"); -+ map.insert(QMailAccountKey::Status,"status"); ++ QStringList pattern; ++ for (int i = 0; i<argNumber; i++) ++ pattern << "(%1 " + op + " %" + QString::number(i+2) + ")"; + -+ return map; ++ if (argNumber > 1) ++ return "(" + pattern.join(comp) + ")"; ++ else ++ return pattern.join(comp); +} + -+static QString accountPropertyName(QMailAccountKey::Property property) ++template <> ++QString operatorString<QMailKey::Comparator>(QMailKey::Comparator op, int argsNumber) +{ -+ static const AccountPropertyMap map(accountPropertyMap()); -+ -+ AccountPropertyMap::const_iterator it = map.find(property); -+ if (it != map.end()) -+ return it.value(); -+ -+ if (property != QMailAccountKey::Custom) -+ qWarning() << "Unknown account property:" << property; -+ -+ return QString(); -+} ++ switch (op) ++ { ++ case Equal: ++ // "(%1 = \"%2\")" : "(%1 = \"%2\") || (%1 = \"%3\")" ++ return (argsNumber == 1 ? operatorStringPattern(argsNumber, "=", "") : operatorStringPattern(argsNumber, "=", " || ")); ++ break; + -+typedef QMap<QMailFolderKey::Property, QString> FolderPropertyMap; ++ case NotEqual: ++ // "(%1 != \"%2\")" : "(%1 != \"%2\") && (%1 != \"%3\")" ++ return (argsNumber == 1 ? operatorStringPattern(argsNumber, "!=", "") : operatorStringPattern(argsNumber, "!=", " && ")); ++ break; + -+// Properties of the mailfolders table -+static FolderPropertyMap folderPropertyMap() -+{ -+ FolderPropertyMap map; ++ case LessThan: ++ return "(%1 < %2)"; ++ break; + -+ map.insert(QMailFolderKey::Id,"id"); -+ map.insert(QMailFolderKey::Path,"name"); -+ map.insert(QMailFolderKey::ParentFolderId,"parentid"); -+ map.insert(QMailFolderKey::ParentAccountId,"parentaccountid"); -+ map.insert(QMailFolderKey::DisplayName,"displayname"); -+ map.insert(QMailFolderKey::Status,"status"); -+ map.insert(QMailFolderKey::ServerCount,"servercount"); -+ map.insert(QMailFolderKey::ServerUnreadCount,"serverunreadcount"); ++ case LessThanEqual: ++ return "(%1 <= %2)"; ++ break; + -+ return map; -+} ++ case GreaterThan: ++ return "(%1 > %2)"; ++ break; + -+static QString folderPropertyName(QMailFolderKey::Property property) -+{ -+ static const FolderPropertyMap map(folderPropertyMap()); ++ case GreaterThanEqual: ++ return "(%1 >= %2)"; ++ break; + -+ FolderPropertyMap::const_iterator it = map.find(property); -+ if (it != map.end()) -+ return it.value(); ++ case Includes: ++ case Present: ++ // "(%1 & \"%2\")" : "(%1 = \"%2\") || (%1 = \"%3\")" ++ return (argsNumber == 1 ? operatorStringPattern(argsNumber, "&", "") : operatorStringPattern(argsNumber, "=", " || ")); ++ break; + -+ if ((property != QMailFolderKey::AncestorFolderIds) && -+ (property != QMailFolderKey::Custom)) -+ qWarning() << "Unknown folder property:" << property; ++ case Excludes: ++ case Absent: ++ // "!(%1 & \"%2\")" : "(%1 != \"%2\") && (%1 != \"%3\")" ++ return (argsNumber == 1 ? "(!" + operatorStringPattern(argsNumber, "&", "") + ")": operatorStringPattern(argsNumber, "!=", " && ")); ++ break; ++ } + + return QString(); +} + -+// Build lists of column names from property values -+ -+static QString qualifiedName(const QString &name, const QString &alias) -+{ -+ if (alias.isEmpty()) -+ return name; -+ -+ return (alias + '.' + name); -+} -+ -+template<typename PropertyType> -+QString fieldName(PropertyType property, const QString &alias); -+ -+template<> -+QString fieldName<QMailMessageKey::Property>(QMailMessageKey::Property property, const QString& alias) -+{ -+ return qualifiedName(messagePropertyName(property), alias); -+} -+ -+template<> -+QString fieldName<QMailFolderKey::Property>(QMailFolderKey::Property property, const QString& alias) -+{ -+ return qualifiedName(folderPropertyName(property), alias); -+} -+ -+template<> -+QString fieldName<QMailAccountKey::Property>(QMailAccountKey::Property property, const QString& alias) -+{ -+ return qualifiedName(accountPropertyName(property), alias); -+} -+ -+template<typename SourceType, typename TargetType> -+TargetType matchingProperty(SourceType source); ++template <class Property> ++QString propertyNameString(Property property); + -+static QMap<QMailMessageSortKey::Property, QMailMessageKey::Property> messageSortMapInit() ++template <> ++QString propertyNameString<QMailMessageKey::Property>(QMailMessageKey::Property property) +{ -+ QMap<QMailMessageSortKey::Property, QMailMessageKey::Property> map; ++ switch (property) ++ { ++ case QMailMessageKey::Id: ++ return "?id"; + -+ // Provide a mapping of sort key properties to the corresponding filter key -+ map.insert(QMailMessageSortKey::Id, QMailMessageKey::Id); -+ map.insert(QMailMessageSortKey::Type, QMailMessageKey::Type); -+ map.insert(QMailMessageSortKey::ParentFolderId, QMailMessageKey::ParentFolderId); -+ map.insert(QMailMessageSortKey::Sender, QMailMessageKey::Sender); -+ map.insert(QMailMessageSortKey::Recipients, QMailMessageKey::Recipients); -+ map.insert(QMailMessageSortKey::Subject, QMailMessageKey::Subject); -+ map.insert(QMailMessageSortKey::TimeStamp, QMailMessageKey::TimeStamp); -+ map.insert(QMailMessageSortKey::ReceptionTimeStamp, QMailMessageKey::ReceptionTimeStamp); -+ map.insert(QMailMessageSortKey::Status, QMailMessageKey::Status); -+ map.insert(QMailMessageSortKey::ParentAccountId, QMailMessageKey::ParentAccountId); -+ map.insert(QMailMessageSortKey::ServerUid, QMailMessageKey::ServerUid); -+ map.insert(QMailMessageSortKey::Size, QMailMessageKey::Size); -+ map.insert(QMailMessageSortKey::ContentType, QMailMessageKey::ContentType); -+ map.insert(QMailMessageSortKey::PreviousParentFolderId, QMailMessageKey::PreviousParentFolderId); ++ case QMailMessageKey::Type: ++ return "?type"; + -+ return map; -+} ++ case QMailMessageKey::ParentFolderId: ++ return "?parentFolderId"; + -+template<> -+QMailMessageKey::Property matchingProperty<QMailMessageSortKey::Property, QMailMessageKey::Property>(QMailMessageSortKey::Property source) -+{ -+ static QMap<QMailMessageSortKey::Property, QMailMessageKey::Property> map(messageSortMapInit()); -+ return map.value(source); -+} ++ case QMailMessageKey::Sender: ++ return "?sender"; + -+static QMap<QMailFolderSortKey::Property, QMailFolderKey::Property> folderSortMapInit() -+{ -+ QMap<QMailFolderSortKey::Property, QMailFolderKey::Property> map; ++ case QMailMessageKey::Recipients: ++ return "?recipients"; + -+ // Provide a mapping of sort key properties to the corresponding filter key -+ map.insert(QMailFolderSortKey::Id, QMailFolderKey::Id); -+ map.insert(QMailFolderSortKey::Path, QMailFolderKey::Path); -+ map.insert(QMailFolderSortKey::ParentFolderId, QMailFolderKey::ParentFolderId); -+ map.insert(QMailFolderSortKey::ParentAccountId, QMailFolderKey::ParentAccountId); -+ map.insert(QMailFolderSortKey::DisplayName, QMailFolderKey::DisplayName); -+ map.insert(QMailFolderSortKey::Status, QMailFolderKey::Status); -+ map.insert(QMailFolderSortKey::ServerCount, QMailFolderKey::ServerCount); -+ map.insert(QMailFolderSortKey::ServerUnreadCount, QMailFolderKey::ServerUnreadCount); ++ case QMailMessageKey::Subject: ++ return "?subject"; + -+ return map; -+} ++ case QMailMessageKey::TimeStamp: ++ return "?timestamp"; + -+template<> -+QMailFolderKey::Property matchingProperty<QMailFolderSortKey::Property, QMailFolderKey::Property>(QMailFolderSortKey::Property source) -+{ -+ static QMap<QMailFolderSortKey::Property, QMailFolderKey::Property> map(folderSortMapInit()); -+ return map.value(source); -+} ++ case QMailMessageKey::Status: ++ return "?status"; + -+static QMap<QMailAccountSortKey::Property, QMailAccountKey::Property> accountSortMapInit() -+{ -+ QMap<QMailAccountSortKey::Property, QMailAccountKey::Property> map; ++ case QMailMessageKey::Conversation: ++ return "?conversation"; + -+ // Provide a mapping of sort key properties to the corresponding filter key -+ map.insert(QMailAccountSortKey::Id, QMailAccountKey::Id); -+ map.insert(QMailAccountSortKey::Name, QMailAccountKey::Name); -+ map.insert(QMailAccountSortKey::MessageType, QMailAccountKey::MessageType); -+ map.insert(QMailAccountSortKey::Status, QMailAccountKey::Status); ++ case QMailMessageKey::ReceptionTimeStamp: ++ return "?receptionTimeStamp"; + -+ return map; -+} ++ case QMailMessageKey::ServerUid: ++ return "?serverUid"; + -+template<> -+QMailAccountKey::Property matchingProperty<QMailAccountSortKey::Property, QMailAccountKey::Property>(QMailAccountSortKey::Property source) -+{ -+ static QMap<QMailAccountSortKey::Property, QMailAccountKey::Property> map(accountSortMapInit()); -+ return map.value(source); -+} ++ case QMailMessageKey::Size: ++ return "?size"; + -+template<> -+QString fieldName<QMailMessageSortKey::Property>(QMailMessageSortKey::Property property, const QString &alias) -+{ -+ return qualifiedName(messagePropertyName(matchingProperty<QMailMessageSortKey::Property, QMailMessageKey::Property>(property)), alias); -+} ++ case QMailMessageKey::ParentAccountId: ++ return "?parentAccountId"; + -+template<> -+QString fieldName<QMailFolderSortKey::Property>(QMailFolderSortKey::Property property, const QString &alias) -+{ -+ return qualifiedName(folderPropertyName(matchingProperty<QMailFolderSortKey::Property, QMailFolderKey::Property>(property)), alias); -+} ++ case QMailMessageKey::AncestorFolderIds: ++ return "?ancestorFolderIds"; + -+template<> -+QString fieldName<QMailAccountSortKey::Property>(QMailAccountSortKey::Property property, const QString &alias) -+{ -+ return qualifiedName(accountPropertyName(matchingProperty<QMailAccountSortKey::Property, QMailAccountKey::Property>(property)), alias); -+} ++ case QMailMessageKey::ContentType: ++ return "?contentType"; + -+template<typename PropertyType> -+QString fieldNames(const QList<PropertyType> &properties, const QString &separator, const QString &alias) -+{ -+ QStringList fields; -+ foreach (const PropertyType &property, properties) -+ fields.append(fieldName(property, alias)); ++ case QMailMessageKey::PreviousParentFolderId: ++ return "?previousParentFolderId"; + -+ return fields.join(separator); -+} ++ case QMailMessageKey::ContentScheme: ++ return "?contentScheme"; + -+template<typename ArgumentType> -+void appendWhereValues(const ArgumentType &a, QVariantList &values); ++ case QMailMessageKey::ContentIdentifier: ++ return "?contentIdentifier"; + -+template<typename KeyType> -+QVariantList whereClauseValues(const KeyType& key) -+{ -+ QVariantList values; ++ case QMailMessageKey::InResponseTo: ++ return "?inResponseTo"; + -+ foreach (const typename KeyType::ArgumentType& a, key.arguments()) -+ ::appendWhereValues(a, values); ++ case QMailMessageKey::ResponseType: ++ return "?responseType"; + -+ foreach (const KeyType& subkey, key.subKeys()) -+ values += ::whereClauseValues<KeyType>(subkey); ++ case QMailMessageKey::Custom: ++ return "?custom"; + -+ return values; ++ default: ++ Q_ASSERT(false); ++ } ++ return QString(); +} + -+template <typename Key, typename Argument = typename Key::ArgumentType> -+class ArgumentExtractorBase ++template <> ++QString propertyNameString<QMailFolderKey::Property>(QMailFolderKey::Property property) +{ -+protected: -+ const Argument &arg; -+ -+ ArgumentExtractorBase(const Argument &a) : arg(a) {} -+ -+ QString minimalString(const QString &s) const -+ { -+ // If the argument is a phone number, ensure it is in minimal form -+ QMailAddress address(s); -+ if (address.isPhoneNumber()) { -+ QString minimal(address.minimalPhoneNumber()); -+ -+ // Rather than compare exact numbers, we will only use the trailing -+ // digits to compare phone numbers - otherwise, slightly different -+ // forms of the same number will not be matched -+ static const int significantDigits = 8; -+ -+ int extraneous = minimal.length() - significantDigits; -+ if (extraneous > 0) -+ minimal.remove(0, extraneous); -+ -+ return minimal; -+ } -+ -+ return s; -+ } -+ -+ QString submatchString(const QString &s, bool valueMinimalised) const -+ { -+ if (!s.isEmpty()) { -+ // Delimit data for sql "LIKE" operator -+ if (((arg.op == Includes) || (arg.op == Excludes)) || (((arg.op == Equal) || (arg.op == NotEqual)) && valueMinimalised)) -+ return QString("\%" + s + "\%"); -+ } else if ((arg.op == Includes) || (arg.op == Excludes)) { -+ return QString("\%"); -+ } -+ -+ return s; -+ } -+ -+ QString addressStringValue() const ++ switch (property) + { -+ return submatchString(minimalString(QMailStorePrivate::extractValue<QString>(arg.valueList.first())), true); -+ } ++ case QMailFolderKey::Id: ++ return "?id"; + -+ QString stringValue() const -+ { -+ return submatchString(QMailStorePrivate::extractValue<QString>(arg.valueList.first()), false); -+ } ++ case QMailFolderKey::Path: ++ return "?path"; + -+ QVariantList stringValues() const -+ { -+ QVariantList values; ++ case QMailFolderKey::ParentFolderId: ++ return "?parentFolderId"; + -+ if (arg.valueList.count() == 1) { -+ values.append(stringValue()); -+ } else { -+ // Includes/Excludes is not a pattern match with multiple values -+ foreach (const QVariant &item, arg.valueList) -+ values.append(QMailStorePrivate::extractValue<QString>(item)); -+ } ++ case QMailFolderKey::ParentAccountId: ++ return "?parentAccountId"; + -+ return values; -+ } ++ case QMailFolderKey::DisplayName: ++ return "?displayName"; + -+ template<typename ID> -+ quint64 idValue() const -+ { -+ return QMailStorePrivate::extractValue<ID>(arg.valueList.first()).toULongLong(); -+ } ++ case QMailFolderKey::Status: ++ return "?status"; + -+ template<typename ClauseKey> -+ QVariantList idValues() const -+ { -+ const QVariant& var = arg.valueList.first(); ++ case QMailFolderKey::AncestorFolderIds: ++ return "?ancestorFolderIds"; + -+ if (qVariantCanConvert<ClauseKey>(var)) { -+ return ::whereClauseValues(qVariantValue<ClauseKey>(var)); -+ } else { -+ QVariantList values; ++ case QMailFolderKey::ServerCount: ++ return "?serverCount"; + -+ foreach (const QVariant &item, arg.valueList) -+ values.append(QMailStorePrivate::extractValue<typename ClauseKey::IdType>(item).toULongLong()); ++ case QMailFolderKey::ServerUnreadCount: ++ return "?serverUnreadCount"; + -+ return values; -+ } -+ } ++ case QMailFolderKey::Custom: ++ return "?custom"; + -+ int intValue() const -+ { -+ return QMailStorePrivate::extractValue<int>(arg.valueList.first()); ++ default: ++ Q_ASSERT(false); + } ++ return QString(); ++} + -+ QVariantList intValues() const ++template <> ++QString propertyNameString<QMailAccountKey::Property>(QMailAccountKey::Property property) ++{ ++ switch (property) + { -+ QVariantList values; -+ -+ foreach (const QVariant &item, arg.valueList) -+ values.append(QMailStorePrivate::extractValue<int>(item)); ++ case QMailAccountKey::Id: ++ return "?id"; + -+ return values; -+ } ++ case QMailAccountKey::Name: ++ return "?name"; + -+ int quint64Value() const -+ { -+ return QMailStorePrivate::extractValue<quint64>(arg.valueList.first()); -+ } ++ case QMailAccountKey::MessageType: ++ return "?messageType"; + -+ QVariantList customValues() const -+ { -+ QVariantList values; ++ case QMailAccountKey::FromAddress: ++ return "?fromAddress"; + -+ QStringList constraints = QMailStorePrivate::extractValue<QStringList>(arg.valueList.first()); -+ // Field name required for existence or value test -+ values.append(constraints.takeFirst()); ++ case QMailAccountKey::Status: ++ return "?status"; + -+ if (!constraints.isEmpty()) { -+ // For a value test, we need the comparison value also -+ values.append(submatchString(constraints.takeFirst(), false)); -+ } ++ case QMailAccountKey::Custom: ++ return "?custom"; + -+ return values; ++ default: ++ Q_ASSERT(false); + } -+}; -+ ++ return QString(); ++} + -+template<typename PropertyType, typename BitmapType = int> -+class RecordExtractorBase ++template <> ++QString propertyNameString<QMailMessageSortKey::Property>(QMailMessageSortKey::Property property) +{ -+protected: -+ const QSqlRecord &record; -+ const BitmapType bitmap; -+ -+ RecordExtractorBase(const QSqlRecord &r, BitmapType b = 0) : record(r), bitmap(b) {} -+ virtual ~RecordExtractorBase() {} -+ -+ template<typename ValueType> -+ ValueType value(const QString &field, const ValueType &defaultValue = ValueType()) const -+ { -+ int index(fieldIndex(field, bitmap)); -+ -+ if (record.isNull(index)) -+ return defaultValue; -+ else -+ return QMailStorePrivate::extractValue<ValueType>(record.value(index), defaultValue); -+ } -+ -+ template<typename ValueType> -+ ValueType value(PropertyType p, const ValueType &defaultValue = ValueType()) const -+ { -+ return value(fieldName(p, QString()), defaultValue); -+ } -+ -+ virtual int fieldIndex(const QString &field, BitmapType b) const = 0; -+ -+ int mappedFieldIndex(const QString &field, BitmapType bitmap, QMap<BitmapType, QMap<QString, int> > &fieldIndex) const ++ switch (property) + { -+ typename QMap<BitmapType, QMap<QString, int> >::iterator it = fieldIndex.find(bitmap); -+ if (it == fieldIndex.end()) { -+ it = fieldIndex.insert(bitmap, QMap<QString, int>()); -+ } -+ -+ QMap<QString, int> &fields(it.value()); -+ -+ QMap<QString, int>::iterator fit = fields.find(field); -+ if (fit != fields.end()) -+ return fit.value(); -+ -+ int index = record.indexOf(field); -+ fields.insert(field, index); -+ return index; -+ } -+}; -+ -+ -+// Class to extract data from records of the mailmessages table -+class MessageRecord : public RecordExtractorBase<QMailMessageKey::Property, QMailMessageKey::Properties> -+{ -+public: -+ MessageRecord(const QSqlRecord &r, QMailMessageKey::Properties props) -+ : RecordExtractorBase<QMailMessageKey::Property, QMailMessageKey::Properties>(r, props) {} -+ -+ QMailMessageId id() const { return QMailMessageId(value<quint64>(QMailMessageKey::Id)); } -+ -+ QMailMessage::MessageType messageType() const { return QMailMessage::MessageType(value<int>(QMailMessageKey::Type, QMailMessage::None)); } -+ -+ QMailFolderId parentFolderId() const { return QMailFolderId(value<quint64>(QMailMessageKey::ParentFolderId)); } -+ -+ QMailAddress from() const { return QMailAddress(value<QString>(QMailMessageKey::Sender)); } -+ -+ QList<QMailAddress> to() const { return QMailAddress::fromStringList(value<QString>(QMailMessageKey::Recipients)); } -+ -+ QString subject() const { return value<QString>(QMailMessageKey::Subject); } -+ -+ QMailTimeStamp date() const { return QMailTimeStamp(value<QDateTime>(QMailMessageKey::TimeStamp)); } ++ case QMailMessageSortKey::Id: ++ return "?id"; + -+ QMailTimeStamp receivedDate() const { return QMailTimeStamp(value<QDateTime>(QMailMessageKey::TimeStamp)); } ++ case QMailMessageSortKey::Type: ++ return "?type"; + -+ quint64 status() const { return value<quint64>(QMailMessageKey::Status, 0); } ++ case QMailMessageSortKey::ParentFolderId: ++ return "?parentFolderId"; + -+ QMailAccountId parentAccountId() const { return QMailAccountId(value<quint64>(QMailMessageKey::ParentAccountId)); } ++ case QMailMessageSortKey::Sender: ++ return "?sender"; + -+ QString serverUid() const { return value<QString>(QMailMessageKey::ServerUid); } ++ case QMailMessageSortKey::Recipients: ++ return "?recipients"; + -+ int size() const { return value<int>(QMailMessageKey::Size); } ++ case QMailMessageSortKey::Subject: ++ return "?subject"; + -+ QMailMessage::ContentType content() const { return QMailMessage::ContentType(value<int>(QMailMessageKey::ContentType, QMailMessage::UnknownContent)); } ++ case QMailMessageSortKey::TimeStamp: ++ return "?timestamp"; + -+ QMailFolderId previousParentFolderId() const { return QMailFolderId(value<quint64>(QMailMessageKey::PreviousParentFolderId)); } ++ case QMailMessageSortKey::Status: ++ return "?status"; + -+ QString contentScheme() const -+ { -+ if (_uriElements.first.isNull()) -+ _uriElements = ::uriElements(value<QString>(QMailMessageKey::ContentScheme)); ++ case QMailMessageSortKey::ReceptionTimeStamp: ++ return "?receptionTimeStamp"; + -+ return _uriElements.first; -+ } ++ case QMailMessageSortKey::ServerUid: ++ return "?serverUid"; + -+ QString contentIdentifier() const -+ { -+ if (_uriElements.first.isNull()) -+ _uriElements = ::uriElements(value<QString>(QMailMessageKey::ContentIdentifier)); ++ case QMailMessageSortKey::Size: ++ return "?size"; + -+ return _uriElements.second; -+ } ++ case QMailMessageSortKey::ParentAccountId: ++ return "?parentAccountId"; + -+ QMailMessageId inResponseTo() const { return QMailMessageId(value<quint64>(QMailMessageKey::InResponseTo)); } ++ case QMailMessageSortKey::ContentType: ++ return "?contentType"; + -+ QMailMessage::ResponseType responseType() const { return QMailMessage::ResponseType(value<int>(QMailMessageKey::ResponseType, QMailMessage::NoResponse)); } ++ case QMailMessageSortKey::PreviousParentFolderId: ++ return "?previousParentFolderId"; + -+private: -+ int fieldIndex(const QString &field, QMailMessageKey::Properties props) const -+ { -+ return mappedFieldIndex(field, props, _fieldIndex); ++ default: ++ Q_ASSERT(false); + } ++ return QString(); ++} + -+ mutable QPair<QString, QString> _uriElements; -+ -+ static QMap<QMailMessageKey::Properties, QMap<QString, int> > _fieldIndex; -+}; -+ -+QMap<QMailMessageKey::Properties, QMap<QString, int> > MessageRecord::_fieldIndex; -+ -+ -+// Class to convert QMailMessageKey argument values to SQL bind values -+class MessageKeyArgumentExtractor : public ArgumentExtractorBase<QMailMessageKey> ++template <> ++QString propertyNameString<QMailFolderSortKey::Property>(QMailFolderSortKey::Property property) +{ -+public: -+ MessageKeyArgumentExtractor(const QMailMessageKey::ArgumentType &a) -+ : ArgumentExtractorBase<QMailMessageKey>(a) {} -+ -+ QVariantList id() const { return idValues<QMailMessageKey>(); } -+ -+ QVariant messageType() const { return intValue(); } -+ -+ QVariantList parentFolderId() const { return idValues<QMailFolderKey>(); } -+ -+ QVariantList ancestorFolderIds() const { return idValues<QMailFolderKey>(); } -+ -+ QVariantList sender() const { return stringValues(); } -+ -+ QVariant recipients() const { return addressStringValue(); } -+ -+ QVariantList subject() const { return stringValues(); } -+ -+ QVariant date() const { return QMailStorePrivate::extractValue<QDateTime>(arg.valueList.first()); } -+ -+ QVariant receivedDate() const { return QMailStorePrivate::extractValue<QDateTime>(arg.valueList.first()); } -+ -+ QVariant status() const ++ switch (property) + { -+ // The UnloadedData flag has no meaningful persistent value -+ return (QMailStorePrivate::extractValue<quint64>(arg.valueList.first()) & ~QMailMessage::UnloadedData); -+ } ++ case QMailFolderSortKey::Id: ++ return "?id"; + -+ QVariantList parentAccountId() const { return idValues<QMailAccountKey>(); } ++ case QMailFolderSortKey::Path: ++ return "?path"; + -+ QVariantList serverUid() const { return stringValues(); } ++ case QMailFolderSortKey::ParentFolderId: ++ return "?parentFolderId"; + -+ QVariant size() const { return intValue(); } ++ case QMailFolderSortKey::ParentAccountId: ++ return "?parentAccountId"; + -+ QVariantList content() const { return intValues(); } ++ case QMailFolderSortKey::DisplayName: ++ return "?displayName"; + -+ QVariantList previousParentFolderId() const { return idValues<QMailFolderKey>(); } ++ case QMailFolderSortKey::Status: ++ return "?status"; + -+ QVariant contentScheme() const -+ { -+ // Any colons in the field will be stored in escaped format -+ QString value(::escape(QMailStorePrivate::extractValue<QString>(arg.valueList.first()), ':')); ++ case QMailFolderSortKey::ServerCount: ++ return "?serverCount"; + -+ if ((arg.op == Includes) || (arg.op == Excludes)) { -+ value.prepend('%').append('%'); -+ } else if ((arg.op == Equal) || (arg.op == NotEqual)) { -+ value.append(":%"); -+ } -+ return value; ++ case QMailFolderSortKey::ServerUnreadCount: ++ return "?serverUnreadCount"; ++ ++ default: ++ Q_ASSERT(false); + } ++ return QString(); ++} + -+ QVariant contentIdentifier() const -+ { -+ // Any colons in the field will be stored in escaped format -+ QString value(::escape(QMailStorePrivate::extractValue<QString>(arg.valueList.first()), ':')); ++template <> ++QString propertyNameString<QMailAccountSortKey::Property>(QMailAccountSortKey::Property property) ++{ ++ switch (property) ++ { ++ case QMailAccountSortKey::Id: ++ return "?id"; + -+ if ((arg.op == Includes) || (arg.op == Excludes)) { -+ value.prepend('%').append('%'); -+ } else if ((arg.op == Equal) || (arg.op == NotEqual)) { -+ value.prepend("%:"); -+ } -+ return value; -+ } ++ case QMailAccountSortKey::Name: ++ return "?name"; + -+ QVariantList inResponseTo() const { return idValues<QMailMessageKey>(); } ++ case QMailAccountSortKey::MessageType: ++ return "?messageType"; + -+ QVariantList responseType() const { return intValues(); } ++ case QMailAccountSortKey::Status: ++ return "?status"; + -+ QVariant conversation() const -+ { -+ // TODO: Not yet implemented -+ return QVariant(); ++ default: ++ Q_ASSERT(false); + } ++ return QString(); ++} + -+ QVariantList custom() const { return customValues(); } -+}; ++template <class Property> ++QString sparqlPropertyStatmentString(const QString& uri, Property property); + -+template<> -+void appendWhereValues<QMailMessageKey::ArgumentType>(const QMailMessageKey::ArgumentType &a, QVariantList &values) ++template <> ++QString sparqlPropertyStatmentString<QMailMessageKey::Property>(const QString& uri, QMailMessageKey::Property property) +{ -+ const MessageKeyArgumentExtractor extractor(a); ++ /* ++ * TBD: Complete this function with all properties description. ++ */ ++ switch (property) ++ { ++ case QMailMessageKey::Id: ++ return QString(); + -+ switch (a.property) -+ { -+ case QMailMessageKey::Id: -+ if (a.valueList.count() < IdLookupThreshold) { -+ values += extractor.id(); -+ } else { -+ // This value match has been replaced by a table lookup -+ } -+ break; ++ case QMailMessageKey::Type: ++ return QString(); + -+ case QMailMessageKey::Type: -+ values += extractor.messageType(); -+ break; ++ case QMailMessageKey::ParentFolderId: ++ return QString("%1 nie:isLogicalPartOf %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailMessageKey::ParentFolderId: -+ values += extractor.parentFolderId(); -+ break; ++ case QMailMessageKey::Sender: ++ return QString("%1 nmo:sender [ rdf:type nco:Contact ; nco:hasEmailAddress %2 ] .").arg(uri).arg(propertyNameString(property)); + -+ case QMailMessageKey::AncestorFolderIds: -+ values += extractor.ancestorFolderIds(); -+ break; ++ case QMailMessageKey::Recipients: ++ return QString("%1 nmo:recipient [ rdf:type nco:Contact ; nco:hasEmailAddress %2 ] .").arg(uri).arg(propertyNameString(property)); + -+ case QMailMessageKey::Sender: -+ values += extractor.sender(); -+ break; ++ case QMailMessageKey::Subject: ++ return QString("%1 nmo:messageSubject %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailMessageKey::Recipients: -+ values += extractor.recipients(); -+ break; ++ case QMailMessageKey::TimeStamp: ++ return QString("%1 nmo:sentDate %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailMessageKey::Subject: -+ values += extractor.subject(); -+ break; ++ case QMailMessageKey::Status: ++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailMessageKey::TimeStamp: -+ values += extractor.date(); -+ break; ++ case QMailMessageKey::Conversation: ++ return QString(); + -+ case QMailMessageKey::ReceptionTimeStamp: -+ values += extractor.receivedDate(); -+ break; ++ case QMailMessageKey::ReceptionTimeStamp: ++ return QString(); + -+ case QMailMessageKey::Status: -+ values += extractor.status(); -+ break; ++ case QMailMessageKey::ServerUid: ++ return QString("%1 nmo:messageId %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailMessageKey::ParentAccountId: -+ values += extractor.parentAccountId(); -+ break; ++ case QMailMessageKey::Size: ++ return QString("%1 nie:contentSize %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailMessageKey::ServerUid: -+ values += extractor.serverUid(); -+ break; ++ case QMailMessageKey::ParentAccountId: ++ return QString("%1 nie:relatedTo %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailMessageKey::Size: -+ values += extractor.size(); -+ break; ++ case QMailMessageKey::AncestorFolderIds: ++ return QString(); + -+ case QMailMessageKey::ContentType: -+ values += extractor.content(); -+ break; ++ case QMailMessageKey::ContentType: ++ return QString(); + -+ case QMailMessageKey::PreviousParentFolderId: -+ values += extractor.previousParentFolderId(); -+ break; ++ case QMailMessageKey::PreviousParentFolderId: ++ return QString(); + -+ case QMailMessageKey::ContentScheme: -+ values += extractor.contentScheme(); -+ break; ++ case QMailMessageKey::ContentScheme: ++ return QString(); + -+ case QMailMessageKey::ContentIdentifier: -+ values += extractor.contentIdentifier(); -+ break; ++ case QMailMessageKey::ContentIdentifier: ++ return QString("%1 nie:isStoredAs [ rdf:type nie:DataObject ; nie:dataSource %2 ] .").arg(uri).arg(propertyNameString(property)); + -+ case QMailMessageKey::InResponseTo: -+ values += extractor.inResponseTo(); -+ break; ++ case QMailMessageKey::InResponseTo: ++ return QString("%1 nmo:inReplyTo %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailMessageKey::ResponseType: -+ values += extractor.responseType(); -+ break; ++ case QMailMessageKey::ResponseType: ++ return QString(); + -+ case QMailMessageKey::Conversation: -+ values += extractor.conversation(); -+ break; ++ case QMailMessageKey::Custom: ++ return QString(); + -+ case QMailMessageKey::Custom: -+ values += extractor.custom(); -+ break; ++ default: ++ Q_ASSERT(false); + } ++ return QString(); +} + -+ -+// Class to extract data from records of the mailaccounts table -+class AccountRecord : public RecordExtractorBase<QMailAccountKey::Property> ++template <> ++QString sparqlPropertyStatmentString<QMailFolderKey::Property>(const QString& uri, QMailFolderKey::Property property) +{ -+public: -+ AccountRecord(const QSqlRecord &r) -+ : RecordExtractorBase<QMailAccountKey::Property>(r) {} -+ -+ QMailAccountId id() const { return QMailAccountId(value<quint64>(QMailAccountKey::Id)); } -+ -+ QString name() const { return value<QString>(QMailAccountKey::Name); } -+ -+ QMailMessage::MessageType messageType() const { return QMailMessage::MessageType(value<int>(QMailAccountKey::MessageType, -1)); } -+ -+ QString fromAddress() const { return value<QString>(QMailAccountKey::FromAddress); } -+ -+ quint64 status() const { return value<quint64>(QMailAccountKey::Status); } -+ -+ QString signature() const { return value<QString>("signature"); } -+ -+private: -+ int fieldIndex(const QString &field, int props) const ++ /* ++ * TBD: Complete this function with all properties description. ++ */ ++ switch (property) + { -+ return mappedFieldIndex(field, props, _fieldIndex); -+ } ++ case QMailFolderKey::Id: ++ return "id"; + -+ static QMap<int, QMap<QString, int> > _fieldIndex; -+}; ++ case QMailFolderKey::Path: ++ return QString("%1 nmo:folderName %2 .").arg(uri).arg(propertyNameString(property)); + -+QMap<int, QMap<QString, int> > AccountRecord::_fieldIndex; ++ 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)); + -+// Class to convert QMailAccountKey argument values to SQL bind values -+class AccountKeyArgumentExtractor : public ArgumentExtractorBase<QMailAccountKey> -+{ -+public: -+ AccountKeyArgumentExtractor(const QMailAccountKey::ArgumentType &a) -+ : ArgumentExtractorBase<QMailAccountKey>(a) {} ++ case QMailFolderKey::DisplayName: ++ return QString("%1 nmo:folderDisplayName %2 .").arg(uri).arg(propertyNameString(property)); + -+ QVariantList id() const { return idValues<QMailAccountKey>(); } ++ case QMailFolderKey::Status: ++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property)); + -+ QVariantList name() const { return stringValues(); } ++ case QMailFolderKey::AncestorFolderIds: ++ return QString(); + -+ QVariant messageType() const { return intValue(); } ++ case QMailFolderKey::ServerCount: ++ return QString("%1 nmo:serverCount %2 .").arg(uri).arg(propertyNameString(property)); + -+ QVariant fromAddress() const -+ { -+ QString value(QMailStorePrivate::extractValue<QString>(arg.valueList.first())); ++ case QMailFolderKey::ServerUnreadCount: ++ return QString("%1 nmo:serverUnreadCount %2 .").arg(uri).arg(propertyNameString(property)); + -+ // This test will be converted to a LIKE test, for all comparators -+ if (arg.op == Equal || arg.op == NotEqual) { -+ // Ensure exact match by testing for address delimiters -+ value.prepend('<').append('>'); -+ } ++ case QMailFolderKey::Custom: ++ return QString(); + -+ return value.prepend('%').append('%'); ++ default: ++ Q_ASSERT(false); + } ++ return QString(); ++} + -+ QVariant status() const { return quint64Value(); } -+ -+ QVariantList custom() const { return customValues(); } -+}; -+ -+template<> -+void appendWhereValues<QMailAccountKey::ArgumentType>(const QMailAccountKey::ArgumentType &a, QVariantList &values) ++template <> ++QString sparqlPropertyStatmentString<QMailAccountKey::Property>(const QString& uri, QMailAccountKey::Property property) +{ -+ const AccountKeyArgumentExtractor extractor(a); -+ -+ switch (a.property) ++ /* ++ * TBD: Complete this function with all properties description. ++ */ ++ switch (property) + { -+ case QMailAccountKey::Id: -+ values += extractor.id(); -+ break; ++ case QMailAccountKey::Id: ++ return QString(); + -+ case QMailAccountKey::Name: -+ values += extractor.name(); -+ break; ++ case QMailAccountKey::Name: ++ return QString("%1 nmo:accountName %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailAccountKey::MessageType: -+ values += extractor.messageType(); -+ break; ++ case QMailAccountKey::MessageType: ++ return QString(); + -+ case QMailAccountKey::FromAddress: -+ values += extractor.fromAddress(); -+ break; ++ case QMailAccountKey::FromAddress: ++ return QString("%1 nmo:fromAddress [ rdf:type nco:EmailAddress ; nco:emailAddress %2 ] .").arg(uri).arg(propertyNameString(property)); + -+ case QMailAccountKey::Status: -+ values += extractor.status(); -+ break; ++ case QMailAccountKey::Status: ++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailAccountKey::Custom: -+ values += extractor.custom(); -+ break; ++ case QMailAccountKey::Custom: ++ return QString(); ++ ++ default: ++ Q_ASSERT(false); + } ++ return QString(); +} + -+ -+// Class to extract data from records of the mailfolders table -+class FolderRecord : public RecordExtractorBase<QMailFolderKey::Property> ++template <> ++QString sparqlPropertyStatmentString<QMailMessageSortKey::Property>(const QString& uri, QMailMessageSortKey::Property property) +{ -+public: -+ FolderRecord(const QSqlRecord &r) -+ : RecordExtractorBase<QMailFolderKey::Property>(r) {} -+ -+ QMailFolderId id() const { return QMailFolderId(value<quint64>(QMailFolderKey::Id)); } -+ -+ QString path() const { return value<QString>(QMailFolderKey::Path); } -+ -+ QMailFolderId parentFolderId() const { return QMailFolderId(value<quint64>(QMailFolderKey::ParentFolderId)); } -+ -+ QMailAccountId parentAccountId() const { return QMailAccountId(value<quint64>(QMailFolderKey::ParentAccountId)); } -+ -+ QString displayName() const { return value<QString>(QMailFolderKey::DisplayName); } -+ -+ quint64 status() const { return value<quint64>(QMailFolderKey::Status); } -+ -+ uint serverCount() const { return value<uint>(QMailFolderKey::ServerCount); } -+ -+ uint serverUnreadCount() const { return value<uint>(QMailFolderKey::ServerUnreadCount); } -+ -+private: -+ int fieldIndex(const QString &field, int props) const ++ /* ++ * TBD: Complete this function with all properties description. ++ */ ++ switch (property) + { -+ return mappedFieldIndex(field, props, _fieldIndex); -+ } ++ case QMailMessageSortKey::Id: ++ return QString(); + -+ static QMap<int, QMap<QString, int> > _fieldIndex; -+}; ++ case QMailMessageSortKey::Type: ++ return QString(); + -+QMap<int, QMap<QString, int> > FolderRecord::_fieldIndex; ++ 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)); + -+// Class to convert QMailFolderKey argument values to SQL bind values -+class FolderKeyArgumentExtractor : public ArgumentExtractorBase<QMailFolderKey> -+{ -+public: -+ FolderKeyArgumentExtractor(const QMailFolderKey::ArgumentType &a) -+ : ArgumentExtractorBase<QMailFolderKey>(a) {} ++ case QMailMessageSortKey::Recipients: ++ return QString("%1 nmo:recipient [ rdf:type nco:Contact ; nco:hasEmailAddress %2 ] .").arg(uri).arg(propertyNameString(property)); + -+ QVariantList id() const { return idValues<QMailFolderKey>(); } ++ case QMailMessageSortKey::Subject: ++ return QString("%1 nmo:messageSubject %2 .").arg(uri).arg(propertyNameString(property)); + -+ QVariantList path() const { return stringValues(); } ++ case QMailMessageSortKey::TimeStamp: ++ return QString("%1 nmo:sentDate %2 .").arg(uri).arg(propertyNameString(property)); + -+ QVariantList parentFolderId() const { return idValues<QMailFolderKey>(); } ++ case QMailMessageSortKey::Status: ++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property)); + -+ QVariantList ancestorFolderIds() const { return idValues<QMailFolderKey>(); } ++ case QMailMessageSortKey::ReceptionTimeStamp: ++ return QString(); + -+ QVariantList parentAccountId() const { return idValues<QMailAccountKey>(); } ++ case QMailMessageSortKey::ServerUid: ++ return QString("%1 nmo:messageId %2 .").arg(uri).arg(propertyNameString(property)); + -+ QVariantList displayName() const { return stringValues(); } ++ case QMailMessageSortKey::Size: ++ return QString("%1 nie:contentSize %2 .").arg(uri).arg(propertyNameString(property)); + -+ QVariant status() const { return quint64Value(); } ++ case QMailMessageSortKey::ParentAccountId: ++ return QString("%1 nie:relatedTo %2 .").arg(uri).arg(propertyNameString(property)); + -+ QVariant serverCount() const { return intValue(); } ++ case QMailMessageSortKey::ContentType: ++ return QString(); + -+ QVariant serverUnreadCount() const { return intValue(); } ++ case QMailMessageSortKey::PreviousParentFolderId: ++ return QString(); + -+ QVariantList custom() const { return customValues(); } -+}; ++ default: ++ Q_ASSERT(false); ++ } ++ return QString(); ++} + -+template<> -+void appendWhereValues<QMailFolderKey::ArgumentType>(const QMailFolderKey::ArgumentType &a, QVariantList &values) ++template <> ++QString sparqlPropertyStatmentString<QMailFolderSortKey::Property>(const QString& uri, QMailFolderSortKey::Property property) +{ -+ const FolderKeyArgumentExtractor extractor(a); -+ -+ switch (a.property) ++ /* ++ * TBD: Complete this function with all properties description. ++ */ ++ switch (property) + { -+ case QMailFolderKey::Id: -+ values += extractor.id(); -+ break; -+ -+ case QMailFolderKey::Path: -+ values += extractor.path(); -+ break; ++ case QMailFolderSortKey::Id: ++ return "id"; + -+ case QMailFolderKey::ParentFolderId: -+ values += extractor.parentFolderId(); -+ break; ++ case QMailFolderSortKey::Path: ++ return QString("%1 nmo:folderName %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailFolderKey::AncestorFolderIds: -+ values += extractor.ancestorFolderIds(); -+ break; ++ case QMailFolderSortKey::ParentFolderId: ++ return QString("%1 nie:isLogicalPartOf %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailFolderKey::ParentAccountId: -+ values += extractor.parentAccountId(); -+ break; ++ case QMailFolderSortKey::ParentAccountId: ++ return QString("%1 nie:relatedTo %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailFolderKey::DisplayName: -+ values += extractor.displayName(); -+ break; ++ case QMailFolderSortKey::DisplayName: ++ return QString("%1 nmo:folderDisplayName %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailFolderKey::Status: -+ values += extractor.status(); -+ break; ++ case QMailFolderSortKey::Status: ++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailFolderKey::ServerCount: -+ values += extractor.serverCount(); -+ break; ++ case QMailFolderSortKey::ServerCount: ++ return QString("%1 nmo:serverCount %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailFolderKey::ServerUnreadCount: -+ values += extractor.serverUnreadCount(); -+ break; ++ case QMailFolderSortKey::ServerUnreadCount: ++ return QString("%1 nmo:serverUnreadCount %2 .").arg(uri).arg(propertyNameString(property)); + -+ case QMailFolderKey::Custom: -+ values += extractor.custom(); -+ break; ++ default: ++ Q_ASSERT(false); + } ++ return QString(); +} + -+ -+// Class to extract data from records of the deletedmessages table -+class MessageRemovalRecord : public RecordExtractorBase<int> ++template <> ++QString sparqlPropertyStatmentString<QMailAccountSortKey::Property>(const QString& uri, QMailAccountSortKey::Property property) +{ -+public: -+ MessageRemovalRecord(const QSqlRecord &r) -+ : RecordExtractorBase<int>(r) {} -+ -+ quint64 id() const { return value<quint64>("id"); } -+ -+ QMailAccountId parentAccountId() const { return QMailAccountId(value<quint64>("parentaccountid")); } -+ -+ QString serverUid() const { return value<QString>("serveruid"); } -+ -+ QMailFolderId parentFolderId() const { return QMailFolderId(value<quint64>("parentfolderid")); } -+ -+private: -+ int fieldIndex(const QString &field, int props) const ++ /* ++ * TBD: Complete this function with all properties description. ++ */ ++ switch (property) + { -+ return mappedFieldIndex(field, props, _fieldIndex); -+ } ++ case QMailAccountSortKey::Id: ++ return QString(); + -+ static QMap<int, QMap<QString, int> > _fieldIndex; -+}; ++ case QMailAccountSortKey::Name: ++ return QString("%1 nmo:accountName %2 .").arg(uri).arg(propertyNameString(property)); + -+QMap<int, QMap<QString, int> > MessageRemovalRecord::_fieldIndex; ++ case QMailAccountSortKey::MessageType: ++ return QString(); + ++ case QMailAccountSortKey::Status: ++ return QString("%1 nmo:status %2 .").arg(uri).arg(propertyNameString(property)); + -+static QString incrementAlias(const QString &alias) -+{ -+ QRegExp aliasPattern("([a-z]+)([0-9]+)"); -+ if (aliasPattern.exactMatch(alias)) { -+ return aliasPattern.cap(1) + QString::number(aliasPattern.cap(2).toInt() + 1); ++ default: ++ Q_ASSERT(false); + } -+ + return QString(); +} + -+template<typename ArgumentListType> -+QString buildOrderClause(const ArgumentListType &list, const QString &alias) ++template <class Key, class SortKey> ++QString keyStatment(const QString& uri, const Key& key, const SortKey& sort = SortKey()) +{ -+ if (list.isEmpty()) -+ return QString(); -+ -+ QStringList sortColumns; -+ foreach (typename ArgumentListType::const_reference arg, list) -+ sortColumns.append(fieldName(arg.first, alias) + ' ' + (arg.second == Qt::AscendingOrder ? "ASC" : "DESC")); -+ -+ return QString(" ORDER BY ") + sortColumns.join(","); -+} -+ ++ typedef typename Key::ArgumentType ArgumentType; ++ typedef typename SortKey::ArgumentType SortArgumentType; + -+QString operatorString(QMailKey::Comparator op, bool multipleArgs = false, bool patternMatch = false, bool bitwiseMultiples = false) -+{ -+ switch (op) ++ QStringList arguments; ++ foreach (SortArgumentType argument, sort.arguments()) + { -+ case Equal: -+ return (multipleArgs ? " IN " : (patternMatch ? " LIKE " : " = ")); -+ break; -+ -+ case NotEqual: -+ return (multipleArgs ? " NOT IN " : (patternMatch ? " NOT LIKE " : " <> ")); -+ break; -+ -+ case LessThan: -+ return " < "; -+ break; -+ -+ case LessThanEqual: -+ return " <= "; -+ break; -+ -+ case GreaterThan: -+ return " > "; -+ break; -+ -+ case GreaterThanEqual: -+ return " >= "; -+ break; -+ -+ case Includes: -+ case Present: -+ return (multipleArgs ? " IN " : (bitwiseMultiples ? " & " : " LIKE ")); -+ break; ++ QString statement = sparqlPropertyStatmentString(uri, argument.first); ++ if (!arguments.contains(statement)) ++ arguments << statement; ++ } + -+ case Excludes: -+ case Absent: -+ // Note: the result is not correct in the bitwiseMultiples case! -+ return (multipleArgs ? " NOT IN " : (bitwiseMultiples ? " & " : " NOT LIKE ")); -+ break; ++ foreach (ArgumentType argument, key.arguments()) ++ { ++ QString statement = sparqlPropertyStatmentString(uri, argument.property); ++ if (!arguments.contains(statement)) ++ arguments << statement; + } + -+ return QString(); ++ foreach (const Key& subkey, key.subKeys()) ++ arguments << keyStatment(uri, subkey, SortKey()); ++ ++ return arguments.join("\n"); +} + -+QString combineOperatorString(QMailKey::Combiner op) ++QString argumentValue(const QVariant& value) +{ -+ switch (op) -+ { -+ case And: -+ return " AND "; -+ break; -+ -+ case Or: -+ return " OR "; -+ break; -+ -+ case None: -+ break; ++ 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(); +} + -+QString columnExpression(const QString &column, QMailKey::Comparator op, const QString &value, bool multipleArgs = false, bool patternMatch = false, bool bitwiseMultiples = false) ++template <class ArgumentType> ++QString keyArgument(const ArgumentType& argument) +{ -+ QString operation(operatorString(op, multipleArgs, patternMatch, bitwiseMultiples)); ++ typedef typename ArgumentType::Property Property; ++ typedef typename ArgumentType::Comparator Comparator; + -+ QString expression(column + operation); ++ QString pattern = operatorString(argument.op, argument.valueList.count()); ++ pattern = pattern.arg(propertyNameString(argument.property)); + -+ // Special case handling: -+ if (bitwiseMultiples && (op == QMailKey::Excludes)) { -+ if (!value.isEmpty()) { -+ return "0 = (" + expression + value + ")"; -+ } else { -+ return "0 = " + expression; -+ } -+ } ++ foreach (QVariant value, argument.valueList) ++ pattern = pattern.arg(argumentValue(value)); + -+ return expression + value; ++ return pattern; +} + -+QString columnExpression(const QString &column, QMailKey::Comparator op, const QVariantList &valueList, bool patternMatch = false, bool bitwiseMultiples = false) ++template <class Key> ++QString keyFilter(const Key& key) +{ -+ QString value(QMailStorePrivate::expandValueList(valueList)); -+ -+ return columnExpression(column, op, value, (valueList.count() > 1), patternMatch, bitwiseMultiples); -+} ++ typedef typename Key::ArgumentType ArgumentType; + -+QString baseExpression(const QString &column, QMailKey::Comparator op, bool multipleArgs = false, bool patternMatch = false, bool bitwiseMultiples = false) -+{ -+ return columnExpression(column, op, QString(), multipleArgs, patternMatch, bitwiseMultiples); -+} ++ QStringList arguments; ++ foreach (ArgumentType argument, key.arguments()) ++ arguments << keyArgument<ArgumentType>(argument); + ++ foreach (const Key& subkey, key.subKeys()) ++ arguments << keyFilter<Key>(subkey); + -+template<typename Key> -+QString whereClauseItem(const Key &key, const typename Key::ArgumentType &arg, const QString &alias, const QMailStorePrivate &store); ++ QString filter = arguments.size() > 1 ? QString(key.isNegated() ? "!(%1)" : "(%1)") : ++ QString(key.isNegated() ? "!(%1)" : "%1"); ++ return filter.arg(arguments.join(combineOperatorString(key.combiner()))); ++} + -+template<> -+QString whereClauseItem<QMailAccountKey>(const QMailAccountKey &, const QMailAccountKey::ArgumentType &a, const QString &alias, const QMailStorePrivate &store) ++template <class SortKey> ++QString sortKey(const SortKey& sortKey) +{ -+ QString item; -+ { -+ QTextStream q(&item); -+ -+ QString columnName = fieldName(a.property, alias); -+ -+ bool bitwise((a.property == QMailAccountKey::Status) || (a.property == QMailAccountKey::MessageType)); -+ bool patternMatching(a.property == QMailAccountKey::FromAddress); -+ -+ QString expression = columnExpression(columnName, a.op, a.valueList, patternMatching, bitwise); -+ -+ switch(a.property) -+ { -+ case QMailAccountKey::Id: -+ if (a.valueList.first().canConvert<QMailAccountKey>()) { -+ QMailAccountKey subKey = a.valueList.first().value<QMailAccountKey>(); -+ QString nestedAlias(incrementAlias(alias)); -+ -+ // Expand comparison to sub-query result -+ q << baseExpression(columnName, a.op, true) << "( SELECT " << qualifiedName("id", nestedAlias) << " FROM mailaccounts " << nestedAlias; -+ q << store.buildWhereClause(QMailStorePrivate::Key(subKey, nestedAlias)) << ")"; -+ } else { -+ q << expression; -+ } -+ break; -+ -+ case QMailAccountKey::Custom: -+ // Match on custom field -+ { -+ QString nestedAlias(incrementAlias(alias)); ++ typedef typename SortKey::ArgumentType ArgumentType; + -+ // Is this an existence test or a value test? -+ if ((a.op == QMailKey::Present) || (a.op == QMailKey::Absent)) { -+ q << qualifiedName("id", alias) << operatorString(a.op, true) << "( SELECT " << qualifiedName("id", nestedAlias); -+ q << " FROM mailaccountcustom " << nestedAlias << " WHERE name=? )"; -+ } else { -+ q << qualifiedName("id", alias) << " IN ( SELECT " << qualifiedName("id", nestedAlias); q << " FROM mailaccountcustom " << nestedAlias; -+ q << " WHERE " << qualifiedName("name", nestedAlias) << "=? AND " << qualifiedName("value", nestedAlias) << operatorString(a.op, false) << "? )"; -+ } -+ } -+ break; ++ 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)); + -+ case QMailAccountKey::Status: -+ case QMailAccountKey::MessageType: -+ case QMailAccountKey::Name: -+ case QMailAccountKey::FromAddress: ++ if (!orderCondition.isEmpty()) ++ return QString("ORDER BY %1").arg(orderCondition); + -+ q << expression; -+ break; -+ } -+ } -+ return item; ++ return QString(); +} + -+template<> -+QString whereClauseItem<QMailMessageKey>(const QMailMessageKey &key, const QMailMessageKey::ArgumentType &a, const QString &alias, const QMailStorePrivate &store) ++QString keyQuery(const QMailMessageKey& key, const QMailMessageSortKey& sort = QMailMessageSortKey()) +{ -+ QString item; -+ { -+ QTextStream q(&item); -+ -+ QString columnName = fieldName(a.property, alias); -+ -+ bool bitwise((a.property == QMailMessageKey::Type) || (a.property == QMailMessageKey::Status)); -+ bool patternMatching((a.property == QMailMessageKey::Sender) || (a.property == QMailMessageKey::Recipients) || -+ (a.property == QMailMessageKey::ContentScheme) || (a.property == QMailMessageKey::ContentIdentifier)); -+ -+ QString expression = columnExpression(columnName, a.op, a.valueList, patternMatching, bitwise); -+ -+ switch(a.property) -+ { -+ case QMailMessageKey::Id: -+ if (a.valueList.count() >= IdLookupThreshold) { -+ q << baseExpression(columnName, a.op, true) << "( SELECT id FROM " << QMailStorePrivate::temporaryTableName(key) << ")"; -+ } else { -+ if (a.valueList.first().canConvert<QMailMessageKey>()) { -+ QMailMessageKey subKey = a.valueList.first().value<QMailMessageKey>(); -+ QString nestedAlias(incrementAlias(alias)); -+ -+ // Expand comparison to sub-query result -+ q << baseExpression(columnName, a.op, true) << "( SELECT " << qualifiedName("id", nestedAlias) << " FROM mailmessages " << nestedAlias; -+ q << store.buildWhereClause(QMailStorePrivate::Key(subKey, nestedAlias)) << ")"; -+ } else { -+ q << expression; -+ } -+ } -+ break; -+ -+ case QMailMessageKey::ParentFolderId: -+ case QMailMessageKey::PreviousParentFolderId: -+ if(a.valueList.first().canConvert<QMailFolderKey>()) { -+ QMailFolderKey parentFolderKey = a.valueList.first().value<QMailFolderKey>(); -+ QString nestedAlias(incrementAlias(alias)); -+ -+ q << baseExpression(columnName, a.op, true) << "( SELECT " << qualifiedName("id", nestedAlias) << " FROM mailfolders " << nestedAlias; -+ q << store.buildWhereClause(QMailStorePrivate::Key(parentFolderKey, nestedAlias)) << ")"; -+ } else { -+ q << expression; -+ } -+ break; -+ -+ case QMailMessageKey::AncestorFolderIds: -+ if (a.valueList.first().canConvert<QMailFolderKey>()) { -+ QMailFolderKey folderSubKey = a.valueList.first().value<QMailFolderKey>(); -+ QString nestedAlias(incrementAlias(alias)); -+ -+ q << baseExpression(fieldName(QMailMessageKey::ParentFolderId, alias), a.op, true); -+ q << "( SELECT DISTINCT descendantid FROM mailfolderlinks WHERE id IN ( SELECT " << qualifiedName("id", nestedAlias) << " FROM mailfolders" << nestedAlias; -+ q << store.buildWhereClause(QMailStorePrivate::Key(folderSubKey, nestedAlias)) << ") )"; -+ } else { -+ q << baseExpression(fieldName(QMailMessageKey::ParentFolderId, alias), a.op, true) << "( SELECT DISTINCT descendantid FROM mailfolderlinks WHERE id"; -+ if (a.valueList.count() > 1) { -+ q << " IN " << QMailStorePrivate::expandValueList(a.valueList) << ")"; -+ } else { -+ q << "=? )"; -+ } -+ } -+ break; -+ -+ case QMailMessageKey::ParentAccountId: -+ if(a.valueList.first().canConvert<QMailAccountKey>()) { -+ QMailAccountKey parentAccountKey = a.valueList.first().value<QMailAccountKey>(); -+ QString nestedAlias(incrementAlias(alias)); ++ QString query("SELECT ?mail \n" ++ "WHERE { \n" ++ "?mail rdf:type nmo:Email . \n" ++ "%1" ++ "%2" ++ "} %3\n"); + -+ q << baseExpression(columnName, a.op, true) << "( SELECT " << qualifiedName("id", nestedAlias) << " FROM mailaccounts " << nestedAlias; -+ q << store.buildWhereClause(QMailStorePrivate::Key(parentAccountKey, nestedAlias)) << ")"; -+ } else { -+ q << expression; -+ } -+ break; ++ QString statement = keyStatment("?mail", key, sort); ++ if (!statement.isEmpty()) ++ statement = QString("%1 \n").arg(statement); + -+ case QMailMessageKey::Custom: -+ // Match on custom field -+ { -+ QString nestedAlias(incrementAlias(alias)); ++ QString filter; ++ if (!key.isEmpty()) ++ filter = QString("FILTER %1 \n").arg(keyFilter(key)); + -+ // Is this an existence test or a value test? -+ if ((a.op == QMailKey::Present) || (a.op == QMailKey::Absent)) { -+ q << qualifiedName("id", alias) << operatorString(a.op, true) << "( SELECT " << qualifiedName("id", nestedAlias); -+ q << " FROM mailmessagecustom " << nestedAlias << " WHERE name=? )"; -+ } else { -+ q << qualifiedName("id", alias) << " IN ( SELECT " << qualifiedName("id", nestedAlias); q << " FROM mailmessagecustom " << nestedAlias; -+ q << " WHERE " << qualifiedName("name", nestedAlias) << "=? AND " << qualifiedName("value", nestedAlias) << operatorString(a.op, false) << "? )"; -+ } -+ } -+ break; ++ return query.arg(statement).arg(filter).arg(sortKey(sort)); ++} + -+ case QMailMessageKey::InResponseTo: -+ if (a.valueList.first().canConvert<QMailMessageKey>()) { -+ QMailMessageKey messageKey = a.valueList.first().value<QMailMessageKey>(); -+ QString nestedAlias(incrementAlias(alias)); ++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"); + -+ q << baseExpression(columnName, a.op, true) << "( SELECT " << qualifiedName("id", nestedAlias) << " FROM mailmessages " << nestedAlias; -+ q << store.buildWhereClause(QMailStorePrivate::Key(messageKey, nestedAlias)) << ")"; -+ } else { -+ q << expression; -+ } -+ break; ++ QString statement = keyStatment("?folder", key, sort); ++ if (!statement.isEmpty()) ++ statement = QString("%1 \n").arg(statement); + -+ case QMailMessageKey::Type: -+ case QMailMessageKey::Status: -+ case QMailMessageKey::Sender: -+ case QMailMessageKey::Recipients: -+ case QMailMessageKey::Subject: -+ case QMailMessageKey::TimeStamp: -+ case QMailMessageKey::ReceptionTimeStamp: -+ case QMailMessageKey::ServerUid: -+ case QMailMessageKey::Size: -+ case QMailMessageKey::ContentType: -+ case QMailMessageKey::ContentScheme: -+ case QMailMessageKey::ContentIdentifier: -+ case QMailMessageKey::ResponseType: -+ q << expression; -+ break; ++ QString filter; ++ if (!key.isEmpty()) ++ filter = QString("FILTER %1 \n").arg(keyFilter(key)); + -+ case QMailMessageKey::Conversation: -+ // TODO: Not yet implemented -+ break; -+ } -+ } -+ return item; ++ return query.arg(statement).arg(filter).arg(sortKey(sort)); +} + -+template<> -+QString whereClauseItem<QMailFolderKey>(const QMailFolderKey &, const QMailFolderKey::ArgumentType &a, const QString &alias, const QMailStorePrivate &store) ++QString keyQuery(const QMailAccountKey& key, const QMailAccountSortKey& sort = QMailAccountSortKey()) +{ -+ QString item; -+ { -+ QTextStream q(&item); -+ -+ QString columnName(fieldName(a.property, alias)); -+ -+ bool bitwise(a.property == QMailFolderKey::Status); -+ QString expression = columnExpression(columnName, a.op, a.valueList, false, bitwise); -+ -+ switch (a.property) -+ { -+ case QMailFolderKey::Id: -+ if (a.valueList.first().canConvert<QMailFolderKey>()) { -+ QMailFolderKey subKey = a.valueList.first().value<QMailFolderKey>(); -+ QString nestedAlias(incrementAlias(alias)); ++ QString query("SELECT ?account \n" ++ "WHERE { \n" ++ "?account rdf:type nmo:Mailbox . \n" ++ "%1" ++ "%2" ++ "} %3\n"); + -+ // Expand comparison to sub-query result -+ q << baseExpression(columnName, a.op, true) << "( SELECT " << qualifiedName("id", nestedAlias) << " FROM mailfolders " << nestedAlias; -+ q << store.buildWhereClause(QMailStorePrivate::Key(subKey, nestedAlias)) << ")"; -+ } else { -+ q << expression; -+ } -+ break; ++ QString statement = keyStatment("?account", key, sort); ++ if (!statement.isEmpty()) ++ statement = QString("%1 \n").arg(statement); + -+ case QMailFolderKey::ParentFolderId: -+ if(a.valueList.first().canConvert<QMailFolderKey>()) { -+ QMailFolderKey folderSubKey = a.valueList.first().value<QMailFolderKey>(); -+ QString nestedAlias(incrementAlias(alias)); ++ QString filter; ++ if (!key.isEmpty()) ++ filter = QString("FILTER %1 \n").arg(keyFilter(key)); + -+ q << baseExpression(columnName, a.op, true) << "( SELECT " << qualifiedName("id", nestedAlias) << " FROM mailfolders " << nestedAlias; -+ q << store.buildWhereClause(QMailStorePrivate::Key(folderSubKey, nestedAlias)) << ")"; -+ } else { -+ q << expression; -+ } -+ break; ++ return query.arg(statement).arg(filter).arg(sortKey(sort)); ++} + -+ case QMailFolderKey::AncestorFolderIds: -+ if (a.valueList.first().canConvert<QMailFolderKey>()) { -+ QMailFolderKey folderSubKey = a.valueList.first().value<QMailFolderKey>(); -+ QString nestedAlias(incrementAlias(alias)); ++QString keyCount(const QMailMessageKey& key) ++{ ++ QString query("SELECT COUNT(?mail) AS count \n" ++ "WHERE { \n" ++ "?mail rdf:type nmo:Email . \n" ++ "%1" ++ "%2" ++ "}\n"); + -+ q << baseExpression(fieldName(QMailFolderKey::Id, alias), a.op, true); -+ q << "( SELECT DISTINCT descendantid FROM mailfolderlinks WHERE id IN ( SELECT " << qualifiedName("id", nestedAlias) << " FROM mailfolders" << nestedAlias; -+ q << store.buildWhereClause(QMailStorePrivate::Key(folderSubKey, nestedAlias)) << ") )"; -+ } else { -+ q << baseExpression(fieldName(QMailFolderKey::Id, alias), a.op, true) << "( SELECT DISTINCT descendantid FROM mailfolderlinks WHERE id"; -+ if (a.valueList.count() > 1) { -+ q << " IN " << QMailStorePrivate::expandValueList(a.valueList) << ")"; -+ } else { -+ q << "=? )"; -+ } -+ } -+ break; ++ QString statement = keyStatment("?mail", key, QMailAccountSortKey()); ++ if (!statement.isEmpty()) ++ statement = QString("%1 \n").arg(statement); + -+ case QMailFolderKey::ParentAccountId: -+ if(a.valueList.first().canConvert<QMailAccountKey>()) { -+ QMailAccountKey accountSubKey = a.valueList.first().value<QMailAccountKey>(); -+ QString nestedAlias(incrementAlias(alias)); ++ QString filter; ++ if (!key.isEmpty()) ++ filter = QString("FILTER %1 \n").arg(keyFilter(key)); + -+ q << baseExpression(columnName, a.op, true) << "( SELECT " << qualifiedName("id", nestedAlias) << " FROM mailaccounts " << nestedAlias; -+ q << store.buildWhereClause(QMailStorePrivate::Key(accountSubKey, nestedAlias)) << ")"; -+ } else { -+ q << expression; -+ } -+ break; ++ return query.arg(statement).arg(filter); ++} + -+ case QMailFolderKey::Custom: -+ // Match on custom field -+ { -+ QString nestedAlias(incrementAlias(alias)); ++QString keyCount(const QMailFolderKey& key) ++{ ++ QString query("SELECT COUNT(?folder) AS count \n" ++ "WHERE { \n" ++ "?folder rdf:type nmo:MailFolder . \n" ++ "%1" ++ "%2" ++ "}\n"); + -+ // Is this an existence test or a value test? -+ if ((a.op == QMailKey::Present) || (a.op == QMailKey::Absent)) { -+ q << qualifiedName("id", alias) << operatorString(a.op, true) << "( SELECT " << qualifiedName("id", nestedAlias); -+ q << " FROM mailfoldercustom " << nestedAlias << " WHERE name=? )"; -+ } else { -+ q << qualifiedName("id", alias) << " IN ( SELECT " << qualifiedName("id", nestedAlias); q << " FROM mailfoldercustom " << nestedAlias; -+ q << " WHERE " << qualifiedName("name", nestedAlias) << "=? AND " << qualifiedName("value", nestedAlias) << operatorString(a.op, false) << "? )"; -+ } -+ } -+ break; ++ QString statement = keyStatment("?folder", key, QMailAccountSortKey()); ++ if (!statement.isEmpty()) ++ statement = QString("%1 \n").arg(statement); + -+ case QMailFolderKey::Status: -+ case QMailFolderKey::Path: -+ case QMailFolderKey::DisplayName: -+ case QMailFolderKey::ServerCount: -+ case QMailFolderKey::ServerUnreadCount: ++ QString filter; ++ if (!key.isEmpty()) ++ filter = QString("FILTER %1 \n").arg(keyFilter(key)); + -+ q << expression; -+ break; -+ } -+ } -+ return item; ++ return query.arg(statement).arg(filter); +} + -+template<typename KeyType, typename ArgumentListType, typename KeyListType, typename CombineType> -+QString buildWhereClause(const KeyType &key, -+ const ArgumentListType &args, -+ const KeyListType &subKeys, -+ CombineType combine, -+ bool negated, -+ bool nested, -+ bool firstClause, -+ const QString &alias, -+ const QMailStorePrivate& store) ++QString keyCount(const QMailAccountKey& key) +{ -+ QString whereClause; -+ QString logicalOpString(combineOperatorString(combine)); ++ QString query("SELECT COUNT(?account) AS count \n" ++ "WHERE { \n" ++ "?account rdf:type nmo:Mailbox . \n" ++ "%1" ++ "%2" ++ "}\n"); + -+ if (!key.isEmpty()) { -+ QTextStream s(&whereClause); ++ QString statement = keyStatment("?account", key, QMailAccountSortKey()); ++ if (!statement.isEmpty()) ++ statement = QString("%1 \n").arg(statement); + -+ QString op = " "; -+ foreach (typename ArgumentListType::const_reference a, args) { -+ s << op << whereClauseItem(key, a, alias, store); -+ op = logicalOpString; -+ } ++ QString filter; ++ if (!key.isEmpty()) ++ filter = QString("FILTER %1 \n").arg(keyFilter(key)); + -+ // subkeys -+ s.flush(); -+ if (whereClause.isEmpty()) -+ op = " "; ++ return query.arg(statement).arg(filter); ++} + -+ foreach (typename KeyListType::const_reference subkey, subKeys) { -+ QString nestedWhere(store.buildWhereClause(QMailStorePrivate::Key(subkey, alias), true)); -+ if (!nestedWhere.isEmpty()) -+ s << op << " (" << nestedWhere << ") "; ++template <class Key> ++void debugKey(const Key& key) ++{ ++ typedef typename Key::ArgumentType ArgumentType; + -+ op = logicalOpString; -+ } -+ } ++ qDebug() << "Key Combiner:" << key.combiner(); ++ qDebug() << "Key Is empty:" << key.isEmpty(); ++ qDebug() << "Key Non Matching:" << key.isNonMatching(); ++ qDebug() << "Key Is Negated:" << key.isNegated(); + -+ // Finalise the where clause -+ if (!whereClause.isEmpty()) { -+ if (negated) { -+ whereClause = " NOT (" + whereClause + ")"; -+ } -+ if (!nested) { -+ whereClause.prepend(firstClause ? " WHERE " : " AND "); -+ } ++ 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; + } + -+ return whereClause; -+} -+ -+QPair<QString, qint64> tableInfo(const QString &name, qint64 version) -+{ -+ return qMakePair(name, version); -+} -+ -+QPair<quint64, QString> folderInfo(QMailFolder::StandardFolder id, const QString &name) -+{ -+ return qMakePair(static_cast<quint64>(id), name); ++ foreach (const Key& subkey, key.subKeys()) ++ debugKey(subkey); +} + -+/* SPARQL CODE */ +QString nmoRecipients(const QList<QMailAddress>& recipients) +{ + QString result; @@ -2331,181 +1659,8 @@ index 0000000..029ca4e + return T(); +} + -+QString comparator(QMailKey::Comparator comparator) -+{ -+ static QMap<QMailKey::Comparator, QString> comparatorMap; -+ comparatorMap.insert(QMailKey::LessThan, "<"); -+ comparatorMap.insert(QMailKey::LessThanEqual, "<-"); -+ comparatorMap.insert(QMailKey::GreaterThan, ">"); -+ comparatorMap.insert(QMailKey::GreaterThanEqual, ">="); -+ comparatorMap.insert(QMailKey::Equal, "="); -+ comparatorMap.insert(QMailKey::NotEqual, "!="); -+ comparatorMap.insert(QMailKey::Includes, "IN"); -+ comparatorMap.insert(QMailKey::Excludes, "NOT IN"); -+ comparatorMap.insert(QMailKey::Present, "EXISTS"); -+ comparatorMap.insert(QMailKey::Absent, "NOT EXISTS"); -+ -+ return comparatorMap.value(comparator); -+} -+ -+QString messageConstraint(const QString& variable, const QMailMessageKey& key) -+{ -+ QString constraint; -+ foreach (QMailMessageKey::ArgumentType argument, key.arguments()) -+ { -+ switch (argument.property) -+ { -+ case QMailMessageKey::Id: -+ // Nothing to select -+ break; -+ case QMailMessageKey::Type: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::ParentFolderId: -+ constraint += QString(variable + " nie:isLogicalPartOf <qmf://groove.nokia.com/folder#%1> . \n").arg(argument.valueList.first().value<QMailFolderId>().toULongLong()); -+ break; -+ case QMailMessageKey::Sender: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::Recipients: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::Subject: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::TimeStamp: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::Status: -+ constraint += QString(variable + " nmo:status \"%1\" . \n").arg(argument.valueList.first().toULongLong()); -+ break; -+ case QMailMessageKey::Conversation: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::ReceptionTimeStamp: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::ServerUid: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::Size: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::ParentAccountId: -+ constraint += QString(variable + " nie:relatedTo <qmf://groove.nokia.com/accounts#%1> . \n").arg(argument.valueList.first().value<QMailAccountId>().toULongLong()); -+ break; -+ case QMailMessageKey::AncestorFolderIds: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::ContentType: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::PreviousParentFolderId: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::ContentScheme: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::ContentIdentifier: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::InResponseTo: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::ResponseType: -+ Q_ASSERT(false); -+ break; -+ case QMailMessageKey::Custom: -+ Q_ASSERT(false); -+ break; -+ -+ default: -+ Q_ASSERT(false); -+ } -+ } -+ return " " + constraint; -+} -+ -+QString folderConstraint(const QString& variable, const QMailFolderKey& key) -+{ -+ QString constraint; -+ foreach (QMailFolderKey::ArgumentType argument, key.arguments()) -+ { -+ switch (argument.property) -+ { -+ case QMailFolderKey::Id: -+ // Nothing to select -+ break; -+ case QMailFolderKey::Path: -+ constraint += QString(variable + " nmo:folderName \"%1\" . \n").arg(argument.valueList.first().toString()); -+ break; -+ case QMailFolderKey::ParentFolderId: -+ constraint += QString(variable + " nie:isLogicalPartOf <qmf://groove.nokia.com/folder#%1> . \n").arg(argument.valueList.first().value<QMailFolderId>().toULongLong()); -+ break; -+ case QMailFolderKey::ParentAccountId: -+ constraint += QString(variable + " nie:relatedTo <qmf://groove.nokia.com/accounts#%1> . \n").arg(argument.valueList.first().value<QMailAccountId>().toULongLong()); -+ break; -+ case QMailFolderKey::DisplayName: -+ constraint += QString(variable + " nmo:folderDisplayName \"%1\" . \n").arg(argument.valueList.first().toULongLong()); -+ break; -+ case QMailFolderKey::Status: -+ constraint += QString(variable + " nmo:status : \"%1\" . \n").arg(argument.valueList.first().toULongLong()); -+ break; -+ case QMailFolderKey::AncestorFolderIds: -+ Q_ASSERT(false); -+ break; -+ case QMailFolderKey::ServerCount: -+ constraint += QString(variable + " nmo:serverCount \"%1\" . \n").arg(argument.valueList.first().toULongLong()); -+ break; -+ case QMailFolderKey::ServerUnreadCount: -+ constraint += QString(variable + " nmo:serverUnreadCount \"%1\" . \n").arg(argument.valueList.first().toULongLong()); -+ break; -+ case QMailFolderKey::Custom: -+ Q_ASSERT(false); -+ break; -+ default: -+ Q_ASSERT(false); -+ } -+ } -+ return " " + constraint; -+} -+ -+QString accountConstraint(const QString& variable, const QMailAccountKey& key) -+{ -+ QString constraint; -+ foreach (QMailAccountKey::ArgumentType argument, key.arguments()) -+ { -+ switch (argument.property) -+ { -+ case QMailAccountKey::Id: -+ // Nothing to select -+ break; -+ case QMailAccountKey::Name: -+ constraint += QString(variable + " nmo:accountName \"%1\" . \n").arg(argument.valueList.first().toString()); -+ break; -+ case QMailAccountKey::MessageType: -+ constraint += QString(variable + " nmo:fromAddress [ nco:emailAddress \"%1\" ] . \n").arg(argument.valueList.first().toString()); -+ break; -+ case QMailAccountKey::FromAddress: -+ Q_ASSERT(false); -+ break; -+ case QMailAccountKey::Status: -+ constraint += QString(variable + " nmo:status \"%1\"^^xsd:integer . \n").arg(argument.valueList.first().toULongLong()); -+ break; -+ case QMailAccountKey::Custom: -+ Q_ASSERT(false); -+ break; -+ default: -+ Q_ASSERT(false); -+ } -+ } -+ return " " + constraint; -+} -+ -+ +} // namespace + -+ +// We need to support recursive locking, per-process +static volatile int mutexLockCount = 0; +static volatile int readLockCount = 0; @@ -2526,7 +1681,7 @@ index 0000000..029ca4e +}; + +QMailStorePrivate::Transaction::Transaction(QMailStorePrivate* d) -+ : m_d(d), ++ : m_d(d), + m_initted(false), + m_committed(false) +{ @@ -2539,10 +1694,8 @@ index 0000000..029ca4e + if (m_d->databaseMutex().lock(10000)) { + // Wait for any readers to complete + if (m_d->databaseReadLock().wait(10000)) { -+ if (m_d->transaction()) { + ++mutexLockCount; + m_initted = true; -+ } + } else { + qWarning() << "Unable to wait for database read lock to reach zero!"; + } @@ -2559,7 +1712,6 @@ index 0000000..029ca4e +QMailStorePrivate::Transaction::~Transaction() +{ + if (m_initted && !m_committed) { -+ m_d->rollback(); + + --mutexLockCount; + if (mutexLockCount == 0) @@ -2570,11 +1722,12 @@ index 0000000..029ca4e +bool QMailStorePrivate::Transaction::commit() +{ + if (m_initted && !m_committed) { -+ if ((m_committed = m_d->commit())) { -+ --mutexLockCount; -+ if (mutexLockCount == 0) -+ m_d->databaseMutex().unlock(); -+ } ++ // TBD: Pretend that we've ++ // commited that already. ++ m_committed = true; ++ --mutexLockCount; ++ if (mutexLockCount == 0) ++ m_d->databaseMutex().unlock(); + } + + return m_committed; @@ -2585,7 +1738,6 @@ index 0000000..029ca4e + return m_committed; +} + -+ +class QMailStorePrivate::ReadLock +{ + QMailStorePrivate *m_d; @@ -2629,7 +1781,6 @@ index 0000000..029ca4e + } +} + -+ +template<typename FunctionType> +QMailStorePrivate::AttemptResult evaluate(QMailStorePrivate::WriteAccess, FunctionType func, const QString& description, QMailStorePrivate* d) +{ @@ -2653,7 +1804,6 @@ index 0000000..029ca4e + return func(l); +} + -+ +QMailStore::ErrorCode errorType(QMailStorePrivate::ReadAccess) +{ + return QMailStore::InvalidId; @@ -2664,6 +1814,32 @@ index 0000000..029ca4e + 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() +{ @@ -2693,13 +1869,13 @@ index 0000000..029ca4e + return p; +} + -+const QMailStorePrivate::MessagePropertyMap& QMailStorePrivate::messagePropertyMap() ++const QMailStorePrivate::MessagePropertyMap& QMailStorePrivate::messagePropertyMap() +{ + static const MessagePropertyMap map(::messagePropertyMap()); + return map; +} + -+const QMailStorePrivate::MessagePropertyList& QMailStorePrivate::messagePropertyList() ++const QMailStorePrivate::MessagePropertyList& QMailStorePrivate::messagePropertyList() +{ + static const MessagePropertyList list(messagePropertyMap().keys()); + return list; @@ -2718,7 +1894,9 @@ index 0000000..029ca4e + +int QMailStorePrivate::databaseIdentifier(int n) const +{ -+ int result = static_cast<int>(::ftok(database.databaseName().toAscii(), n)); ++ // 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; @@ -2739,10 +1917,6 @@ index 0000000..029ca4e + qDebug() << "QMailStorePrivate::QMailStorePrivate"; + ProcessMutex creationMutex(pathIdentifier(QDir::rootPath())); + MutexGuard guard(creationMutex); -+ if (guard.lock(1000)) { -+ //open the database -+ database = QMail::createDatabase(); -+ } + mutex = new ProcessMutex(databaseIdentifier(1)); + readLock = new ProcessReadLock(databaseIdentifier(2)); + if (contentMutex == 0) { @@ -2779,50 +1953,22 @@ index 0000000..029ca4e + return init; + } + -+ if (database.isOpenError()) { ++ if (sparqlDatabase.isOpenError()) { + qMailLog(Messaging) << "Unable to open database in initStore!"; + return false; + } + -+ { -+ Transaction t(this); -+ -+ if (!ensureVersionInfo() || -+ !setupTables(QList<TableInfo>() << tableInfo("mailaccounts", 106) -+ << tableInfo("mailaccountcustom", 100) -+ << tableInfo("mailaccountconfig", 100) -+ << tableInfo("mailaccountfolders", 100) -+ << tableInfo("mailfolders", 102) -+ << tableInfo("mailfoldercustom", 100) -+ << tableInfo("mailfolderlinks", 100) -+ << tableInfo("mailmessages", 105) -+ << tableInfo("mailmessagecustom", 100) -+ << tableInfo("mailstatusflags", 101) -+ << tableInfo("deletedmessages", 101)) || -+ !setupFolders(QList<FolderInfo>() << folderInfo(QMailFolder::InboxFolder, tr("Inbox")) -+ << folderInfo(QMailFolder::OutboxFolder, tr("Outbox")) -+ << folderInfo(QMailFolder::DraftsFolder, tr("Drafts")) -+ << folderInfo(QMailFolder::SentFolder, tr("Sent")) -+ << folderInfo(QMailFolder::TrashFolder, tr("Trash")))) { -+ return false; -+ } -+ -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit setup operation to database"; ++ 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 defined(Q_USE_SQLITE) -+ // default sqlite cache_size of 2000*1.5KB is too large, as we only want -+ // to cache 100 metadata records -+ QSqlQuery query( database ); -+ query.exec(QLatin1String("PRAGMA cache_size=50")); -+#endif + + if (!QMailContentManagerFactory::init()) { + qMailLog(Messaging) << "Could not initialize content manager factory"; @@ -2841,1037 +1987,127 @@ index 0000000..029ca4e + folderCache.clear(); + headerCache.clear(); + -+ // Drop all data -+ foreach (const QString &table, database.tables()) { -+ if (table != "versioninfo") { -+ QString sql("DELETE FROM %1"); -+ QSqlQuery query(database); -+ if (!query.exec(sql.arg(table))) { -+ qMailLog(Messaging) << "Failed to delete from table - query:" << sql << "- error:" << query.lastError().text(); -+ } -+ } -+ } ++ // TBD: Drop all data + + // Remove all content + QMailContentManagerFactory::clearContent(); +} + -+bool QMailStorePrivate::transaction(void) -+{ -+ if (inTransaction) { -+ qMailLog(Messaging) << "(" << ::getpid() << ")" << "Transaction already exists at begin!"; -+ qWarning() << "Transaction already exists at begin!"; -+ } -+ -+ clearQueryError(); -+ -+ // Ensure any outstanding temp tables are removed before we begin this transaction -+ destroyTemporaryTables(); -+ -+ if (!database.transaction()) { -+ setQueryError(database.lastError(), "Failed to initiate transaction"); -+ return false; -+ } -+ -+ inTransaction = true; -+ return true; -+} -+ -+static QString queryText(const QString &query, const QList<QVariant> &values) -+{ -+ static const QChar marker('?'); -+ static const QChar quote('\''); -+ -+ QString result(query); -+ -+ QList<QVariant>::const_iterator it = values.begin(), end = values.end(); -+ int index = result.indexOf(marker); -+ while ((index != -1) && (it != end)) { -+ QString substitute((*it).toString()); -+ if ((*it).type() == QVariant::String) -+ substitute.prepend(quote).append(quote); -+ -+ result.replace(index, 1, substitute); -+ -+ ++it; -+ index = result.indexOf(marker, index + substitute.length()); -+ } -+ -+ return result; -+} -+ -+static QString queryText(const QSqlQuery &query) -+{ -+ // Note: we currently only handle positional parameters -+ return queryText(query.lastQuery().simplified(), query.boundValues().values()); -+} -+ -+QSqlQuery QMailStorePrivate::prepare(const QString& sql) -+{ -+ if (!inTransaction) { -+ // Ensure any outstanding temp tables are removed before we begin this query -+ destroyTemporaryTables(); -+ } -+ -+ clearQueryError(); -+ -+ QSqlQuery query(database); -+ -+ // Create any temporary tables needed for this query -+ while (!requiredTableKeys.isEmpty()) { -+ const QMailMessageKey *key = requiredTableKeys.takeFirst(); -+ if (!temporaryTableKeys.contains(key)) { -+ QString tableName = temporaryTableName(*key); -+ -+ bool ok = true; -+ QSqlQuery tableQuery(database); -+ if (!tableQuery.exec(QString("CREATE TEMP TABLE %1 ( id INTEGER PRIMARY KEY )").arg(tableName))) { -+ ok = false; -+ } else { -+ temporaryTableKeys.append(key); -+ -+ // Add the ID values to the temp table -+ foreach (const QVariant &var, key->arguments().first().valueList) { -+ quint64 id = 0; -+ -+ if (qVariantCanConvert<QMailMessageId>(var)) { -+ id = var.value<QMailMessageId>().toULongLong(); -+ } else if (qVariantCanConvert<QMailFolderId>(var)) { -+ id = var.value<QMailFolderId>().toULongLong(); -+ } else if (qVariantCanConvert<QMailAccountId>(var)) { -+ id = var.value<QMailAccountId>().toULongLong(); -+ } -+ -+ if (id != 0) { -+ tableQuery = QSqlQuery(database); -+ if (!tableQuery.exec(QString("INSERT INTO %1 VALUES (%2)").arg(tableName).arg(id))) { -+ ok = false; -+ break; -+ } -+ } else { -+ qMailLog(Messaging) << "Unable to extract ID value from valuelist!"; -+ ok = false; -+ break; -+ } -+ } -+ } -+ -+ if (!ok) { -+ setQueryError(tableQuery.lastError(), "Failed to create temporary table", queryText(tableQuery)); -+ qMailLog(Messaging) << "Unable to prepare query:" << sql; -+ return query; -+ } -+ } -+ } -+ -+ if (!query.prepare(sql)) { -+ setQueryError(query.lastError(), "Failed to prepare query", queryText(query)); -+ } -+ -+ // TODO: setForwardOnly? -+ return query; -+} -+ -+bool QMailStorePrivate::execute(QSqlQuery& query, bool batch) -+{ -+ bool success = (batch ? query.execBatch() : query.exec()); -+ if (!success) { -+ setQueryError(query.lastError(), "Failed to execute query", queryText(query)); -+ return false; -+ } -+ -+#ifdef QMAILSTORE_LOG_SQL -+ qMailLog(Messaging) << "(" << ::getpid() << ")" << qPrintable(queryText(query)); -+#endif -+ -+ if (!inTransaction) { -+ // We should be finished with these temporary tables -+ expiredTableKeys = temporaryTableKeys; -+ temporaryTableKeys.clear(); -+ } -+ -+ return true; -+} -+ -+bool QMailStorePrivate::commit(void) -+{ -+ if (!inTransaction) { -+ qMailLog(Messaging) << "(" << ::getpid() << ")" << "Transaction does not exist at commit!"; -+ qWarning() << "Transaction does not exist at commit!"; -+ } -+ -+ if (!database.commit()) { -+ setQueryError(database.lastError(), "Failed to commit transaction"); -+ return false; -+ } else { -+ inTransaction = false; -+ -+ // Expire any temporary tables we were using -+ expiredTableKeys = temporaryTableKeys; -+ temporaryTableKeys.clear(); -+ } -+ -+ return true; -+} -+ -+void QMailStorePrivate::rollback(void) -+{ -+ if (!inTransaction) { -+ qMailLog(Messaging) << "(" << ::getpid() << ")" << "Transaction does not exist at rollback!"; -+ qWarning() << "Transaction does not exist at rollback!"; -+ } -+ -+ inTransaction = false; -+ -+ if (!database.rollback()) { -+ setQueryError(database.lastError(), "Failed to rollback transaction"); -+ } -+} -+ -+int QMailStorePrivate::queryError() const -+{ -+ return lastQueryError; -+} -+ -+void QMailStorePrivate::setQueryError(const QSqlError &error, const QString &description, const QString &statement) ++void QMailStorePrivate::setQueryError(const SparqlQuery& query, const QString &description) +{ + QString s; + QTextStream ts(&s); + -+ lastQueryError = error.number(); -+ -+ ts << qPrintable(description) << "; error:\"" << error.text() << '"'; -+ if (!statement.isEmpty()) -+ ts << "; statement:\"" << statement.simplified() << '"'; ++ lastQueryError = query.error(); + ++ ts << qPrintable(description) << "; error:\"" << query.query() << '"'; + qMailLog(Messaging) << "(" << ::getpid() << ")" << qPrintable(s); + qWarning() << qPrintable(s); +} + -+void QMailStorePrivate::clearQueryError(void) -+{ -+ lastQueryError = 0; -+} -+ -+template<bool PtrSizeExceedsLongSize> -+QString numericPtrValue(const void *ptr) -+{ -+ return QString::number(reinterpret_cast<unsigned long long>(ptr), 16).rightJustified(16, '0'); -+} -+ -+template<> -+QString numericPtrValue<false>(const void *ptr) -+{ -+ return QString::number(reinterpret_cast<unsigned long>(ptr), 16).rightJustified(8, '0');; -+} -+ -+QString QMailStorePrivate::temporaryTableName(const QMailMessageKey& key) -+{ -+ const QMailMessageKey *ptr = &key; -+ return QString("qtopiamail_idmatch_%1").arg(numericPtrValue<(sizeof(void*) > sizeof(unsigned long))>(ptr)); -+} -+ -+void QMailStorePrivate::createTemporaryTable(const QMailMessageKey& key) const -+{ -+ requiredTableKeys.append(&key); -+} -+ -+void QMailStorePrivate::destroyTemporaryTables() -+{ -+ while (!expiredTableKeys.isEmpty()) { -+ const QMailMessageKey *key = expiredTableKeys.takeFirst(); -+ QString tableName = temporaryTableName(*key); -+ -+ QSqlQuery query(database); -+ if (!query.exec(QString("DROP TABLE %1").arg(tableName))) { -+ QString sql = queryText(query); -+ QString err = query.lastError().text(); -+ -+ qMailLog(Messaging) << "(" << ::getpid() << ")" << "Failed to drop temporary table - query:" << qPrintable(sql) << "; error:" << qPrintable(err); -+ qWarning() << "Failed to drop temporary table - query:" << qPrintable(sql) << "; error:" << qPrintable(err); -+ } -+ } -+} -+ -+bool QMailStorePrivate::idValueExists(quint64 id, const QString& table) -+{ -+ QSqlQuery query(database); -+ QString sql = "SELECT id FROM " + table + " WHERE id=?"; -+ if(!query.prepare(sql)) { -+ setQueryError(query.lastError(), "Failed to prepare idExists query", queryText(query)); -+ return false; -+ } -+ -+ query.addBindValue(id); -+ -+ if(!query.exec()) { -+ setQueryError(query.lastError(), "Failed to execute idExists query", queryText(query)); -+ return false; -+ } -+ -+ return (query.first()); -+} -+ -+bool QMailStorePrivate::idExists(const QMailAccountId& id, const QString& table) -+{ -+ return idValueExists(id.toULongLong(), (table.isEmpty() ? "mailaccounts" : table)); -+} -+ -+bool QMailStorePrivate::idExists(const QMailFolderId& id, const QString& table) -+{ -+ return idValueExists(id.toULongLong(), (table.isEmpty() ? "mailfolders" : table)); -+} -+ -+bool QMailStorePrivate::idExists(const QMailMessageId& id, const QString& table) -+{ -+ return idValueExists(id.toULongLong(), (table.isEmpty() ? "mailmessages" : table)); -+} -+ -+QMailAccount QMailStorePrivate::extractAccount(const QSqlRecord& r) -+{ -+ const AccountRecord record(r); -+ -+ QMailAccount result; -+ result.setId(record.id()); -+ result.setName(record.name()); -+ result.setMessageType(record.messageType()); -+ result.setStatus(record.status()); -+ result.setSignature(record.signature()); -+ result.setFromAddress(QMailAddress(record.fromAddress())); -+ -+ return result; -+} -+ -+QMailFolder QMailStorePrivate::extractFolder(const QSqlRecord& r) -+{ -+ const FolderRecord record(r); -+ -+ QMailFolder result(record.path(), record.parentFolderId(), record.parentAccountId()); -+ result.setId(record.id()); -+ result.setDisplayName(record.displayName()); -+ result.setStatus(record.status()); -+ result.setServerCount(record.serverCount()); -+ result.setServerUnreadCount(record.serverUnreadCount()); -+ return result; -+} -+ -+void QMailStorePrivate::extractMessageMetaData(const QSqlRecord& r, -+ QMailMessageKey::Properties recordProperties, -+ const QMailMessageKey::Properties& properties, -+ QMailMessageMetaData* metaData) -+{ -+ // Record whether we have loaded all data for this message -+ bool unloadedProperties = (properties != allMessageProperties()); -+ if (!unloadedProperties) { -+ // If there is message content, mark the object as not completely loaded -+ if (!r.value("mailfile").toString().isEmpty()) -+ unloadedProperties = true; -+ } -+ -+ // Use wrapper to extract data items -+ const MessageRecord messageRecord(r, recordProperties); -+ -+ foreach (QMailMessageKey::Property p, messagePropertyList()) { -+ switch (properties & p) -+ { -+ case QMailMessageKey::Id: -+ metaData->setId(messageRecord.id()); -+ break; -+ -+ case QMailMessageKey::Type: -+ metaData->setMessageType(messageRecord.messageType()); -+ break; -+ -+ case QMailMessageKey::ParentFolderId: -+ metaData->setParentFolderId(messageRecord.parentFolderId()); -+ break; -+ -+ case QMailMessageKey::Sender: -+ metaData->setFrom(messageRecord.from()); -+ break; -+ -+ case QMailMessageKey::Recipients: -+ metaData->setTo(messageRecord.to()); -+ break; -+ -+ case QMailMessageKey::Subject: -+ metaData->setSubject(messageRecord.subject()); -+ break; -+ -+ case QMailMessageKey::TimeStamp: -+ metaData->setDate(messageRecord.date()); -+ break; -+ -+ case QMailMessageKey::ReceptionTimeStamp: -+ metaData->setReceivedDate(messageRecord.receivedDate()); -+ break; -+ -+ case QMailMessageKey::Status: -+ metaData->setStatus(messageRecord.status()); -+ break; -+ -+ case QMailMessageKey::ParentAccountId: -+ metaData->setParentAccountId(messageRecord.parentAccountId()); -+ break; -+ -+ case QMailMessageKey::ServerUid: -+ metaData->setServerUid(messageRecord.serverUid()); -+ break; -+ -+ case QMailMessageKey::Size: -+ metaData->setSize(messageRecord.size()); -+ break; -+ -+ case QMailMessageKey::ContentType: -+ metaData->setContent(messageRecord.content()); -+ break; -+ -+ case QMailMessageKey::PreviousParentFolderId: -+ metaData->setPreviousParentFolderId(messageRecord.previousParentFolderId()); -+ break; -+ -+ case QMailMessageKey::ContentScheme: -+ metaData->setContentScheme(messageRecord.contentScheme()); -+ break; -+ -+ case QMailMessageKey::ContentIdentifier: -+ metaData->setContentIdentifier(messageRecord.contentIdentifier()); -+ break; -+ -+ case QMailMessageKey::InResponseTo: -+ metaData->setInResponseTo(messageRecord.inResponseTo()); -+ break; -+ -+ case QMailMessageKey::ResponseType: -+ metaData->setResponseType(messageRecord.responseType()); -+ break; -+ } -+ } -+ -+ if (unloadedProperties) { -+ // This message is not completely loaded -+ metaData->setStatus(QMailMessage::UnloadedData, true); -+ } -+ -+ metaData->setUnmodified(); -+} -+ -+QMailMessageMetaData QMailStorePrivate::extractMessageMetaData(const QSqlRecord& r, QMailMessageKey::Properties recordProperties, const QMailMessageKey::Properties& properties) -+{ -+ QMailMessageMetaData metaData; -+ -+ extractMessageMetaData(r, recordProperties, properties, &metaData); -+ return metaData; -+} -+ -+QMailMessage QMailStorePrivate::extractMessage(const QSqlRecord& r, const QMap<QString, QString> &customFields, const QMailMessageKey::Properties& properties) -+{ -+ QMailMessage newMessage; -+ -+ // Load the meta data items (note 'SELECT *' does not give the same result as 'SELECT expand(allMessageProperties())') -+ extractMessageMetaData(r, QMailMessageKey::Properties(0), properties, &newMessage); -+ newMessage.setUnmodified(); -+ -+ newMessage.setCustomFields(customFields); -+ newMessage.setCustomFieldsModified(false); -+ -+ QString contentUri(r.value("mailfile").toString()); -+ if (!contentUri.isEmpty()) { -+ QPair<QString, QString> elements(::uriElements(contentUri)); -+ -+ MutexGuard lock(contentManagerMutex()); -+ if (!lock.lock(1000)) { -+ qMailLog(Messaging) << "Unable to acquire message body mutex in extractMessage!"; -+ return QMailMessage(); -+ } -+ -+ QMailContentManager *contentManager = QMailContentManagerFactory::create(elements.first); -+ if (contentManager) { -+ // Load the message content (manager should be able to access the metadata also) -+ QMailStore::ErrorCode code = contentManager->load(elements.second, &newMessage); -+ if (code != QMailStore::NoError) { -+ setLastError(code); -+ qMailLog(Messaging) << "Unable to load message content:" << contentUri; -+ return QMailMessage(); -+ } -+ } else { -+ qMailLog(Messaging) << "Unable to create content manager for scheme:" << elements.first; -+ return QMailMessage(); -+ } -+ -+ // Re-load the meta data items so that they take precedence over the loaded content -+ extractMessageMetaData(r, QMailMessageKey::Properties(0), properties, &newMessage); -+ newMessage.setUnmodified(); -+ -+ newMessage.setCustomFields(customFields); -+ newMessage.setCustomFieldsModified(false); -+ } -+ -+ return newMessage; -+} -+ -+QMailMessageRemovalRecord QMailStorePrivate::extractMessageRemovalRecord(const QSqlRecord& r) -+{ -+ const MessageRemovalRecord record(r); -+ -+ QMailMessageRemovalRecord result(record.parentAccountId(), record.serverUid(), record.parentFolderId()); -+ return result; -+} -+ -+QString QMailStorePrivate::buildOrderClause(const Key& key) const -+{ -+ if (key.isType<QMailMessageSortKey>()) { -+ const QMailMessageSortKey &sortKey(key.key<QMailMessageSortKey>()); -+ return ::buildOrderClause(sortKey.arguments(), key.alias()); -+ } else if (key.isType<QMailFolderSortKey>()) { -+ const QMailFolderSortKey &sortKey(key.key<QMailFolderSortKey>()); -+ return ::buildOrderClause(sortKey.arguments(), key.alias()); -+ } else if (key.isType<QMailAccountSortKey>()) { -+ const QMailAccountSortKey &sortKey(key.key<QMailAccountSortKey>()); -+ return ::buildOrderClause(sortKey.arguments(), key.alias()); -+ } -+ -+ return QString(); -+} -+ -+QString QMailStorePrivate::buildWhereClause(const Key& key, bool nested, bool firstClause) const ++QString QMailStorePrivate::queryError() const +{ -+ if (key.isType<QMailMessageKey>()) { -+ const QMailMessageKey &messageKey(key.key<QMailMessageKey>()); -+ -+ // See if we need to create any temporary tables to use in this query -+ foreach (const QMailMessageKey::ArgumentType &a, messageKey.arguments()) { -+ if (a.property == QMailMessageKey::Id && a.valueList.count() >= IdLookupThreshold) { -+ createTemporaryTable(messageKey); -+ } -+ } -+ -+ return ::buildWhereClause(messageKey, messageKey.arguments(), messageKey.subKeys(), messageKey.combiner(), messageKey.isNegated(), nested, firstClause, key.alias(), *this); -+ } else if (key.isType<QMailFolderKey>()) { -+ const QMailFolderKey &folderKey(key.key<QMailFolderKey>()); -+ return ::buildWhereClause(folderKey, folderKey.arguments(), folderKey.subKeys(), folderKey.combiner(), folderKey.isNegated(), nested, firstClause, key.alias(), *this); -+ } else if (key.isType<QMailAccountKey>()) { -+ const QMailAccountKey &accountKey(key.key<QMailAccountKey>()); -+ return ::buildWhereClause(accountKey, accountKey.arguments(), accountKey.subKeys(), accountKey.combiner(), accountKey.isNegated(), nested, firstClause, key.alias(), *this); -+ } -+ -+ return QString(); ++ return lastQueryError; +} + -+QVariantList QMailStorePrivate::whereClauseValues(const Key& key) const ++void QMailStorePrivate::clearQueryError(void) +{ -+ if (key.isType<QMailMessageKey>()) { -+ const QMailMessageKey &messageKey(key.key<QMailMessageKey>()); -+ return ::whereClauseValues(messageKey); -+ } else if (key.isType<QMailFolderKey>()) { -+ const QMailFolderKey &folderKey(key.key<QMailFolderKey>()); -+ return ::whereClauseValues(folderKey); -+ } else if (key.isType<QMailAccountKey>()) { -+ const QMailAccountKey &accountKey(key.key<QMailAccountKey>()); -+ return ::whereClauseValues(accountKey); -+ } -+ -+ return QVariantList(); ++ lastQueryError.clear(); +} + -+bool QMailStorePrivate::containsProperty(const QMailMessageKey::Property& p, -+ const QMailMessageKey& key) const ++bool QMailStorePrivate::uriExists(const QString& uri) +{ -+ foreach(const QMailMessageKey::ArgumentType &a, key.arguments()) -+ if(a.property == p) -+ return true; -+ -+ foreach(const QMailMessageKey &k, key.subKeys()) -+ if(containsProperty(p,k)) -+ return true; -+ ++ // TBD: Check whether value exists already ++ Q_UNUSED(uri); + return false; +} + -+bool QMailStorePrivate::containsProperty(const QMailMessageSortKey::Property& p, -+ const QMailMessageSortKey& key) const -+{ -+ foreach(const QMailMessageSortKey::ArgumentType &a, key.arguments()) -+ if(a.first == p) -+ return true; -+ -+ return false; -+} -+ -+QVariantList QMailStorePrivate::messageValues(const QMailMessageKey::Properties& prop, const QMailMessageMetaData& data) -+{ -+ QVariantList values; -+ -+ const MessageValueExtractor<QMailMessageMetaData> extractor(data); -+ -+ // The ContentScheme and ContentIdentifier properties map to the same field -+ QMailMessageKey::Properties properties(prop); -+ if ((properties & QMailMessageKey::ContentScheme) && (properties & QMailMessageKey::ContentIdentifier)) -+ properties &= ~QMailMessageKey::ContentIdentifier; -+ -+ foreach (QMailMessageKey::Property p, messagePropertyList()) { -+ switch (properties & p) -+ { -+ case QMailMessageKey::Id: -+ values.append(extractor.id()); -+ break; -+ -+ case QMailMessageKey::Type: -+ values.append(extractor.messageType()); -+ break; -+ -+ case QMailMessageKey::ParentFolderId: -+ values.append(extractor.parentFolderId()); -+ break; -+ -+ case QMailMessageKey::Sender: -+ values.append(extractor.from()); -+ break; -+ -+ case QMailMessageKey::Recipients: -+ values.append(extractor.to()); -+ break; -+ -+ case QMailMessageKey::Subject: -+ values.append(extractor.subject()); -+ break; -+ -+ case QMailMessageKey::TimeStamp: -+ values.append(extractor.date()); -+ break; -+ -+ case QMailMessageKey::ReceptionTimeStamp: -+ values.append(extractor.receivedDate()); -+ break; -+ -+ case QMailMessageKey::Status: -+ values.append(extractor.status()); -+ break; -+ -+ case QMailMessageKey::ParentAccountId: -+ values.append(extractor.parentAccountId()); -+ break; -+ -+ case QMailMessageKey::ServerUid: -+ values.append(extractor.serverUid()); -+ break; -+ -+ case QMailMessageKey::Size: -+ values.append(extractor.size()); -+ break; -+ -+ case QMailMessageKey::ContentType: -+ values.append(extractor.content()); -+ break; -+ -+ case QMailMessageKey::PreviousParentFolderId: -+ values.append(extractor.previousParentFolderId()); -+ break; -+ -+ case QMailMessageKey::ContentScheme: -+ case QMailMessageKey::ContentIdentifier: -+ // For either of these (there can be only one) we want to produce the entire URI -+ values.append(::contentUri(extractor.contentScheme().toString(), extractor.contentIdentifier().toString())); -+ break; -+ -+ case QMailMessageKey::InResponseTo: -+ values.append(extractor.inResponseTo()); -+ break; -+ -+ case QMailMessageKey::ResponseType: -+ values.append(extractor.responseType()); -+ break; -+ } -+ } -+ -+ return values; -+} -+ -+void QMailStorePrivate::updateMessageValues(const QMailMessageKey::Properties& properties, const QVariantList& values, const QMap<QString, QString>& customFields, QMailMessageMetaData& metaData) -+{ -+ QPair<QString, QString> uriElements; -+ QVariantList::const_iterator it = values.constBegin(); -+ -+ foreach (QMailMessageKey::Property p, messagePropertyList()) { -+ const MessageValueExtractor<QVariant> extractor(*it); -+ bool valueConsumed(true); -+ -+ switch (properties & p) -+ { -+ case QMailMessageKey::Id: -+ metaData.setId(extractor.id()); -+ break; -+ -+ case QMailMessageKey::Type: -+ metaData.setMessageType(extractor.messageType()); -+ break; -+ -+ case QMailMessageKey::ParentFolderId: -+ metaData.setParentFolderId(extractor.parentFolderId()); -+ break; -+ -+ case QMailMessageKey::Sender: -+ metaData.setFrom(extractor.from()); -+ break; -+ -+ case QMailMessageKey::Recipients: -+ metaData.setTo(extractor.to()); -+ break; -+ -+ case QMailMessageKey::Subject: -+ metaData.setSubject(extractor.subject()); -+ break; -+ -+ case QMailMessageKey::TimeStamp: -+ metaData.setDate(extractor.date()); -+ break; -+ -+ case QMailMessageKey::ReceptionTimeStamp: -+ metaData.setReceivedDate(extractor.receivedDate()); -+ break; -+ -+ case QMailMessageKey::Status: -+ metaData.setStatus(extractor.status()); -+ break; -+ -+ case QMailMessageKey::ParentAccountId: -+ metaData.setParentAccountId(extractor.parentAccountId()); -+ break; -+ -+ case QMailMessageKey::ServerUid: -+ metaData.setServerUid(extractor.serverUid()); -+ break; -+ -+ case QMailMessageKey::Size: -+ metaData.setSize(extractor.size()); -+ break; -+ -+ case QMailMessageKey::ContentType: -+ metaData.setContent(extractor.content()); -+ break; -+ -+ case QMailMessageKey::PreviousParentFolderId: -+ metaData.setPreviousParentFolderId(extractor.previousParentFolderId()); -+ break; -+ -+ case QMailMessageKey::ContentScheme: -+ if (uriElements.first.isEmpty()) { -+ uriElements = ::uriElements(extractor.contentUri()); -+ } else { -+ valueConsumed = false; -+ } -+ metaData.setContentScheme(uriElements.first); -+ break; -+ -+ case QMailMessageKey::ContentIdentifier: -+ if (uriElements.first.isEmpty()) { -+ uriElements = ::uriElements(extractor.contentUri()); -+ } else { -+ valueConsumed = false; -+ } -+ metaData.setContentIdentifier(uriElements.second); -+ break; -+ -+ case QMailMessageKey::InResponseTo: -+ metaData.setInResponseTo(extractor.inResponseTo()); -+ break; -+ -+ case QMailMessageKey::ResponseType: -+ metaData.setResponseType(extractor.responseType()); -+ break; -+ -+ case QMailMessageKey::Custom: -+ metaData.setCustomFields(customFields); -+ break; -+ -+ default: -+ valueConsumed = false; -+ break; -+ } -+ -+ if (valueConsumed) -+ ++it; -+ } -+ -+ if (it != values.constEnd()) -+ qWarning() << QString("updateMessageValues: %1 values not consumed!").arg(values.constEnd() - it); -+ -+ // The target message is not completely loaded -+ metaData.setStatus(QMailMessage::UnloadedData, true); -+} -+ -+bool QMailStorePrivate::executeFile(QFile &file) -+{ -+ bool result(true); -+ -+ // read assuming utf8 encoding. -+ QTextStream ts(&file); -+ ts.setCodec(QTextCodec::codecForName("utf8")); -+ ts.setAutoDetectUnicode(true); -+ -+ QString sql = parseSql(ts); -+ while (result && !sql.isEmpty()) { -+ QSqlQuery query(database); -+ if (!query.exec(sql)) { -+ qMailLog(Messaging) << "Failed to exec table creation SQL query:" << sql << "- error:" << query.lastError().text(); -+ result = false; -+ } -+ sql = parseSql(ts); -+ } -+ -+ return result; -+} -+ -+bool QMailStorePrivate::ensureVersionInfo() -+{ -+ if (!database.tables().contains("versioninfo", Qt::CaseInsensitive)) { -+ // Use the same version scheme as dbmigrate, in case we need to cooperate later -+ QString sql("CREATE TABLE versioninfo (" -+ " tableName NVARCHAR (255) NOT NULL," -+ " versionNum INTEGER NOT NULL," -+ " lastUpdated NVARCHAR(20) NOT NULL," -+ " PRIMARY KEY(tableName, versionNum))"); -+ -+ QSqlQuery query(database); -+ if (!query.exec(sql)) { -+ qMailLog(Messaging) << "Failed to create versioninfo table - query:" << sql << "- error:" << query.lastError().text(); -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+qint64 QMailStorePrivate::tableVersion(const QString &name) const ++bool QMailStorePrivate::setupStandardFolder(enum QMailFolder::StandardFolder folder, const QString& name) +{ -+ QString sql("SELECT COALESCE(MAX(versionNum), 0) FROM versioninfo WHERE tableName=?"); -+ -+ QSqlQuery query(database); -+ query.prepare(sql); -+ query.addBindValue(name); -+ if (query.exec() && query.first()) -+ return query.value(0).value<qint64>(); -+ -+ qMailLog(Messaging) << "Failed to query versioninfo - query:" << sql << "- error:" << query.lastError().text(); -+ return 0; -+} ++ MailFolderUri folderUri(QMailFolderId((int)folder)); ++ MailFolderUri parentFolderUri(QMailFolderId(0)); ++ MailAccountUri parentAccountUri(QMailAccountId(0)); + -+bool QMailStorePrivate::setTableVersion(const QString &name, qint64 version) -+{ -+ QString sql("DELETE FROM versioninfo WHERE tableName=? AND versionNum=?"); ++ 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)); + -+ // Delete any existing entry for this table -+ QSqlQuery query(database); -+ query.prepare(sql); -+ query.addBindValue(name); -+ query.addBindValue(version); ++ // TBD: Add custom fields later + -+ if (!query.exec()) { -+ qMailLog(Messaging) << "Failed to delete versioninfo - query:" << sql << "- error:" << query.lastError().text(); ++ if (!query.exec()) ++ { ++ qDebug() << "Query failed:" << query.error(); + return false; -+ } else { -+ sql = "INSERT INTO versioninfo (tablename,versionNum,lastUpdated) VALUES (?,?,?)"; -+ -+ // Insert the updated info -+ query = QSqlQuery(database); -+ query.prepare(sql); -+ query.addBindValue(name); -+ query.addBindValue(version); -+ query.addBindValue(QDateTime::currentDateTime().toString()); -+ -+ if (!query.exec()) { -+ qMailLog(Messaging) << "Failed to insert versioninfo - query:" << sql << "- error:" << query.lastError().text(); -+ return false; -+ } + } + -+ return true; -+} -+ -+qint64 QMailStorePrivate::incrementTableVersion(const QString &name, qint64 current) -+{ -+ qint64 next = current + 1; -+ -+ QString versionInfo("-" + QString::number(current) + "-" + QString::number(next)); -+ QString scriptName(":/QtopiaSql/" + database.driverName() + "/" + name + versionInfo); -+ -+ QFile data(scriptName); -+ if (!data.open(QIODevice::ReadOnly)) { -+ qMailLog(Messaging) << "Failed to load table upgrade resource:" << name; -+ } else { -+ if (executeFile(data)) { -+ // Update the table version number -+ if (setTableVersion(name, next)) -+ current = next; -+ } -+ } -+ -+ return current; -+} -+ -+bool QMailStorePrivate::upgradeTableVersion(const QString &name, qint64 current, qint64 final) -+{ -+ while (current < final) { -+ int newVersion = incrementTableVersion(name, current); -+ if (newVersion == current) { -+ qMailLog(Messaging) << "Failed to increment table version from:" << current << "(" << name << ")"; -+ break; -+ } else { -+ current = newVersion; -+ } -+ } -+ -+ return (current == final); -+} -+ -+bool QMailStorePrivate::createTable(const QString &name) -+{ -+ bool result = true; -+ -+ // load schema. -+ QFile data(":/QtopiaSql/" + database.driverName() + "/" + name); -+ if (!data.open(QIODevice::ReadOnly)) { -+ qMailLog(Messaging) << "Failed to load table schema resource:" << name; -+ result = false; -+ } else { -+ result = executeFile(data); -+ } -+ -+ return result; -+} -+ -+bool QMailStorePrivate::setupTables(const QList<TableInfo> &tableList) -+{ -+ bool result = true; -+ -+ QStringList tables = database.tables(); -+ -+ foreach (const TableInfo &table, tableList) { -+ const QString &tableName(table.first); -+ qint64 version(table.second); ++ qDebug() << "Query succeeded"; + -+ if (!tables.contains(tableName, Qt::CaseInsensitive)) { -+ // Create the table -+ result &= (createTable(tableName) && setTableVersion(tableName, version)); -+ } else { -+ // Ensure the table does not have an incompatible version -+ qint64 dbVersion = tableVersion(tableName); -+ if (dbVersion == 0) { -+ qWarning() << "No version for existing table:" << tableName; -+ result = false; -+ } else if (dbVersion != version) { -+ if (version > dbVersion) { -+ // Try upgrading the table -+ result = upgradeTableVersion(tableName, dbVersion, version); -+ qMailLog(Messaging) << (result ? "Upgraded" : "Unable to upgrade") << "version for table:" << tableName << " from" << dbVersion << "to" << version; -+ } else { -+ qWarning() << "Incompatible version for table:" << tableName << "- existing" << dbVersion << "!=" << version; -+ result = false; -+ } -+ } -+ } -+ } -+ -+ return result; ++ // TBD: Update folder links also ++ return true; +} + -+bool QMailStorePrivate::setupFolders(const QList<FolderInfo> &folderList) ++QMailAccount QMailStorePrivate::extractAccount(const QMailAccountId& id, const QStringList& list) +{ -+ QSet<quint64> folderIds; -+ -+ { -+ QSqlQuery query(simpleQuery("SELECT id FROM mailfolders", -+ "folder ids query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ -+ while (query.next()) -+ folderIds.insert(query.value(0).toULongLong()); -+ } -+ -+ foreach (const FolderInfo &folder, folderList) { -+ if (folderIds.contains(folder.first)) -+ continue; -+ QSqlQuery query(simpleQuery("INSERT INTO mailfolders (id,name,parentid,parentaccountid,displayname,status,servercount,serverunreadcount) VALUES (?,?,?,?,?,?,?,?)", -+ QVariantList() << folder.first -+ << folder.second -+ << quint64(0) -+ << quint64(0) -+ << QString() -+ << quint64(0) -+ << int(0) -+ << int(0), -+ "setupFolders insert query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } ++ QMailAccount account; + -+ return true; -+} ++ // 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))); + -+QString QMailStorePrivate::parseSql(QTextStream& ts) -+{ -+ QString qry = ""; -+ while(!ts.atEnd()) -+ { -+ QString line = ts.readLine(); -+ // comment, remove. -+ if (line.contains(QLatin1String("--"))) -+ line.truncate (line.indexOf (QLatin1String("--"))); -+ if (line.trimmed ().length () == 0) -+ continue; -+ qry += line; -+ -+ if ( line.contains( ';' ) == false) -+ qry += QLatin1String(" "); -+ else -+ return qry; -+ } -+ return qry; ++ return account; +} + -+QString QMailStorePrivate::expandValueList(const QVariantList& valueList) ++QMailFolder QMailStorePrivate::extractFolder(const QMailFolderId& id, const QStringList& list) +{ -+ Q_ASSERT(!valueList.isEmpty()); -+ return expandValueList(valueList.count()); -+} ++ // Load folder data ++ QMailFolder folder(list.at(0), IdFromUri<QMailFolderId>(list.at(1)), IdFromUri<QMailAccountId>(list.at(2))); + -+QString QMailStorePrivate::expandValueList(int valueCount) -+{ -+ Q_ASSERT(valueCount > 0); ++ 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()); + -+ if (valueCount == 1) { -+ return "(?)"; -+ } else { -+ QString inList = " (?"; -+ for (int i = 1; i < valueCount; ++i) -+ inList += ",?"; -+ inList += ")"; -+ return inList; -+ } ++ return folder; +} + -+QString QMailStorePrivate::expandProperties(const QMailMessageKey::Properties& prop, bool update) const ++void QMailStorePrivate::extractMessageMetaData(const QStringList& list, QMailMessageMetaData* metaData) +{ -+ QString out; ++ // Load message properties + -+ // The ContentScheme and ContentIdentifier properties map to the same field -+ QMailMessageKey::Properties properties(prop); -+ if ((properties & QMailMessageKey::ContentScheme) && (properties & QMailMessageKey::ContentIdentifier)) -+ properties &= ~QMailMessageKey::ContentIdentifier; ++ 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))); + -+ const QMailStorePrivate::MessagePropertyMap &map(messagePropertyMap()); -+ foreach (QMailMessageKey::Property p, messagePropertyList()) { -+ if (properties & p) { -+ if (!out.isEmpty()) -+ out += ","; -+ out += map.value(p); -+ if (update) -+ out += "=?"; -+ } -+ } -+ -+ return out; ++ metaData->setUnmodified(); +} + +bool QMailStorePrivate::addAccount(QMailAccount *account, QMailAccountConfiguration *config, @@ -4196,7 +2432,7 @@ index 0000000..029ca4e +{ + QMailMessageMetaDataList metaData; + repeatedly<ReadAccess>(bind(&QMailStorePrivate::attemptMessagesMetaData, const_cast<QMailStorePrivate*>(this), -+ cref(key), cref(properties), option, &metaData), ++ cref(key), cref(properties), option, &metaData), + "messagesMetaData"); + return metaData; +} @@ -4375,7 +2611,7 @@ index 0000000..029ca4e + return false; + } else { + // result == DatabaseFailure -+ if (queryError() == Sqlite3BusyErrorNumber) { ++ if (queryError() == "Sqlite3BusyErrorNumber") { + if (attemptCount < MaxAttempts) { + qMailLog(Messaging) << ::getpid() << "Failed to" << qPrintable(description) << "- busy, pausing to retry"; + @@ -4389,7 +2625,7 @@ index 0000000..029ca4e + qMailLog(Messaging) << ::getpid() << "Retry count exceeded - failed to" << qPrintable(description); + break; + } -+ } else if (queryError() == Sqlite3ConstraintErrorNumber) { ++ } else if (queryError() == "Sqlite3ConstraintErrorNumber") { + qMailLog(Messaging) << ::getpid() << "Unable to" << qPrintable(description) << "- constraint failure"; + setLastError(QMailStore::ConstraintFailure); + break; @@ -4407,7 +2643,7 @@ index 0000000..029ca4e + return false; +} + -+QMailStorePrivate::AttemptResult QMailStorePrivate::addCustomFields(quint64 id, const QMap<QString, QString> &fields, const QString &tableName) ++QMailStorePrivate::AttemptResult QMailStorePrivate::addCustomFields(quint64 id, const QMap<QString, QString> &fields) +{ + if (!fields.isEmpty()) { + QVariantList customFields; @@ -4419,35 +2655,21 @@ index 0000000..029ca4e + customFields.append(QVariant(it.key())); + customValues.append(QVariant(it.value())); + } -+ -+ // Batch insert the custom fields -+ QString sql("INSERT INTO %1 (id,name,value) VALUES (%2,?,?)"); -+ QSqlQuery query(batchQuery(sql.arg(tableName).arg(QString::number(id)), -+ QVariantList() << QVariant(customFields) -+ << QVariant(customValues), -+ QString("%1 custom field insert query").arg(tableName))); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; ++ // TBD: Add custom fields ++ Q_UNUSED(id); + } + + return Success; +} + -+QMailStorePrivate::AttemptResult QMailStorePrivate::updateCustomFields(quint64 id, const QMap<QString, QString> &fields, const QString &tableName) ++QMailStorePrivate::AttemptResult QMailStorePrivate::updateCustomFields(quint64 id, const QMap<QString, QString> &fields) +{ + QMap<QString, QString> existing; + + { + // Find the existing fields -+ QString sql("SELECT name,value FROM %1 WHERE id=?"); -+ QSqlQuery query(simpleQuery(sql.arg(tableName), -+ QVariantList() << id, -+ QString("%1 update custom select query").arg(tableName))); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ existing.insert(query.value(0).toString(), query.value(1).toString()); ++ // TBD: Put actual code here ++ Q_UNUSED(id); + } + + QVariantList obsoleteFields; @@ -4476,338 +2698,30 @@ index 0000000..029ca4e + } + } + -+ if (!obsoleteFields.isEmpty()) { -+ // Remove the obsolete fields -+ QString sql("DELETE FROM %1 WHERE id=? AND name IN %2"); -+ QSqlQuery query(simpleQuery(sql.arg(tableName).arg(expandValueList(obsoleteFields)), -+ QVariantList() << id << obsoleteFields, -+ QString("%1 update custom delete query").arg(tableName))); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ if (!modifiedFields.isEmpty()) { -+ // Batch update the modified fields -+ QString sql("UPDATE %1 SET value=? WHERE id=%2 AND name=?"); -+ QSqlQuery query(batchQuery(sql.arg(tableName).arg(QString::number(id)), -+ QVariantList() << QVariant(modifiedValues) -+ << QVariant(modifiedFields), -+ QString("%1 update custom update query").arg(tableName))); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ if (!addedFields.isEmpty()) { -+ // Batch insert the added fields -+ QString sql("INSERT INTO %1 (id,name,value) VALUES (%2,?,?)"); -+ QSqlQuery query(batchQuery(sql.arg(tableName).arg(QString::number(id)), -+ QVariantList() << QVariant(addedFields) -+ << QVariant(addedValues), -+ QString("%1 update custom insert query").arg(tableName))); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ return Success; -+} -+ -+QMailStorePrivate::AttemptResult QMailStorePrivate::customFields(quint64 id, QMap<QString, QString> *fields, const QString &tableName) -+{ -+ QString sql("SELECT name,value FROM %1 WHERE id=?"); -+ QSqlQuery query(simpleQuery(sql.arg(tableName), -+ QVariantList() << id, -+ QString("%1 custom field query").arg(tableName))); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ fields->insert(query.value(0).toString(), query.value(1).toString()); -+ ++ // TBD: Update custom fields + return Success; +} + -+/* Replaced with SPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptAddAccount(QMailAccount *account, QMailAccountConfiguration* config, -+ QMailAccountIdList *addedAccountIds, -+ Transaction &t) ++QMailStorePrivate::AttemptResult QMailStorePrivate::customFields(quint64 id, QMap<QString, QString> *fields) +{ -+ if (account->id().isValid() && idExists(account->id())) { -+ qMailLog(Messaging) << "Account already exists in database, use update instead"; -+ return Failure; -+ } -+ -+ QMailAccountId insertId; -+ -+ { -+ QString properties("type,name,status,signature,emailaddress"); -+ QString values("?,?,?,?,?"); -+ QVariantList propertyValues; -+ propertyValues << static_cast<int>(account->messageType()) -+ << account->name() -+ << account->status() -+ << account->signature() -+ << account->fromAddress().toString(true); -+ -+ { -+ QSqlQuery query(simpleQuery(QString("INSERT INTO mailaccounts (%1) VALUES (%2)").arg(properties).arg(values), -+ propertyValues, -+ "addAccount mailaccounts query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ //Extract the insert id -+ insertId = QMailAccountId(extractValue<quint64>(query.lastInsertId())); -+ } ++ // TBD: Load information about custom fields ++ Q_UNUSED(id); ++ Q_UNUSED(fields); + -+ // Insert any standard folders configured for this account -+ const QMap<QMailFolder::StandardFolder, QMailFolderId> &folders(account->standardFolders()); -+ if (!folders.isEmpty()) { -+ QVariantList types; -+ QVariantList folderIds; -+ -+ QMap<QMailFolder::StandardFolder, QMailFolderId>::const_iterator it = folders.begin(), end = folders.end(); -+ for ( ; it != end; ++it) { -+ types.append(QVariant(static_cast<int>(it.key()))); -+ folderIds.append(QVariant(it.value().toULongLong())); -+ } -+ -+ // Batch insert the folders -+ QString sql("INSERT into mailaccountfolders (id,foldertype,folderid) VALUES (%1,?,?)"); -+ QSqlQuery query(batchQuery(sql.arg(QString::number(insertId.toULongLong())), -+ QVariantList() << QVariant(types) -+ << QVariant(folderIds), -+ "addAccount mailaccountfolders query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ // Insert any custom fields belonging to this account -+ AttemptResult result = addCustomFields(insertId.toULongLong(), account->customFields(), "mailaccountcustom"); -+ if (result != Success) -+ return result; -+ } -+ -+ if (config) { -+ foreach (const QString &service, config->services()) { -+ QMailAccountConfiguration::ServiceConfiguration &serviceConfig(config->serviceConfiguration(service)); -+ const QMap<QString, QString> &fields = serviceConfig.values(); -+ -+ QVariantList configFields; -+ QVariantList configValues; -+ -+ // Insert any configuration fields belonging to this account -+ QMap<QString, QString>::const_iterator it = fields.begin(), end = fields.end(); -+ for ( ; it != end; ++it) { -+ configFields.append(QVariant(it.key())); -+ configValues.append(QVariant(it.value())); -+ } -+ -+ // Batch insert the custom fields -+ QString sql("INSERT INTO mailaccountconfig (id,service,name,value) VALUES (%1,'%2',?,?)"); -+ QSqlQuery query(batchQuery(sql.arg(QString::number(insertId.toULongLong())).arg(service), -+ QVariantList() << QVariant(configFields) -+ << QVariant(configValues), -+ "addAccount mailaccountconfig query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ config->setId(insertId); -+ } -+ -+ account->setId(insertId); -+ -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit account changes to database"; -+ -+ account->setId(QMailAccountId()); //revert the id -+ return DatabaseFailure; -+ } -+ -+ addedAccountIds->append(insertId); + return Success; +} -+*/ -+/* Replaced with SQPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptAddFolder(QMailFolder *folder, -+ QMailFolderIdList *addedFolderIds, QMailAccountIdList *modifiedAccountIds, -+ Transaction &t) -+{ -+ //check that the parent folder actually exists -+ if (!checkPreconditions(*folder)) -+ return Failure; -+ -+ QMailFolderId insertId; + -+ { -+ { -+ QSqlQuery query(simpleQuery("INSERT INTO mailfolders (name,parentid,parentaccountid,displayname,status,servercount,serverunreadcount) VALUES (?,?,?,?,?,?,?)", -+ QVariantList() << folder->path() -+ << folder->parentFolderId().toULongLong() -+ << folder->parentAccountId().toULongLong() -+ << folder->displayName() -+ << folder->status() -+ << folder->serverCount() -+ << folder->serverUnreadCount(), -+ "addFolder mailfolders query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ // Extract the inserted id -+ insertId = QMailFolderId(extractValue<quint64>(query.lastInsertId())); -+ } -+ -+ // Insert any custom fields belonging to this folder -+ AttemptResult result = addCustomFields(insertId.toULongLong(), folder->customFields(), "mailfoldercustom"); -+ if (result != Success) -+ return result; -+ } -+ -+ folder->setId(insertId); -+ -+ //create links to ancestor folders -+ if (folder->parentFolderId().isValid()) { -+ { -+ //add records for each ancestor folder -+ QSqlQuery query(simpleQuery("INSERT INTO mailfolderlinks " -+ "SELECT DISTINCT id,? FROM mailfolderlinks WHERE descendantid=?", -+ QVariantList() << folder->id().toULongLong() -+ << folder->parentFolderId().toULongLong(), -+ "mailfolderlinks insert ancestors")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ { -+ // Our direct parent is also an ancestor -+ QSqlQuery query(simpleQuery("INSERT INTO mailfolderlinks VALUES (?,?)", -+ QVariantList() << folder->parentFolderId().toULongLong() -+ << folder->id().toULongLong(), -+ "mailfolderlinks insert parent")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ } -+ -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit folder changes to database"; -+ -+ folder->setId(QMailFolderId()); //revert the id -+ return DatabaseFailure; -+ } -+ -+ addedFolderIds->append(insertId); -+ if (folder->parentAccountId().isValid()) -+ modifiedAccountIds->append(folder->parentAccountId()); -+ return Success; -+} -+*/ -+ -+/* Replaced with SQPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptAddMessage(QMailMessageMetaData *metaData, -+ QMailMessageIdList *addedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds, -+ Transaction &t) -+{ -+ if (!metaData->parentFolderId().isValid()) { -+ qMailLog(Messaging) << "Unable to add message. Invalid parent folder id"; -+ return Failure; -+ } -+ -+ if (metaData->id().isValid() && idExists(metaData->id())) { -+ qMailLog(Messaging) << "Message ID" << metaData->id() << "already exists in database, use update instead"; -+ return Failure; -+ } -+ -+ // Ensure that any phone numbers are added in minimal form -+ QMailAddress from(metaData->from()); -+ QString fromText(from.isPhoneNumber() ? from.minimalPhoneNumber() : from.toString()); -+ -+ QStringList recipients; -+ foreach (const QMailAddress& address, metaData->to()) -+ recipients.append(address.isPhoneNumber() ? address.minimalPhoneNumber() : address.toString()); -+ -+ QMailMessageId insertId; -+ -+ { -+ // Add the record to the mailmessages table -+ QSqlQuery query(simpleQuery("INSERT INTO mailmessages (type," -+ "parentfolderid," -+ "sender," -+ "recipients," -+ "subject," -+ "stamp," -+ "status," -+ "parentaccountid," -+ "mailfile," -+ "serveruid," -+ "size," -+ "contenttype," -+ "responseid," -+ "responsetype," -+ "receivedstamp" -+ ") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", -+ QVariantList() << static_cast<int>(metaData->messageType()) -+ << metaData->parentFolderId().toULongLong() -+ << fromText -+ << recipients.join(",") -+ << metaData->subject() -+ << QMailTimeStamp(metaData->date()).toLocalTime() -+ << static_cast<int>(metaData->status()) -+ << metaData->parentAccountId().toULongLong() -+ << ::contentUri(*metaData) -+ << metaData->serverUid() -+ << metaData->size() -+ << static_cast<int>(metaData->content()) -+ << metaData->inResponseTo().toULongLong() -+ << metaData->responseType() -+ << QMailTimeStamp(metaData->receivedDate()).toLocalTime(), -+ "addMessage mailmessages query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ //retrieve the insert id -+ insertId = QMailMessageId(extractValue<quint64>(query.lastInsertId())); -+ } -+ -+ // Insert any custom fields belonging to this message -+ AttemptResult result = addCustomFields(insertId.toULongLong(), metaData->customFields(), "mailmessagecustom"); -+ if (result != Success) -+ return result; -+ -+ // Find the complete set of modified folders, including ancestor folders -+ QMailFolderIdList folderIds; -+ folderIds.append(metaData->parentFolderId()); -+ folderIds += folderAncestorIds(folderIds, true, &result); -+ if (result != Success) -+ return result; -+ -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit message changes to database"; -+ return DatabaseFailure; -+ } -+ -+ metaData->setId(insertId); -+ addedMessageIds->append(insertId); -+ *modifiedFolderIds = folderIds; -+ if (metaData->parentAccountId().isValid()) -+ modifiedAccountIds->append(metaData->parentAccountId()); -+ return Success; -+} -+*/ + +QMailStorePrivate::AttemptResult QMailStorePrivate::attemptRemoveAccounts(const QMailAccountKey &key, + QMailAccountIdList *deletedAccounts, QMailFolderIdList *deletedFolders, QMailMessageIdList *deletedMessages, + Transaction &t) +{ -+ QStringList expiredContent; -+ -+ if (deleteAccounts(key, *deletedAccounts, *deletedFolders, *deletedMessages, expiredContent)) { -+ if (t.commit()) { -+ //remove deleted objects from caches -+ removeExpiredData(*deletedMessages, expiredContent, *deletedFolders, *deletedAccounts); -+ return Success; -+ } -+ } ++ // TBD: Delete accounts ++ Q_UNUSED(key); ++ Q_UNUSED(deletedAccounts); ++ Q_UNUSED(deletedFolders); ++ Q_UNUSED(deletedMessages); ++ Q_UNUSED(t); + + return DatabaseFailure; +} @@ -4816,15 +2730,13 @@ index 0000000..029ca4e + QMailFolderIdList *deletedFolders, QMailMessageIdList *deletedMessages, QMailAccountIdList *modifiedAccounts, + Transaction &t) +{ -+ QStringList expiredContent; -+ -+ if (deleteFolders(key, option, *deletedFolders, *deletedMessages, expiredContent, *modifiedAccounts)) { -+ if (t.commit()) { -+ //remove deleted objects from caches -+ removeExpiredData(*deletedMessages, expiredContent, *deletedFolders); -+ return Success; -+ } -+ } ++ // TBD: Remove folders ++ Q_UNUSED(key); ++ Q_UNUSED(option); ++ Q_UNUSED(deletedFolders); ++ Q_UNUSED(deletedMessages); ++ Q_UNUSED(modifiedAccounts); ++ Q_UNUSED(t); + + return DatabaseFailure; +} @@ -4833,15 +2745,13 @@ index 0000000..029ca4e + QMailMessageIdList *deletedMessages, QMailAccountIdList *modifiedAccounts, QMailFolderIdList *modifiedFolders, + Transaction &t) +{ -+ QStringList expiredContent; -+ -+ if (deleteMessages(key, option, *deletedMessages, expiredContent, *modifiedAccounts, *modifiedFolders)) { -+ if (t.commit()) { -+ //remove deleted objects from caches -+ removeExpiredData(*deletedMessages, expiredContent); -+ return Success; -+ } -+ } ++ // TBD: Remove messages ++ Q_UNUSED(key); ++ Q_UNUSED(option); ++ Q_UNUSED(deletedMessages); ++ Q_UNUSED(modifiedAccounts); ++ Q_UNUSED(modifiedFolders); ++ Q_UNUSED(t); + + return DatabaseFailure; +} @@ -4850,221 +2760,13 @@ index 0000000..029ca4e + QMailAccountIdList *updatedAccountIds, + Transaction &t) +{ ++ Q_UNUSED(t); ++ + QMailAccountId id(account ? account->id() : config ? config->id() : QMailAccountId()); + if (!id.isValid()) + return Failure; + + if (account) { -+ QString properties("type=?, name=?, status=?, signature=?, emailaddress=?"); -+ QVariantList propertyValues; -+ propertyValues << static_cast<int>(account->messageType()) -+ << account->name() -+ << account->status() -+ << account->signature() -+ << account->fromAddress().toString(true); -+ -+ { -+ QSqlQuery query(simpleQuery(QString("UPDATE mailaccounts SET %1 WHERE id=?").arg(properties), -+ propertyValues << id.toULongLong(), -+ "updateAccount mailaccounts query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ // Update any standard folders configured -+ const QMap<QMailFolder::StandardFolder, QMailFolderId> &folders(account->standardFolders()); -+ QMap<QMailFolder::StandardFolder, QMailFolderId> existingFolders; -+ -+ { -+ // Find the existing folders -+ QSqlQuery query(simpleQuery("SELECT foldertype,folderid FROM mailaccountfolders WHERE id=?", -+ QVariantList() << id.toULongLong(), -+ "updateAccount mailaccountfolders select query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ existingFolders.insert(QMailFolder::StandardFolder(query.value(0).toInt()), QMailFolderId(query.value(1).toULongLong())); -+ } -+ -+ QVariantList obsoleteTypes; -+ QVariantList modifiedTypes; -+ QVariantList modifiedFolders; -+ QVariantList addedTypes; -+ QVariantList addedFolders; -+ -+ // Compare the sets -+ QMap<QMailFolder::StandardFolder, QMailFolderId>::const_iterator fend = folders.end(), eend = existingFolders.end(); -+ QMap<QMailFolder::StandardFolder, QMailFolderId>::const_iterator it = existingFolders.begin(); -+ for ( ; it != eend; ++it) { -+ QMap<QMailFolder::StandardFolder, QMailFolderId>::const_iterator current = folders.find(it.key()); -+ if (current == fend) { -+ obsoleteTypes.append(QVariant(static_cast<int>(it.key()))); -+ } else if (*current != *it) { -+ modifiedTypes.append(QVariant(static_cast<int>(current.key()))); -+ modifiedFolders.append(QVariant(current.value().toULongLong())); -+ } -+ } -+ -+ for (it = folders.begin(); it != fend; ++it) { -+ if (existingFolders.find(it.key()) == eend) { -+ addedTypes.append(QVariant(static_cast<int>(it.key()))); -+ addedFolders.append(QVariant(it.value().toULongLong())); -+ } -+ } -+ -+ if (!obsoleteTypes.isEmpty()) { -+ // Remove the obsolete folders -+ QString sql("DELETE FROM mailaccountfolders WHERE id=? AND foldertype IN %2"); -+ QSqlQuery query(simpleQuery(sql.arg(expandValueList(obsoleteTypes)), -+ QVariantList() << id.toULongLong() << obsoleteTypes, -+ "updateAccount mailaccountfolders delete query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ if (!modifiedTypes.isEmpty()) { -+ // Batch update the modified folders -+ QString sql("UPDATE mailaccountfolders SET folderid=? WHERE id=%2 AND foldertype=?"); -+ QSqlQuery query(batchQuery(sql.arg(QString::number(id.toULongLong())), -+ QVariantList() << QVariant(modifiedFolders) -+ << QVariant(modifiedTypes), -+ "updateAccount mailaccountfolders update query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ if (!addedTypes.isEmpty()) { -+ // Batch insert the added fields -+ QString sql("INSERT INTO mailaccountfolders (id,foldertype,folderid) VALUES (%2,?,?)"); -+ QSqlQuery query(batchQuery(sql.arg(QString::number(id.toULongLong())), -+ QVariantList() << QVariant(addedTypes) -+ << QVariant(addedFolders), -+ "updateAccount mailaccountfolders insert query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ if (account->customFieldsModified()) { -+ AttemptResult result = updateCustomFields(id.toULongLong(), account->customFields(), "mailaccountcustom"); -+ if (result != Success) -+ return result; -+ } -+ } -+ -+ if (config) { -+ // Find the complete set of configuration fields -+ QMap<QPair<QString, QString>, QString> fields; -+ -+ foreach (const QString &service, config->services()) { -+ QMailAccountConfiguration::ServiceConfiguration &serviceConfig(config->serviceConfiguration(service)); -+ const QMap<QString, QString> &values = serviceConfig.values(); -+ -+ // Insert any configuration fields belonging to this account -+ QMap<QString, QString>::const_iterator it = values.begin(), end = values.end(); -+ for ( ; it != end; ++it) -+ fields.insert(qMakePair(service, it.key()), it.value()); -+ } -+ -+ // Find the existing fields in the database -+ QMap<QPair<QString, QString>, QString> existing; -+ -+ { -+ QSqlQuery query(simpleQuery("SELECT service,name,value FROM mailaccountconfig WHERE id=?", -+ QVariantList() << id.toULongLong(), -+ "updateAccount mailaccountconfig select query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ existing.insert(qMakePair(query.value(0).toString(), query.value(1).toString()), query.value(2).toString()); -+ } -+ -+ QMap<QString, QVariantList> obsoleteFields; -+ QMap<QString, QVariantList> modifiedFields; -+ QMap<QString, QVariantList> modifiedValues; -+ QMap<QString, QVariantList> addedFields; -+ QMap<QString, QVariantList> addedValues; -+ -+ // Compare the sets -+ QMap<QPair<QString, QString>, QString>::const_iterator fend = fields.end(), eend = existing.end(); -+ QMap<QPair<QString, QString>, QString>::const_iterator it = existing.begin(); -+ for ( ; it != eend; ++it) { -+ const QPair<QString, QString> &name = it.key(); -+ QMap<QPair<QString, QString>, QString>::const_iterator current = fields.find(name); -+ if (current == fend) { -+ obsoleteFields[name.first].append(QVariant(name.second)); -+ } else if (*current != *it) { -+ modifiedFields[name.first].append(QVariant(name.second)); -+ modifiedValues[name.first].append(QVariant(current.value())); -+ } -+ } -+ -+ for (it = fields.begin(); it != fend; ++it) { -+ const QPair<QString, QString> &name = it.key(); -+ if (existing.find(name) == eend) { -+ addedFields[name.first].append(QVariant(name.second)); -+ addedValues[name.first].append(QVariant(it.value())); -+ } -+ } -+ -+ if (!obsoleteFields.isEmpty()) { -+ // Remove the obsolete fields -+ QMap<QString, QVariantList>::const_iterator it = obsoleteFields.begin(), end = obsoleteFields.end(); -+ for ( ; it != end; ++it) { -+ const QString &service = it.key(); -+ const QVariantList &fields = it.value(); -+ -+ QString sql("DELETE FROM mailaccountconfig WHERE id=? AND service='%1' AND name IN %2"); -+ QSqlQuery query(simpleQuery(sql.arg(service).arg(expandValueList(fields)), -+ QVariantList() << id.toULongLong() << fields, -+ "updateAccount mailaccountconfig delete query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ } -+ -+ if (!modifiedFields.isEmpty()) { -+ // Batch update the modified fields -+ QMap<QString, QVariantList>::const_iterator it = modifiedFields.begin(), end = modifiedFields.end(); -+ for (QMap<QString, QVariantList>::const_iterator vit = modifiedValues.begin(); it != end; ++it, ++vit) { -+ const QString &service = it.key(); -+ const QVariantList &fields = it.value(); -+ const QVariantList &values = vit.value(); -+ -+ QString sql("UPDATE mailaccountconfig SET value=? WHERE id=%1 AND service='%2' AND name=?"); -+ QSqlQuery query(batchQuery(sql.arg(QString::number(id.toULongLong())).arg(service), -+ QVariantList() << QVariant(values) << QVariant(fields), -+ "updateAccount mailaccountconfig update query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ } -+ -+ if (!addedFields.isEmpty()) { -+ // Batch insert the added fields -+ QMap<QString, QVariantList>::const_iterator it = addedFields.begin(), end = addedFields.end(); -+ for (QMap<QString, QVariantList>::const_iterator vit = addedValues.begin(); it != end; ++it, ++vit) { -+ const QString &service = it.key(); -+ const QVariantList &fields = it.value(); -+ const QVariantList &values = vit.value(); -+ -+ QString sql("INSERT INTO mailaccountconfig (id,service,name,value) VALUES (%1,'%2',?,?)"); -+ QSqlQuery query(batchQuery(sql.arg(QString::number(id.toULongLong())).arg(service), -+ QVariantList() << QVariant(fields) << QVariant(values), -+ "updateAccount mailaccountconfig insert query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ } -+ } -+ -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit account update to database"; -+ return DatabaseFailure; -+ } -+ -+ if (account) { + // Update the account cache + if (accountCache.contains(id)) + accountCache.insert(*account); @@ -5085,82 +2787,9 @@ index 0000000..029ca4e + QMailFolderId parentFolderId; + QMailAccountId parentAccountId; + -+ { -+ //find the current parent folder -+ QSqlQuery query(simpleQuery("SELECT parentid, parentaccountid FROM mailfolders WHERE id=?", -+ QVariantList() << folder->id().toULongLong(), -+ "mailfolder parent query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ if (query.first()) { -+ parentFolderId = QMailFolderId(extractValue<quint64>(query.value(0))); -+ parentAccountId = QMailAccountId(extractValue<quint64>(query.value(1))); -+ } -+ } -+ -+ { -+ QSqlQuery query(simpleQuery("UPDATE mailfolders SET name=?,parentid=?,parentaccountid=?,displayname=?,status=?,servercount=?,serverunreadcount=? WHERE id=?", -+ QVariantList() << folder->path() -+ << folder->parentFolderId().toULongLong() -+ << folder->parentAccountId().toULongLong() -+ << folder->displayName() -+ << folder->status() -+ << folder->serverCount() -+ << folder->serverUnreadCount() -+ << folder->id().toULongLong(), -+ "updateFolder mailfolders query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ if (folder->customFieldsModified()) { -+ AttemptResult result = updateCustomFields(folder->id().toULongLong(), folder->customFields(), "mailfoldercustom"); -+ if (result != Success) -+ return result; -+ } -+ -+ if (parentFolderId != folder->parentFolderId()) { -+ // QMailAccount contains a copy of the folder data; we need to tell it to reload -+ if (parentFolderId.isValid()) -+ modifiedAccountIds->append(parentAccountId); -+ if (folder->parentFolderId().isValid() && !modifiedAccountIds->contains(folder->parentAccountId())) -+ modifiedAccountIds->append(folder->parentAccountId()); -+ -+ { -+ //remove existing links to this folder -+ QSqlQuery query(simpleQuery("DELETE FROM mailfolderlinks WHERE descendantid = ?", -+ QVariantList() << folder->id().toULongLong(), -+ "mailfolderlinks delete in update")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ { -+ //add links to the new parent -+ QSqlQuery query(simpleQuery("INSERT INTO mailfolderlinks " -+ "SELECT DISTINCT id,? FROM mailfolderlinks WHERE descendantid=?", -+ QVariantList() << folder->id().toULongLong() -+ << folder->parentFolderId().toULongLong(), -+ "mailfolderlinks insert ancestors")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ { -+ QSqlQuery query(simpleQuery("INSERT INTO mailfolderlinks VALUES (?,?)", -+ QVariantList() << folder->parentFolderId().toULongLong() -+ << folder->id().toULongLong(), -+ "mailfolderlinks insert parent")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ } -+ -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit folder update to database"; -+ return DatabaseFailure; -+ } ++ // TBD: Update folder ++ Q_UNUSED(modifiedAccountIds); ++ Q_UNUSED(t); + + //update the folder cache + if (folderCache.contains(folder->id())) @@ -5190,34 +2819,8 @@ index 0000000..029ca4e + if (metaData->dataModified() || updateContent) { + // Find the existing properties + { -+ QSqlQuery query(simpleQuery("SELECT parentaccountId,parentfolderId,mailfile FROM mailmessages WHERE id=?", -+ QVariantList() << metaData->id().toULongLong(), -+ "updateMessage existing properties query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ if (query.first()) { -+ parentAccountId = QMailAccountId(extractValue<quint64>(query.value(0))); -+ parentFolderId = QMailFolderId(extractValue<quint64>(query.value(1))); -+ contentUri = extractValue<QString>(query.value(2)); -+ -+ // Find any folders affected by this update -+ folderIds.append(metaData->parentFolderId()); -+ if (parentFolderId != metaData->parentFolderId()) { -+ // The previous location folder has also changed -+ folderIds.append(parentFolderId); -+ metaData->setPreviousParentFolderId(parentFolderId); -+ } -+ -+ // Ancestor folders are also considered to be affected -+ AttemptResult result; -+ folderIds += folderAncestorIds(folderIds, true, &result); -+ if (result != Success) -+ return result; -+ } else { -+ qMailLog(Messaging) << "Could not query parent account, folder and content URI"; -+ return Failure; -+ } ++ // TBD: Query database ++ Q_UNUSED(t); + } + + if (updateContent) { @@ -5271,16 +2874,11 @@ index 0000000..029ca4e + extractedValues = messageValues(updateProperties, *metaData); + + { -+ QString sql("UPDATE mailmessages SET %1 WHERE id=?"); -+ QSqlQuery query(simpleQuery(sql.arg(expandProperties(updateProperties, true)), -+ extractedValues + (QVariantList() << metaData->id().toULongLong()), -+ "updateMessage mailmessages update")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; ++ // TBD: update exctracted values + } + + if (metaData->customFieldsModified()) { -+ AttemptResult result = updateCustomFields(metaData->id().toULongLong(), metaData->customFields(), "mailmessagecustom"); ++ AttemptResult result = updateCustomFields(metaData->id().toULongLong(), metaData->customFields()); + if (result != Success) + return result; + @@ -5288,11 +2886,6 @@ index 0000000..029ca4e + } + } + -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit folder update to database"; -+ return DatabaseFailure; -+ } -+ + if (parentAccountId.isValid()) { + // The message is now up-to-date with data store + metaData->setUnmodified(); @@ -5376,92 +2969,20 @@ index 0000000..029ca4e + QMailMessageKey::Properties properties(props); + + if (properties & QMailMessageKey::ParentFolderId) { -+ if (!idExists(data.parentFolderId())) { ++ MailFolderUri folderUri(data.parentFolderId()); ++ if (!uriExists(folderUri)) { + qMailLog(Messaging) << "Update of messages failed. Parent folder does not exist"; + return Failure; + } + } + -+ QVariantList extractedValues; -+ -+ //get the valid ids -+ *updatedMessageIds = queryMessages(key, QMailMessageSortKey()); -+ if (!updatedMessageIds->isEmpty()) { -+ // Find the set of folders and accounts whose contents are modified by this update -+ QMailMessageKey modifiedMessageKey(QMailMessageKey::id(*updatedMessageIds)); -+ AttemptResult result = affectedByMessageIds(*updatedMessageIds, modifiedFolderIds, modifiedAccountIds); -+ if (result != Success) -+ return result; -+ -+ // If we're setting parentFolderId, that folder is modified also -+ if (properties & QMailMessageKey::ParentFolderId) { -+ if (!modifiedFolderIds->contains(data.parentFolderId())) -+ modifiedFolderIds->append(data.parentFolderId()); -+ -+ // All these messages need to have previousparentfolderid updated, where it will change -+ QSqlQuery query(simpleQuery("UPDATE mailmessages SET previousparentfolderid=parentfolderid", -+ QVariantList(), -+ QList<Key>() << Key(modifiedMessageKey), -+ "updateMessagesMetaData mailmessages previousparentfolderid update query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ if (properties & QMailMessageKey::Custom) { -+ // Here, we can't compare the input to each target individually. Instead, remove -+ // all custom fields from the affected messages, and add (or re-add) the new ones -+ QVariantList addedFields; -+ QVariantList addedValues; -+ -+ const QMap<QString, QString> &fields = data.customFields(); -+ QMap<QString, QString>::const_iterator it = fields.begin(), end = fields.end(); -+ for ( ; it != end; ++it) { -+ addedFields.append(QVariant(it.key())); -+ addedValues.append(QVariant(it.value())); -+ } -+ -+ { -+ // Remove the obsolete fields -+ QSqlQuery query(simpleQuery("DELETE FROM mailmessagecustom", -+ Key(modifiedMessageKey), -+ "updateMessagesMetaData mailmessagecustom delete query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ if (!addedFields.isEmpty()) { -+ foreach (const QMailMessageId &id, *updatedMessageIds) { -+ // Batch insert the added fields -+ QString sql("INSERT INTO mailmessagecustom (id,name,value) VALUES (%1,?,?)"); -+ QSqlQuery query(batchQuery(sql.arg(QString::number(id.toULongLong())), -+ QVariantList() << QVariant(addedFields) -+ << QVariant(addedValues), -+ "updateMessagesMetaData mailmessagecustom insert query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ } -+ -+ properties &= ~QMailMessageKey::Custom; -+ } -+ -+ if (properties != 0) { -+ extractedValues = messageValues(properties, data); -+ -+ QString sql("UPDATE mailmessages SET %1"); -+ QSqlQuery query(simpleQuery(sql.arg(expandProperties(properties, true)), -+ extractedValues, -+ Key(modifiedMessageKey), -+ "updateMessagesMetaData mailmessages query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ } ++ // TBD: Update message metadata ++ Q_UNUSED(key); ++ Q_UNUSED(modifiedFolderIds); ++ Q_UNUSED(modifiedAccountIds); ++ Q_UNUSED(t); + -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit metadata update to database"; -+ return DatabaseFailure; -+ } ++ QVariantList extractedValues; + + // Update the header cache + foreach (const QMailMessageId& id, *updatedMessageIds) { @@ -5482,27 +3003,11 @@ index 0000000..029ca4e +{ + //get the valid ids + *updatedMessageIds = queryMessages(key, QMailMessageSortKey()); -+ if (!updatedMessageIds->isEmpty()) { -+ // Find the set of folders and accounts whose contents are modified by this update -+ AttemptResult result = affectedByMessageIds(*updatedMessageIds, modifiedFolderIds, modifiedAccountIds); -+ if (result != Success) -+ return result; + -+ { -+ QString sql("UPDATE mailmessages SET status=(status %1 ?)"); -+ QSqlQuery query(simpleQuery(sql.arg(set ? "|" : "&"), -+ QVariantList() << (set ? status : ~status), -+ Key(QMailMessageKey::id(*updatedMessageIds)), -+ "updateMessagesMetaData status query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ } -+ -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit metadata status update to database"; -+ return DatabaseFailure; -+ } ++ // TBD: Update status ++ Q_UNUSED(modifiedFolderIds); ++ Q_UNUSED(modifiedAccountIds); ++ Q_UNUSED(t); + + // Update the header cache + foreach (const QMailMessageId& id, *updatedMessageIds) { @@ -5523,43 +3028,11 @@ index 0000000..029ca4e + QMailMessageIdList *updatedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds, + Transaction &t) +{ -+ // Find the message and folders that are affected by this update -+ QSqlQuery query(simpleQuery("SELECT t0.id, t0.parentfolderid, t0.previousparentfolderid FROM mailmessages t0", -+ Key(key, "t0"), -+ "restoreToPreviousFolder info query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ QSet<quint64> folderIdSet; -+ while (query.next()) { -+ updatedMessageIds->append(QMailMessageId(extractValue<quint64>(query.value(0)))); -+ -+ folderIdSet.insert(extractValue<quint64>(query.value(1))); -+ folderIdSet.insert(extractValue<quint64>(query.value(2))); -+ } -+ -+ if (!folderIdSet.isEmpty()) { -+ QMailFolderIdList folderIds; -+ foreach (quint64 id, folderIdSet) -+ folderIds.append(QMailFolderId(id)); -+ -+ // Find the set of folders and accounts whose contents are modified by this update -+ AttemptResult result = affectedByFolderIds(folderIds, modifiedFolderIds, modifiedAccountIds); -+ if (result != Success) -+ return result; -+ -+ // Update the message records -+ QSqlQuery query(simpleQuery("UPDATE mailmessages SET parentfolderid=previousparentfolderid, previousparentfolderid=NULL", -+ Key(QMailMessageKey::id(*updatedMessageIds)), -+ "restoreToPreviousFolder update query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit message folder restoration to database"; -+ return DatabaseFailure; -+ } ++ // 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) { @@ -5580,290 +3053,34 @@ index 0000000..029ca4e +{ + QMailMessageIdList removalIds; + -+ { -+ QString sql("SELECT id FROM deletedmessages WHERE parentaccountid=?"); -+ -+ QVariantList bindValues; -+ bindValues << accountId.toULongLong(); -+ -+ if (!serverUids.isEmpty()) { -+ QVariantList uidValues; -+ foreach (const QString& uid, serverUids) -+ uidValues.append(uid); -+ -+ sql.append(" AND serveruid IN %1"); -+ sql = sql.arg(expandValueList(uidValues)); -+ -+ bindValues << uidValues; -+ } -+ -+ QSqlQuery query(simpleQuery(sql, -+ bindValues, -+ "purgeMessageRemovalRecord info query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ removalIds.append(QMailMessageId(extractValue<quint64>(query.value(0)))); -+ } -+ -+ // anything to remove? -+ if (!removalIds.isEmpty()) { -+ QSqlQuery query(simpleQuery("DELETE FROM deletedmessages", -+ Key(QMailMessageKey::id(removalIds)), -+ "purgeMessageRemovalRecord delete query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ } -+ -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit message removal record deletion to database"; -+ return DatabaseFailure; -+ } -+ -+ return Success; -+} -+ -+/* Replaced with SPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptCountAccounts(const QMailAccountKey &key, int *result, -+ ReadLock &) -+{ -+ QSqlQuery query(simpleQuery("SELECT COUNT(*) FROM mailaccounts", -+ Key(key), -+ "countAccounts mailaccounts query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ if (query.first()) -+ *result = extractValue<int>(query.value(0)); -+ -+ return Success; -+} -+*/ -+ -+/* Replaced with SPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptCountFolders(const QMailFolderKey &key, int *result, -+ ReadLock &) -+{ -+ QSqlQuery query(simpleQuery("SELECT COUNT(*) FROM mailfolders", -+ Key(key), -+ "countFolders mailfolders query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ if (query.first()) -+ *result = extractValue<int>(query.value(0)); ++ // TBD: Purge remove records ++ Q_UNUSED(accountId); ++ Q_UNUSED(serverUids); ++ Q_UNUSED(t); + + return Success; +} -+*/ + -+/* Replaced with SPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptCountMessages(const QMailMessageKey &key, -+ int *result, -+ ReadLock &) -+{ -+ QSqlQuery query(simpleQuery("SELECT COUNT(*) FROM mailmessages", -+ Key(key), -+ "countMessages mailmessages query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ if (query.first()) -+ *result = extractValue<int>(query.value(0)); -+ -+ return Success; -+} -+*/ + +QMailStorePrivate::AttemptResult QMailStorePrivate::attemptSizeOfMessages(const QMailMessageKey &key, + int *result, + ReadLock &) +{ -+ QSqlQuery query(simpleQuery("SELECT SUM(size FROM mailmessages", -+ Key(key), -+ "sizeOfMessages mailmessages query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ if (query.first()) -+ *result = extractValue<int>(query.value(0)); ++ // TBD: Count overal size of the messages ++ Q_UNUSED(key); ++ Q_UNUSED(result); + + return Success; +} + -+/* Replaced with SPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptQueryAccounts(const QMailAccountKey &key, const QMailAccountSortKey &sortKey, -+ QMailAccountIdList *ids, -+ ReadLock &) -+{ -+ QSqlQuery query(simpleQuery("SELECT id FROM mailaccounts", -+ QVariantList(), -+ QList<Key>() << Key(key) << Key(sortKey), -+ "queryAccounts mailaccounts query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ ids->append(QMailAccountId(extractValue<quint64>(query.value(0)))); -+ -+ return Success; -+} -+*/ -+ -+/* Replaced with SPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptQueryFolders(const QMailFolderKey &key, const QMailFolderSortKey &sortKey, -+ QMailFolderIdList *ids, -+ ReadLock &) -+{ -+ QSqlQuery query(simpleQuery("SELECT id FROM mailfolders", -+ QVariantList(), -+ QList<Key>() << Key(key) << Key(sortKey), -+ "queryFolders mailfolders query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ ids->append(QMailFolderId(extractValue<quint64>(query.value(0)))); -+ -+ return Success; -+} -+*/ -+ -+/* Replaced with SPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptQueryMessages(const QMailMessageKey &key, const QMailMessageSortKey &sortKey, -+ QMailMessageIdList *ids, -+ ReadLock &) -+{ -+ QSqlQuery query(simpleQuery("SELECT id FROM mailmessages", -+ QVariantList(), -+ QList<Key>() << Key(key) << Key(sortKey), -+ "queryMessages mailmessages query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ ids->append(QMailMessageId(extractValue<quint64>(query.value(0)))); -+ -+ //store the results of this call for cache preloading -+ lastQueryMessageResult = *ids; -+ -+ return Success; -+} -+*/ -+ -+/* Replaced with SPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptAccount(const QMailAccountId &id, -+ QMailAccount *result, -+ ReadLock &) -+{ -+ { -+ QSqlQuery query(simpleQuery("SELECT * FROM mailaccounts WHERE id=?", -+ QVariantList() << id.toULongLong(), -+ "account mailaccounts query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ if (query.first()) { -+ *result = extractAccount(query.record()); -+ } -+ } -+ -+ if (result->id().isValid()) { -+ { -+ // Find any standard folders configured for this account -+ QSqlQuery query(simpleQuery("SELECT foldertype,folderid FROM mailaccountfolders WHERE id=?", -+ QVariantList() << id.toULongLong(), -+ "account mailaccountfolders query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ result->setStandardFolder(QMailFolder::StandardFolder(query.value(0).toInt()), QMailFolderId(query.value(1).toULongLong())); -+ } -+ -+ // Find any custom fields for this account -+ QMap<QString, QString> fields; -+ AttemptResult attemptResult = customFields(id.toULongLong(), &fields, "mailaccountcustom"); -+ if (attemptResult != Success) -+ return attemptResult; -+ -+ result->setCustomFields(fields); -+ result->setCustomFieldsModified(false); -+ -+ { -+ // Find the type of the account -+ QSqlQuery query(simpleQuery("SELECT service,value FROM mailaccountconfig WHERE id=? AND name='servicetype'", -+ QVariantList() << id.toULongLong(), -+ "account mailaccountconfig query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) { -+ QString service(query.value(0).toString()); -+ QString type(query.value(1).toString()); -+ -+ if (type.contains("source")) { -+ result->addMessageSource(service); -+ } -+ if (type.contains("sink")) { -+ result->addMessageSink(service); -+ } -+ } -+ } -+ -+ //update cache -+ accountCache.insert(*result); -+ return Success; -+ } -+ -+ return Failure; -+} -+*/ -+ +QMailStorePrivate::AttemptResult QMailStorePrivate::attemptAccountConfiguration(const QMailAccountId &id, + QMailAccountConfiguration *result, + ReadLock &) +{ -+ // Find any configuration fields for this account -+ QSqlQuery query(simpleQuery("SELECT service,name,value FROM mailaccountconfig WHERE id=? ORDER BY service", -+ QVariantList() << id.toULongLong(), -+ "accountConfiguration mailaccountconfig query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ QString service; -+ QMailAccountConfiguration::ServiceConfiguration *serviceConfig = 0; -+ -+ while (query.next()) { -+ QString svc(query.value(0).toString()); -+ if (svc != service) { -+ service = svc; -+ -+ if (!result->services().contains(service)) { -+ // Add this service to the configuration -+ result->addServiceConfiguration(service); -+ } -+ -+ serviceConfig = &result->serviceConfiguration(service); -+ } -+ -+ serviceConfig->setValue(query.value(1).toString(), query.value(2).toString()); -+ } ++ // TBD: Find any configuration fields for this account + -+ if (service.isEmpty()) { -+ // No services - is this an error? -+ QSqlQuery query(simpleQuery("SELECT COUNT(*) FROM mailaccounts WHERE id=?", -+ QVariantList() << id.toULongLong(), -+ "accountConfiguration mailaccounts query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; ++ // TBD: Fill account configuration with information + -+ if (query.first()) { -+ if (extractValue<int>(query.value(0)) == 0) -+ return Failure; -+ } -+ } + + result->setId(id); + result->setModified(false); @@ -5871,69 +3088,6 @@ index 0000000..029ca4e + return Success; +} + -+/* Replaced with SPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptFolder(const QMailFolderId &id, -+ QMailFolder *result, -+ ReadLock &) -+{ -+ { -+ QSqlQuery query(simpleQuery("SELECT * FROM mailfolders WHERE id=?", -+ QVariantList() << id.toULongLong(), -+ "folder mailfolders query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ if (query.first()) { -+ *result = extractFolder(query.record()); -+ } -+ } -+ -+ if (result->id().isValid()) { -+ // Find any custom fields for this folder -+ QMap<QString, QString> fields; -+ AttemptResult attemptResult = customFields(id.toULongLong(), &fields, "mailfoldercustom"); -+ if (attemptResult != Success) -+ return attemptResult; -+ -+ result->setCustomFields(fields); -+ result->setCustomFieldsModified(false); -+ -+ //update cache -+ folderCache.insert(*result); -+ return Success; -+ } -+ -+ return Failure; -+} -+*/ -+ -+/* Replaced with SPARQL -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptMessage(const QMailMessageId &id, -+ QMailMessage *result, -+ ReadLock &) -+{ -+ // Find any custom fields for this message -+ QMap<QString, QString> fields; -+ AttemptResult attemptResult = customFields(id.toULongLong(), &fields, "mailmessagecustom"); -+ if (attemptResult != Success) -+ return attemptResult; -+ -+ QSqlQuery query(simpleQuery("SELECT * FROM mailmessages WHERE id=?", -+ QVariantList() << id.toULongLong(), -+ "message mailmessages id query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ if (query.first()) { -+ *result = extractMessage(query.record(), fields); -+ if (result->id().isValid()) -+ return Success; -+ } -+ -+ return Failure; -+} -+*/ -+ +QMailStorePrivate::AttemptResult QMailStorePrivate::attemptMessage(const QString &uid, const QMailAccountId &accountId, + QMailMessage *result, + ReadLock &lock) @@ -5941,15 +3095,9 @@ index 0000000..029ca4e + quint64 id(0); + + { -+ QSqlQuery query(simpleQuery("SELECT id FROM mailmessages WHERE serveruid=? AND parentaccountid=?", -+ QVariantList() << uid << accountId.toULongLong(), -+ "message mailmessages uid/parentaccountid query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ if (query.first()) { -+ id = extractValue<quint64>(query.value(0)); -+ } ++ // TBD: Search for the message with particular server UID ++ Q_UNUSED(uid); ++ Q_UNUSED(accountId); + } + + if (id == 0) { @@ -5959,31 +3107,17 @@ index 0000000..029ca4e + return attemptMessage(QMailMessageId(id), result, lock); +} + -+QMailStorePrivate::AttemptResult QMailStorePrivate::attemptMessagesMetaData(const QMailMessageKey& key, const QMailMessageKey::Properties &properties, QMailStore::ReturnOption option, -+ QMailMessageMetaDataList *result, ++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 -+ QString sql("SELECT %1 name, value FROM mailmessagecustom WHERE id IN ( SELECT t0.id FROM mailmessages t0"); -+ sql += buildWhereClause(Key(key, "t0")) + " )"; -+ -+ QVariantList whereValues(::whereClauseValues(key)); -+ QSqlQuery query(simpleQuery(sql.arg(option == QMailStore::ReturnDistinct ? "DISTINCT " : ""), -+ whereValues, -+ "messagesMetaData combined query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; + -+ // Find all the values for each parameter name in the set ++ // TBD: Search by custom fields + QMap<QString, QStringList> fields; -+ while (query.next()) -+ fields[query.value(0).toString()].append(query.value(1).toString()); -+ -+ // Create records for each of these parameters + int maxLen = 0; -+ foreach (const QStringList &list, fields.values()) -+ maxLen = qMax<uint>(maxLen, list.count()); ++ Q_UNUSED(key); + + for (int i = 0; i < maxLen; ++i) + result->append(QMailMessageMetaData()); @@ -6006,9 +3140,6 @@ index 0000000..029ca4e + qWarning() << "Warning: Distinct-ness is not supported with custom fields!"; + } + -+ QString sql("SELECT %1 %2 FROM mailmessages t0"); -+ sql = sql.arg(option == QMailStore::ReturnDistinct ? "DISTINCT " : ""); -+ + QMailMessageKey::Properties props(properties); + + bool removeId(false); @@ -6019,14 +3150,7 @@ index 0000000..029ca4e + } + + { -+ QSqlQuery query(simpleQuery(sql.arg(expandProperties(props, false)), -+ Key(key, "t0"), -+ "messagesMetaData mailmessages query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ result->append(extractMessageMetaData(query.record(), props, props)); ++ // TBD: Search messages by fields + } + + if (includeCustom) { @@ -6034,7 +3158,7 @@ index 0000000..029ca4e + for ( ; it != end; ++it) { + // Add the custom fields to the record + QMap<QString, QString> fields; -+ AttemptResult attemptResult = customFields((*it).id().toULongLong(), &fields, "mailmessagecustom"); ++ AttemptResult attemptResult = customFields((*it).id().toULongLong(), &fields); + if (attemptResult != Success) + return attemptResult; + @@ -6055,23 +3179,10 @@ index 0000000..029ca4e + QMailMessageRemovalRecordList *result, + ReadLock &) +{ -+ QVariantList values; -+ values << accountId.toULongLong(); -+ -+ QString sql("SELECT * FROM deletedmessages WHERE parentaccountid=?"); -+ if (folderId.isValid()) { -+ sql += " AND parentfolderid=?"; -+ values << folderId.toULongLong(); -+ } -+ -+ QSqlQuery query(simpleQuery(sql, -+ values, -+ "messageRemovalRecords deletedmessages query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ result->append(extractMessageRemovalRecord(query.record())); ++ // TBD: Search for deleted messages ++ Q_UNUSED(accountId); ++ Q_UNUSED(folderId); ++ Q_UNUSED(result); + + return Success; +} @@ -6080,14 +3191,9 @@ index 0000000..029ca4e + QMailFolderIdList *result, + ReadLock &) +{ -+ QSqlQuery query(simpleQuery("SELECT DISTINCT t0.parentfolderid FROM mailmessages t0", -+ Key(key, "t0"), -+ "messageFolderIds folder select query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ result->append(QMailFolderId(extractValue<quint64>(query.value(0)))); ++ // TBD: Look for message ID ++ Q_UNUSED(key); ++ Q_UNUSED(result); + + return Success; +} @@ -6096,14 +3202,9 @@ index 0000000..029ca4e + QMailAccountIdList *result, + ReadLock &) +{ -+ QSqlQuery query(simpleQuery("SELECT DISTINCT parentaccountid FROM mailfolders t0", -+ Key(key, "t0"), -+ "folderAccountIds account select query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ result->append(QMailAccountId(extractValue<quint64>(query.value(0)))); ++ // TBD: Look for message folder ID ++ Q_UNUSED(key); ++ Q_UNUSED(result); + + return Success; +} @@ -6112,19 +3213,9 @@ index 0000000..029ca4e + QMailFolderIdList *result, + ReadLock &) +{ -+ QVariantList idValues; -+ foreach (const QMailFolderId& id, ids) -+ idValues.append(id.toULongLong()); -+ -+ QString sql("SELECT DISTINCT id FROM mailfolderlinks WHERE descendantid IN %1"); -+ QSqlQuery query(simpleQuery(sql.arg(expandValueList(idValues)), -+ idValues, -+ "folderAncestorIds id select query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ while (query.next()) -+ result->append(QMailFolderId(extractValue<quint64>(query.value(0)))); ++ // TBD: Look for ancestor message folder ID ++ Q_UNUSED(ids); ++ Q_UNUSED(result); + + return Success; +} @@ -6200,15 +3291,10 @@ index 0000000..029ca4e + int *result, + ReadLock &) +{ -+ QSqlQuery query(simpleQuery("SELECT COALESCE(statusbit,0) FROM mailstatusflags WHERE name=? AND context=?", -+ QVariantList() << name << context, -+ "mailstatusflags select")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ *result = 0; -+ if (query.next()) -+ *result = extractValue<int>(query.value(0)); ++ // TBD: Find out wheither this status bit is present ++ Q_UNUSED(name); ++ Q_UNUSED(context); ++ Q_UNUSED(result); + + return Success; +} @@ -6218,32 +3304,18 @@ index 0000000..029ca4e +{ + int highest = 0; + -+ { -+ // Find the highest -+ QSqlQuery query(simpleQuery("SELECT MAX(statusbit) FROM mailstatusflags WHERE context=?", -+ QVariantList() << context, -+ "mailstatusflags register select")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; -+ -+ if (query.next()) -+ highest = extractValue<int>(query.value(0)); -+ } ++ // TBD: Find out the highest bit ++ Q_UNUSED(name); ++ Q_UNUSED(context); ++ Q_UNUSED(t); + + if (highest == maximum) { + return Failure; + } else { -+ QSqlQuery query(simpleQuery("INSERT INTO mailstatusflags (name,context,statusbit) VALUES (?,?,?)", -+ QVariantList() << name << context << (highest + 1), -+ "mailstatusflags register insert")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return DatabaseFailure; ++ // TBD: Add new status bit + } + -+ if (!t.commit()) { -+ qMailLog(Messaging) << "Could not commit statusflag changes to database"; -+ return DatabaseFailure; -+ } ++ t.commit(); + + return Success; +} @@ -6278,7 +3350,8 @@ index 0000000..029ca4e + + if(folder.parentFolderId().isValid()) + { -+ if(!idExists(folder.parentFolderId(),"mailfolders")) ++ MailFolderUri folderUri(folder.parentFolderId()); ++ if(!uriExists(folderUri)) + { + qMailLog(Messaging) << "Parent folder does not exist!"; + return false; @@ -6287,7 +3360,8 @@ index 0000000..029ca4e + + if(folder.parentAccountId().isValid()) + { -+ if(!idExists(folder.parentAccountId(),"mailaccounts")) ++ MailAccountUri accountUri(folder.parentAccountId()); ++ if(!uriExists(accountUri)) + { + qMailLog(Messaging) << "Parent account does not exist!"; + return false; @@ -6304,103 +3378,13 @@ index 0000000..029ca4e + QMailAccountIdList& modifiedAccounts, + QMailFolderIdList& modifiedFolders) +{ -+ QString elements("id,mailfile,parentaccountid,parentfolderId"); -+ if (option == QMailStore::CreateRemovalRecord) -+ elements += ",serveruid,previousparentfolderid"; -+ -+ QVariantList removalAccountIds; -+ QVariantList removalServerUids; -+ QVariantList removalFolderIds; -+ -+ { -+ // Get the information we need to delete these messages -+ QSqlQuery query(simpleQuery(QString("SELECT %1 FROM mailmessages").arg(elements), -+ Key(key), -+ "deleteMessages info query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ -+ while (query.next()) { -+ QMailMessageId messageId(extractValue<quint64>(query.value(0))); -+ deletedMessages.append(messageId); -+ -+ QString contentUri(extractValue<QString>(query.value(1))); -+ if (!contentUri.isEmpty()) -+ expiredContent.append(contentUri); -+ -+ QMailAccountId parentAccountId(extractValue<quint64>(query.value(2))); -+ if (!modifiedAccounts.contains(parentAccountId)) -+ modifiedAccounts.append(parentAccountId); -+ -+ QMailFolderId folderId(extractValue<quint64>(query.value(3))); -+ if (!modifiedFolders.contains(folderId)) -+ modifiedFolders.append(folderId); -+ -+ if (option == QMailStore::CreateRemovalRecord) { -+ // Extract the info needed to create removal records -+ removalAccountIds.append(parentAccountId.toULongLong()); -+ removalServerUids.append(extractValue<QString>(query.value(4))); -+ if (folderId == QMailFolderId(QMailFolder::TrashFolder)) { -+ removalFolderIds.append(extractValue<quint64>(query.value(5))); -+ } else { -+ removalFolderIds.append(folderId.toULongLong()); -+ } -+ } -+ } -+ } -+ -+ // No messages? Then we're already done -+ if (deletedMessages.isEmpty()) -+ return true; -+ -+ // Any ancestor folders of the directly modified folders are indirectly modified -+ QVariantList folderIdValues(idValueList(modifiedFolders)); -+ -+ if (!folderIdValues.isEmpty()) { -+ QString sql("SELECT DISTINCT id FROM mailfolderlinks WHERE descendantid IN %1"); -+ QSqlQuery query(simpleQuery(sql.arg(expandValueList(folderIdValues)), -+ folderIdValues, -+ "deleteMessages mailfolderlinks ancestor query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ -+ while (query.next()) -+ modifiedFolders.append(QMailFolderId(extractValue<quint64>(query.value(0)))); -+ } -+ -+ // Insert the removal records -+ if (!removalAccountIds.isEmpty()) { -+ // WARNING - QList::operator<<(QList) actually appends the list items to the object, -+ // rather than insert the actual list! -+ QSqlQuery query(batchQuery("INSERT INTO deletedmessages (parentaccountid,serveruid,parentfolderid) VALUES (?,?,?)", -+ QVariantList() << QVariant(removalAccountIds) -+ << QVariant(removalServerUids) -+ << QVariant(removalFolderIds), -+ "deleteMessages insert removal records query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } -+ -+ // Use the derived ID list rather than the key, in case the deletion statements affect the key result -+ QVariantList idValues(idValueList(deletedMessages)); -+ -+ { -+ // Delete any custom fields associated with these messages -+ QString sql("DELETE FROM mailmessagecustom"); -+ QSqlQuery query(simpleQuery(sql, Key(QMailMessageKey::id(deletedMessages)), -+ "deleteMessages delete mailmessagecustom query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } -+ -+ { -+ // Perform the message deletion -+ QString sql("DELETE FROM mailmessages"); -+ QSqlQuery query(simpleQuery(sql, Key(QMailMessageKey::id(deletedMessages)), -+ "deleteMessages delete mailmessages query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } ++ // TBD: Delete messages ++ Q_UNUSED(key); ++ Q_UNUSED(option); ++ Q_UNUSED(deletedMessages); ++ Q_UNUSED(expiredContent); ++ Q_UNUSED(modifiedAccounts); ++ Q_UNUSED(modifiedFolders); + + return true; +} @@ -6412,76 +3396,13 @@ index 0000000..029ca4e + QStringList& expiredContent, + QMailAccountIdList& modifiedAccounts) +{ -+ { -+ // Get the identifiers for all the folders we're deleting -+ QSqlQuery query(simpleQuery("SELECT t0.id FROM mailfolders t0", -+ Key(key, "t0"), -+ "deleteFolders info query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ -+ while (query.next()) -+ deletedFolders.append(QMailFolderId(extractValue<quint64>(query.value(0)))); -+ } -+ -+ // No folders? Then we're already done -+ if (deletedFolders.isEmpty()) -+ return true; -+ -+ // Create a key to select messages in the folders to be deleted -+ QMailMessageKey messagesKey(QMailMessageKey::parentFolderId(key)); -+ -+ // We won't report the modified folders, since they're about to be deleted -+ QMailFolderIdList modifiedFolders; -+ -+ // Delete all the messages contained by the folders we're deleting -+ if (!deleteMessages(messagesKey, option, deletedMessages, expiredContent, modifiedAccounts, modifiedFolders)) -+ return false; -+ -+ // Delete any references to these folders in the mailfolderlinks table -+ QString statement("DELETE FROM mailfolderlinks WHERE %1 IN ( SELECT t0.id FROM mailfolders t0"); -+ statement += buildWhereClause(Key(key, "t0")) + " )"; -+ -+ QVariantList whereValues(::whereClauseValues(key)); -+ -+ { -+ // Delete where target folders are ancestors -+ QSqlQuery query(simpleQuery(statement.arg("id"), -+ whereValues, -+ "deleteFolders mailfolderlinks ancestor query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } -+ -+ { -+ // Delete where target folders are descendants -+ QSqlQuery query(simpleQuery(statement.arg("descendantid"), -+ whereValues, -+ "deleteFolders mailfolderlinks descendant query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } -+ -+ // Use the derived ID list rather than the key, in case the deletion statements affect the key result -+ QVariantList idValues(idValueList(deletedFolders)); -+ -+ { -+ // Delete any custom fields associated with these folders -+ QString sql("DELETE FROM mailfoldercustom"); -+ QSqlQuery query(simpleQuery(sql, Key(QMailFolderKey::id(deletedFolders)), -+ "deleteFolders delete mailfoldercustom query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } -+ -+ { -+ // Perform the folder deletion -+ QString sql("DELETE FROM mailfolders"); -+ QSqlQuery query(simpleQuery(sql, Key(QMailFolderKey::id(deletedFolders)), -+ "deleteFolders delete mailfolders query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } ++ // 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; +} @@ -6492,176 +3413,16 @@ index 0000000..029ca4e + QMailMessageIdList& deletedMessages, + QStringList& expiredContent) +{ -+ { -+ // Get the identifiers for all the accounts we're deleting -+ QSqlQuery query(simpleQuery("SELECT t0.id FROM mailaccounts t0", -+ Key(key, "t0"), -+ "deleteAccounts info query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ -+ while (query.next()) -+ deletedAccounts.append(QMailAccountId(extractValue<quint64>(query.value(0)))); -+ } -+ -+ // No accounts? Then we're already done -+ if (deletedAccounts.isEmpty()) -+ return true; -+ -+ // Create a key to select folders from the accounts to be deleted -+ QMailFolderKey foldersKey(QMailFolderKey::parentAccountId(key)); -+ -+ // We won't create new message removal records, since there will be no account to link them to -+ QMailStore::MessageRemovalOption option(QMailStore::NoRemovalRecord); -+ QMailAccountIdList modifiedAccounts; -+ -+ // Delete all the folders contained by the accounts we're deleting -+ if (!deleteFolders(foldersKey, option, deletedFolders, deletedMessages, expiredContent, modifiedAccounts)) -+ return false; -+ -+ // Also delete any messages belonging to these accounts, that aren't in folders owned by the accounts -+ -+ // Create a key to select messages for the accounts to be deleted -+ QMailMessageKey messagesKey(QMailMessageKey::parentAccountId(key)); -+ -+ // We won't report the modified folders, since they're about to be deleted -+ QMailFolderIdList modifiedFolders; -+ -+ // Delete all the messages contained by the folders we're deleting -+ if (!deleteMessages(messagesKey, option, deletedMessages, expiredContent, modifiedAccounts, modifiedFolders)) -+ return false; -+ -+ QVariantList idValues(idValueList(deletedAccounts)); -+ -+ { -+ // Delete the removal records related to these accounts -+ QString sql("DELETE FROM deletedmessages WHERE parentaccountid IN %1"); -+ QSqlQuery query(simpleQuery(sql.arg(expandValueList(idValues)), -+ idValues, -+ "deleteAccounts removal record delete query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } -+ -+ { -+ // Remove any standard folders associated with these accounts -+ QString sql("DELETE FROM mailaccountfolders WHERE id IN %1"); -+ QSqlQuery query(simpleQuery(sql.arg(expandValueList(idValues)), -+ idValues, -+ "deleteAccounts delete mailaccountfolders query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } -+ -+ { -+ // Remove any custom fields associated with these accounts -+ QString sql("DELETE FROM mailaccountcustom WHERE id IN %1"); -+ QSqlQuery query(simpleQuery(sql.arg(expandValueList(idValues)), -+ idValues, -+ "deleteAccounts delete mailaccountcustom query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } -+ -+ { -+ // Remove any configuration fields associated with these accounts -+ QString sql("DELETE FROM mailaccountconfig WHERE id IN %1"); -+ QSqlQuery query(simpleQuery(sql.arg(expandValueList(idValues)), -+ idValues, -+ "deleteAccounts delete mailaccountconfig query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } -+ -+ { -+ // Perform the account deletion -+ QString sql("DELETE FROM mailaccounts WHERE id IN %1"); -+ QSqlQuery query(simpleQuery(sql.arg(expandValueList(idValues)), -+ idValues, -+ "deleteAccounts delete mailaccounts query")); -+ if (query.lastError().type() != QSqlError::NoError) -+ return false; -+ } ++ // 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; +} + -+QSqlQuery QMailStorePrivate::simpleQuery(const QString& statement, const QString& descriptor) -+{ -+ return performQuery(statement, false, QVariantList(), QList<Key>(), descriptor); -+} -+ -+QSqlQuery QMailStorePrivate::simpleQuery(const QString& statement, const QVariantList& bindValues, const QString& descriptor) -+{ -+ return performQuery(statement, false, bindValues, QList<Key>(), descriptor); -+} -+ -+QSqlQuery QMailStorePrivate::simpleQuery(const QString& statement, const Key& key, const QString& descriptor) -+{ -+ return performQuery(statement, false, QVariantList(), QList<Key>() << key, descriptor); -+} -+ -+QSqlQuery QMailStorePrivate::simpleQuery(const QString& statement, const QVariantList& bindValues, const Key& key, const QString& descriptor) -+{ -+ return performQuery(statement, false, bindValues, QList<Key>() << key, descriptor); -+} -+ -+QSqlQuery QMailStorePrivate::simpleQuery(const QString& statement, const QVariantList& bindValues, const QList<Key>& keys, const QString& descriptor) -+{ -+ return performQuery(statement, false, bindValues, keys, descriptor); -+} -+ -+QSqlQuery QMailStorePrivate::batchQuery(const QString& statement, const QVariantList& bindValues, const QString& descriptor) -+{ -+ return performQuery(statement, true, bindValues, QList<Key>(), descriptor); -+} -+ -+QSqlQuery QMailStorePrivate::batchQuery(const QString& statement, const QVariantList& bindValues, const Key& key, const QString& descriptor) -+{ -+ return performQuery(statement, true, bindValues, QList<Key>() << key, descriptor); -+} -+ -+QSqlQuery QMailStorePrivate::batchQuery(const QString& statement, const QVariantList& bindValues, const QList<Key>& keys, const QString& descriptor) -+{ -+ return performQuery(statement, true, bindValues, keys, descriptor); -+} -+ -+QSqlQuery QMailStorePrivate::performQuery(const QString& statement, bool batch, const QVariantList& bindValues, const QList<Key>& keys, const QString& descriptor) -+{ -+ QString keyStatements; -+ QVariantList keyValues; -+ -+ bool firstClause(true); -+ foreach (const Key &key, keys) { -+ if (key.isType<QMailMessageKey>() || key.isType<QMailFolderKey>() || key.isType<QMailAccountKey>()) { -+ keyStatements.append(buildWhereClause(key, false, firstClause)); -+ keyValues << whereClauseValues(key); -+ } else if (key.isType<QMailMessageSortKey>() || key.isType<QMailFolderSortKey>() || key.isType<QMailAccountSortKey>()) { -+ keyStatements.append(buildOrderClause(key)); -+ } else if (key.isType<QString>()) { -+ keyStatements.append(key.key<QString>()); -+ } -+ -+ firstClause = false; -+ } -+ -+ QSqlQuery query(prepare(statement + keyStatements)); -+ if (query.lastError().type() != QSqlError::NoError) { -+ qMailLog(Messaging) << "Could not prepare query" << descriptor; -+ } else { -+ foreach (const QVariant& value, bindValues) -+ query.addBindValue(value); -+ foreach (const QVariant& value, keyValues) -+ query.addBindValue(value); -+ -+ if (!execute(query, batch)){ -+ qMailLog(Messaging) << "Could not execute query" << descriptor; -+ } -+ } -+ -+ return query; -+} -+ +void QMailStorePrivate::emitIpcNotification(QMailStoreImplementation::AccountUpdateSignal signal, const QMailAccountIdList &ids) +{ + if ((signal == &QMailStore::accountsUpdated) || (signal == &QMailStore::accountsRemoved)) { @@ -6692,7 +3453,6 @@ index 0000000..029ca4e + QMailStoreImplementation::emitIpcNotification(signal, ids); +} + -+/* SPARQL Code */ +QMailStorePrivate::AttemptResult QMailStorePrivate::attemptAddMessage(QMailMessageMetaData *metaData, + QMailMessageIdList *addedMessageIds, QMailFolderIdList *modifiedFolderIds, QMailAccountIdList *modifiedAccountIds, + Transaction &t) @@ -6704,43 +3464,44 @@ index 0000000..029ca4e + return Failure; + } + -+ SparqlUri uri("qmf://groove.harmattan.com/email#"); ++ 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 <qmf://groove.nokia.com/folder#%2> ;\n" -+ " nmo:sender [\n" -+ " rdf:type nco:Contact ;\n" -+ " nco:fullname \"%3\" ; \n" -+ " nco:hasEmailAddress <mailto:%4> ] ;\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 <qmf://groove.nokia.com/accounts#%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(uri.uri()) -+ .arg(metaData->parentFolderId().toULongLong()) ++ " 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(metaData->parentAccountId().toULongLong()) ++ .arg(parentAccountUri.uri()) + .arg(::contentUri(*metaData)) + .arg(metaData->serverUid()) + .arg(metaData->size()) @@ -6758,12 +3519,13 @@ index 0000000..029ca4e + } + + qDebug() << "Query succeeded"; -+ metaData->setId(QMailMessageId(uri.id())); ++ metaData->setId(QMailMessageId(messageUri.id())); + + addedMessageIds->append(metaData->id()); + *modifiedFolderIds = QMailFolderIdList() << metaData->parentFolderId(); + if (metaData->parentAccountId().isValid()) + modifiedAccountIds->append(metaData->parentAccountId()); ++ + return Success; +} + @@ -6777,22 +3539,25 @@ index 0000000..029ca4e + if (!checkPreconditions(*folder)) + return Failure; + -+ SparqlUri uri("qmf://groove.nokia.com/folder#"); ++ 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" ++ "%1 rdf:type nmo:MailFolder ; \n" + " nmo:folderName \"%2\" ; \n" -+ " nie:isLogicalPartOf <qmf://groove.nokia.com/folder#%3> ; \n" -+ " nie:relatedTo <qmf://groove.nokia.com/accounts#%4> ; \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(uri.uri()) ++ "}").arg(folderUri.uri()) + .arg(folder->path()) -+ .arg(folder->parentFolderId().toULongLong()) -+ .arg(folder->parentAccountId().toULongLong()) ++ .arg(parentFolderUri.uri()) ++ .arg(parentAccountUri.uri()) + .arg(folder->displayName()) + .arg(folder->status()) + .arg(folder->serverCount()) @@ -6807,13 +3572,14 @@ index 0000000..029ca4e + } + + qDebug() << "Query succeeded"; -+ folder->setId(QMailFolderId(uri.id())); ++ folder->setId(QMailFolderId(folderUri.id())); + + // TBD: Update folder links also + + addedFolderIds->append(folder->id()); + if (folder->parentAccountId().isValid()) + modifiedAccountIds->append(folder->parentAccountId()); ++ + return Success; +} + @@ -6821,27 +3587,27 @@ index 0000000..029ca4e + QMailAccountIdList *addedAccountIds, + Transaction &t) +{ ++ Q_UNUSED(config); + Q_UNUSED(t); + -+ SparqlUri uri("qmf://groove.nokia.com/accounts#"); ++ MailAccountUri accountUri; + SparqlQuery query(SparqlQuery::UpdateQuery); + query.prepare(QString( + "INSERT { \n" -+ "<%1> rdf:type nmo:Mailbox ; \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(uri.uri()) ++ "}").arg(accountUri.uri()) + .arg(account->name()) + .arg(account->status()) + .arg(account->signature()) + .arg(account->fromAddress().toString(true))); + + // TBD: Add custom fields later -+ // TBD: Add account configuration + + if (!query.exec()) + { @@ -6850,7 +3616,7 @@ index 0000000..029ca4e + } + + qDebug() << "Query succeeded"; -+ account->setId(QMailAccountId(uri.id())); ++ account->setId(QMailAccountId(accountUri.id())); + + addedAccountIds->append(account->id()); + return Success; @@ -6860,20 +3626,19 @@ index 0000000..029ca4e + QMailAccount *result, + ReadLock &) +{ -+ QMailAccount account; -+ ++ MailAccountUri messageUri(id); + SparqlQuery query(SparqlQuery::SearchQuery); + query.prepare(QString( + "SELECT ?name ?signature ?fromAddress \n" + "WHERE { \n" -+ "<qmf://groove.nokia.com/accounts#%1> rdf:type nmo:Mailbox ; \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(id.toULongLong())); ++ "}").arg(messageUri.uri())); + + if (!query.exec()) + { @@ -6882,18 +3647,9 @@ index 0000000..029ca4e + } + + SparqlResult res = query.result(); -+ + Q_ASSERT(!res.end()); + -+ QStringList list = res.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))); -+ -+ *result = account; ++ *result = extractAccount(id, res.fetchRow()); + + // Update cache + accountCache.insert(*result); @@ -6905,11 +3661,12 @@ index 0000000..029ca4e + QMailFolder *result, + ReadLock &) +{ ++ MailFolderUri folderUri(id); + SparqlQuery query(SparqlQuery::SearchQuery); + query.prepare(QString( + "SELECT ?name ?parentFolder ?parentAccount ?displayName \n" + "WHERE { \n" -+ "<qmf://groove.nokia.com/folder#%1> rdf:type nmo:MailFolder ; \n" ++ "%1 rdf:type nmo:MailFolder ; \n" + " nmo:folderName ?name ; \n" + " nie:isLogicalPartOf ?parentFolder ; \n" + " nie:relatedTo ?parentAccount ; \n" @@ -6917,7 +3674,7 @@ index 0000000..029ca4e +// " nmo:status ?status ; \n" +// " nmo:serverCount ?serverCount ; \n" +// " nmo:serverUnreadCount ?serverUnreadCount . \n" -+ "}").arg(id.toULongLong())); ++ "}").arg(folderUri.uri())); + + if (!query.exec()) + { @@ -6926,22 +3683,13 @@ index 0000000..029ca4e + } + + SparqlResult res = query.result(); -+ + Q_ASSERT(!res.end()); + -+ QStringList list = res.fetchRow(); ++ *result = extractFolder(id, res.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()); -+ -+ *result = folder; -+ -+ //update cache ++ // Update cache + folderCache.insert(*result); ++ + return Success; +} + @@ -6952,16 +3700,17 @@ index 0000000..029ca4e + if (!id.isValid()) + return Failure; + ++ MailMessageUri messageUri(id); + SparqlQuery query(SparqlQuery::SearchQuery); + query.prepare(QString( + "SELECT ?fullName ?mailAddress \n" + "WHERE { \n" -+ "<qmf://groove.harmattan.com/email#%1> rdf:type nmo:Email ;\n" -+ "nmo:recipient [\n" -+ " rdf:type nco:Contact ;\n" -+ " nco:fullname ?fullName ; \n" -+ " nco:hasEmailAddress ?mailAddress ] \n" -+ "}").arg(id.toULongLong())); ++ "%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()) + { @@ -6981,29 +3730,29 @@ index 0000000..029ca4e + query.prepare(QString( + "SELECT ?folderId ?senderFullName ?senderEmailAddress ?messageSubject ?sentDate ?status ?accountId ?dataSource ?uid ?contentSize ?mimeType ?inReplyTo ?headerValue ?receivedDate \n" + "WHERE { \n" -+ " <qmf://groove.harmattan.com/email#%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(id.toULongLong())); ++ "%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()) + { @@ -7012,26 +3761,11 @@ index 0000000..029ca4e + } + + res = query.result(); -+ + Q_ASSERT(!res.end()); + -+ QStringList list = res.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))); -+ ++ extractMessageMetaData(res.fetchRow(), &message); + message.setTo(recipients); + + *result = message; @@ -7044,12 +3778,7 @@ index 0000000..029ca4e + ReadLock &) +{ + SparqlQuery query(SparqlQuery::SearchQuery); -+ query.prepare(QString( -+ "SELECT ?account \n" -+ "WHERE { \n" -+ " ?account rdf:type nmo:Mailbox . \n" -+ + accountConstraint("?account", key) + -+ "} \n")); ++ query.prepare(keyQuery(key, sortKey)); + + if (!query.exec()) + { @@ -7075,12 +3804,7 @@ index 0000000..029ca4e + ReadLock &) +{ + SparqlQuery query(SparqlQuery::SearchQuery); -+ query.prepare(QString( -+ "SELECT ?folder \n" -+ "WHERE { \n" -+ " ?folder rdf:type nmo:MailFolder . \n" -+ + folderConstraint("?folder", key) + -+ "} \n")); ++ query.prepare(keyQuery(key, sortKey)); + + if (!query.exec()) + { @@ -7106,12 +3830,7 @@ index 0000000..029ca4e + ReadLock &) +{ + SparqlQuery query(SparqlQuery::SearchQuery); -+ query.prepare(QString( -+ "SELECT ?message \n" -+ "WHERE { \n" -+ " ?message rdf:type nmo:Email . \n" -+ + messageConstraint("?message", key) + -+ "} \n")); ++ query.prepare(keyQuery(key, sortKey)); + + if (!query.exec()) + { @@ -7136,12 +3855,7 @@ index 0000000..029ca4e + ReadLock &) +{ + SparqlQuery query(SparqlQuery::SearchQuery); -+ query.prepare(QString( -+ "SELECT COUNT(?accountId) AS count \n" -+ "WHERE { \n" -+ " ?accountId rdf:type nmo:Mailbox . \n" -+ + accountConstraint("?accountId", key) + -+ "} \n")); ++ query.prepare(keyCount(key)); + + if (!query.exec()) + { @@ -7162,12 +3876,7 @@ index 0000000..029ca4e + ReadLock &) +{ + SparqlQuery query(SparqlQuery::SearchQuery); -+ query.prepare(QString( -+ "SELECT COUNT(?folderId) AS count \n" -+ "WHERE { \n" -+ " ?folderId rdf:type nmo:MailFolder . \n" -+ + folderConstraint("?folderId", key) + -+ "} \n")); ++ query.prepare(keyCount(key)); + + if (!query.exec()) + { @@ -7189,12 +3898,7 @@ index 0000000..029ca4e + ReadLock &) +{ + SparqlQuery query(SparqlQuery::SearchQuery); -+ query.prepare(QString( -+ "SELECT COUNT(?emailId) AS count \n" -+ "WHERE { \n" -+ " ?emailId rdf:type nmo:Email . \n" -+ + messageConstraint("?emailId", key) + -+ "} \n")); ++ query.prepare(keyCount(key)); + + if (!query.exec()) + { @@ -7212,10 +3916,10 @@ index 0000000..029ca4e +} diff --git a/src/libraries/qtopiamail/qmailstore_sparql.h b/src/libraries/qtopiamail/qmailstore_sparql.h new file mode 100644 -index 0000000..e7ec13a +index 0000000..4d185cd --- /dev/null +++ b/src/libraries/qtopiamail/qmailstore_sparql.h -@@ -0,0 +1,530 @@ +@@ -0,0 +1,470 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. @@ -7243,7 +3947,6 @@ index 0000000..e7ec13a +#include "qmailstoreimplementation_p.h" +#include "sparqldatabase.h" + -+#include <QSqlDatabase> +#include <QCache> + +//#define QMAILSTORE_LOG_SQL //define to enable SQL query logging @@ -7255,7 +3958,8 @@ index 0000000..e7ec13a + +class ProcessMutex; +class ProcessReadLock; -+ ++class SparqlResult; ++class SparqlQuery; + +class QMailStorePrivate : public QMailStoreImplementation +{ @@ -7343,7 +4047,6 @@ index 0000000..e7ec13a + 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); @@ -7355,21 +4058,13 @@ index 0000000..e7ec13a + bool registerMessageStatusFlag(const QString &name); + quint64 messageStatusMask(const QString &name) const; + -+ QString buildOrderClause(const Key& key) const; -+ -+ QString buildWhereClause(const Key& key, bool nested = false, bool firstClause = true) const; -+ QVariantList whereClauseValues(const Key& key) const; -+ + static QString expandValueList(const QVariantList& valueList); + static QString expandValueList(int valueCount); + -+ static QString temporaryTableName(const QMailMessageKey &key); -+ + template<typename ValueType> + static ValueType extractValue(const QVariant& var, const ValueType &defaultValue = ValueType()); + +private: -+ friend class Transaction; + friend class ReadLock; + + enum AttemptResult { Success = 0, Failure, DatabaseFailure }; @@ -7388,59 +4083,15 @@ index 0000000..e7ec13a + bool containsProperty(const QMailMessageKey::Property& p, const QMailMessageKey& key) const; + bool containsProperty(const QMailMessageSortKey::Property& p, const QMailMessageSortKey& sortkey) const; + -+ QString expandProperties(const QMailMessageKey::Properties& p, bool update = false) const; -+ + int databaseIdentifier(int n) const; + -+ bool ensureVersionInfo(); -+ qint64 tableVersion(const QString &name) const; -+ bool setTableVersion(const QString &name, qint64 version); -+ -+ qint64 incrementTableVersion(const QString &name, qint64 current); -+ bool upgradeTableVersion(const QString &name, qint64 current, qint64 final); -+ -+ bool createTable(const QString &name); -+ -+ typedef QPair<QString, qint64> TableInfo; -+ bool setupTables(const QList<TableInfo> &tableList); -+ -+ typedef QPair<quint64, QString> FolderInfo; -+ bool setupFolders(const QList<FolderInfo> &folderList); -+ -+ void createTemporaryTable(const QMailMessageKey &key) const; -+ void destroyTemporaryTables(void); ++ bool setupStandardFolder(QMailFolder::StandardFolder folder, const QString& name); + -+ bool transaction(void); -+ bool commit(void); -+ void rollback(void); -+ -+ void setQueryError(const QSqlError&, const QString& description = QString(), const QString& statement = QString()); ++ void setQueryError(const SparqlQuery& query, const QString& description = QString()); ++ QString queryError() const; + void clearQueryError(void); + -+ QSqlQuery prepare(const QString& sql); -+ bool execute(QSqlQuery& q, bool batch = false); -+ int queryError(void) const; -+ -+ QSqlQuery performQuery(const QString& statement, bool batch, const QVariantList& bindValues, const QList<Key>& keys, const QString& descriptor); -+ -+ bool executeFile(QFile &file); -+ -+ QSqlQuery simpleQuery(const QString& statement, const QString& descriptor); -+ QSqlQuery simpleQuery(const QString& statement, const QVariantList& bindValues, const QString& descriptor); -+ -+ QSqlQuery simpleQuery(const QString& statement, const Key& key, const QString& descriptor); -+ QSqlQuery simpleQuery(const QString& statement, const QVariantList& bindValues, const Key& key, const QString& descriptor); -+ QSqlQuery simpleQuery(const QString& statement, const QVariantList& bindValues, const QList<Key>& keys, const QString& descriptor); -+ -+ QSqlQuery batchQuery(const QString& statement, const QVariantList& bindValues, const QString& descriptor); -+ QSqlQuery batchQuery(const QString& statement, const QVariantList& bindValues, const Key& key, const QString& descriptor); -+ QSqlQuery batchQuery(const QString& statement, const QVariantList& bindValues, const QList<Key>& keys, const QString& descriptor); -+ -+ bool idValueExists(quint64 id, const QString& table); -+ -+ bool idExists(const QMailAccountId& id, const QString& table = QString()); -+ bool idExists(const QMailFolderId& id, const QString& table = QString()); -+ bool idExists(const QMailMessageId& id, const QString& table = QString()); ++ bool uriExists(const QString& uri); + + bool checkPreconditions(const QMailFolder& folder, bool update = false); + @@ -7478,9 +4129,9 @@ index 0000000..e7ec13a + template<typename AccessType, typename FunctionType> + bool repeatedly(FunctionType func, const QString &description) const; + -+ AttemptResult addCustomFields(quint64 id, const QMap<QString, QString> &fields, const QString &tableName); -+ AttemptResult updateCustomFields(quint64 id, const QMap<QString, QString> &fields, const QString &tableName); -+ AttemptResult customFields(quint64 id, QMap<QString, QString> *fields, const QString &tableName); ++ 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, @@ -7587,7 +4238,7 @@ index 0000000..e7ec13a + QMailMessage *result, + ReadLock &); + -+ AttemptResult attemptMessagesMetaData(const QMailMessageKey& key, const QMailMessageKey::Properties &properties, QMailStore::ReturnOption option, ++ AttemptResult attemptMessagesMetaData(const QMailMessageKey& key, const QMailMessageKey::Properties &properties, QMailStore::ReturnOption option, + QMailMessageMetaDataList *result, + ReadLock &); + @@ -7614,11 +4265,10 @@ index 0000000..e7ec13a + AttemptResult attemptRegisterStatusBit(const QString &name, const QString &context, int maximum, + Transaction &t); + -+ QMailAccount extractAccount(const QSqlRecord& r); -+ QMailFolder extractFolder(const QSqlRecord& r); -+ QMailMessageMetaData extractMessageMetaData(const QSqlRecord& r, QMailMessageKey::Properties recordProperties, const QMailMessageKey::Properties& properties = allMessageProperties()); -+ QMailMessage extractMessage(const QSqlRecord& r, const QMap<QString, QString> &customFields, const QMailMessageKey::Properties& properties = allMessageProperties()); -+ QMailMessageRemovalRecord extractMessageRemovalRecord(const QSqlRecord& r); ++ 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); @@ -7629,8 +4279,6 @@ index 0000000..e7ec13a + static const int accountCacheSize = 10; + static const int lookAhead = 5; + -+ static QString parseSql(QTextStream& ts); -+ + 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); + @@ -7639,8 +4287,6 @@ index 0000000..e7ec13a + static QString messageFilePath(const QString &fileName); + static int pathIdentifier(const QString &filePath); + -+ static void extractMessageMetaData(const QSqlRecord& r, QMailMessageKey::Properties recordProperties, const QMailMessageKey::Properties& properties, QMailMessageMetaData* metaData); -+ +private: + template <typename T, typename ID> + class Cache @@ -7659,8 +4305,6 @@ index 0000000..e7ec13a + QCache<quint64,T> mCache; + }; + -+ mutable QSqlDatabase database; -+ + mutable QMailMessageIdList lastQueryMessageResult; + + mutable Cache<QMailMessageMetaData, QMailMessageId> headerCache; @@ -7672,7 +4316,7 @@ index 0000000..e7ec13a + QList<const QMailMessageKey*> expiredTableKeys; + + bool inTransaction; -+ mutable int lastQueryError; ++ mutable QString lastQueryError; + + ProcessMutex *mutex; + ProcessReadLock *readLock; @@ -7882,12 +4526,40 @@ index d63acdf..ce4b0a7 100644 } 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..7a56540 +index 0000000..b323449 --- /dev/null +++ b/src/libraries/sparql/sparql.pro -@@ -0,0 +1,31 @@ +@@ -0,0 +1,39 @@ +TEMPLATE = lib + +TARGET = sparql @@ -7897,13 +4569,18 @@ index 0000000..7a56540 +QT *= dbus + +# Input -+HEADERS += sparqldatabase.h \ -+ sparqlquery.h \ -+ sparqlresult.h \ -+ tracker/registertypes.h \ -+ tracker/resourcesproxy.h \ -+ sparqluri.h -+SOURCES += sparqldatabase.cpp \ ++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 \ @@ -7911,20 +4588,23 @@ index 0000000..7a56540 + sparqluri.cpp + +# Install headers -+headers.files = $$HEADERS include/* -+headers.path = $$QMF_INSTALL_ROOT/include/qmf ++sparql_headers.files = $$SPARQL_HEADERS include/* ++sparql_headers.path = $$QMF_INSTALL_ROOT/include/qmf + -+INSTALLS += headers ++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..dce2971 +index 0000000..7568a09 --- /dev/null +++ b/src/libraries/sparql/sparqldatabase.cpp -@@ -0,0 +1,31 @@ +@@ -0,0 +1,44 @@ +#include "sparqldatabase.h" + +#include <QDBusConnection> @@ -7934,7 +4614,8 @@ index 0000000..dce2971 + + +SparqlDatabase::SparqlDatabase(const QString& databaseName) : -+ _proxy(databaseName, "/org/freedesktop/Tracker/Resources", QDBusConnection::sessionBus()) ++ _proxy(databaseName, "/org/freedesktop/Tracker/Resources", QDBusConnection::sessionBus()), ++ _databaseName(databaseName) +{ + qDebug() << "SparqlDatabase::SparqlDatabase"; + if (!_defaultDatabase) @@ -7956,26 +4637,38 @@ index 0000000..dce2971 +{ + 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..5b8c246 +index 0000000..ab1d6b5 --- /dev/null +++ b/src/libraries/sparql/sparqldatabase.h -@@ -0,0 +1,44 @@ +@@ -0,0 +1,59 @@ +#ifndef SPARQLDATABASE_H +#define SPARQLDATABASE_H + +#include "tracker/resourcesproxy.h" + +/** -+ * @brief SparqlDatabase represents connection to the SPARQL data base. ++ * \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 ++ * \see SparqlQuery + */ +class SparqlDatabase +{ @@ -7983,35 +4676,50 @@ index 0000000..5b8c246 + +public: + /** -+ * @brief Creates new database ++ * \brief Creates new database + * -+ * @param databaseName Name of the data base. ++ * \param databaseName Name of the data base. + */ + SparqlDatabase(const QString& databaseName = "org.freedesktop.Tracker"); -+ /// Default destructor -+ ~SparqlDatabase(); + ++ /** ++ * \brief Default destructor ++ */ ++ ~SparqlDatabase(); + + /** -+ * @brief Returns default database ++ * \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..3241e07 +index 0000000..951c115 --- /dev/null +++ b/src/libraries/sparql/sparqlquery.cpp -@@ -0,0 +1,81 @@ +@@ -0,0 +1,86 @@ +#include "sparqlquery.h" +#include "sparqldatabase.h" +#include "sparqlresult.h" @@ -8093,12 +4801,17 @@ index 0000000..3241e07 +{ + 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..bca2387 +index 0000000..a030cfb --- /dev/null +++ b/src/libraries/sparql/sparqlquery.h -@@ -0,0 +1,84 @@ +@@ -0,0 +1,102 @@ +#ifndef SPARQLQUERY_H +#define SPARQLQUERY_H + @@ -8110,7 +4823,7 @@ index 0000000..bca2387 +class SparqlResult; + +/** -+ * @brief SparqlQuery represents SPARQL query. ++ * \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 @@ -8119,14 +4832,16 @@ index 0000000..bca2387 + * Database can be defeined explicitely or default database can be used. In anycase at least one SparqlDatabase + * object must be created. + * -+ * @see SparqlDatabase ++ * \see SparqlDatabase + */ +class SparqlQuery +{ + friend class SparqlResult; + +public: -+ /// Type of the query ++ /** ++ * \brief Type of the query ++ */ + enum QueryType + { + SearchQuery, ///< Query can use SELECT, CONSTRUCT, DESCRIBE or ASK SPARQL statments @@ -8134,22 +4849,29 @@ index 0000000..bca2387 + }; + + /** -+ * @brief Constructs SPARQL query ++ * \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. ++ * \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); + -+ /// Default destructor ++ /** ++ * \brief Default destructor ++ */ + ~SparqlQuery(); + -+ /// Prepare query for execution ++ /** ++ * \brief Prepare query for execution ++ * ++ * \param SPARQL query to prepare. ++ * \return Status of the application. ++ */ + bool prepare(const QString query); + + /** -+ * @brief Execute prepared 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 @@ -8158,20 +4880,29 @@ index 0000000..bca2387 + * 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. ++ * \return true in case of success and false in case of failure. + */ + bool exec(); + + /** -+ * @brief Returns result of the operation ++ * \brief Returns result of the operation + * -+ * @return result can be NULL in case of error or Update query was executed. ++ * \return result can be NULL in case of error or Update query was executed. + */ + SparqlResult result() const; + -+ /// Returns textual representation of the error. ++ /** ++ * \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; @@ -8222,10 +4953,10 @@ index 0000000..de7f2a0 +} diff --git a/src/libraries/sparql/sparqlresult.h b/src/libraries/sparql/sparqlresult.h new file mode 100644 -index 0000000..a6ce68e +index 0000000..2c9be91 --- /dev/null +++ b/src/libraries/sparql/sparqlresult.h -@@ -0,0 +1,46 @@ +@@ -0,0 +1,56 @@ +#ifndef SPARQLRESULT_H +#define SPARQLRESULT_H + @@ -8235,7 +4966,7 @@ index 0000000..a6ce68e +class SparqlQuery; + +/** -+ * @brief SparqlResult provides convenient way to fetch data from the executed query. ++ * \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(). @@ -8245,23 +4976,33 @@ index 0000000..a6ce68e + * to the query and you should not access any methods of this class in case of SparqlQuery + * was destroyed. + * -+ * @see SparqlQuery ++ * \see SparqlQuery + */ +class SparqlResult +{ + friend class SparqlQuery; + +public: -+ /// Fetch the row with results of the query ++ /** ++ * \brief Fetch the row with results of the query ++ * ++ * \return List of values of the row. ++ */ + const QStringList& fetchRow(); + -+ /// Does the result point to the beginig of data set ++ /** ++ * \brief Does the result point to the beginig of data set ++ */ + bool begin() const; + -+ /// Does the result point to the end of the data set ++ /** ++ * \brief Does the result point to the end of the data set ++ */ + bool end() const; + -+ /// Reset result and make it points to the begining again ++ /** ++ * \brief Reset result and make it points to the begining again ++ */ + void reset(); + +private: @@ -8274,37 +5015,13 @@ index 0000000..a6ce68e +#endif // SPARQLRESULT_H diff --git a/src/libraries/sparql/sparqluri.cpp b/src/libraries/sparql/sparqluri.cpp new file mode 100644 -index 0000000..2caa6d4 +index 0000000..6963010 --- /dev/null +++ b/src/libraries/sparql/sparqluri.cpp -@@ -0,0 +1,154 @@ -+/** -+ * \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 -+ */ -+ +@@ -0,0 +1,88 @@ +#include "sparqluri.h" -+ +#include <QUuid> + -+/** -+ * \brief Constructor of the URI -+ * -+ * Unique id will be autogenerated. -+ * -+ * \param base Fixed part of the URI. -+ */ +SparqlUri::SparqlUri(const QString& base) : + _id(generate()) +{ @@ -8312,14 +5029,6 @@ index 0000000..2caa6d4 + Q_ASSERT(ret); +} + -+/** -+ * \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::SparqlUri(const QString& base, quint64 id) : + _id(id) +{ @@ -8327,54 +5036,32 @@ index 0000000..2caa6d4 + Q_ASSERT(ret); +} + -+/** -+ * \brief Set new fixed base of the URI -+ */ +bool SparqlUri::setBase(const QString& base) +{ + _base = base; + return true; +} + -+/** -+ * \brief Get fixed base part of the URI -+ */ +QString SparqlUri::base() const +{ + return _base; +} + -+/** -+ * \brief Get current URI as a string -+ */ +QString SparqlUri::uri() const +{ -+ return base() + QString::number(_id); ++ return QString("<%1>").arg(base() + QString::number(_id)); +} + -+/** -+ * \brief Set current nnnnnn part as 64-bit integer -+ */ +void SparqlUri::setId(quint64 id) +{ + _id = id; +} + -+/** -+ * \brief Get current nnnnnn part as 64-bit integer -+ */ +quint64 SparqlUri::id() const +{ + return _id; +} + -+/** -+ * \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 SparqlUri::generate() +{ + /* @@ -8398,34 +5085,22 @@ index 0000000..2caa6d4 + return id; +} + -+/** -+ * \brief Convenience operator returns URI -+ */ +SparqlUri::operator QString () const +{ + return uri(); +} + -+/** -+ * \brief Convenience operator returns nnnnnn part of the URI -+ */ +SparqlUri::operator quint64 () const +{ + return id(); +} + -+/** -+ * \brief Generates new URI and returns new value -+ */ +QString SparqlUri::operator++ () +{ + _id = generate(); + return uri(); +} + -+/** -+ * \brief Generates new URI and returns old value -+ */ +QString SparqlUri::operator++ (int) +{ + QString result(uri()); @@ -8434,35 +5109,104 @@ index 0000000..2caa6d4 +} diff --git a/src/libraries/sparql/sparqluri.h b/src/libraries/sparql/sparqluri.h new file mode 100644 -index 0000000..21e0556 +index 0000000..44aeab1 --- /dev/null +++ b/src/libraries/sparql/sparqluri.h -@@ -0,0 +1,33 @@ +@@ -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: @@ -8713,7 +5457,7 @@ index 0000000..9d8f79d +</node> diff --git a/tools/sparql-import/main.cpp b/tools/sparql-import/main.cpp new file mode 100644 -index 0000000..86153dd +index 0000000..c8a8b28 --- /dev/null +++ b/tools/sparql-import/main.cpp @@ -0,0 +1,141 @@ @@ -8737,12 +5481,10 @@ index 0000000..86153dd + + QMailStore* sqlStore = QMailStore::instance(); + -+/* + qDebug() << sqlStore->countAccounts(); + qDebug() << sqlStore->countFolders(); + qDebug() << sqlStore->countMessages(); + -+ + qDebug() << "Number of accounts:" << sparqlStore.countAccounts(); + + QMailAccountIdList accountIdList = sparqlStore.queryAccounts(); @@ -8777,14 +5519,30 @@ index 0000000..86153dd + } + } + -+ */ ++ QMailFolderKey folderKey = QMailFolderKey::parentAccountId(QMailAccountId()); ++ QMailFolderIdList folderIdList = sparqlStore.queryFolders(folderKey); ++ ++ foreach (QMailFolderId folderId, folderIdList) ++ { ++ QMailFolder folder = sparqlStore.folder(folderId); ++ ++ QMailMessageKey messageKey = QMailMessageKey::parentFolderId(folderId); ++ ++ qDebug() << "Number of Messages (" << folder.displayName() << ")" << sparqlStore.countMessages(messageKey); ++ ++ QMailMessageIdList messageIdList = sparqlStore.queryMessages(messageKey); + -+ // Add standard folders -+ sparqlStore.setupStandardFolder(QMailFolder::InboxFolder, "Inbox"); -+ sparqlStore.setupStandardFolder(QMailFolder::OutboxFolder, "Outbox"); -+ sparqlStore.setupStandardFolder(QMailFolder::DraftsFolder, "Drafts"); -+ sparqlStore.setupStandardFolder(QMailFolder::SentFolder, "Sent"); -+ sparqlStore.setupStandardFolder(QMailFolder::TrashFolder, "Trash"); ++ foreach (QMailMessageId messageId, messageIdList) ++ { ++ QMailMessage message = sparqlStore.message(messageId); ++ ++ qDebug() << message.subject(); ++ } ++ ++ } ++ ++ ++ /* + + QMailAccountIdList accountIdList = sqlStore->queryAccounts(); + @@ -8802,12 +5560,7 @@ index 0000000..86153dd + { + QMailFolder folder(folderId); + -+ if (!(QMailFolder::InboxFolder <= folder.id().toULongLong()) || -+ !(folder.id().toULongLong() <= QMailFolder::TrashFolder)) -+ { -+ sparqlStore.addFolder(&folder); -+ } -+ folder.setParentAccountId(account.id()); ++ sparqlStore.addFolder(&folder); + + QMailMessageKey messageKey = QMailMessageKey::parentFolderId(folderId); + @@ -8817,9 +5570,6 @@ index 0000000..86153dd + { + QMailMessage message(messageId); + -+ message.setParentAccountId(account.id()); -+ message.setParentFolderId(folder.id()); -+ + sparqlStore.addMessage(&message); + } + } @@ -8833,11 +5583,7 @@ index 0000000..86153dd + { + QMailFolder folder(folderId); + -+ if (!(QMailFolder::InboxFolder <= folder.id().toULongLong()) || -+ !(folder.id().toULongLong() <= QMailFolder::TrashFolder)) -+ { -+ sparqlStore.addFolder(&folder); -+ } ++ sparqlStore.addFolder(&folder); + + QMailMessageKey messageKey = QMailMessageKey::parentFolderId(folderId); + @@ -8847,13 +5593,11 @@ index 0000000..86153dd + { + QMailMessage message(messageId); + -+ message.setParentFolderId(folder.id()); -+ + sparqlStore.addMessage(&message); + } + } + -+ //*/ ++ */ + return 0; +} + @@ -8889,10 +5633,10 @@ index 0000000..3429430 +INSTALLS += target diff --git a/tools/sparql-import/sparqlmailstore.cpp b/tools/sparql-import/sparqlmailstore.cpp new file mode 100644 -index 0000000..d1ad530 +index 0000000..b524f72 --- /dev/null +++ b/tools/sparql-import/sparqlmailstore.cpp -@@ -0,0 +1,1371 @@ +@@ -0,0 +1,1404 @@ +#include "sparqlmailstore.h" + +#include "sparqluri.h" @@ -8939,10 +5683,25 @@ index 0000000..d1ad530 + return qMakePair(unescape(uri.mid(0, index), ':'), unescape(uri.mid(index + 1), ':')); +} + -+namespace { -+ +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<1> MailMessageUri; ++typedef WellKnownUri<2> MailFolderUri; ++typedef WellKnownUri<3> MailAccountUri; ++ +QString combineOperatorString(QMailKey::Combiner op) +{ + switch (op) @@ -8969,7 +5728,7 @@ index 0000000..d1ad530 +{ + QStringList pattern; + for (int i = 0; i<argNumber; i++) -+ pattern << "(%1 " + op + " \"%" + QString::number(i+2) + "\")"; ++ pattern << "(%1 " + op + " %" + QString::number(i+2) + ")"; + + if (argNumber > 1) + return "(" + pattern.join(comp) + ")"; @@ -9588,11 +6347,11 @@ index 0000000..d1ad530 +QString argumentValue(const QVariant& value) +{ + if (qVariantCanConvert<QMailAccountId>(value)) -+ return QString::number(qVariantValue<QMailAccountId>(value).toULongLong()); ++ return MailAccountUri(qVariantValue<QMailAccountId>(value).toULongLong()); + else if (qVariantCanConvert<QMailFolderId>(value)) -+ return QString::number(qVariantValue<QMailFolderId>(value).toULongLong()); ++ return MailFolderUri(qVariantValue<QMailFolderId>(value).toULongLong()); + else if (qVariantCanConvert<QMailMessageId>(value)) -+ return QString::number(qVariantValue<QMailMessageId>(value).toULongLong()); ++ return MailMessageUri(qVariantValue<QMailMessageId>(value).toULongLong()); + else if (qVariantCanConvert<QString>(value)) + return qVariantValue<QString>(value); + else if (qVariantCanConvert<int>(value)) @@ -9658,11 +6417,19 @@ index 0000000..d1ad530 + QString query("SELECT ?mail \n" + "WHERE { \n" + "?mail rdf:type nmo:Email . \n" -+ "%1 \n" -+ "FILTER %2 \n" ++ "%1" ++ "%2" + "} %3\n"); + -+ return query.arg(keyStatment("?mail", key, sort), keyFilter(key), sortKey(sort)); ++ 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()) @@ -9670,11 +6437,19 @@ index 0000000..d1ad530 + QString query("SELECT ?folder \n" + "WHERE { \n" + "?folder rdf:type nmo:MailFolder . \n" -+ "%1 \n" -+ "FILTER %2 \n" ++ "%1" ++ "%2" + "} %3\n"); + -+ return query.arg(keyStatment("?folder", key, sort), keyFilter(key), sortKey(sort)); ++ 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()) @@ -9682,11 +6457,19 @@ index 0000000..d1ad530 + QString query("SELECT ?account \n" + "WHERE { \n" + "?account rdf:type nmo:Mailbox . \n" -+ "%1 \n" -+ "FILTER %2 \n" ++ "%1" ++ "%2" + "} %3\n"); + -+ return query.arg(keyStatment("?account", key, sort), keyFilter(key), sortKey(sort)); ++ 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) @@ -9694,11 +6477,19 @@ index 0000000..d1ad530 + QString query("SELECT COUNT(?mail) AS count \n" + "WHERE { \n" + "?mail rdf:type nmo:Email . \n" -+ "%1 \n" -+ "FILTER %2 \n" ++ "%1" ++ "%2" + "}\n"); + -+ return query.arg(keyStatment("?mail", key, QMailMessageSortKey()), keyFilter(key)); ++ 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) @@ -9706,11 +6497,19 @@ index 0000000..d1ad530 + QString query("SELECT COUNT(?folder) AS count \n" + "WHERE { \n" + "?folder rdf:type nmo:MailFolder . \n" -+ "%1 \n" -+ "FILTER %2 \n" ++ "%1" ++ "%2" + "}\n"); + -+ return query.arg(keyStatment("?folder", key, QMailFolderSortKey()), keyFilter(key)); ++ 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) @@ -9718,11 +6517,19 @@ index 0000000..d1ad530 + QString query("SELECT COUNT(?account) AS count \n" + "WHERE { \n" + "?account rdf:type nmo:Mailbox . \n" -+ "%1 \n" -+ "FILTER %2 \n" ++ "%1" ++ "%2" + "}\n"); + -+ return query.arg(keyStatment("?account", key, QMailAccountSortKey()), keyFilter(key)); ++ 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> @@ -9747,9 +6554,6 @@ index 0000000..d1ad530 + debugKey(subkey); +} + -+} // End namespace -+ -+ +QString nmoRecipients(const QList<QMailAddress>& recipients) +{ + QString result; @@ -9787,43 +6591,44 @@ index 0000000..d1ad530 + +void SparqlMailStore::addMessage(QMailMessageMetaData* metaData) +{ -+ SparqlUri uri("qmf://groove.harmattan.com/email#"); ++ 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 <qmf://groove.nokia.com/folder#%2> ;\n" -+ " nmo:sender [\n" -+ " rdf:type nco:Contact ;\n" -+ " nco:fullname \"%3\" ; \n" -+ " nco:hasEmailAddress <mailto:%4> ] ;\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 <qmf://groove.nokia.com/accounts#%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(uri.uri()) -+ .arg(metaData->parentFolderId().toULongLong()) ++ " 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(metaData->parentAccountId().toULongLong()) ++ .arg(parentAccountUri.uri()) + .arg(::contentUri(*metaData)) + .arg(metaData->serverUid()) + .arg(metaData->size()) @@ -9841,27 +6646,30 @@ index 0000000..d1ad530 + } + + qDebug() << "Query succeeded"; -+ metaData->setId(QMailMessageId(uri.id())); ++ metaData->setId(QMailMessageId(messageUri.id())); +} + +void SparqlMailStore::addFolder(QMailFolder* folder) +{ -+ SparqlUri uri("qmf://groove.nokia.com/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" ++ "%1 rdf:type nmo:MailFolder ; \n" + " nmo:folderName \"%2\" ; \n" -+ " nie:isLogicalPartOf <qmf://groove.nokia.com/folder#%3> ; \n" -+ " nie:relatedTo <qmf://groove.nokia.com/accounts#%4> ; \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(uri.uri()) ++ "}").arg(folderUri.uri()) + .arg(folder->path()) -+ .arg(folder->parentFolderId().toULongLong()) -+ .arg(folder->parentAccountId().toULongLong()) ++ .arg(parentFolderUri.uri()) ++ .arg(parentAccountUri.uri()) + .arg(folder->displayName()) + .arg(folder->status()) + .arg(folder->serverCount()) @@ -9876,25 +6684,25 @@ index 0000000..d1ad530 + } + + qDebug() << "Query succeeded"; -+ folder->setId(QMailFolderId(uri.id())); ++ folder->setId(QMailFolderId(folderUri.id())); + + // TBD: Update folder links also +} + +void SparqlMailStore::addAccount(QMailAccount* account) +{ -+ SparqlUri uri("qmf://groove.nokia.com/accounts#"); ++ MailAccountUri accountUri(account->id().toULongLong()); + SparqlQuery query(SparqlQuery::UpdateQuery); + query.prepare(QString( + "INSERT { \n" -+ "<%1> rdf:type nmo:Mailbox ; \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(uri.uri()) ++ "}").arg(accountUri.uri()) + .arg(account->name()) + .arg(account->status()) + .arg(account->signature()) @@ -9909,25 +6717,26 @@ index 0000000..d1ad530 + } + + qDebug() << "Query succeeded"; -+ account->setId(QMailAccountId(uri.id())); ++ 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" -+ "<qmf://groove.nokia.com/accounts#%1> rdf:type nmo:Mailbox ; \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(id.toULongLong())); ++ "}").arg(messageUri.uri())); + + if (!query.exec()) + { @@ -9952,11 +6761,12 @@ index 0000000..d1ad530 + +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" -+ "<qmf://groove.nokia.com/folder#%1> rdf:type nmo:MailFolder ; \n" ++ "%1 rdf:type nmo:MailFolder ; \n" + " nmo:folderName ?name ; \n" + " nie:isLogicalPartOf ?parentFolder ; \n" + " nie:relatedTo ?parentAccount ; \n" @@ -9964,7 +6774,7 @@ index 0000000..d1ad530 +// " nmo:status ?status ; \n" +// " nmo:serverCount ?serverCount ; \n" +// " nmo:serverUnreadCount ?serverUnreadCount . \n" -+ "}").arg(id.toULongLong())); ++ "}").arg(folderUri.uri())); + + if (!query.exec()) + { @@ -9990,16 +6800,17 @@ index 0000000..d1ad530 + +QMailMessage SparqlMailStore::message(const QMailMessageId& id) const +{ ++ MailMessageUri messageUri(id.toULongLong()); + SparqlQuery query(SparqlQuery::SearchQuery); + query.prepare(QString( + "SELECT ?fullName ?mailAddress \n" + "WHERE { \n" -+ "<qmf://groove.harmattan.com/email#%1> rdf:type nmo:Email ;\n" -+ "nmo:recipient [\n" -+ " rdf:type nco:Contact ;\n" -+ " nco:fullname ?fullName ; \n" -+ " nco:hasEmailAddress ?mailAddress ] \n" -+ "}").arg(id.toULongLong())); ++ "%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()) + { @@ -10019,29 +6830,29 @@ index 0000000..d1ad530 + query.prepare(QString( + "SELECT ?folderId ?senderFullName ?senderEmailAddress ?messageSubject ?sentDate ?status ?accountId ?dataSource ?uid ?contentSize ?mimeType ?inReplyTo ?headerValue ?receivedDate \n" + "WHERE { \n" -+ " <qmf://groove.harmattan.com/email#%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(id.toULongLong())); ++ "%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()) + { @@ -10129,7 +6940,6 @@ index 0000000..d1ad530 + return result.fetchRow().first().toInt(); +} + -+ +QMailAccountIdList SparqlMailStore::queryAccounts(const QMailAccountKey &key, const QMailAccountSortKey &sortKey) const +{ + QMailAccountIdList accountIdList; @@ -10231,45 +7041,12 @@ index 0000000..d1ad530 +{ + Q_UNUSED(account); +} -+ -+void SparqlMailStore::setupStandardFolder(QMailFolder::StandardFolder folder, const QString& name) -+{ -+ SparqlQuery query(SparqlQuery::UpdateQuery); -+ query.prepare(QString( -+ "INSERT { \n" -+ "<%1> rdf:type nmo:MailFolder ; \n" -+ " nmo:folderName \"%2\" ; \n" -+ " nie:isLogicalPartOf <qmf://groove.nokia.com/folder#%3> ; \n" -+ " nie:relatedTo <qmf://groove.nokia.com/accounts#%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("qmf://groove.nokia.com/folder#" + QString::number(folder)) -+ .arg(name) -+ .arg(0) -+ .arg(0) -+ .arg(name) -+ .arg(0) -+ .arg(0) -+ .arg(0)); -+ -+ // TBD: Add custom fields later -+ -+ if (!query.exec()) -+ { -+ qDebug() << "Query failed:" << query.error(); -+ return; -+ } -+ -+ qDebug() << "Query succeeded"; -+} diff --git a/tools/sparql-import/sparqlmailstore.h b/tools/sparql-import/sparqlmailstore.h new file mode 100644 -index 0000000..60f8b20 +index 0000000..9bcd838 --- /dev/null +++ b/tools/sparql-import/sparqlmailstore.h -@@ -0,0 +1,45 @@ +@@ -0,0 +1,42 @@ +#ifndef MAILSTORE_H +#define MAILSTORE_H + @@ -10309,9 +7086,6 @@ index 0000000..60f8b20 + void removeMessage(const QMailMessageMetaData& metaData); + void removeFolder(const QMailFolder& folder); + void removeAccount(const QMailAccount& account); -+ -+ void setupStandardFolder(QMailFolder::StandardFolder folder, const QString& name); -+ +}; + +#endif // MAILSTORE_H |