diff -r cfcbf08528c4 -r 2b40d63a9c3d qtmobility/src/messaging/qmessageservice_qmf.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qtmobility/src/messaging/qmessageservice_qmf.cpp Fri Apr 16 15:51:22 2010 +0300 @@ -0,0 +1,611 @@ +/**************************************************************************** +** +** 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 "qmfhelpers_p.h" + +#include + +#include +#include + + +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 _matchingIds; + QList _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(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(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(limit); + d_ptr->_offset = static_cast(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(limit); + d_ptr->_offset = static_cast(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