--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/messaging/qmessageservice_qmf.cpp Wed Aug 25 15:49:42 2010 +0300
@@ -0,0 +1,611 @@
+/****************************************************************************
+**
+** 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 "qmessageservice.h"
+#include "qmfhelpers_p.h"
+
+#include <qmailserviceaction.h>
+
+#include <QTimer>
+#include <qmessage_p.h>
+
+
+QTM_BEGIN_NAMESPACE
+
+namespace {
+
+struct TextPartSearcher
+{
+ QString _search;
+
+ TextPartSearcher(const QString &searchText) : _search(searchText) {}
+
+ bool operator()(const QMailMessagePart &part)
+ {
+ if (part.contentType().type().toLower() == "text") {
+ if (part.body().data().contains(_search, Qt::CaseInsensitive)) {
+ // We have located some matching text - stop the traversal
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
+}
+
+using namespace QmfHelpers;
+
+class QMessageServicePrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ QMessageServicePrivate();
+
+ QMailTransmitAction _transmit;
+ QMailRetrievalAction _retrieval;
+ QMailServiceAction *_active;
+ QMessageManager::Error _error;
+ bool _activeStoreAction;
+
+ QList<QMessageId> _matchingIds;
+ QList<QMailMessageId> _candidateIds;
+ QMessageFilter _lastFilter;
+ QMessageSortOrder _lastOrdering;
+ QString _match;
+ int _limit;
+ int _offset;
+
+ QMailMessageIdList _transmitIds;
+
+ bool isBusy() const;
+
+signals:
+ void stateChanged(QMessageService::State);
+ void progressChanged(uint, uint);
+ void messagesFound(const QMessageIdList&);
+ void messagesCounted(int);
+
+protected slots:
+ void transmitActivityChanged(QMailServiceAction::Activity a);
+ void retrievalActivityChanged(QMailServiceAction::Activity a);
+ void statusChanged(const QMailServiceAction::Status &s);
+ void completed();
+ void reportMatchingIds();
+ void reportMatchingCount();
+ void findMatchingIds();
+ void testNextMessage();
+
+private:
+ bool messageMatch(const QMailMessageId &messageid);
+};
+
+QMessageServicePrivate::QMessageServicePrivate()
+ : QObject(),
+ _active(0),
+ _error(QMessageManager::NoError),
+ _activeStoreAction(false),
+ _limit(0),
+ _offset(0)
+{
+ connect(&_transmit, SIGNAL(activityChanged(QMailServiceAction::Activity)), this, SLOT(transmitActivityChanged(QMailServiceAction::Activity)));
+ connect(&_transmit, SIGNAL(statusChanged(QMailServiceAction::Status)), this, SLOT(statusChanged(QMailServiceAction::Status)));
+
+ connect(&_retrieval, SIGNAL(activityChanged(QMailServiceAction::Activity)), this, SLOT(retrievalActivityChanged(QMailServiceAction::Activity)));
+ connect(&_retrieval, SIGNAL(statusChanged(QMailServiceAction::Status)), this, SLOT(statusChanged(QMailServiceAction::Status)));
+}
+
+bool QMessageServicePrivate::isBusy() const
+{
+ if ((_active && ((_active->activity() == QMailServiceAction::Pending) || (_active->activity() == QMailServiceAction::InProgress))) ||
+ _activeStoreAction) {
+ qWarning() << "Action is currently busy";
+ return true;
+ }
+
+ return false;
+}
+
+void QMessageServicePrivate::transmitActivityChanged(QMailServiceAction::Activity a)
+{
+ if (a == QMailServiceAction::Successful) {
+ if (!_transmitIds.isEmpty()) {
+ // If these messages were transmitted, we need to move them to Sent folder
+ QMailMessageKey filter(QMailMessageKey::id(_transmitIds));
+ foreach (const QMailMessageId &id, QMailStore::instance()->queryMessages(filter & QMailMessageKey::status(QMailMessage::Sent))) {
+ QMessage message(convert(id));
+
+ QMessagePrivate::setStandardFolder(message,QMessage::SentFolder);
+ if (!QMessageManager().updateMessage(&message)) {
+ qWarning() << "Unable to mark message as sent!";
+ }
+ }
+
+ _transmitIds.clear();
+ }
+ } else if (a == QMailServiceAction::Failed) {
+ _transmitIds.clear();
+
+ if (_error == QMessageManager::NoError) {
+ // We may have failed due to some part of the request remaining incomplete
+ _error = QMessageManager::RequestIncomplete;
+ }
+ }
+
+ emit stateChanged(convert(a));
+}
+
+void QMessageServicePrivate::statusChanged(const QMailServiceAction::Status &s)
+{
+ if (s.errorCode != QMailServiceAction::Status::ErrNoError) {
+ qWarning() << QString("Service error %1: \"%2\"").arg(s.errorCode).arg(s.text);
+
+ if (s.errorCode == QMailServiceAction::Status::ErrNotImplemented) {
+ _error = QMessageManager::NotYetImplemented;
+ } else if ((s.errorCode == QMailServiceAction::Status::ErrNonexistentMessage) ||
+ (s.errorCode == QMailServiceAction::Status::ErrEnqueueFailed) ||
+ (s.errorCode == QMailServiceAction::Status::ErrInvalidAddress) ||
+ (s.errorCode == QMailServiceAction::Status::ErrInvalidData)) {
+ _error = QMessageManager::ConstraintFailure;
+ } else {
+ _error = QMessageManager::FrameworkFault;
+ }
+ }
+}
+
+void QMessageServicePrivate::retrievalActivityChanged(QMailServiceAction::Activity a)
+{
+ if ((a == QMailServiceAction::Failed) && (_error == QMessageManager::NoError)) {
+ // We may have failed due to some part of the request remaining incomplete
+ _error = QMessageManager::RequestIncomplete;
+ }
+
+ emit stateChanged(convert(a));
+}
+
+void QMessageServicePrivate::completed()
+{
+ _activeStoreAction = false;
+ emit stateChanged(QMessageService::FinishedState);
+}
+
+bool QMessageServicePrivate::messageMatch(const QMailMessageId &messageId)
+{
+ if (_match.isEmpty()) {
+ return true;
+ }
+
+ const QMailMessage candidate(messageId);
+ if (candidate.id().isValid()) {
+ // Search only messages or message parts that are of type 'text/*'
+ if (candidate.hasBody()) {
+ if (candidate.contentType().type().toLower() == "text") {
+ if (candidate.body().data().contains(_match, Qt::CaseInsensitive))
+ return true;
+ }
+ } else if (candidate.multipartType() != QMailMessage::MultipartNone) {
+ // Search all 'text/*' parts within this message
+ TextPartSearcher searcher(_match);
+ if (candidate.foreachPart<TextPartSearcher&>(searcher) == false) {
+ // We found a matching part in the message
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void QMessageServicePrivate::reportMatchingIds()
+{
+ emit messagesFound(convert(_candidateIds));
+ completed();
+}
+
+void QMessageServicePrivate::reportMatchingCount()
+{
+ emit messagesCounted(_candidateIds.count());
+ completed();
+}
+
+void QMessageServicePrivate::findMatchingIds()
+{
+ int required = ((_offset + _limit) - _matchingIds.count());
+
+ // Are any of the existing IDs part of the result set?
+ if (required < _limit) {
+ emit messagesFound(_matchingIds.mid(_offset, _limit));
+ }
+
+ if ((required > 0 || _limit == 0) && !_candidateIds.isEmpty()) {
+ QTimer::singleShot(0, this, SLOT(testNextMessage()));
+ } else {
+ completed();
+ }
+}
+
+void QMessageServicePrivate::testNextMessage()
+{
+ int required = ((_offset + _limit) - _matchingIds.count());
+ if (required > 0 || _limit==0) {
+ QMailMessageId messageId(_candidateIds.takeFirst());
+ if (messageMatch(messageId)) {
+ _matchingIds.append(convert(messageId));
+ --required;
+
+ if (required < _limit) {
+ // This is within the result set
+ emit messagesFound(QMessageIdList() << _matchingIds.last());
+ }
+ }
+
+ if ((required > 0 || _limit == 0) && !_candidateIds.isEmpty()) {
+ QTimer::singleShot(0, this, SLOT(testNextMessage()));
+ return;
+ }
+ }
+
+ completed();
+}
+
+QMessageService::QMessageService(QObject *parent)
+ : QObject(parent),
+ d_ptr(new QMessageServicePrivate)
+{
+ // Ensure the message store is initialized
+ QMessageManager();
+
+ connect(d_ptr, SIGNAL(stateChanged(QMessageService::State)),
+ this, SIGNAL(stateChanged(QMessageService::State)));
+ connect(d_ptr, SIGNAL(messagesFound(QMessageIdList)),
+ this, SIGNAL(messagesFound(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;
+}
+
+bool QMessageService::queryMessages(const QMessageFilter &filter, const QMessageSortOrder &sortOrder, uint limit, uint offset)
+{
+ if (d_ptr->isBusy()) {
+ return false;
+ }
+ d_ptr->_active = 0;
+ d_ptr->_activeStoreAction = true;
+ emit stateChanged(QMessageService::ActiveState);
+
+ d_ptr->_candidateIds = QMailStore::instance()->queryMessages(convert(filter), convert(sortOrder), limit, offset);
+ d_ptr->_error = convert(QMailStore::instance()->lastError());
+
+ if (d_ptr->_error == QMessageManager::NoError) {
+ d_ptr->_lastFilter = QMessageFilter();
+ d_ptr->_lastOrdering = QMessageSortOrder();
+ d_ptr->_match = QString();
+ d_ptr->_limit = static_cast<int>(limit);
+ d_ptr->_offset = 0;
+ d_ptr->_matchingIds.clear();
+ QTimer::singleShot(0, d_ptr, SLOT(reportMatchingIds()));
+ return true;
+ }
+
+ return false;
+}
+
+bool QMessageService::queryMessages(const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset)
+{
+ if (matchFlags) {
+ //TODO: Support matchFlags
+ return false;
+ }
+
+ if (body.isEmpty()) {
+ return queryMessages(filter, sortOrder, limit, offset);
+ }
+
+ if (d_ptr->isBusy()) {
+ return false;
+ }
+
+ d_ptr->_active = 0;
+ d_ptr->_activeStoreAction = true;
+ emit stateChanged(QMessageService::ActiveState);
+
+ if ((filter == d_ptr->_lastFilter) && (sortOrder == d_ptr->_lastOrdering) && (body == d_ptr->_match)) {
+ // This is a continuation of the last search
+ d_ptr->_limit = static_cast<int>(limit);
+ d_ptr->_offset = static_cast<int>(offset);
+ QTimer::singleShot(0, d_ptr, SLOT(findMatchingIds()));
+ return true;
+ }
+
+ // Find all messages to perform the body search on
+ d_ptr->_candidateIds = QMailStore::instance()->queryMessages(convert(filter), convert(sortOrder));
+ d_ptr->_error = convert(QMailStore::instance()->lastError());
+
+ if (d_ptr->_error == QMessageManager::NoError) {
+ d_ptr->_lastFilter = filter;
+ d_ptr->_lastOrdering = sortOrder;
+ d_ptr->_match = body;
+ d_ptr->_limit = static_cast<int>(limit);
+ d_ptr->_offset = static_cast<int>(offset);
+ d_ptr->_matchingIds.clear();
+ QTimer::singleShot(0, d_ptr, SLOT(findMatchingIds()));
+ return true;
+ }
+
+ return false;
+}
+
+bool QMessageService::countMessages(const QMessageFilter &filter)
+{
+ if (d_ptr->isBusy()) {
+ return false;
+ }
+ d_ptr->_active = 0;
+ d_ptr->_activeStoreAction = true;
+
+ d_ptr->_candidateIds = QMailStore::instance()->queryMessages(convert(filter));
+ d_ptr->_error = convert(QMailStore::instance()->lastError());
+
+ if (d_ptr->_error == QMessageManager::NoError) {
+ d_ptr->_lastFilter = QMessageFilter();
+ d_ptr->_lastOrdering = QMessageSortOrder();
+ d_ptr->_match = QString();
+ d_ptr->_limit = 0;
+ d_ptr->_offset = 0;
+ d_ptr->_matchingIds.clear();
+ QTimer::singleShot(0, d_ptr, SLOT(reportMatchingCount()));
+ return true;
+ }
+
+ return false;
+}
+
+bool QMessageService::send(QMessage &message)
+{
+ if (d_ptr->isBusy()) {
+ return false;
+ }
+ d_ptr->_active = 0;
+
+ if (!message.parentAccountId().isValid()) {
+ // Attach to the default account
+ message.setParentAccountId(QMessageAccount::defaultAccount(message.type()));
+ if (!message.parentAccountId().isValid()) {
+ d_ptr->_error = QMessageManager::InvalidId;
+ qWarning() << "Invalid message account ID";
+ return false;
+ }
+ }
+
+ // Ensure the message contains a timestamp
+ if (!message.date().isValid()) {
+ message.setDate(QDateTime::currentDateTime());
+ }
+
+ QMessageFolderId existingFolderId(message.parentFolderId());
+
+ // Move the message to the Outbox folder
+ QMessagePrivate::setStandardFolder(message,QMessage::OutboxFolder);
+
+ QMailMessage *msg(convert(&message));
+
+ // Ensure that the from address is added
+ if (msg->from().isNull()) {
+ QMailAccount account(msg->parentAccountId());
+ msg->setFrom(account.fromAddress());
+ }
+
+ // Mark this message as outgoing
+ msg->setStatus(QMailMessage::Outbox, true);
+
+ if (msg->id().isValid()) {
+ // Update the message
+ if (!QMailStore::instance()->updateMessage(msg)) {
+ d_ptr->_error = QMessageManager::FrameworkFault;
+ qWarning() << "Unable to mark message as outgoing";
+ return false;
+ }
+ } else {
+ // Add this message to the store
+ if (!QMailStore::instance()->addMessage(msg)) {
+ d_ptr->_error = QMessageManager::FrameworkFault;
+ qWarning() << "Unable to store message for transmission";
+ return false;
+ }
+ }
+
+ d_ptr->_transmitIds = QMailStore::instance()->queryMessages(QMailMessageKey::status(QMailMessage::Outgoing) & QMailMessageKey::parentAccountId(msg->parentAccountId()));
+
+ d_ptr->_error = QMessageManager::NoError;
+ d_ptr->_active = &d_ptr->_transmit;
+ d_ptr->_transmit.transmitMessages(msg->parentAccountId());
+ return true;
+}
+
+bool QMessageService::compose(const QMessage &message)
+{
+ if (d_ptr->isBusy()) {
+ return false;
+ }
+ d_ptr->_active = 0;
+
+ // TODO: To be implemented by integrator
+ d_ptr->_error = QMessageManager::NotYetImplemented;
+ qWarning() << "QMessageService::compose not yet implemented";
+ return false;
+
+ Q_UNUSED(message)
+}
+
+bool QMessageService::retrieveHeader(const QMessageId& id)
+{
+ if (d_ptr->isBusy()) {
+ return false;
+ }
+ d_ptr->_active = 0;
+
+ QMailMessageId messageId(convert(id));
+ if (!messageId.isValid()) {
+ d_ptr->_error = QMessageManager::InvalidId;
+ qWarning() << "Invalid message ID";
+ return false;
+ }
+
+ // Operation is not relevant to QMF - meta data retrieval always includes header information
+ d_ptr->_error = QMessageManager::NoError;
+ d_ptr->_active = 0;
+ QTimer::singleShot(0, d_ptr, SLOT(completed()));
+ return true;
+}
+
+bool QMessageService::retrieveBody(const QMessageId& id)
+{
+ if (d_ptr->isBusy()) {
+ return false;
+ }
+ d_ptr->_active = 0;
+
+ QMailMessageId messageId(convert(id));
+ if (!messageId.isValid()) {
+ d_ptr->_error = QMessageManager::InvalidId;
+ qWarning() << "Invalid message ID";
+ return false;
+ }
+
+ d_ptr->_error = QMessageManager::NoError;
+ d_ptr->_active = &d_ptr->_retrieval;
+ d_ptr->_retrieval.retrieveMessages(QMailMessageIdList() << messageId, QMailRetrievalAction::Content);
+ return true;
+}
+
+bool QMessageService::retrieve(const QMessageId &messageId, const QMessageContentContainerId& id)
+{
+ if (d_ptr->isBusy()) {
+ return false;
+ }
+ d_ptr->_active = 0;
+
+ QMailMessagePart::Location location(convert(id));
+ if (!location.isValid()) {
+ d_ptr->_error = QMessageManager::InvalidId;
+ qWarning() << "Invalid message part location";
+ return false;
+ }
+
+ d_ptr->_error = QMessageManager::NoError;
+ d_ptr->_active = &d_ptr->_retrieval;
+ d_ptr->_retrieval.retrieveMessagePart(location);
+ return true;
+
+ Q_UNUSED(messageId)
+}
+
+bool QMessageService::show(const QMessageId& id)
+{
+ if (d_ptr->isBusy()) {
+ return false;
+ }
+ d_ptr->_active = 0;
+
+ // TODO: To be implemented by integrator
+ d_ptr->_error = QMessageManager::NotYetImplemented;
+ qWarning() << "QMessageService::show not yet implemented";
+ return false;
+
+ Q_UNUSED(id)
+}
+
+bool QMessageService::exportUpdates(const QMessageAccountId &id)
+{
+ if (d_ptr->isBusy()) {
+ return false;
+ }
+ d_ptr->_active = 0;
+
+ QMailAccountId accountId(convert(id));
+ if (!accountId.isValid()) {
+ d_ptr->_error = QMessageManager::InvalidId;
+ qWarning() << "Account ID is not valid";
+ return false;
+ }
+
+ d_ptr->_error = QMessageManager::NoError;
+ d_ptr->_active = &d_ptr->_retrieval;
+ d_ptr->_retrieval.exportUpdates(accountId);
+ return true;
+}
+
+QMessageService::State QMessageService::state() const
+{
+ if (d_ptr->_active) {
+ return convert(d_ptr->_active->activity());
+ }
+ else if(d_ptr->_activeStoreAction)
+ return QMessageService::ActiveState;
+
+ return FinishedState;
+}
+
+void QMessageService::cancel()
+{
+ if (d_ptr->_active) {
+ d_ptr->_active->cancelOperation();
+ }
+ else if(d_ptr->_activeStoreAction)
+ d_ptr->_activeStoreAction = false;
+}
+
+QMessageManager::Error QMessageService::error() const
+{
+ return d_ptr->_error;
+}
+
+#include "qmessageservice_qmf.moc"
+
+
+QTM_END_NAMESPACE