/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Mobility Components. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** 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, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "storageengine_maemo6_p.h" #include "telepathyhelpers_maemo6_p.h" #include "maemo6helpers_p.h" #include "qmessageservice_maemo6_p.h" #include "qmessagefolder_p.h" #include "qmessagefolderid_p.h" #include "qmessagefilter_p.h" #include "qmessage_p.h" #include namespace { //! returns text prefix used in SMS storage engine to identify the type of processing message /*! returns text prefix used in SMS storage engine to identify the type of processing message. \a event communication event (message) Returns QString representing text prefix for the message Id. */ QString prefixForEvent(const Event &event) { QString prefix; switch(event.type()) { case Event::SMSEvent: prefix = "SMS_"; break; case Event::IMEvent: prefix = "IMS_"; break; default: prefix = ""; qWarning() << __PRETTY_FUNCTION__ << "wrong type"; } return prefix; } struct MessageCounter { MessageCounter(const QMessageFilter &filter) : _filter(filter) , _count(0) { _privateFilter = QMessageFilterPrivate::implementation(_filter); } void operator()(const Event &event) { if (_filter.isEmpty()) { _count++; } else { const QMessage message = StorageEngine::messageFromEvent(event); if (_privateFilter->filter(message)) { _count++; } } } QMessageFilter _filter; const QMessageFilterPrivate *_privateFilter; int _count; }; struct MessageFilter { MessageFilter(const QMessageFilter &filter) : _filter(filter) { _privateFilter = QMessageFilterPrivate::implementation(_filter); } void operator()(const Event &event) { if (_filter.isEmpty()) { _ids << QMessageId(prefixForEvent(event) + QString::number(event.id())); } else { const QMessage message = StorageEngine::messageFromEvent(event); if (_privateFilter->filter(message)) { _ids << message.id(); } } } QMessageFilter _filter; const QMessageFilterPrivate *_privateFilter; QMessageIdList _ids; }; struct MessageFilterAndBodySearcher { MessageFilterAndBodySearcher(const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchflags) : _filter(filter) , _body(body) , _matchFlags(matchflags) { _privateFilter = QMessageFilterPrivate::implementation(_filter); } void operator()(const Event &event) { const QMessage message = StorageEngine::messageFromEvent(event); if (_privateFilter->filter(message)) { const QString text = message.textContent(); if (text.length() >= _body.length()) { bool found = false; if (_matchFlags & QMessageDataComparator::MatchCaseSensitive) found = text.contains(_body, Qt::CaseSensitive); else found = text.contains(_body, Qt::CaseInsensitive); if (found) _ids << message.id(); } } } QMessageFilter _filter; QString _body; QMessageDataComparator::MatchFlags _matchFlags; const QMessageFilterPrivate *_privateFilter; QMessageIdList _ids; }; } Q_GLOBAL_STATIC(StorageEngine, storageEngine); /*! returns pointer to the singleton instance */ StorageEngine* StorageEngine::instance() { return storageEngine(); } //! constructor StorageEngine::StorageEngine(QObject *parent) : QObject(parent) , m_sync(true) , m_ready(false) , m_error(QMessageManager::NoError) , m_updatedEventId(0) { QDEBUG_FUNCTION_BEGIN m_SMSModel.setQueryMode(EventModel::AsyncQuery); connect(&m_SMSModel, SIGNAL(modelReady(bool)), SLOT(onModelReady(bool))); connect(&m_SMSModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(onRowsInserted(const QModelIndex &, int, int))); connect(&m_SMSModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(onDataChanged(const QModelIndex &, const QModelIndex &))); connect(&m_SMSModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), this, SLOT(onRowsRemoved(const QModelIndex &, int, int))); if (m_SMSModel.getEvents() && m_sync) m_loop.exec(); QDEBUG_FUNCTION_END } /*! Converts message to event. \a message source message Returns SMS event filled by the corresponding data. * */ Event StorageEngine::eventFromMessage(const QMessage &message) { QDEBUG_FUNCTION_BEGIN Event event; //event.setDeleted(false); switch(message.type()) { case QMessage::Sms: event.setType(Event::SMSEvent); break; case QMessage::InstantMessage: event.setType( Event::IMEvent); break; default: qWarning() << __PRETTY_FUNCTION__ << "wrong type"; return event; } switch (message.standardFolder()) { case QMessage::InboxFolder: event.setParentId(INBOX); event.setDirection(Event::Inbound); event.setIsDraft(false); break; case QMessage::OutboxFolder: event.setParentId(OUTBOX); event.setDirection(Event::Outbound); event.setIsDraft(false); break; case QMessage::SentFolder: event.setParentId(SENT); event.setDirection(Event::Outbound); event.setIsDraft(false); break; case QMessage::DraftsFolder: event.setParentId(DRAFT); event.setDirection(Event::Outbound); event.setIsDraft(true); break; default: event.setParentId(0); event.setDirection(Event::UnknownDirection); event.setIsDraft(true); } // depends on direction event.setRemoteUid(event.direction() == Event::Inbound ? message.from().addressee() : MessagingHelper::addressListToString(message.to())); event.setLocalUid(event.direction() == Event::Inbound ? MessagingHelper::addressListToString(message.to()) : message.from().addressee()); // message body event.setFreeText(message.textContent()); /* TODO: libcommhistory does not process time setting correctly event.setStartTime(message.date()); event.setEndTime(message.receivedDate()); */ event.setIsRead(message.status() & QMessage::Read); bool ok = false; int eId = message.id().toString().mid(4).toInt(&ok); if (!ok) eId = message.id().toString().toInt(&ok); if (ok || (message.id().toString().length() == 0)) event.setId(eId); else qWarning() << __PRETTY_FUNCTION__ << "Cannot convert event ID " << message.id().toString() << " to int"; QDEBUG_FUNCTION_END return event; } /** * * Converts event to message. * */ /*! Converts event to message \a event source event Returns SMS message filled by the corresponding data. * */ QMessage StorageEngine::messageFromEvent(const Event &ev) { QMessage message; if (!ev.isValid()) return message; switch(ev.type()) { case Event::SMSEvent: message.setType(QMessage::Sms); break; case Event::IMEvent: message.setType(QMessage::InstantMessage); break; default: message.setType(QMessage::NoType); qWarning() << __PRETTY_FUNCTION__ << "wrong type"; } message.setParentAccountId(QMessageAccount::defaultAccount(QMessage::Sms)); QMessage::StatusFlags status(0); if (ev.isRead()) { status |= QMessage::Read; } if (ev.isDeleted()) { status |= QMessage::Removed; } message.setStatus(status); message.setPriority(QMessage::NormalPriority); message.setDate(ev.startTime()); message.setReceivedDate(ev.endTime()); switch (ev.parentId()) { case INBOX: QMessagePrivate::setStandardFolder(message, QMessage:: InboxFolder); QMessagePrivate::setParentFolderId(message, QMessageFolderId(FOLDER_ID_INBOX)); break; case OUTBOX: QMessagePrivate::setStandardFolder(message, QMessage:: OutboxFolder); QMessagePrivate::setParentFolderId(message, QMessageFolderId(FOLDER_ID_OUTBOX)); break; case DRAFT: QMessagePrivate::setStandardFolder(message, QMessage:: DraftsFolder); QMessagePrivate::setParentFolderId(message, QMessageFolderId(FOLDER_ID_DRAFTS)); break; case SENT: QMessagePrivate::setStandardFolder(message, QMessage:: SentFolder); QMessagePrivate::setParentFolderId(message, QMessageFolderId(FOLDER_ID_SENT)); break; default: QMessagePrivate::setStandardFolder(message, QMessage:: TrashFolder); QMessagePrivate::setParentFolderId(message, QMessageFolderId(FOLDER_ID_TRASH)); } if (ev.direction() == Event::Inbound) { message.setFrom(QMessageAddress(QMessageAddress::Phone, ev.remoteUid())); message.setTo(QMessageAddress(QMessageAddress::Phone, ev.localUid())); } else { message.setFrom(QMessageAddress(QMessageAddress::Phone, ev.localUid())); message.setTo(MessagingHelper::stringToAddressList(ev.remoteUid())); } message.setBody(QString(ev.freeText())); QMessagePrivate* privateMessage = QMessagePrivate::implementation(message); privateMessage->_id = QMessageId(prefixForEvent(ev) + QString::number(ev.id())); privateMessage->_modified = false; return message; } /*! returns error value */ QMessageManager::Error StorageEngine::error() const { return m_error; } /*! Synchronous method to count filtered messages \a filter Filter Returns number of messages satisfying the filter condition. */ int StorageEngine::countMessagesSync(const QMessageFilter &filter) { QDEBUG_FUNCTION_BEGIN m_error = QMessageManager::NoError; QMessageFilterPrivate *pf = QMessageFilterPrivate::implementation(filter); if (pf->_field == QMessageFilterPrivate::None && pf->_filterList.count() == 0 && pf->_notFilter) { return 0; } MessageCounter counter(filter); foreachEvent(counter); QDEBUG_FUNCTION_END return counter._count; } /*! Synchronous method that returns list of filtered messages. List will be sorted in \l QMessageStore::queryMessages(). \a filter Filter \a body specifies the string that message have to contain \a matchFlags specifies the matching method to use \a sortOrder specifies how to sort identifiers \a limit an upper bound on the number of ids in the list returned \a offset specifies how many ids to skip at the beginning of the list returned Returns list of messages satisfying the filter and containing the body. */ QMessageIdList StorageEngine::queryMessagesSync(const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset) { QDEBUG_FUNCTION_BEGIN; Q_UNUSED(sortOrder); Q_UNUSED(limit); Q_UNUSED(offset); m_error = QMessageManager::NoError; QMessageFilterPrivate *pf = QMessageFilterPrivate::implementation(filter); if (pf->_field == QMessageFilterPrivate::None && pf->_filterList.count() == 0 && pf->_notFilter) { return QMessageIdList(); } MessageFilterAndBodySearcher searcher(filter, body, matchFlags); foreachEvent(searcher); QDEBUG_FUNCTION_END return searcher._ids; } /*! Synchronous method that returns list of filtered messages. List will be sorted in \l QMessageStore::queryMessages(). \a filter Filter \a sortOrder specifies how to sort identifiers \a limit an upper bound on the number of ids in the list returned \a offset specifies how many ids to skip at the beginning of the list returned Returns list of messages satisfying the filter. */ QMessageIdList StorageEngine::queryMessagesSync(const QMessageFilter &filter, const QMessageSortOrder &sortOrder, uint limit, uint offset) { QDEBUG_FUNCTION_BEGIN Q_UNUSED(sortOrder); Q_UNUSED(limit); Q_UNUSED(offset); m_error = QMessageManager::NoError; QMessageFilterPrivate *pf = QMessageFilterPrivate::implementation(filter); if (pf->_field == QMessageFilterPrivate::None && pf->_filterList.count() == 0 && pf->_notFilter) { return QMessageIdList(); } MessageFilter searcher(filter); foreachEvent(searcher); QDEBUG_FUNCTION_END return searcher._ids; } /*! Asynchronous method to count filtered messages \a filter Filter Returns number of messages satisfying the filter. */ bool StorageEngine::countMessages(QMessageService *service, const QMessageFilter &filter) { QDEBUG_FUNCTION_BEGIN m_error = QMessageManager::NoError; ServiceQuery *query = new ServiceQuery(service, filter); QTimer::singleShot(0, query, SLOT(doQuery())); QDEBUG_FUNCTION_END return true; } bool StorageEngine::queryMessages(QMessageService *service, const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset) { QDEBUG_FUNCTION_BEGIN; m_error = QMessageManager::NoError; ServiceQuery *query = new ServiceQuery(service, filter, body, matchFlags, sortOrder, limit, offset); QTimer::singleShot(0, query, SLOT(doQuery())); QDEBUG_FUNCTION_END return true; } bool StorageEngine::queryMessages(QMessageService *service, const QMessageFilter &filter, const QMessageSortOrder &sortOrder, uint limit, uint offset) { QDEBUG_FUNCTION_BEGIN m_error = QMessageManager::NoError; ServiceQuery *query = new ServiceQuery(service, filter, sortOrder, limit, offset); QTimer::singleShot(0, query, SLOT(doQuery())); QDEBUG_FUNCTION_END return true; } /** * Slot that is called when m_SMSModel is ready. */ void StorageEngine::onModelReady(bool successful) { QDEBUG_FUNCTION_BEGIN; if (successful) m_ready = true; if (m_sync) { m_sync = false; m_loop.quit(); } QDEBUG_FUNCTION_END } void StorageEngine::unlockEventModifiers(const QList &events) { QDEBUG_FUNCTION_BEGIN; if (!m_ready && m_updatedEventId != 0) { bool foundRequiredId = (m_updatedEventId == -1); if (!foundRequiredId) { foreach(CommHistory::Event event, events) { if (event.id() == m_updatedEventId) { foundRequiredId = true; break; } } } if (foundRequiredId){ QPRETTYDEBUG("Quitting the loop. Event id" << m_updatedEventId); m_updatedEventId = 0; m_ready = true; m_loop.quit(); } } QDEBUG_FUNCTION_END } /*! * * Returns message from m_SMSModel by id. Sync call. * */ QMessage StorageEngine::message(const QMessageId &id) const { if (id.isValid()) { m_error = QMessageManager::NoError; int eventId = id.toString().mid(4).toInt(); QModelIndex index = m_SMSModel.findEvent(eventId); if (index.isValid()) { const Event event = m_SMSModel.event(index); return messageFromEvent(event); } } else { m_error = QMessageManager::InvalidId; } return QMessage(); } /*! * * Removes message m_SMSModel and events database by id. Sync call. * */ bool StorageEngine::removeMessage(const QMessageId &id) { QDEBUG_FUNCTION_BEGIN bool ret = false; if (id.isValid()) { bool isConverted = false; int iId = id.toString().mid(4).toInt(&isConverted); if (isConverted && iId > 0) { ret = m_SMSModel.deleteEvent(iId); if (ret) { m_error = QMessageManager::NoError; QPRETTYDEBUG("Removed successfully"); } else { m_error = QMessageManager::FrameworkFault; qWarning() << __PRETTY_FUNCTION__ << "Cannot removeMessage"; } } else { qWarning() << __PRETTY_FUNCTION__ << "Invalid ID"; m_error = QMessageManager::InvalidId; } } else { qWarning() << __PRETTY_FUNCTION__ << "Invalid ID"; m_error = QMessageManager::InvalidId; } QDEBUG_FUNCTION_END return ret; } /*! * * Adds message to m_SMSModel and events database. Sync call. * */ bool StorageEngine::addMessage(QMessage &message) { bool ret = false; Event event = eventFromMessage(message); if (m_SMSModel.addEvent(event)) { QMessagePrivate *privateMessage = QMessagePrivate::implementation(message); privateMessage->_id = QMessageId(prefixForEvent(event) + QString::number(event.id())); privateMessage->_modified = false; QPRETTYDEBUG("Message added to store. new id = " << message.id().toString()); m_error = QMessageManager::NoError; ret = true; } else { qWarning() << __PRETTY_FUNCTION__ << "Cannot add message"; m_error = QMessageManager::FrameworkFault; } return ret; } /*! * * Updates existing message data in m_SMSModel and tracker database. * */ bool StorageEngine::updateMessage(QMessage &message) { QDEBUG_FUNCTION_BEGIN bool ret = false; QMessageId id(message.id()); if (!m_ready) m_error = QMessageManager::Busy; else if (id.isValid()) { Event event = eventFromMessage(message); m_ready = false; m_updatedEventId = event.id(); ret = m_SMSModel.modifyEvent(event); // waiting for onDataChanged() signal from m_SMSModel m_loop.exec(); m_error = ret ? QMessageManager::NoError : QMessageManager::FrameworkFault; } else { m_error = QMessageManager::InvalidId; } QDEBUG_FUNCTION_END return ret; } /*! * * Returns instance of QMessageFolder, corresponding to one of standard SMS folders * */ QMessageFolder StorageEngine::folder(const QMessageFolderId& id) { QMessageFolder folder; QString name = id.toString(); if (!id.isValid()) { m_error = QMessageManager::InvalidId; return folder; } m_error = QMessageManager::NoError; if (name.startsWith(FOLDER_PREFIX_SMS)) { name.remove(0, 4); folder = QMessageFolderPrivate::from(id, QMessageAccount::defaultAccount(QMessage::Sms), QMessageFolderId(), name, QString()); } return folder; } /*! * * Returns the constant number od standard SMS folders. Sync call. * */ int StorageEngine::countFolders(const QMessageFolderFilter& filter) { QMessageFolderIdList result; m_error = QMessageManager::NoError; result << QMessageFolderId(FOLDER_ID_INBOX) << QMessageFolderId(FOLDER_ID_OUTBOX) << QMessageFolderId(FOLDER_ID_DRAFTS) << QMessageFolderId(FOLDER_ID_SENT) << QMessageFolderId(FOLDER_ID_TRASH); QPRETTYDEBUG("size before filtering:" << result.size()); MessagingHelper::filterFolders(result, filter); QPRETTYDEBUG("size after filtering:" << result.size()); return result.size(); } /*! * * Returns list of standard SMS folders acceptable by filter. Sync call. * */ QMessageFolderIdList StorageEngine::queryFolders(const QMessageFolderFilter &filter, const QMessageFolderSortOrder &sortOrder, uint limit, uint offset) { Q_UNUSED(sortOrder); Q_UNUSED(limit); Q_UNUSED(offset); QMessageFolderIdList result; m_error = QMessageManager::NoError; result << QMessageFolderId(FOLDER_ID_INBOX) << QMessageFolderId(FOLDER_ID_OUTBOX) << QMessageFolderId(FOLDER_ID_DRAFTS) << QMessageFolderId(FOLDER_ID_SENT) << QMessageFolderId(FOLDER_ID_TRASH); MessagingHelper::filterFolders(result, filter); return result; } QList StorageEngine::eventsListFromModelRows(const int start, const int end) { QList events; for (int row = start; row <= end; ++row) { QModelIndex index = m_SMSModel.index(row, 0); if (index.isValid()) events.append(m_SMSModel.event(index)); } return events; } /*! Internal slot for events addition */ void StorageEngine::onRowsInserted(const QModelIndex & parent, int start, int end) { QDEBUG_FUNCTION_BEGIN Q_UNUSED(parent); if (m_ready) processFilters(eventsListFromModelRows(start, end), &StorageEngine::messageAdded); QDEBUG_FUNCTION_END } //TODO: remove this old commented code after testing of SMS removing /* void StorageEngine::eventDeleted(int id) { QMessageId messageId("SMS_" + QString::number(id)); QMessageManager::NotificationFilterIdSet idSet; NotificationFilterMap::const_iterator it = m_filters.begin(), end = m_filters.end(); for (; it != end; ++it) { const QMessageFilter &filter = it.value(); if (filter.isEmpty()) idSet.insert(it.key()); } if (!idSet.isEmpty()) emit messageRemoved(messageId, idSet); } */ void StorageEngine::onRowsRemoved(const QModelIndex & parent, int start, int end) { QDEBUG_FUNCTION_BEGIN Q_UNUSED(parent); if (m_ready) processFilters(eventsListFromModelRows(start, end), &StorageEngine::messageRemoved); QDEBUG_FUNCTION_END } /*! Internal slot for events update */ void StorageEngine::onDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight) { QDEBUG_FUNCTION_BEGIN QList events = eventsListFromModelRows(topLeft.row(), bottomRight.row()); unlockEventModifiers(events); if (m_ready) processFilters(events, &StorageEngine::messageUpdated); QDEBUG_FUNCTION_END } /*! Add filter to the map */ void StorageEngine::registerNotificationFilter(QMessageManager::NotificationFilterId id, const QMessageFilter &filter) { m_filters[id] = filter; } /*! Delete filter specified by id from the map of filters */ void StorageEngine::unregisterNotificationFilter(QMessageManager::NotificationFilterId id) { m_filters.remove(id); } void StorageEngine::processFilters(const QList &events, void (StorageEngine::*signal)(const QMessageId &, const QMessageManager::NotificationFilterIdSet &)) { if (events.count() == 0) { QPRETTYDEBUG("No events to process"); return; } QMap matches; QList messages; foreach (const Event &event, events) { messages << messageFromEvent(event); QPRETTYDEBUG("added/updated/removed" << event.id()); } NotificationFilterMap::const_iterator it = m_filters.begin(), end = m_filters.end(); for (; it != end; ++it) { const QMessageFilter &filter = it.value(); const QMessageFilterPrivate *pf = QMessageFilterPrivate::implementation(filter); foreach (const QMessage &message, messages) { if (filter.isEmpty() || pf->filter(message)) { QMessageId id(message.id()); if (id.isValid()) matches[id].insert(it.key()); } } } QMap::const_iterator mit = matches.begin(), mend = matches.end(); for ( ; mit != mend; ++mit) { emit (this->*signal)(mit.key(), mit.value()); } } /*! Start Messaging UI composer passing contacts list and message text */ bool StorageEngine::compose(const QMessage &message) { QDEBUG_FUNCTION_BEGIN m_error = QMessageManager::NoError; QStringList contacts = MessagingHelper::stringListFromAddressList(message.to()); QPRETTYDEBUG(contacts << message.textContent()); MessagingIf l_pMessagingIf; l_pMessagingIf.showSmsEditor(contacts, message.textContent(), QString()); QDEBUG_FUNCTION_END return true; } /*! Get message by Id and start Messaging UI passing message data */ bool StorageEngine::show(const QMessageId &id) { QDEBUG_FUNCTION_BEGIN bool ret = false; m_error = QMessageManager::NoError; if (id.isValid()) { QMessage message(id); ret = compose(message); } else { qWarning() << __PRETTY_FUNCTION__ << "ERROR: InvalidId"; m_error = QMessageManager::InvalidId; } QDEBUG_FUNCTION_END return ret; } ServiceQuery::ServiceQuery(QMessageService *service, const QMessageFilter &filter) : QObject(service) , _type(CountQuery) , _service(service) , _filter(filter) , _count(0) { } ServiceQuery::ServiceQuery(QMessageService *service, const QMessageFilter &filter, const QMessageSortOrder &sortOrder, uint limit, uint offset) : QObject(service) , _type(MessageQuery) , _service(service) , _filter(filter) , _sortOrder(sortOrder) , _limit(limit) , _offset(offset) , _count(0) { } ServiceQuery::ServiceQuery(QMessageService *service, const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset) : QObject(service) , _type(MessageAndBodySearchQuery) , _service(service) , _filter(filter) , _body(body) , _matchFlags(matchFlags) , _sortOrder(sortOrder) , _limit(limit) , _offset(offset) , _count(0) { } ServiceQuery::~ServiceQuery() { QPRETTYDEBUG(""); } /*! main processing */ void ServiceQuery::doQuery() { if (_type == CountQuery) { _count = StorageEngine::instance()->countMessagesSync(_filter); QTimer::singleShot(0, this, SLOT(completed())); } else { _ids = StorageEngine::instance()->queryMessagesSync(_filter); if (_ids.count()) { if (_type == MessageQuery || _body.isEmpty()) { QTimer::singleShot(0, this, SLOT(sortMessages())); } else { QTimer::singleShot(0, this, SLOT(searchBody())); } } else { QTimer::singleShot(0, this, SLOT(completed())); } } } /*! Sort internal list of messages and apply limit and offset parameters */ void ServiceQuery::sortMessages() { MessagingHelper::orderMessages(_ids, _sortOrder); MessagingHelper::applyOffsetAndLimitToMessageIdList(_ids, _limit, _offset); QTimer::singleShot(0, this, SLOT(completed())); } void ServiceQuery::searchBody() { QMessageIdList ids(_ids); _ids.clear(); foreach (const QMessageId &id, ids) { const QMessage message(id); const QString text = message.textContent(); if (text.length() >= _body.length()) { bool found = false; if (_matchFlags & QMessageDataComparator::MatchCaseSensitive) found = text.contains(_body, Qt::CaseSensitive); else found = text.contains(_body, Qt::CaseInsensitive); if (found) _ids << message.id(); } } if (_ids.count()) { QTimer::singleShot(0, this, SLOT(sortMessages())); } else { QTimer::singleShot(0, this, SLOT(completed())); } } /*! Slot that inform upper layer (QMessageService) about the operation completion and return results. */ void ServiceQuery::completed() { QMessageServicePrivate *p = QMessageServicePrivate::implementation(*_service); if (_type == CountQuery) p->messagesCounted(_count); else p->messagesFound(_ids, true, true); deleteLater(); } #include "moc_storageengine_maemo6_p.cpp"