--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/messaging/qmessagestore_win.cpp Wed Aug 25 15:49:42 2010 +0300
@@ -0,0 +1,613 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qmessagemanager.h"
+#include "qmessagestore_p.h"
+#include "qmessage_p.h"
+#include "qmessageid_p.h"
+#include "qmessagefolderid_p.h"
+#include "qmessageaccountid_p.h"
+#include "qmessageaccount_p.h"
+#include "qmessagecontentcontainer.h"
+#include "winhelpers_p.h"
+#include <QCoreApplication>
+#include <QMutex>
+#include <qdebug.h>
+#include <QThread>
+
+QTM_BEGIN_NAMESPACE
+
+namespace {
+
+class MutexTryLocker
+{
+ QMutex *_mutex;
+ QString _location;
+
+public:
+ MutexTryLocker(QMutex *mutex)
+ : _mutex(0)
+ {
+ if (mutex->tryLock()) {
+ _mutex = mutex;
+ }
+ }
+
+ ~MutexTryLocker()
+ {
+ if (_mutex) {
+
+ _mutex->unlock();
+
+ QMessageManager::Error le = QMessageManager::NoError;
+ MapiSessionPtr p = MapiSession::createSession(&le);
+ if(le == QMessageManager::NoError)
+ p->flushNotifyQueue();
+
+ }
+ }
+
+ operator bool() const
+ {
+ return (_mutex != 0);
+ }
+};
+
+}
+
+class QMessageStorePrivatePlatform : public QObject
+{
+ Q_OBJECT
+
+public:
+ QMessageStorePrivatePlatform(QMessageStorePrivate *d, QMessageStore *q);
+ ~QMessageStorePrivatePlatform();
+
+ QMessageStorePrivate *d_ptr;
+ QMessageStore *q_ptr;
+ QMessageManager::Error error;
+
+ MapiSessionPtr session;
+ QMutex mutex;
+
+private slots:
+ void appDestroyed();
+};
+
+QMessageStorePrivatePlatform::QMessageStorePrivatePlatform(QMessageStorePrivate *d, QMessageStore *q)
+ :d_ptr(d),
+ q_ptr(q),
+ error(QMessageManager::NoError),
+ session(MapiSession::createSession(&error)),
+ mutex(QMutex::Recursive)
+{
+ connect(QCoreApplication::instance(), SIGNAL(destroyed()), this, SLOT(appDestroyed()));
+
+ if (session && (error == QMessageManager::NoError)) {
+ MapiSession *o(session.data());
+ connect(o, SIGNAL(messageAdded(QMessageId, QMessageManager::NotificationFilterIdSet)), q, SIGNAL(messageAdded(QMessageId, QMessageManager::NotificationFilterIdSet)));
+ connect(o, SIGNAL(messageRemoved(QMessageId, QMessageManager::NotificationFilterIdSet)), q, SIGNAL(messageRemoved(QMessageId, QMessageManager::NotificationFilterIdSet)));
+ connect(o, SIGNAL(messageUpdated(QMessageId, QMessageManager::NotificationFilterIdSet)), q, SIGNAL(messageUpdated(QMessageId, QMessageManager::NotificationFilterIdSet)));
+ }
+}
+
+QMessageStorePrivatePlatform::~QMessageStorePrivatePlatform()
+{
+}
+
+void QMessageStorePrivatePlatform::appDestroyed()
+{
+ // We need to terminate our session before main finishes
+ session.clear();
+}
+
+QMessageStorePrivate::QMessageStorePrivate()
+ :p_ptr(0),
+ q_ptr(0)
+{
+}
+
+QMessageStorePrivate::~QMessageStorePrivate()
+{
+ delete p_ptr;
+}
+
+void QMessageStorePrivate::initialize(QMessageStore *store)
+{
+ q_ptr = store;
+ p_ptr = new QMessageStorePrivatePlatform(this, store);
+}
+
+#ifdef Q_OS_WIN
+QMutex* QMessageStorePrivate::mutex(QMessageStore* store)
+{
+ return &(store->d_ptr->p_ptr->mutex);
+}
+
+QMutex* QMessageStorePrivate::mutex(QMessageManager& manager)
+{
+ return &(manager.store->d_ptr->p_ptr->mutex);
+}
+#endif
+
+Q_GLOBAL_STATIC(QMessageStorePrivate,data);
+
+QMessageStore::QMessageStore(QObject *parent)
+ : QObject(parent),
+ d_ptr(data())
+{
+ Q_ASSERT(d_ptr != 0);
+ Q_ASSERT(d_ptr->q_ptr == 0); // QMessageStore should be singleton
+}
+
+QMessageStore::~QMessageStore()
+{
+ d_ptr = 0; // should be cleaned up by automatically
+}
+
+QMessageStore* QMessageStore::instance()
+{
+ QMessageStorePrivate *d = data();
+ Q_ASSERT(d != 0);
+ if (!d->q_ptr) {
+ d->initialize(new QMessageStore());
+ }
+ return d->q_ptr;
+}
+
+QMessageManager::Error QMessageStore::error() const
+{
+ return d_ptr->p_ptr->error;
+}
+
+QMessageIdList QMessageStore::queryMessages(const QMessageFilter &filter, const QMessageSortOrder &sortOrder, uint limit, uint offset) const
+{
+ QMessageIdList result;
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ return result;
+ } else {
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+ result = d_ptr->p_ptr->session->queryMessages(&d_ptr->p_ptr->error, filter, sortOrder, limit, offset);
+ }
+
+ return result;
+}
+
+QMessageIdList QMessageStore::queryMessages(const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset) const
+{
+ QMessageIdList result;
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (matchFlags & QMessageDataComparator::MatchFullWord) {
+ d_ptr->p_ptr->error = QMessageManager::NotYetImplemented;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ return result;
+ } else {
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+ result = d_ptr->p_ptr->session->queryMessages(&d_ptr->p_ptr->error, filter, sortOrder, limit, offset, body, matchFlags);
+ }
+
+ return result;
+}
+
+QMessageFolderIdList QMessageStore::queryFolders(const QMessageFolderFilter &filter, const QMessageFolderSortOrder &sortOrder, uint limit, uint offset) const
+{
+ QMessageFolderIdList result;
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ return result;
+ }
+
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+ foreach (const MapiFolderPtr &folder, d_ptr->p_ptr->session->filterFolders(&d_ptr->p_ptr->error, filter, sortOrder, limit, offset)) {
+ result.append(folder->id());
+ }
+
+ return result;
+}
+
+QMessageAccountIdList QMessageStore::queryAccounts(const QMessageAccountFilter &filter, const QMessageAccountSortOrder &sortOrder, uint limit, uint offset) const
+{
+ QMessageAccountIdList result;
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ return result;
+ }
+
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+ foreach (const MapiStorePtr &store, d_ptr->p_ptr->session->filterStores(&d_ptr->p_ptr->error, filter, sortOrder, limit, offset)) {
+ result.append(store->id());
+ }
+
+ return result;
+}
+
+int QMessageStore::countMessages(const QMessageFilter& filter) const
+{
+ return queryMessages(filter).count();
+}
+
+int QMessageStore::countFolders(const QMessageFolderFilter& filter) const
+{
+ return queryFolders(filter).count();
+}
+
+int QMessageStore::countAccounts(const QMessageAccountFilter& filter) const
+{
+ return queryAccounts(filter).count();
+}
+
+bool QMessageStore::removeMessage(const QMessageId& id, QMessageManager::RemovalOption option)
+{
+ // TODO: implement option
+ Q_UNUSED(option)
+
+ bool result(false);
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ } else {
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+
+ QMessageIdList ids;
+ ids.append(id);
+ d_ptr->p_ptr->session->removeMessages(&d_ptr->p_ptr->error, ids);
+
+ result = (d_ptr->p_ptr->error == QMessageManager::NoError);
+ }
+
+ return result;
+}
+
+bool QMessageStore::removeMessages(const QMessageFilter& filter, QMessageManager::RemovalOption option)
+{
+ // TODO: implement option
+ Q_UNUSED(option)
+
+ bool result(false);
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ } else {
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+
+ QMessageIdList ids = queryMessages(filter, QMessageSortOrder(), 0, 0);
+ if (d_ptr->p_ptr->error == QMessageManager::NoError) {
+ d_ptr->p_ptr->session->removeMessages(&d_ptr->p_ptr->error, ids);
+ }
+
+ result = (d_ptr->p_ptr->error == QMessageManager::NoError);
+ }
+
+ return result;
+}
+
+bool QMessageStore::addMessage(QMessage *message)
+{
+ bool result(false);
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ return result;
+ } else {
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+ }
+
+ if (message && !message->id().isValid()) {
+ QMessageManager::Error* lError = &d_ptr->p_ptr->error;
+
+ MapiStorePtr mapiStore = d_ptr->p_ptr->session->findStore(lError,message->parentAccountId(),false);
+ if (*lError == QMessageManager::NoError && !mapiStore.isNull()) {
+
+ //check store/message type compatibility
+ if(!(mapiStore->types() & message->type()))
+ {
+ *lError = QMessageManager::ConstraintFailure;
+ return false;
+ }
+
+ MapiFolderPtr mapiFolder;
+
+ // Find the parent folder for this message
+ QMessageFolderId folderId(message->parentFolderId());
+ if (folderId.isValid()) {
+#ifdef _WIN32_WCE
+ mapiFolder = mapiStore->openFolder(lError,QMessageFolderIdPrivate::entryId(folderId));
+#else
+ mapiFolder = mapiStore->openFolderWithKey(lError, QMessageFolderIdPrivate::folderRecordKey(folderId));
+#endif
+ } else {
+ mapiFolder = mapiStore->findFolder(lError, message->standardFolder());
+ }
+
+ if (*lError == QMessageManager::NoError && !mapiFolder.isNull()) {
+ IMessage* mapiMessage = mapiFolder->createMessage(lError, *message, d_ptr->p_ptr->session);
+ if (*lError == QMessageManager::NoError) {
+ //set the new QMessageId
+ //we can only be guaranteed of an entry id after IMessage->SaveChanges has been called
+#ifdef _WIN32_WCE
+ SizedSPropTagArray(1, columns) = {1, {PR_ENTRYID}};
+#else
+ SizedSPropTagArray(2, columns) = {2, {PR_RECORD_KEY, PR_ENTRYID}};
+#endif
+ SPropValue *properties(0);
+ ULONG count;
+ HRESULT rv = mapiMessage->GetProps(reinterpret_cast<LPSPropTagArray>(&columns), 0, &count, &properties);
+#ifdef _WIN32_WCE
+ if (HR_SUCCEEDED(rv) && (properties[0].ulPropTag == PR_ENTRYID)) {
+#else
+ if (HR_SUCCEEDED(rv) && (properties[0].ulPropTag == PR_RECORD_KEY) && (properties[1].ulPropTag == PR_ENTRYID)) {
+#endif
+#ifdef _WIN32_WCE
+ MapiRecordKey recordKey;
+ MapiEntryId entryId(properties[0].Value.bin.lpb, properties[0].Value.bin.cb);
+ message->d_ptr->_id = QMessageIdPrivate::from(mapiFolder->storeEntryId(), entryId, recordKey, mapiFolder->entryId());
+#else
+ MapiRecordKey recordKey(properties[0].Value.bin.lpb, properties[0].Value.bin.cb);
+ MapiEntryId entryId(properties[1].Value.bin.lpb, properties[1].Value.bin.cb);
+ message->d_ptr->_id = QMessageIdPrivate::from(mapiFolder->storeKey(), entryId, recordKey, mapiFolder->recordKey());
+#endif
+ message->d_ptr->_modified = false;
+
+ MAPIFreeBuffer(properties);
+ } else {
+ qWarning() << "Unable to set the new ID in message.";
+ result = false;
+ }
+
+ mapiMessage->Release();
+ result = true;
+ } else {
+ qWarning() << "Cannot createMessage";
+ }
+ } else {
+ qWarning() << "Cannot get MAPI folder from store";
+ }
+ } else {
+ qWarning() << "Cannot get default store";
+ }
+ } else {
+ qWarning() << "Valid message ID at addition";
+ }
+ return result;
+}
+
+bool QMessageStore::updateMessage(QMessage *message)
+{
+ bool result(false);
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ return result;
+ } else {
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+ }
+
+ //check store/message type compatibility
+ if(MapiStorePtr mapiStore = d_ptr->p_ptr->session->findStore(&d_ptr->p_ptr->error,message->parentAccountId()))
+ {
+ if(!(mapiStore->types() & message->type()))
+ {
+ d_ptr->p_ptr->error = QMessageManager::ConstraintFailure;
+ return false;
+ }
+ }
+ else{
+ qWarning() << "Unable to retrieve MAPI store for message at update";
+ return false;
+ }
+
+
+ if (message && message->id().isValid()) {
+ QMessageManager::Error* lError = &d_ptr->p_ptr->error;
+
+ d_ptr->p_ptr->session->updateMessage(lError, *message);
+ if (*lError == QMessageManager::NoError) {
+ result = true;
+ } else {
+ qWarning() << "Cannot updateMessage";
+ }
+ } else {
+ qWarning() << "Invalid message ID at update";
+ }
+
+ return result;
+}
+
+QMessage QMessageStore::message(const QMessageId& id) const
+{
+ QMessage result;
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ return result;
+ } else {
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+ }
+
+ return d_ptr->p_ptr->session->message(&d_ptr->p_ptr->error, id);
+}
+
+QMessageFolder QMessageStore::folder(const QMessageFolderId& id) const
+{
+ QMessageFolder result;
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ return result;
+ } else {
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+ }
+
+ return d_ptr->p_ptr->session->folder(&d_ptr->p_ptr->error, id);
+}
+
+QMessageAccount QMessageStore::account(const QMessageAccountId& id) const
+{
+ QMessageAccount result;
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ return result;
+ } else {
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+ }
+
+ MapiStorePtr mapiStore(d_ptr->p_ptr->session->findStore(&d_ptr->p_ptr->error, id));
+ if (mapiStore && mapiStore->isValid()) {
+ result = QMessageAccountPrivate::from(mapiStore->id(), mapiStore->name(), mapiStore->address(), mapiStore->types());
+ }
+
+ return result;
+}
+
+QMessageManager::NotificationFilterId QMessageStore::registerNotificationFilter(const QMessageFilter &filter)
+{
+ QMessageManager::NotificationFilterId result(0);
+
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return result;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ return result;
+ } else {
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+ }
+
+ return d_ptr->p_ptr->session->registerNotificationFilter(&d_ptr->p_ptr->error, filter);
+}
+
+void QMessageStore::unregisterNotificationFilter(QMessageManager::NotificationFilterId notificationFilterId)
+{
+ MutexTryLocker locker(&d_ptr->p_ptr->mutex);
+ if (!locker) {
+ d_ptr->p_ptr->error = QMessageManager::Busy;
+ return;
+ }
+
+ if (!d_ptr->p_ptr->session) {
+ d_ptr->p_ptr->error = QMessageManager::ContentInaccessible;
+ } else {
+ d_ptr->p_ptr->error = QMessageManager::NoError;
+ d_ptr->p_ptr->session->unregisterNotificationFilter(&d_ptr->p_ptr->error, notificationFilterId);
+ }
+}
+
+#include "qmessagestore_win.moc"
+
+QTM_END_NAMESPACE