--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qtmobility/src/messaging/qmessageservice_win.cpp Fri Apr 16 15:51:22 2010 +0300
@@ -0,0 +1,1037 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmessageservice.h"
+#include "winhelpers_p.h"
+#include "qmessagemanager.h"
+#include "qmessageid_p.h"
+#include "qmessagefolderid_p.h"
+#include "qmessageaccountid_p.h"
+#include "qmessage_p.h"
+#include "qmessagestore_p.h"
+#include "qmessagecontentcontainer_p.h"
+#include "qmessagecontentcontainerid_p.h"
+#include <QDebug>
+#include <QThread>
+#include <QTimer>
+#include <mapix.h>
+#include <objbase.h>
+#include <mapiutil.h>
+#include <qmobilityglobal.h>
+#ifdef _WIN32_WCE
+#include <cemapi.h>
+#endif
+
+using namespace QtMobility::WinHelpers;
+
+QTM_BEGIN_NAMESPACE
+
+static const unsigned long SmsCharLimit = 160;
+
+class QMessageServicePrivate : public QObject
+{
+ Q_OBJECT
+
+ Q_DECLARE_PUBLIC(QMessageService)
+
+public:
+ QMessageServicePrivate(QMessageService* parent);
+ ~QMessageServicePrivate();
+
+ bool send(const QMessage& message, bool showComposer = false);
+ bool show(const QMessageId& id);
+#ifdef _WIN32_WCE
+ bool isPartiallyDownloaded(const QMessageId& id, bool considerAttachments = false);
+ bool markForDownload(const QMessageId& id, bool includeAttachments = false);
+ bool synchronize(const QMessageAccountId& id);
+ bool registerUpdates(const QMessageId& id);
+ void unregisterUpdates();
+ bool retrieveBody(const QMessage& partialMessage);
+#endif
+
+ void setFinished(bool successful);
+
+public slots:
+ void completed();
+ void reportMatchingIds();
+ void reportMessagesCounted();
+
+#ifdef _WIN32_WCE
+ void messageUpdated(const QMessageId& id);
+#endif
+
+signals:
+ void stateChanged(QMessageService::State);
+ void messagesFound(const QMessageIdList&);
+ void messagesCounted(int);
+ void progressChanged(uint, uint);
+
+public:
+ QMessageService* q_ptr;
+ QMessageManager _manager;
+ bool _active;
+ QMessageManager::Error _error;
+ QMessageIdList _candidateIds;
+ int _count;
+ QMessageService::State _state;
+ QMessageId m_bodyDownloadTarget;
+ QMessageManager::NotificationFilterId m_bodyDownloadFilterId;
+ bool m_registeredUpdates;
+ QThread *m_queryThread;
+ QList<QThread*> m_obsoleteThreads;
+};
+
+namespace {
+
+class QueryThread : public QThread
+{
+ Q_OBJECT
+
+ QMessageServicePrivate *_parent;
+ QMessageFilter _filter;
+ QString _body;
+ QMessageDataComparator::MatchFlags _matchFlags;
+ QMessageSortOrder _ordering;
+ uint _limit;
+ uint _offset;
+
+ // Ensure that the main thread has instantiated the store before we access it from another thread:
+ QMessageManager _manager;
+
+public:
+ QueryThread(QMessageServicePrivate *parent, const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset);
+ void run();
+
+signals:
+ void completed();
+};
+
+QueryThread::QueryThread(QMessageServicePrivate *parent, const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset)
+: QThread(),
+ _parent(parent),
+ _filter(filter),
+ _body(body),
+ _matchFlags(matchFlags),
+ _ordering(sortOrder),
+ _limit(limit),
+ _offset(offset)
+{
+}
+
+void QueryThread::run()
+{
+ // Ensure that this thread has initialized MAPI
+ WinHelpers::MapiInitializationToken token(WinHelpers::initializeMapi());
+
+ _parent->_candidateIds = _manager.queryMessages(_filter, _body, _matchFlags, _ordering, _limit, _offset);
+ _parent->_error = _manager.error();
+ emit completed();
+}
+
+}
+
+void QMessageServicePrivate::completed()
+{
+ _active = false;
+ _state = QMessageService::FinishedState;
+ emit stateChanged(_state);
+}
+
+void QMessageServicePrivate::reportMatchingIds()
+{
+ if (_error == QMessageManager::NoError) {
+ emit messagesFound(_candidateIds);
+ }
+
+ completed();
+}
+
+void QMessageServicePrivate::reportMessagesCounted()
+{
+ if (_error == QMessageManager::NoError) {
+ emit messagesCounted(_candidateIds.count());
+ }
+ completed();
+}
+
+#ifdef _WIN32_WCE
+void QMessageServicePrivate::messageUpdated(const QMessageId& id)
+{
+ if (id == m_bodyDownloadTarget) {
+ bool isBodyDownloaded = !isPartiallyDownloaded(id);
+ if (isBodyDownloaded) {
+ unregisterUpdates();
+
+ completed();
+ }
+ }
+}
+
+#endif
+
+QMessageServicePrivate::QMessageServicePrivate(QMessageService* parent)
+ :q_ptr(parent),
+ _active(false),
+ _state(QMessageService::InactiveState),
+ m_registeredUpdates(false),
+ m_queryThread(0)
+{
+}
+
+QMessageServicePrivate::~QMessageServicePrivate()
+{
+ qDeleteAll(m_obsoleteThreads);
+ delete m_queryThread;
+ _manager.unregisterNotificationFilter(m_bodyDownloadFilterId);
+}
+
+static Lptstr createMCFRecipients(QMessageAddress::Type filterAddressType, const QMessageAddressList& addressList)
+{
+ QStringList temp;
+
+ foreach(const QMessageAddress& a, addressList)
+ {
+ if(a.type() == filterAddressType)
+ temp.append(a.recipient());
+ }
+
+ return temp.isEmpty() ? Lptstr(0) : LptstrFromQString(temp.join(";"));
+}
+
+bool QMessageServicePrivate::send(const QMessage& message, bool showComposer)
+{
+ //check message type
+
+ if(message.type() == QMessage::AnyType || message.type() == QMessage::NoType)
+ {
+ qWarning() << "Unsupported message type for sending/composition";
+ _error = QMessageManager::ConstraintFailure;
+ return false;
+ }
+
+ //check account
+
+ QMessageAccountId accountId = message.parentAccountId();
+
+ if(!accountId.isValid())
+ {
+ accountId = QMessageAccount::defaultAccount(message.type());
+ if(!accountId.isValid())
+ {
+ qWarning() << "Invalid account for sending/composition";
+ _error = QMessageManager::InvalidId;
+ return false;
+ }
+ }
+
+ //check account/message type compatibility
+
+ QMessageAccount account(accountId);
+ if(!(account.messageTypes() & message.type()))
+ {
+ qWarning() << "Message type unsupported by account";
+ _error = QMessageManager::ConstraintFailure;
+ return false;
+ }
+
+#ifdef _WIN32_WCE
+ if(showComposer)
+ {
+ MAILCOMPOSEFIELDS mcf;
+ memset(&mcf,0,sizeof(mcf));
+
+ Lptstr accountName = LptstrFromQString(QMessageAccount(accountId).name());
+ Lptstr to;
+ Lptstr cc;
+ Lptstr bcc;
+ Lptstr subject;
+ Lptstr attachments;
+ Lptstr bodyText;
+
+ //account
+
+ mcf.pszAccount = accountName;
+ mcf.dwFlags = MCF_ACCOUNT_IS_NAME;
+
+ if(message.type() == QMessage::Email)
+ {
+ //recipients
+
+ to = createMCFRecipients(QMessageAddress::Email, message.to());
+ cc = createMCFRecipients(QMessageAddress::Email, message.cc());
+ bcc = createMCFRecipients(QMessageAddress::Email, message.bcc());
+ mcf.pszTo = to;
+ mcf.pszCc = cc;
+ mcf.pszBcc = bcc;
+
+ //subject
+
+ subject = LptstrFromQString(message.subject());
+ mcf.pszSubject = subject;
+
+ //body
+
+ QMessageContentContainerId bodyId = message.bodyId();
+ if(bodyId.isValid())
+ {
+ const QMessageContentContainer& bodyContainer = message.find(bodyId);
+ bodyText = LptstrFromQString(bodyContainer.textContent());
+ mcf.pszBody = bodyText;
+ }
+
+ //attachments
+
+ if(message.status() & QMessage::HasAttachments)
+ {
+ QStringList attachmentList;
+
+ foreach(const QMessageContentContainerId& id, message.attachmentIds())
+ {
+ const QMessageContentContainer& attachmentContainer = message.find(id);
+ attachmentList.append(QMessageContentContainerPrivate::attachmentFilename(attachmentContainer));
+ }
+
+ mcf.cAttachments = attachmentList.count();
+ QChar nullChar(0);
+ attachments = LptstrFromQString(attachmentList.join(nullChar));
+ mcf.pszAttachments = attachments;
+ }
+ }
+ else if(message.type() == QMessage::Sms)
+ {
+ //recipients
+
+ to = createMCFRecipients(QMessageAddress::Phone, message.to());
+ mcf.pszTo = to;
+
+ //body
+
+ QMessageContentContainerId bodyId = message.bodyId();
+ if(bodyId.isValid())
+ {
+ const QMessageContentContainer& bodyContainer = message.find(bodyId);
+ QString textContent = bodyContainer.textContent();
+ if(textContent.length() > SmsCharLimit)
+ {
+ textContent.truncate(SmsCharLimit);
+ qWarning() << "SMS messages may not exceed " << SmsCharLimit << " characters. Body trucated.";
+ }
+ bodyText = LptstrFromQString(textContent);
+ mcf.pszBody = bodyText;
+ }
+ }
+
+ mcf.cbSize = sizeof(mcf);
+
+ if(FAILED(MailComposeMessage(&mcf)))
+ {
+ _error = QMessageManager::FrameworkFault;
+ qWarning() << "MailComposeMessage failed";
+ return false;
+ }
+ }
+ else
+ {
+#endif
+
+ //check recipients
+ QMessageAddressList recipients = message.to() + message.bcc() + message.cc();
+ if(recipients.isEmpty() && !showComposer)
+ {
+ qWarning() << "Message must have recipients for sending";
+ _error = QMessageManager::ConstraintFailure;
+ return false;
+ }
+
+ MapiSessionPtr mapiSession(MapiSession::createSession(&_error));
+ if (_error != QMessageManager::NoError)
+ {
+ qWarning() << "Could not create MAPI session for sending";
+ return false;
+ }
+
+ QMessage outgoing(message);
+
+ //ensure the message is marked read otherwise MapiForm displays the message as incomming
+ outgoing.setStatus(QMessage::Read,true);
+
+ //set default account if unset
+ if(!outgoing.parentAccountId().isValid())
+ outgoing.setParentAccountId(accountId);
+
+ MapiStorePtr mapiStore = mapiSession->findStore(&_error, outgoing.parentAccountId(),false);
+
+ if(mapiStore.isNull() || _error != QMessageManager::NoError)
+ {
+ qWarning() << "Unable to retrieve MAPI store for account";
+ return false;
+ }
+
+ //try first to create message in outbox for store, failing that attempt draft
+
+ MapiFolderPtr mapiFolder = mapiStore->findFolder(&_error,QMessage::OutboxFolder);
+
+ if( mapiFolder.isNull() || _error != QMessageManager::NoError ) {
+ qWarning() << "Unable to retrieve outbox MAPI folder for sending, attempting drafts...";
+ mapiFolder = mapiStore->findFolder(&_error,QMessage::DraftsFolder);
+ if(mapiFolder.isNull() || _error != QMessageManager::NoError) {
+ qWarning() << "Unable to retrieve drafts MAPI folder for sending";
+ return false;
+ }
+ }
+
+ IMessage* mapiMessage = mapiFolder->createMessage(&_error, outgoing, mapiSession, DontSavePropertyChanges);
+
+ if(!mapiMessage || _error != QMessageManager::NoError)
+ {
+ qWarning() << "Unable to create MAPI message from source";
+ mapiRelease(mapiMessage);
+ return false;
+ }
+
+#ifndef _WIN32_WCE
+ if(showComposer)
+ {
+ MapiForm* mapiForm = new MapiForm(mapiStore->store(),mapiSession->session(),mapiFolder->folder(),mapiMessage);
+ bool result = mapiForm->show();
+ mapiRelease(mapiForm);
+
+ if(!result)
+ {
+ qWarning() << "MapiForm::Show failed";
+ _error = QMessageManager::FrameworkFault;
+ return false;
+ }
+ }
+ else
+#endif
+ {
+ if(FAILED(mapiMessage->SubmitMessage(0)))
+ {
+ qWarning() << "MAPI SubmitMessage failed.";
+ _error = QMessageManager::FrameworkFault;
+ mapiRelease(mapiMessage);
+ return false;
+ }
+ }
+
+#ifdef _WIN32_WCE
+ }
+#endif
+
+ return true;
+}
+
+bool QMessageServicePrivate::show(const QMessageId& messageId)
+{
+ if(!messageId.isValid())
+ {
+ _error = QMessageManager::InvalidId;
+ qWarning() << "Invalid QMessageId";
+ return false;
+ }
+
+#ifdef _WIN32_WCE
+ MapiEntryId entryId = QMessageIdPrivate::entryId(messageId);
+ LPENTRYID entryIdPtr(reinterpret_cast<LPENTRYID>(const_cast<char*>(entryId.data())));
+ if(FAILED(MailDisplayMessage(entryIdPtr,entryId.length())))
+ {
+ qWarning() << "MailDisplayMessage failed";
+ _error = QMessageManager::FrameworkFault;
+ return false;
+ }
+ return true;
+
+#else
+
+ MapiSessionPtr mapiSession(MapiSession::createSession(&_error));
+ if (_error != QMessageManager::NoError)
+ {
+ qWarning() << "Could not create MAPI seesion";
+ return false;
+ }
+
+ MapiEntryId entryId = QMessageIdPrivate::entryId(messageId);
+ MapiRecordKey folderRecordKey = QMessageIdPrivate::folderRecordKey(messageId);
+ MapiRecordKey storeRecordKey = QMessageIdPrivate::storeRecordKey(messageId);
+
+ MapiStorePtr mapiStore = mapiSession->findStore(&_error,QMessageAccountIdPrivate::from(storeRecordKey));
+
+ if(mapiStore.isNull() || _error != QMessageManager::NoError)
+ {
+ qWarning() << "Unable to retrieve MAPI store for account";
+ return false;
+ }
+
+ MapiFolderPtr mapiFolder = mapiStore->openFolderWithKey(&_error,folderRecordKey);
+
+ if( mapiFolder.isNull() || _error != QMessageManager::NoError ) {
+ qWarning() << "Unable to retrieve MAPI folder for message";
+ return false;
+ }
+
+ IMessage* mapiMessage = mapiFolder->openMessage(&_error,entryId);
+
+ if(!mapiMessage || _error != QMessageManager::NoError)
+ {
+ qWarning() << "Unable to retrieve MAPI message";
+ mapiRelease(mapiMessage);
+ return false;
+ }
+
+ MapiForm* mapiForm = new MapiForm(mapiStore->store(),mapiSession->session(),mapiFolder->folder(),mapiMessage);
+ bool result = mapiForm->show();
+ mapiRelease(mapiForm);
+
+ if(!result)
+ {
+ qWarning() << "MapiForm::show failed.";
+ _error = QMessageManager::FrameworkFault;
+ return false;
+ }
+
+ mapiRelease(mapiMessage);
+
+ return result;
+
+#endif
+}
+
+#ifdef _WIN32_WCE
+
+bool QMessageServicePrivate::isPartiallyDownloaded(const QMessageId& id, bool considerAttachments)
+{
+ if(!id.isValid())
+ {
+ _error = QMessageManager::InvalidId;
+ qWarning() << "Invalid QMessageId";
+ return false;
+ }
+
+ MapiSessionPtr mapiSession(MapiSession::createSession(&_error));
+
+ if (_error != QMessageManager::NoError)
+ {
+ qWarning() << "Could not create MAPI session";
+ return false;
+ }
+
+ MapiStorePtr mapiStore = mapiSession->openStore(&_error,QMessageIdPrivate::storeRecordKey(id));
+
+ if(mapiStore.isNull() || _error != QMessageManager::NoError) {
+ qWarning() << "Unable to retrieve MAPI store for account";
+ return false;
+ }
+
+ IMessage* message = mapiStore->openMessage(&_error,QMessageIdPrivate::entryId(id));
+
+ ULONG status = 0;
+ if(!getMapiProperty(message,PR_MSG_STATUS,&status)) {
+ qWarning() << "Unable to get MAPI message status flags";
+ _error = QMessageManager::FrameworkFault;
+ return false;
+ }
+ else
+ {
+ mapiRelease(message);
+ bool bodyNotDownloaded = (status & MSGSTATUS_HEADERONLY) || (status & MSGSTATUS_PARTIAL);
+ bool attachmentsNotDownloaded = (status & MSGSTATUS_PENDING_ATTACHMENTS);
+ return considerAttachments ? bodyNotDownloaded && attachmentsNotDownloaded : bodyNotDownloaded;
+ }
+}
+
+bool QMessageServicePrivate::markForDownload(const QMessageId& id, bool includeAttachments)
+{
+ if(!id.isValid())
+ {
+ _error = QMessageManager::InvalidId;
+ qWarning() << "Invalid QMessageId";
+ return false;
+ }
+
+ MapiSessionPtr mapiSession(MapiSession::createSession(&_error));
+
+ if (_error != QMessageManager::NoError)
+ {
+ qWarning() << "Could not create MAPI session";
+ return false;
+ }
+
+ MapiStorePtr mapiStore = mapiSession->openStore(&_error,QMessageIdPrivate::storeRecordKey(id));
+
+ if(mapiStore.isNull() || _error != QMessageManager::NoError)
+ {
+ qWarning() << "Unable to retrieve MAPI store for message account";
+ return false;
+ }
+
+ IMessage* message = mapiStore->openMessage(&_error,QMessageIdPrivate::entryId(id));
+
+ ULONG status = 0;
+
+ if(!getMapiProperty(message,PR_MSG_STATUS,&status))
+ {
+ qWarning() << "Unable to get MAPI message status flags";
+ _error = QMessageManager::FrameworkFault;
+ return false;
+ }
+ else
+ {
+ //mark the message to download on the next sync
+
+ status |= MSGSTATUS_REMOTE_DOWNLOAD;
+ if(includeAttachments)
+ status |= MSGSTATUS_REMOTE_DOWNLOAD_ATTACH;
+
+ if(!setMapiProperty(message, PR_MSG_STATUS, status))
+ {
+ qWarning() << "Could not mark the MAPI message for download!";
+ _error = QMessageManager::FrameworkFault;
+ return false;
+ }
+
+ mapiRelease(message);
+
+ //TODO investigate possiblity of interacting with mapi transport directly
+ /*
+ QString transportName = mapiStore->transportName();
+ if(transportName.isEmpty())
+ {
+ qWarning() << "Could not get transport name for mapi store";
+ return false;
+ }
+ */
+ }
+ return true;
+}
+
+bool QMessageServicePrivate::synchronize(const QMessageAccountId& id)
+{
+ if(!id.isValid())
+ {
+ qWarning() << "Cannot synchronize invalid QMessageAccountId";
+ _error = QMessageManager::InvalidId;
+ return false;
+ }
+
+ QMessageAccount account(id);
+ if(FAILED(MailSyncMessages(LptstrFromQString(account.name()),MCF_ACCOUNT_IS_NAME | MCF_RUN_IN_BACKGROUND)))
+ {
+ qWarning() << "MailSyncMessages failed for account: " << account.name();
+ _error = QMessageManager::FrameworkFault;
+ return false;
+ }
+ return true;
+}
+
+bool QMessageServicePrivate::registerUpdates(const QMessageId& id)
+{
+ if(!id.isValid())
+ {
+ qWarning() << "Cannot register for update notifications on invalid QMessageId";
+ _error = QMessageManager::InvalidId;
+ return false;
+ }
+
+ if(!m_registeredUpdates)
+ {
+ connect(&_manager, SIGNAL(messageUpdated(const QMessageId&, const QMessageManager::NotificationFilterIdSet&)),this,SLOT(messageUpdated(const QMessageId&)));
+ m_bodyDownloadFilterId = _manager.registerNotificationFilter(QMessageFilter::byId(id));
+ m_bodyDownloadTarget = id;
+ m_registeredUpdates = true;
+ }
+ return m_registeredUpdates;
+}
+
+void QMessageServicePrivate::unregisterUpdates()
+{
+ disconnect(&_manager, SIGNAL(messageUpdated(const QMessageId&, const QMessageManager::NotificationFilterIdSet&)),this,SLOT(messageUpdated(const QMessageId&)));
+ _manager.unregisterNotificationFilter(m_bodyDownloadFilterId);
+ m_bodyDownloadFilterId = 0;
+ m_registeredUpdates = false;
+}
+
+bool QMessageServicePrivate::retrieveBody(const QMessage& partialMessage)
+{
+ if(partialMessage.type() != QMessage::Email)
+ {
+ qWarning() << "Cannot retrieve body for non-email message type";
+ _error = QMessageManager::ConstraintFailure;
+ return false;
+ }
+
+ if(isPartiallyDownloaded(partialMessage.id()))
+ {
+ //only valid for Email
+ if(markForDownload(partialMessage.id(),true))
+ if(registerUpdates(partialMessage.id()))
+ if(!synchronize(partialMessage.parentAccountId()))
+ unregisterUpdates();
+ }
+ else QTimer::singleShot(0,this,SLOT(completed()));
+
+ return (_error == QMessageManager::NoError);
+}
+
+#endif
+
+void QMessageServicePrivate::setFinished(bool successful)
+{
+ if (!successful && (_error == QMessageManager::NoError)) {
+ _error = QMessageManager::RequestIncomplete;
+ }
+
+ completed();
+}
+
+QMessageService::QMessageService(QObject *parent)
+ : QObject(parent),
+ d_ptr(new QMessageServicePrivate(this))
+{
+ connect(d_ptr, SIGNAL(stateChanged(QMessageService::State)),
+ this, SIGNAL(stateChanged(QMessageService::State)));
+ connect(d_ptr, SIGNAL(messagesFound(const QMessageIdList&)),
+ this, SIGNAL(messagesFound(const QMessageIdList&)));
+ connect(d_ptr, SIGNAL(messagesCounted(int)),
+ this, SIGNAL(messagesCounted(int)));
+ connect(d_ptr, SIGNAL(progressChanged(uint, uint)),
+ this, SIGNAL(progressChanged(uint, uint)));
+}
+
+QMessageService::~QMessageService()
+{
+ delete d_ptr;
+ d_ptr = 0;
+}
+
+bool QMessageService::queryMessages(const QMessageFilter &filter, const QMessageSortOrder &sortOrder, uint limit, uint offset)
+{
+ return queryMessages(filter, QString(), QMessageDataComparator::MatchFlags(), sortOrder, limit, offset);
+}
+
+bool QMessageService::queryMessages(const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset)
+{
+ if (d_ptr->_active) {
+ qWarning() << "Service is currently busy";
+ return false;
+ }
+
+
+ d_ptr->_active = true;
+ d_ptr->_error = QMessageManager::NoError;
+ d_ptr->_state = QMessageService::ActiveState;
+ emit stateChanged(d_ptr->_state);
+
+#if 0
+ d_ptr->_candidateIds = d_ptr->_manager.queryMessages(filter, body, matchFlags, sortOrder, limit, offset);
+ d_ptr->_error = d_ptr->_manager.error();
+ QTimer::singleShot(0,d_ptr,SLOT(reportMatchingIds()));
+#else
+ // Perform the query in another thread to keep the UI thread free
+ QueryThread *query = new QueryThread(d_ptr, filter, body, matchFlags, sortOrder, limit, offset);
+ connect(query, SIGNAL(completed()), d_ptr, SLOT(reportMatchingIds()), Qt::QueuedConnection);
+ query->start();
+
+ if (d_ptr->m_queryThread) {
+ // Don't delete the previous thread object immediately
+ if (!d_ptr->m_obsoleteThreads.isEmpty()) {
+ qDeleteAll(d_ptr->m_obsoleteThreads);
+ d_ptr->m_obsoleteThreads.clear();
+ }
+ d_ptr->m_obsoleteThreads.append(d_ptr->m_queryThread);
+ }
+ d_ptr->m_queryThread = query;
+#endif
+ return true;
+}
+
+bool QMessageService::countMessages(const QMessageFilter &filter)
+{
+ if (d_ptr->_active) {
+ qWarning() << "Service is currently busy";
+ return false;
+ }
+ d_ptr->_active = true;
+ d_ptr->_error = QMessageManager::NoError;
+ d_ptr->_state = QMessageService::ActiveState;
+ emit stateChanged(d_ptr->_state);
+
+ // Perform the query in another thread to keep the UI thread free
+ QueryThread *query = new QueryThread(d_ptr, filter, QString(), QMessageDataComparator::MatchFlags(), QMessageSortOrder(), 0, 0);
+ connect(query, SIGNAL(completed()), d_ptr, SLOT(reportMessagesCounted()), Qt::QueuedConnection);
+ query->start();
+
+ if (d_ptr->m_queryThread) {
+ // Don't delete the previous thread object immediately
+ if (!d_ptr->m_obsoleteThreads.isEmpty()) {
+ qDeleteAll(d_ptr->m_obsoleteThreads);
+ }
+ d_ptr->m_obsoleteThreads.append(d_ptr->m_queryThread);
+ }
+ d_ptr->m_queryThread = query;
+
+ return true;
+}
+
+bool QMessageService::send(QMessage &message)
+{
+ if(d_ptr->_active) {
+ qWarning() << "Service is currently busy";
+ return false;
+ }
+
+ d_ptr->_active = true;
+ d_ptr->_state = QMessageService::ActiveState;
+ d_ptr->_error = QMessageManager::NoError;
+ emit stateChanged(d_ptr->_state);
+
+ bool result = d_ptr->send(message);
+ d_ptr->setFinished(result);
+
+ return result;
+}
+
+bool QMessageService::compose(const QMessage &message)
+{
+ if(d_ptr->_active) {
+ qWarning() << "Service is currently busy";
+ return false;
+ }
+
+ d_ptr->_active = true;
+ d_ptr->_state = QMessageService::ActiveState;
+ d_ptr->_error = QMessageManager::NoError;
+ emit stateChanged(d_ptr->_state);
+
+ bool result = d_ptr->send(message,true);
+ d_ptr->setFinished(result);
+
+ return result;
+}
+
+bool QMessageService::retrieveHeader(const QMessageId& id)
+{
+ Q_UNUSED(id);
+
+ if(d_ptr->_active) {
+ qWarning() << "Service is currently busy";
+ return false;
+ }
+
+ d_ptr->_error = QMessageManager::NoError;
+ d_ptr->setFinished(true);
+
+ return true;
+}
+
+bool QMessageService::retrieveBody(const QMessageId& id)
+{
+
+ if(d_ptr->_active) {
+ qWarning() << "Service is currently busy";
+ return false;
+ }
+
+#ifdef _WIN32_WCE
+
+ d_ptr->_active = true;
+ d_ptr->_state = ActiveState;
+ d_ptr->_error = QMessageManager::NoError;
+ emit stateChanged(d_ptr->_state);
+
+ if(!id.isValid())
+ {
+ qWarning() << "Invalid QMessageId";
+ d_ptr->_error = QMessageManager::InvalidId;
+ }
+
+ QMessage message;
+
+ if(d_ptr->_error == QMessageManager::NoError)
+ {
+ message = QMessage(id);
+ d_ptr->_error = QMessageManager().error();
+ }
+
+
+ if(d_ptr->_error == QMessageManager::NoError)
+ d_ptr->retrieveBody(message);
+
+ //emit failure immediately
+ if (d_ptr->_error != QMessageManager::NoError) {
+ d_ptr->setFinished(false);
+ return false;
+ }
+
+ return true;
+
+#else
+ Q_UNUSED(id);
+
+ d_ptr->_error = QMessageManager::NotYetImplemented;
+ d_ptr->setFinished(false);
+ return false;
+#endif
+}
+
+bool QMessageService::retrieve(const QMessageId& messageId, const QMessageContentContainerId& id)
+{
+
+ if(d_ptr->_active) {
+ qWarning() << "Service is currently busy";
+ return false;
+ }
+
+#ifdef _WIN32_WCE
+
+ d_ptr->_active = true;
+ d_ptr->_state = ActiveState;
+ d_ptr->_error = QMessageManager::NoError;
+ emit stateChanged(d_ptr->_state);
+
+ if(!messageId.isValid())
+ {
+ qWarning() << "Invalid QMessageId";
+ d_ptr->_error = QMessageManager::InvalidId;
+ }
+
+ QMessage message;
+
+ if(d_ptr->_error == QMessageManager::NoError)
+ {
+ message = QMessage(messageId);
+ d_ptr->_error = d_ptr->_manager.error();
+ }
+
+ if(d_ptr->_error == QMessageManager::NoError)
+ {
+ bool isBodyContainer = message.bodyId() == id;
+ if(isBodyContainer)
+ d_ptr->retrieveBody(message);
+ //TODO downloading attachment programatically possible?
+ }
+
+ //emit failure immediately
+ if (d_ptr->_error != QMessageManager::NoError) {
+ d_ptr->setFinished(false);
+ return false;
+ }
+
+ return true;
+
+#else
+ Q_UNUSED(messageId)
+ Q_UNUSED(id)
+
+ d_ptr->_error = QMessageManager::NotYetImplemented;
+ d_ptr->setFinished(false);
+#endif
+
+ return false;
+}
+
+bool QMessageService::show(const QMessageId& id)
+{
+ if(d_ptr->_active) {
+ qWarning() << "Service is currently busy";
+ return false;
+ }
+
+ d_ptr->_active = true;
+ d_ptr->_state = ActiveState;
+ d_ptr->_error = QMessageManager::NoError;
+ emit stateChanged(d_ptr->_state);
+
+ bool result = d_ptr->show(id);
+ d_ptr->setFinished(result);
+
+ return result;
+}
+
+bool QMessageService::exportUpdates(const QMessageAccountId &id)
+{
+ Q_UNUSED(id);
+
+ if(d_ptr->_active) {
+ qWarning() << "Service is currently busy";
+ return false;
+ }
+
+ d_ptr->_error = QMessageManager::NotYetImplemented;
+ d_ptr->setFinished(false);
+
+ return false;
+}
+
+QMessageService::State QMessageService::state() const
+{
+ return d_ptr->_state;
+}
+
+void QMessageService::cancel()
+{
+#ifdef _WIN32_WCE
+ if(d_ptr->_active)
+ {
+ bool awaitingBodyRetrieval(d_ptr->m_bodyDownloadFilterId != 0);
+
+ if(awaitingBodyRetrieval)
+ {
+ d_ptr->unregisterUpdates();
+ d_ptr->_error = QMessageManager::NoError;
+ d_ptr->_state = QMessageService::InactiveState;
+ d_ptr->_active = false;
+ emit stateChanged(d_ptr->_state);
+ }
+ }
+#else
+ //NOOP
+#endif
+}
+
+QMessageManager::Error QMessageService::error() const
+{
+ return d_ptr->_error;
+}
+
+#include <qmessageservice_win.moc>
+
+QTM_END_NAMESPACE