qtmobility/src/messaging/modestengine_maemo.cpp
changeset 4 90517678cc4f
parent 1 2b40d63a9c3d
child 5 453da2cfceef
--- a/qtmobility/src/messaging/modestengine_maemo.cpp	Fri Apr 16 15:51:22 2010 +0300
+++ b/qtmobility/src/messaging/modestengine_maemo.cpp	Mon May 03 13:18:40 2010 +0300
@@ -40,19 +40,162 @@
 ****************************************************************************/
 #include "modestengine_maemo_p.h"
 #include "maemohelpers_p.h"
+#include "qmessage_p.h"
 #include "qmessageaccount.h"
 #include "qmessageaccount_p.h"
 #include "qmessageaccountfilter.h"
 #include "qmessageaccountfilter_p.h"
-#include "qmessageservice.h"
-#include <libmodest-dbus-client/libmodest-dbus-client.h>
-#include <libmodest-dbus-client/libmodest-dbus-api.h>
+#include "qmessagefolder_p.h"
+#include "qmessagestore_p.h"
+#include "qmessageservice_maemo_p.h"
+#include "qmessagecontentcontainer_maemo_p.h"
 #include <QUrl>
-#include <QtDBus/QtDBus>
+#include <QtDBus>
+#include <QFileSystemWatcher>
+#include <QTimer>
+
 #include <dbus/dbus.h>
-
 #include <QDebug>
 
+#include </usr/include/libmodest-dbus-client-1.0/libmodest-dbus-client/libmodest-dbus-api.h>
+#include </usr/include/sys/inotify.h>
+#include </usr/include/sys/ioctl.h>
+#include </usr/include/sys/fcntl.h>
+
+// Marshall the ModestStringMap data into a D-Bus argument
+QDBusArgument &operator<<(QDBusArgument &argument,
+                          const QtMobility::ModestStringMap &map)
+{
+    QtMobility::ModestStringMap::const_iterator iter;
+
+    argument.beginMap (QVariant::String, QVariant::String);
+    for (iter = map.constBegin(); iter != map.constEnd(); iter++) {
+        argument.beginMapEntry();
+        argument << iter.key() << iter.value();
+        argument.endMapEntry();
+    }
+    argument.endMap();
+
+    return argument;
+}
+
+// Retrieve the ModestStringMap data from the D-Bus argument
+const QDBusArgument &operator>>(const QDBusArgument &argument,
+                                QtMobility::ModestStringMap &map)
+{
+    map.clear();
+
+    argument.beginMap();
+    while (!argument.atEnd()) {
+        QString key, value;
+        argument.beginMapEntry();
+        argument >> key >> value;
+        argument.endMapEntry();
+        map[key] = value;
+    }
+    argument.endMap();
+
+    return argument;
+}
+
+QDBusArgument &operator<<(QDBusArgument &argument,
+                          const QtMobility::ModestUnreadMessageDBusStruct &unreadMessage)
+{
+    argument.beginStructure();
+    argument << unreadMessage.timeStamp;
+    argument << unreadMessage.subject;
+    argument.endStructure();
+    return argument;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &argument,
+                                QtMobility::ModestUnreadMessageDBusStruct &unreadMessage)
+{
+    argument.beginStructure();
+    argument >> unreadMessage.timeStamp;
+    argument >> unreadMessage.subject;
+    argument.endStructure();
+    return argument;
+}
+
+QDBusArgument &operator<<(QDBusArgument &argument,
+                          const QtMobility::ModestAccountsUnreadMessagesDBusStruct &unreadMessages)
+{
+    argument.beginStructure();
+    argument << unreadMessages.accountId;
+    argument << unreadMessages.accountName;
+    argument << unreadMessages.accountProtocol;
+    argument << unreadMessages.unreadCount;
+    argument << unreadMessages.unreadMessages;
+    argument.endStructure();
+    return argument;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &argument,
+                                QtMobility::ModestAccountsUnreadMessagesDBusStruct &unreadMessages)
+{
+    argument.beginStructure();
+    argument >> unreadMessages.accountId;
+    argument >> unreadMessages.accountName;
+    argument >> unreadMessages.accountProtocol;
+    argument >> unreadMessages.unreadCount;
+    argument >> unreadMessages.unreadMessages;
+    argument.endStructure();
+    return argument;
+}
+
+QDBusArgument &operator<<(QDBusArgument &argument, const QtMobility::ModestMessage &message)
+{
+    argument.beginStructure();
+    argument << message.id;
+    argument << message.subject;
+    argument << message.folder;
+    argument << message.sender;
+    argument << message.size;
+    argument << message.hasAttachment;
+    argument << message.isUnread;
+    argument << message.timeStamp;
+    argument.endStructure();
+    return argument;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &argument, QtMobility::ModestMessage &message)
+{
+    argument.beginStructure();
+    argument >> message.id;
+    argument >> message.subject;
+    argument >> message.folder;
+    argument >> message.sender;
+    argument >> message.size;
+    argument >> message.hasAttachment;
+    argument >> message.isUnread;
+    argument >> message.timeStamp;
+    argument.endStructure();
+    return argument;
+}
+
+QDBusArgument &operator<<(QDBusArgument &argument, const QtMobility::MessagingModestMimePart &mimePart)
+{
+    argument.beginStructure();
+    argument << mimePart.mimeType;
+    argument << mimePart.isAttachment;
+    argument << mimePart.fileName;
+    argument << mimePart.contentId;
+    argument.endStructure();
+    return argument;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &argument, QtMobility::MessagingModestMimePart &mimePart)
+{
+    argument.beginStructure();
+    argument >> mimePart.mimeType;
+    argument >> mimePart.isAttachment;
+    argument >> mimePart.fileName;
+    argument >> mimePart.contentId;
+    argument.endStructure();
+    return argument;
+}
+
 QTM_BEGIN_NAMESPACE
 
 /* configuration key definitions for modest */
@@ -65,10 +208,32 @@
 #define MODESTENGINE_ACCOUNT_EMAIL             "email"
 #define MODESTENGINE_ACCOUNT_STORE_ACCOUNT     "store_account"
 #define MODESTENGINE_ACCOUNT_TRANSPORT_ACCOUNT "transport_account"
+#define MODESTENGINE_ACCOUNT_PROTOCOL          "proto"
+#define MODESTENGINE_ACCOUNT_USERNAME          "username"
+#define MODESTENGINE_ACCOUNT_HOSTNAME          "hostname"
+#define MODESTENGINE_ACCOUNT_PORT              "port"
+
+// The modest engine has a new plugin, we need service names for it
+#define MODESTENGINE_QTM_PLUGIN_PATH           "/com/nokia/Qtm/Modest/Plugin"
+#define MODESTENGINE_QTM_PLUGIN_NAME           "com.nokia.Qtm.Modest.Plugin"
+
+typedef enum {
+    MODEST_DBUS_SEARCH_SUBJECT   = (1 << 0),
+    MODEST_DBUS_SEARCH_SENDER    = (1 << 1),
+    MODEST_DBUS_SEARCH_RECIPIENT = (1 << 2),
+    MODEST_DBUS_SEARCH_SIZE      = (1 << 3),
+    MODEST_DBUS_SEARCH_BODY      = (1 << 6)
+} ModestDBusSearchFlags;
+
+// Specific priority settings to translate to modest priorities
+#define MODESTENGINE_HIGH_PRIORITY             2
+#define MODESTENGINE_NORMAL_PRIORITY           0
+#define MODESTENGINE_LOW_PRIORITY              1
 
 Q_GLOBAL_STATIC(ModestEngine,modestEngine);
 
 ModestEngine::ModestEngine()
+ : m_queryIds(0)
 {
     g_type_init();
     m_gconfclient = gconf_client_get_default();
@@ -77,6 +242,62 @@
     } else {
         updateEmailAccounts();
     }
+
+    // Setup DBus Interface for Modest
+    m_ModestDBusInterface = new QDBusInterface(MODEST_DBUS_SERVICE,
+                                               MODEST_DBUS_OBJECT,
+                                               MODEST_DBUS_IFACE,
+                                               QDBusConnection::sessionBus(),
+                                               this);
+
+    // Get notifications of Incoming Messages
+    m_ModestDBusInterface->connection().connect(MODEST_DBUS_SERVICE,
+                                                MODEST_DBUS_OBJECT,
+                                                MODEST_DBUS_IFACE,
+                                                MODEST_DBUS_SIGNAL_FOLDER_UPDATED,
+                                                this, SLOT(folderUpdatedSlot(QDBusMessage)));
+
+    // Get notifications of message Read/Unread state changes
+    m_ModestDBusInterface->connection().connect(MODEST_DBUS_SERVICE,
+                                                MODEST_DBUS_OBJECT,
+                                                MODEST_DBUS_IFACE,
+                                                MODEST_DBUS_SIGNAL_MSG_READ_CHANGED,
+                                               this, SLOT(messageReadChangedSlot(QDBusMessage)));
+
+    // Setup Qt Mobility Modest Plugin based DBus Interface for Modest
+    m_QtmPluginDBusInterface = new QDBusInterface(MODESTENGINE_QTM_PLUGIN_NAME,
+                                                  MODESTENGINE_QTM_PLUGIN_PATH,
+                                                  MODESTENGINE_QTM_PLUGIN_NAME,
+                                                  QDBusConnection::sessionBus(),
+                                                  this);
+
+    qDBusRegisterMetaType< ModestStringMap >();
+    qDBusRegisterMetaType< ModestStringMapList >();
+
+    qRegisterMetaType<INotifyWatcher::FileNotification>();
+
+    qRegisterMetaType<ModestUnreadMessageDBusStruct>();
+    qRegisterMetaType<ModestAccountsUnreadMessagesDBusStruct>();
+    qDBusRegisterMetaType<ModestMessage>();
+
+    qRegisterMetaType<MessagingModestMimePart>();
+
+
+    connect(&m_MailFoldersWatcher, SIGNAL(fileChanged(int, QString, uint)),
+            this, SLOT(fileChangedSlot(int, QString, uint)));
+
+    watchAllKnownEmailFolders();
+
+    // Get latest messages from each account
+    // => This ensures that notifications of all incoming messages will be sent
+    int messagesPerAccount = 1;
+    QDBusPendingCall pendingCall = m_ModestDBusInterface->asyncCall(MODEST_DBUS_METHOD_GET_UNREAD_MESSAGES,
+                                                                    messagesPerAccount);
+    QDBusPendingCallWatcher* pendingCallWatcher = new QDBusPendingCallWatcher(pendingCall);
+    pendingCallWatcher->setProperty("setOnlyDates", true);
+    connect(pendingCallWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+            this, SLOT(pendingGetUnreadMessagesFinishedSlot(QDBusPendingCallWatcher*)));
+
 }
 
 ModestEngine::~ModestEngine()
@@ -90,6 +311,51 @@
     return modestEngine();
 }
 
+MessagingModestMessage ModestEngine::messageFromModest(const QString& accountId, const QString &folderId, const QString& messageId) const
+{
+    MessagingModestMessage modestMessage;
+
+    QDBusPendingCall pendingCall = m_QtmPluginDBusInterface->asyncCall("GetMessage",
+                                                                       accountId,
+                                                                       folderId,
+                                                                       messageId);
+    QDBusPendingCallWatcher pendingCallWatcher(pendingCall);
+    pendingCallWatcher.waitForFinished();
+
+    QDBusMessage msg = pendingCallWatcher.reply();
+
+    if (msg.type() == QDBusMessage::ReplyMessage) {
+        modestMessage.id = messageId;
+        modestMessage.accountId = accountId;
+        modestMessage.folderId = folderId;
+        modestMessage.url = msg.arguments()[0].toString();
+        modestMessage.mimeType = msg.arguments()[1].toString();
+        modestMessage.from = msg.arguments()[2].toString();
+        modestMessage.to = msg.arguments()[3].toString();
+        modestMessage.cc = msg.arguments()[4].toString();
+        modestMessage.bcc = msg.arguments()[5].toString();
+        modestMessage.replyTo = msg.arguments()[6].toString();
+        modestMessage.subject = msg.arguments()[7].toString();
+        modestMessage.dateReceived = msg.arguments()[8].toLongLong();
+        modestMessage.dateSent = msg.arguments()[9].toLongLong();
+        modestMessage.size = msg.arguments()[10].toLongLong();
+        modestMessage.flags = static_cast<MessagingModestMessageFlags>(msg.arguments()[11].toUInt());
+        modestMessage.priority = static_cast<MessagingModestMessagePriority>(msg.arguments()[12].toUInt());
+
+        QVariant variant = msg.arguments()[13];
+        QDBusArgument argument = variant.value<QDBusArgument>();
+        argument >> modestMessage.mimeParts;
+    } else {
+        modestMessage.dateReceived = 0;
+        modestMessage.dateSent = 0;
+        modestMessage.size = 0;
+        modestMessage.flags = MessagingModestMessageNotDefined;
+        modestMessage.priority = MessagingModestMessagePriorityDefined;
+    }
+
+    return modestMessage;
+}
+
 void ModestEngine::updateEmailAccounts() const
 {
     iDefaultEmailAccountId = QMessageAccountId();
@@ -105,12 +371,14 @@
 #endif
         g_error_free(error);
     } else {
-        gchar *default_account = gconf_client_get_string(m_gconfclient, MODESTENGINE_DEFAULT_ACCOUNT, &error);
+        gchar *default_account_id = gconf_client_get_string(m_gconfclient, MODESTENGINE_DEFAULT_ACCOUNT, &error);
         if (error) {
             qWarning("qtmessaging: failed to get '%s': %s", MODESTENGINE_DEFAULT_ACCOUNT, error->message);
             g_error_free(error);
         }
 
+        const size_t prefix_len = strlen(MODESTENGINE_ACCOUNT_NAMESPACE) + 1;
+
         GSList *iter = accounts;
         while (iter) {
             if (!(iter->data)) {
@@ -118,61 +386,83 @@
                 continue;
             }
 
-            const gchar* account_name_key = (const gchar*)iter->data;
+            const gchar* account_key = (const gchar*)iter->data;
+            // account_key = /apps/modest/server_accounts/<account id>
+            // => take account id from account_key & unescape account id
+            gchar* unescaped_account_id = gconf_unescape_key(account_key+prefix_len, strlen(account_key)-prefix_len);
 
             gboolean account_ok = FALSE;
             // Check if account is enabled
-            if (account_name_key) {
-                gchar* key = g_strconcat(account_name_key, "/", MODESTENGINE_ACCOUNT_ENABLED, NULL);
+            if (account_key) {
+                gchar* key = g_strconcat(account_key, "/", MODESTENGINE_ACCOUNT_ENABLED, NULL);
                 account_ok = gconf_client_get_bool(m_gconfclient, key, NULL);
                 g_free(key);
             }
+
             // Check if account store is defined
             if (account_ok) {
-                gchar* key = g_strconcat(account_name_key, "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
+                gchar* key = g_strconcat(account_key, "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
                 gchar* server_account_name = gconf_client_get_string(m_gconfclient, key, NULL);
                 if (server_account_name) {
-                    gchar* key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", server_account_name, NULL);
-                    if (!gconf_client_dir_exists(m_gconfclient, key, NULL)) {
+                    gchar* escaped_server_account_name = gconf_escape_key(server_account_name, strlen(server_account_name));
+                    g_free(server_account_name);
+                    gchar* store_account_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_server_account_name, NULL);
+                    if (!gconf_client_dir_exists(m_gconfclient, store_account_key, NULL)) {
                         account_ok = FALSE;
                     }
-                    g_free(server_account_name);
+                    g_free(store_account_key);
+                    g_free(escaped_server_account_name);
                 }
                 g_free(key);
             }
+
             // Check if account transport is defined
             if (account_ok) {
-                gchar* key = g_strconcat(account_name_key, "/", MODESTENGINE_ACCOUNT_TRANSPORT_ACCOUNT, NULL);
+                gchar* key = g_strconcat(account_key, "/", MODESTENGINE_ACCOUNT_TRANSPORT_ACCOUNT, NULL);
                 gchar* server_account_name = gconf_client_get_string(m_gconfclient, key, NULL);
                 if (server_account_name) {
-                    gchar* key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", server_account_name, NULL);
-                    if (!gconf_client_dir_exists(m_gconfclient, key, NULL)) {
+                    gchar* escaped_server_account_name = gconf_escape_key(server_account_name, strlen(server_account_name));
+                    g_free(server_account_name);
+                    gchar* transport_account_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_server_account_name, NULL);
+                    if (!gconf_client_dir_exists(m_gconfclient, transport_account_key, NULL)) {
                         account_ok = FALSE;
                     }
-                    g_free(server_account_name);
+                    g_free(transport_account_key);
+                    g_free(escaped_server_account_name);
                 }
                 g_free(key);
             }
 
             if (account_ok) {
-                QString accountId = QString::fromUtf8(account_name_key);
-                gchar* name_key = g_strconcat(account_name_key, "/", MODESTENGINE_ACCOUNT_DISPLAY_NAME, NULL);
-                QString accountName = QString::fromUtf8(gconf_client_get_string(m_gconfclient, name_key, NULL));
+                gchar* escaped_account_id = gconf_escape_key(unescaped_account_id, strlen(unescaped_account_id));
+                QString accountId = "MO_"+QString::fromUtf8(escaped_account_id);
+                g_free(escaped_account_id);
+
+                gchar* name_key = g_strconcat(account_key, "/", MODESTENGINE_ACCOUNT_DISPLAY_NAME, NULL);
+                gchar* account_name = gconf_client_get_string(m_gconfclient, name_key, NULL);
+                QString accountName = QString::fromUtf8(account_name);
+                g_free(account_name);
                 g_free(name_key);
-                gchar* email_key = g_strconcat(account_name_key, "/", MODESTENGINE_ACCOUNT_EMAIL, NULL);
-                QString accountAddress = QString::fromUtf8(gconf_client_get_string(m_gconfclient, email_key, NULL));
+
+                gchar* email_key = g_strconcat(account_key, "/", MODESTENGINE_ACCOUNT_EMAIL, NULL);
+                gchar* email = gconf_client_get_string(m_gconfclient, email_key, NULL);
+                QString accountAddress = QString::fromUtf8(email);
+                g_free(email);
                 g_free(email_key);
+
                 QMessageAccount account = QMessageAccountPrivate::from(QMessageAccountId(accountId),
                                                                        accountName,
                                                                        QMessageAddress(QMessageAddress::Email, accountAddress),
                                                                        QMessage::Email);
                 iAccounts.insert(accountId, account);
 
-                if (strncmp(account_name_key, default_account, strlen(default_account))) {
+                // Check if newly added account is default account
+                if (!strncmp(default_account_id, unescaped_account_id, strlen(default_account_id))) {
                     iDefaultEmailAccountId = accountId;
                 }
             }
 
+            g_free(unescaped_account_id);
             g_free(iter->data);
             iter->data = NULL;
             iter = g_slist_next(iter);
@@ -180,13 +470,17 @@
         // strings were freed in while loop
         // => it's enough to just free accounts list
         g_slist_free(accounts);
-        g_free(default_account);
+        g_free(default_account_id);
     }
 }
 
 QMessageAccountIdList ModestEngine::queryAccounts(const QMessageAccountFilter &filter, const QMessageAccountSortOrder &sortOrder,
                                                   uint limit, uint offset, bool &isFiltered, bool &isSorted) const
 {
+    Q_UNUSED(sortOrder)
+    Q_UNUSED(limit)
+    Q_UNUSED(offset)
+
     QMessageAccountIdList accountIds;
 
     updateEmailAccounts();
@@ -214,15 +508,410 @@
     return iAccounts[id.toString()];
 }
 
-QMessageAccountId ModestEngine::defaultAccount(QMessage::Type type) const
+QMessageAccountId ModestEngine::defaultAccount() const
 {
     updateEmailAccounts();
     return iDefaultEmailAccountId;
 }
 
+QFileInfoList ModestEngine::localFolders() const
+{
+    QDir dir(localRootFolder());
+    dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
+    QFileInfoList fileInfoList = dir.entryInfoList();
+    appendLocalSubFolders(fileInfoList, 0);
+    return fileInfoList;
+}
+
+void ModestEngine::appendLocalSubFolders(QFileInfoList& fileInfoList, int startIndex) const
+{
+    int endIndex = fileInfoList.count();
+    for (int i=startIndex; i < endIndex; i++) {
+        QDir dir(fileInfoList[i].absoluteFilePath());
+        if (dir.exists()) {
+            dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
+            QFileInfoList dirs = dir.entryInfoList();
+            for (int j = 0; j < dirs.count(); j++) {
+                QString fileName = dirs[j].fileName();
+                if (fileName != "cur" && fileName != "new" && fileName != "tmp") {
+                    fileInfoList.append(dirs[j]);
+                }
+            }
+        }
+    }
+    if (fileInfoList.count() > endIndex) {
+        appendLocalSubFolders(fileInfoList, endIndex);
+    }
+}
+
+void ModestEngine::appendIMAPSubFolders(QFileInfoList& fileInfoList, int startIndex) const
+{
+    int endIndex = fileInfoList.count();
+    for (int i=startIndex; i < endIndex; i++) {
+        QDir dir(fileInfoList[i].absoluteFilePath()+QString("/subfolders"));
+        if (dir.exists()) {
+            dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
+            fileInfoList.append(dir.entryInfoList());
+        }
+    }
+    if (fileInfoList.count() > endIndex) {
+        appendIMAPSubFolders(fileInfoList, endIndex);
+    }
+}
+
+QString ModestEngine::localRootFolder() const
+{
+    return QDir::home().absolutePath()+QString("/.modest/local_folders");
+}
+
+QString ModestEngine::accountRootFolder(QMessageAccountId& accountId) const
+{
+    QString modestAccountId = escapeString(modestAccountIdFromAccountId(accountId));
+
+    QString userName;
+    QString hostName;
+    QString port;
+    QString protocol;
+
+    gchar* store_account_key = g_strconcat(MODESTENGINE_ACCOUNT_NAMESPACE, "/", modestAccountId.toUtf8().data(), "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
+    gchar* store_account_name = gconf_client_get_string(m_gconfclient, store_account_key, NULL);
+    g_free(store_account_key);
+    gchar* escaped_store_account_name = gconf_escape_key(store_account_name, strlen(store_account_name));
+    g_free(store_account_name);
+
+    gchar* username_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_USERNAME, NULL);
+    gchar* account_username = gconf_client_get_string(m_gconfclient, username_key, NULL);
+    userName = QString::fromUtf8(account_username);
+    g_free(account_username);
+    g_free(username_key);
+
+    gchar* hostname_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_HOSTNAME, NULL);
+    gchar* account_hostname = gconf_client_get_string(m_gconfclient, hostname_key, NULL);
+    hostName = QString::fromUtf8(account_hostname);
+    g_free(account_hostname);
+    g_free(hostname_key);
+
+    gchar* port_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_PORT, NULL);
+    gint account_port = gconf_client_get_int(m_gconfclient, port_key, NULL);
+    port = QString::number(account_port);
+    g_free(port_key);
+
+    gchar* protocol_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_PROTOCOL, NULL);
+    gchar* account_protocol = gconf_client_get_string(m_gconfclient, protocol_key, NULL);
+    protocol = QString::fromUtf8(account_protocol);
+    g_free(account_protocol);
+    g_free(protocol_key);
+
+    g_free(escaped_store_account_name);
+
+    if (protocol == "pop") {
+        return QDir::home().absolutePath()+"/.modest/cache/mail/"+protocol+"/"+userName+"__"+hostName+"_"+port;
+    } else if (protocol == "imap") {
+        return QDir::home().absolutePath()+"/.modest/cache/mail/"+protocol+"/"+userName+"__"+hostName+"_"+port+"/folders";
+    }
+    return QString();
+}
+
+QFileInfoList ModestEngine::accountFolders(QMessageAccountId& accountId) const
+{
+    QFileInfoList fileInfoList;
+
+    EmailProtocol protocol = accountEmailProtocol(accountId);
+
+    if (protocol == ModestEngine::EmailProtocolPop3) {
+        QFileInfo fileInfo = QFileInfo(accountRootFolder(accountId)+"/cache");
+        fileInfoList.append(fileInfo);
+    } else if (protocol == ModestEngine::EmailProtocolIMAP) {
+        QDir dir(accountRootFolder(accountId));
+        dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
+        fileInfoList = dir.entryInfoList();
+        appendIMAPSubFolders(fileInfoList, 0);
+    }
+
+    return fileInfoList;
+}
+
+ModestEngine::EmailProtocol ModestEngine::accountEmailProtocol(QMessageAccountId& accountId) const
+{
+    EmailProtocol protocol = EmailProtocolUnknown;
+
+    QString modestAccountId = escapeString(modestAccountIdFromAccountId(accountId));
+
+    gchar* store_account_key = g_strconcat(MODESTENGINE_ACCOUNT_NAMESPACE, "/", modestAccountId.toUtf8().data(), "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
+    gchar* store_account_name = gconf_client_get_string(m_gconfclient, store_account_key, NULL);
+    g_free(store_account_key);
+    gchar* escaped_store_account_name = gconf_escape_key(store_account_name, strlen(store_account_name));
+    g_free(store_account_name);
+
+    gchar* protocol_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_PROTOCOL, NULL);
+    gchar* account_protocol = gconf_client_get_string(m_gconfclient, protocol_key, NULL);
+    if (QString("pop") == account_protocol) {
+        protocol = EmailProtocolPop3;
+    } else if (QString("imap") == account_protocol) {
+        protocol = EmailProtocolIMAP;
+    }
+    g_free(account_protocol);
+    g_free(protocol_key);
+
+    g_free(escaped_store_account_name);
+
+    return protocol;
+}
+
+QString ModestEngine::accountEmailProtocolAsString(const QMessageAccountId& accountId) const
+{
+    QString protocol;
+
+    QString modestAccountId = escapeString(modestAccountIdFromAccountId(accountId));
+
+    gchar* store_account_key = g_strconcat(MODESTENGINE_ACCOUNT_NAMESPACE, "/", modestAccountId.toUtf8().data(), "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
+    gchar* store_account_name = gconf_client_get_string(m_gconfclient, store_account_key, NULL);
+    g_free(store_account_key);
+    gchar* escaped_store_account_name = gconf_escape_key(store_account_name, strlen(store_account_name));
+    g_free(store_account_name);
+
+    gchar* protocol_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_PROTOCOL, NULL);
+    gchar* account_protocol = gconf_client_get_string(m_gconfclient, protocol_key, NULL);
+    protocol = QString::fromUtf8(account_protocol);
+    g_free(account_protocol);
+    g_free(protocol_key);
+
+    g_free(escaped_store_account_name);
+
+    return protocol;
+}
+
+QString ModestEngine::accountUsername(QMessageAccountId& accountId) const
+{
+    QString username;
+
+    QString modestAccountId = escapeString(modestAccountIdFromAccountId(accountId));
+
+    gchar* store_account_key = g_strconcat(MODESTENGINE_ACCOUNT_NAMESPACE, "/", modestAccountId.toUtf8().data(), "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
+    gchar* store_account_name = gconf_client_get_string(m_gconfclient, store_account_key, NULL);
+    g_free(store_account_key);
+    gchar* escaped_store_account_name = gconf_escape_key(store_account_name, strlen(store_account_name));
+    g_free(store_account_name);
+
+    gchar* username_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_USERNAME, NULL);
+    gchar* account_username = gconf_client_get_string(m_gconfclient, username_key, NULL);
+    username = QString::fromUtf8(account_username);
+    g_free(account_username);
+    g_free(username_key);
+
+    g_free(escaped_store_account_name);
+
+    return username;
+}
+
+QString ModestEngine::accountHostname(QMessageAccountId& accountId) const
+{
+    QString host;
+
+    QString modestAccountId = escapeString(modestAccountIdFromAccountId(accountId));
+
+    gchar* store_account_key = g_strconcat(MODESTENGINE_ACCOUNT_NAMESPACE, "/", modestAccountId.toUtf8().data(), "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
+    gchar* store_account_name = gconf_client_get_string(m_gconfclient, store_account_key, NULL);
+    g_free(store_account_key);
+    gchar* escaped_store_account_name = gconf_escape_key(store_account_name, strlen(store_account_name));
+    g_free(store_account_name);
+
+    gchar* host_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_HOSTNAME, NULL);
+    gchar* account_host = gconf_client_get_string(m_gconfclient, host_key, NULL);
+    host = QString::fromUtf8(account_host);
+    g_free(account_host);
+    g_free(host_key);
+
+    g_free(escaped_store_account_name);
+
+    return host;
+}
+
+QMessageFolderIdList ModestEngine::queryFolders(const QMessageFolderFilter &filter, const QMessageFolderSortOrder &sortOrder,
+                                                uint limit, uint offset, bool &isFiltered, bool &isSorted) const
+{
+    Q_UNUSED(sortOrder)
+    Q_UNUSED(limit)
+    Q_UNUSED(offset)
+
+    QMessageFolderIdList folderIds;
+
+    updateEmailAccounts();
+
+    //QDBusMessage msg = m_ModestDBusInterface->call(MODEST_DBUS_METHOD_GET_FOLDERS);
+    QFileInfoList localFolders = this->localFolders();
+    QString localRootFolder = this->localRootFolder();
+
+    foreach (QMessageAccount value, iAccounts) {
+        QMessageAccountId accountId = value.id();
+        QString rootFolder = accountRootFolder(accountId);
+        QFileInfoList folders = this->accountFolders(accountId);
+
+        for (int i=0; i < folders.count(); i++) {
+            QString filePath = folders[i].absoluteFilePath();
+            QString id = accountId.toString()+"&"+accountEmailProtocolAsString(accountId)+"&"+filePath.right(filePath.size()-rootFolder.size()-1);
+            id = id.remove("/subfolders");
+            folderIds.append(QMessageFolderId(id));
+        }
+
+        // Each account sees local folders as account folders
+        for (int i=0; i < localFolders.count(); i++) {
+            QString filePath = localFolders[i].absoluteFilePath();
+            QString id = accountId.toString()+"&"+"maildir"+"&"+filePath.right(filePath.size()-localRootFolder.size()-1);
+            folderIds.append(QMessageFolderId(id));
+        }
+    }
+
+    MessagingHelper::filterFolders(folderIds, filter);
+    isFiltered = true;
+    isSorted = false;
+    return folderIds;
+}
+
+int ModestEngine::countFolders(const QMessageFolderFilter &filter) const
+{
+    bool isFiltered, isSorted;
+    return queryFolders(filter, QMessageFolderSortOrder(), 0, 0, isFiltered, isSorted).count();
+}
+
+QMessageFolder ModestEngine::folder(const QMessageFolderId &id) const
+{
+    QString idString = id.toString();
+    int endOfAccountId = idString.indexOf('&');
+    int endOfProtocolString = idString.lastIndexOf('&');
+    QString accountId = idString.left(endOfAccountId);
+    QString protocolString = idString.mid(endOfAccountId+1, endOfProtocolString-endOfAccountId-1);
+    QString folder = idString.right(idString.length()-idString.lastIndexOf('&')-1);
+    QMessageFolderId parentId;
+    QString name;
+    if (folder.lastIndexOf('/') == -1) {
+        // Folder does not have subfolders
+        name = folder;
+        if ((protocolString == "pop") && (name == "cache")) {
+            name = "Inbox";
+        }
+    } else {
+        // Folder has subfolders
+        name = folder.right(folder.length()-folder.lastIndexOf('/')-1);
+        parentId = idString.left(idString.lastIndexOf('/'));
+    }
+    return QMessageFolderPrivate::from(id, QMessageAccountId(accountId), parentId, name, folder);
+}
+
+void ModestEngine::watchAllKnownEmailFolders()
+{
+    QFileInfoList localFolders = this->localFolders();
+
+    // Changes in local Email folders can be monitored using directory
+    // monitoring. <=> All messages are stored as individual files.
+    for (int i=0; i < localFolders.count(); i++) {
+        m_MailFoldersWatcher.addDirectory(localFolders[i].absoluteFilePath()+"/cur", IN_MOVED_TO | IN_DELETE);
+    }
+
+    // Monitor changes also in root folder to see if new folders are added
+    m_MailFoldersWatcher.addDirectory(localRootFolder(), IN_CREATE);
+
+    // Changes in remote Email folders must be monitored using file monitoring.
+    // That's because message headers are stored into summary.mmap file (and summary.mmap
+    // file maybe the only place that contains message information).
+    // => summary.mmap files will be monitored
+    foreach (QMessageAccount value, iAccounts) {
+        QMessageAccountId accountId = value.id();
+        QString rootFolder = accountRootFolder(accountId);
+        EmailProtocol protocol = accountEmailProtocol(accountId);
+        QFileInfoList folders = this->accountFolders(accountId);
+
+        for (int i=0; i < folders.count(); i++) {
+            if (protocol == ModestEngine::EmailProtocolPop3) {
+                QString folder = folders[i].absoluteFilePath();
+                m_MailFoldersWatcher.addDirectory(folder, IN_CREATE);
+            } else if (protocol == ModestEngine::EmailProtocolIMAP) {
+                m_MailFoldersWatcher.addDirectory(folders[i].absoluteFilePath(), IN_MOVED_TO | IN_DELETE);
+            }
+        }
+
+    }
+}
+
+void ModestEngine::fileChangedSlot(int watchDescriptor, QString filePath, uint events)
+{
+    Q_UNUSED(watchDescriptor)
+
+    if (events & IN_CREATE) {
+        if (QFileInfo(filePath).isDir()) {
+            // New directory was added
+            // => Start watching new folder
+            QString newDirPath = QString(filePath.toUtf8());
+            m_MailFoldersWatcher.addDirectory(newDirPath + "/cur");
+        }
+    }
+
+    int filenameBegin = filePath.lastIndexOf('/')+1;
+    QString fileName = filePath.mid(filenameBegin,filePath.lastIndexOf('.')-filenameBegin);
+    if (fileName != "summary") {
+        if (events & (IN_MOVED_TO | IN_CREATE)) {
+            if (events != (IN_MOVED_TO | IN_MOVED_FROM)) {
+                notification(messageIdFromModestMessageFilePath(filePath), ModestEngine::Added);
+            }
+        } else if (events & IN_DELETE) {
+            notification(messageIdFromModestMessageFilePath(filePath), ModestEngine::Removed);
+        }
+    }
+}
+
 bool ModestEngine::sendEmail(QMessage &message)
 {
-    return composeEmail(message);
+    ModestStringMap senderInfo;
+    ModestStringMap recipients;
+    ModestStringMap messageData;
+    ModestStringMapList attachments;
+    ModestStringMapList images;
+    uint priority = 0;
+    ModestStringMap headers;
+
+    senderInfo = getModestSenderInfo(message);
+
+    if (senderInfo.isEmpty()) {
+        return false;
+    }
+
+    recipients = getModestRecipients(message);
+
+    if (recipients.isEmpty()) {
+        return false;
+    }
+
+    messageData = getModestMessageData(message);
+    attachments = getModestAttachments(message);
+    images = getModestImages(message);
+    priority = getModestPriority(message);
+    headers = getModestHeaders(message);
+
+    qDebug() << "Sending D-BUS message";
+
+    QDBusPendingCall call = m_QtmPluginDBusInterface->asyncCall (
+            "SendEmail",
+            QVariant::fromValue (senderInfo),
+            QVariant::fromValue (recipients),
+            QVariant::fromValue (messageData),
+            QVariant::fromValue (attachments),
+            QVariant::fromValue (images),
+            priority,
+            QVariant::fromValue (headers));
+
+    qDebug() << "Message sent";
+
+    if (call.isError()) {
+        qWarning() << "Call failed! " << call.error();
+        return false;
+    }
+
+    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher (call, this);
+
+    connect (watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+             this, SLOT(sendEmailCallEnded(QDBusPendingCallWatcher*)));
+
+    return true;
 }
 
 bool ModestEngine::composeEmail(const QMessage &message)
@@ -232,10 +921,10 @@
     if (!list.empty()){
         for (int i = 0; i < list.size(); ++i) {
             if (i == 0) {
-                mailString += list.at(i).recipient();
+                mailString += list.at(i).addressee();
             } else {
                 mailString += QString("%2C%20");
-                mailString += list.at(i).recipient();
+                mailString += list.at(i).addressee();
             }
         }
     }
@@ -274,20 +963,2170 @@
     return true;
 }
 
-bool ModestEngine::queryMessages(QMessageService& messageService, const QMessageFilter &filter, const QMessageSortOrder &sortOrder, uint limit, uint offset) const
+bool ModestEngine::showMessage(const QMessageId &id)
 {
+    QMessage msg = message(id, false);
+    QMessagePrivate* privateMessage = QMessagePrivate::implementation(msg);
+    if (privateMessage->_url.isEmpty()) {
+        return false;
+    } else {
+        m_ModestDBusInterface->call(MODEST_DBUS_METHOD_OPEN_MESSAGE,
+                                    privateMessage->_url);
+    }
+    return true;
+}
+
+bool ModestEngine::exportUpdates(const QMessageAccountId &id)
+{
+    Q_UNUSED(id) // Modest does not offer Account specific updates
+
+    m_ModestDBusInterface->call(MODEST_DBUS_METHOD_SEND_RECEIVE);
     return true;
 }
 
-bool ModestEngine::queryMessages(QMessageService& messageService, const QMessageFilter &filter, const QString &body, QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder, uint limit, uint offset) const
+QMessage ModestEngine::message(const QMessageId &id, bool useCache) const
+{
+    if (useCache) {
+        QMessage message = m_messageCache.value(id.toString());
+        if (message.type() != QMessage::NoType) {
+            return message;
+        }
+    }
+
+    QString modestAccountId = modestAccountIdFromMessageId(id);
+    QString modestFolderId = modestFolderIdFromMessageId(id);
+    QString modestMessageId = modestMessageIdFromMessageId(id);
+
+    MessagingModestMessage modestMessage = messageFromModest(modestAccountId,
+                                                             modestFolderId,
+                                                             modestMessageId);
+
+    if (modestMessage.flags & MessagingModestMessageDeleted) {
+        return QMessage();
+    }
+
+    if (modestMessage.accountId.isEmpty()) {
+        return QMessage();
+    }
+
+    return messageFromModestMessage(modestMessage, accountIdFromMessageId(id));
+}
+
+QMessage::StandardFolder ModestEngine::standardFolderFromModestFolderId(const QString& modestFolderId) const
+{
+    if (!QString::compare(modestFolderId, "INBOX", Qt::CaseInsensitive)) {
+        return QMessage::InboxFolder;
+    } else if (!QString::compare(modestFolderId, "drafts", Qt::CaseInsensitive)) {
+        return QMessage::DraftsFolder;
+    } else if (!QString::compare(modestFolderId, "sent", Qt::CaseInsensitive)) {
+        return QMessage::SentFolder;
+    }
+
+    return QMessage::DraftsFolder;
+}
+
+QString ModestEngine::modestFolderIdFromStandardFolder(QMessage::StandardFolder standardFolder) const
+{
+    switch (standardFolder) {
+    case QMessage::InboxFolder:  return "INBOX";
+    case QMessage::DraftsFolder: return "drafts";
+    case QMessage::SentFolder:   return "sent";
+    case QMessage::OutboxFolder: return "outbox";
+    case QMessage::TrashFolder:  return "thrash";
+    }
+    return "drafts";
+}
+
+QMessage ModestEngine::messageFromModestMessage(const MessagingModestMessage& modestMessage,
+                                                QMessageAccountId accountId) const
 {
+    QMessage message;
+    QMessagePrivate* privateMessage = QMessagePrivate::implementation(message);
+    QMessageContentContainerPrivate* container = QMessagePrivate::containerImplementation(message);
+
+    // Type
+    message.setType(QMessage::Email);
+
+    // Parent Account Id
+    QMessageAccountId parentAccountId;
+    if (accountId.isValid()) {
+        parentAccountId = accountId;
+    } else {
+        parentAccountId = realAccountId(modestMessage);
+    }
+    message.setParentAccountId(parentAccountId);
+
+    // Parent Folder Id
+    QMessageFolderId folderId;
+    if (modestMessage.accountId == "local_folders") {
+        folderId = folderIdFromModestFolderId(parentAccountId, true, modestMessage.folderId);
+    } else {
+        // Since Message is not in local folder, message status can be set to Incoming
+        privateMessage->_status = privateMessage->_status | QMessage::Incoming;
+        folderId = folderIdFromModestFolderId(parentAccountId, false, modestMessage.folderId);
+    }
+    privateMessage->_parentFolderId = folderId;
+
+    // Message Id
+    QMessageId messageId = QMessageId(folderId.toString()+"/"+modestMessage.id);
+    privateMessage->_id = messageId;
+
+    // Dates
+    message.setDate(QDateTime::fromTime_t(modestMessage.dateSent));
+    message.setReceivedDate(QDateTime::fromTime_t(modestMessage.dateReceived));
+
+    // Priority
+    switch (modestMessage.priority) {
+    case QtMobility::MessagingModestMessageHighPriority:
+        message.setPriority(QMessage::HighPriority);
+        break;
+    case QtMobility::MessagingModestMessageNormalPriority:
+        message.setPriority(QMessage::NormalPriority);
+        break;
+    case QtMobility::MessagingModestMessageLowPriority:
+        message.setPriority(QMessage::LowPriority);
+        break;
+    case QtMobility::MessagingModestMessageSuspendedPriority:
+        message.setPriority(QMessage::NormalPriority);
+        break;
+    }
+
+    // Standard Folder
+    QMessagePrivate::setStandardFolder(message,
+                                       standardFolderFromModestFolderId(modestMessage.folderId));
+
+    // Body & Attachments handling
+    for (int i=0; i < modestMessage.mimeParts.count(); i++) {
+        if (!modestMessage.mimeParts[i].isAttachment) {
+            // Body
+            QByteArray fullMimeType = modestMessage.mimeParts[i].mimeType.toUtf8();
+            QString contentId = modestMessage.mimeParts[i].contentId;
+            QByteArray fileName = modestMessage.mimeParts[i].fileName.toAscii();
+
+            QByteArray mainType("text");
+            QByteArray subType("plain");
+            QByteArray charset;
+
+            int index = fullMimeType.indexOf("/");
+            if (index != -1) {
+                mainType = fullMimeType.left(index).trimmed();
+
+                subType = fullMimeType.mid(index + 1).trimmed();
+                index = subType.indexOf(";");
+                if (index != -1) {
+                    QString remainder = subType.mid(index + 1);
+                    subType = subType.left(index).trimmed();
+
+                    QRegExp charsetPattern("charset=(\\S+)");
+                    index = charsetPattern.indexIn(remainder);
+                    if (index != -1) {
+                        charset = charsetPattern.cap(1).toLatin1();
+                    }
+                }
+            }
+
+            if (charset.isEmpty()) {
+                charset = "UTF-8";
+            }
+
+            QMessageContentContainerId existingBodyId(message.bodyId());
+            if (existingBodyId.isValid()) {
+                if (existingBodyId == container->bodyContentId()) {
+                    // The body content is in the message itself
+                    container->_containingMessageId = messageId.toString();
+                    container->_attachmentId = contentId;
+                    container->_name = fileName;
+                    container->_type = mainType;
+                    container->_subType = subType;
+                    container->_charset = charset;
+                    container->_size = 0;
+                    container->_available = true;
+                } else {
+                    // The body content is in the first attachment
+                    QMessageContentContainerPrivate *attachmentContainer(QMessageContentContainerPrivate::implementation(*container->attachment(existingBodyId)));
+                    attachmentContainer->_containingMessageId = messageId.toString();
+                    attachmentContainer->_attachmentId = contentId;
+                    attachmentContainer->_name = fileName;
+                    attachmentContainer->_type = mainType;
+                    attachmentContainer->_subType = subType;
+                    attachmentContainer->_charset = charset;
+                    attachmentContainer->_size = 0;
+                    attachmentContainer->_available = true;
+                }
+            } else {
+                if (container->_attachments.isEmpty()) {
+                    // Put the content directly into the message
+                    container->_containingMessageId = messageId.toString();
+                    container->_attachmentId = contentId;
+                    container->_name = fileName;
+                    container->_type = mainType;
+                    container->_subType = subType;
+                    container->_charset = charset;
+                    container->_size = 0;
+                    container->_available = true;
+                    privateMessage->_bodyId = container->bodyContentId();
+                } else {
+                    // Add the body as the first attachment
+                    QMessageContentContainer newBody;
+                    QMessageContentContainerPrivate *attachmentContainer = QMessageContentContainerPrivate::implementation(newBody);
+                    attachmentContainer->_containingMessageId = messageId.toString();
+                    attachmentContainer->_attachmentId = contentId;
+                    attachmentContainer->_name = fileName;
+                    attachmentContainer->_type = mainType;
+                    attachmentContainer->_subType = subType;
+                    attachmentContainer->_charset = charset;
+                    attachmentContainer->_size = 0;
+                    attachmentContainer->_available = true;
+                    privateMessage->_bodyId = container->prependContent(newBody);
+                }
+            }
+        } else {
+            // Attachment
+            QString fullMimeType = modestMessage.mimeParts[i].mimeType;
+            QString contentId = modestMessage.mimeParts[i].contentId;
+            int slashIndex = fullMimeType.indexOf('/');
+            QByteArray mimeType = fullMimeType.left(slashIndex).toAscii();
+            QByteArray mimeSubType = fullMimeType.mid(slashIndex+1).toAscii();
+            // TODO: Attachment size
+            QByteArray fileName = modestMessage.mimeParts[i].fileName.toAscii();
+            fileName = fileName.mid(fileName.lastIndexOf('/')+1);
+            QString msgId = messageId.toString();
+            QMessageContentContainer attachment =
+                    QMessageContentContainerPrivate::from(msgId,
+                                                          contentId,
+                                                          fileName,
+                                                          mimeType,
+                                                          mimeSubType,
+                                                          0);
+            appendAttachmentToMessage(message, attachment);
+        }
+    }
+
+    // From
+    if (modestMessage.from.size() > 0) {
+        message.setFrom(QMessageAddress(QMessageAddress::Email, modestMessage.from));
+        QMessagePrivate::setSenderName(message, modestMessage.from);
+    }
+
+    // To
+    if (modestMessage.to.size() > 0) {
+        QMessageAddressList toAddresses;
+        foreach (const QString &element, modestMessage.to.split(",", QString::SkipEmptyParts)) {
+            QMessageAddress addr;
+            addr.setType(QMessageAddress::Email);
+            addr.setAddressee(element.trimmed());
+            toAddresses.append(addr);
+        }
+        message.setTo(toAddresses);
+    }
+
+    // Cc
+    if (modestMessage.cc.size() > 0) {
+        QMessageAddressList ccAddresses;
+        foreach (const QString &element, modestMessage.cc.split(",", QString::SkipEmptyParts)) {
+            QMessageAddress addr;
+            addr.setType(QMessageAddress::Email);
+            addr.setAddressee(element.trimmed());
+            ccAddresses.append(addr);
+        }
+        message.setCc(ccAddresses);
+    }
+
+    // Bcc
+    if (modestMessage.bcc.size() > 0) {
+        QMessageAddressList bccAddresses;
+        foreach (const QString &element, modestMessage.bcc.split(",", QString::SkipEmptyParts)) {
+            QMessageAddress addr;
+            addr.setType(QMessageAddress::Email);
+            addr.setAddressee(element.trimmed());
+            bccAddresses.append(addr);
+        }
+        message.setBcc(bccAddresses);
+    }
+
+    // Subject
+    message.setSubject(modestMessage.subject);
+
+    // Size
+    privateMessage->_size = modestMessage.size;
+
+    // Read Status
+    if (modestMessage.flags & MessagingModestMessageSeen) {
+        privateMessage->_status = privateMessage->_status | QMessage::Read;
+    }
+
+    // Message MIME type
+    QString fullMimeType = modestMessage.mimeType;
+    int slashIndex = fullMimeType.indexOf('/');
+    QByteArray mimeType = fullMimeType.left(slashIndex).toAscii();
+    QByteArray mimeSubType = fullMimeType.mid(slashIndex+1).toAscii();
+    container->_type = mimeType.data();
+    container->_subType = mimeSubType.data();
+
+    // Modest specific url
+    privateMessage->_url = modestMessage.url;
+
+    // Modified flag
+    privateMessage->_modified = false;
+
+    return message;
+}
+
+void ModestEngine::appendAttachmentToMessage(QMessage& message, QMessageContentContainer& attachment) const
+{
+    QMessagePrivate* privateMessage = QMessagePrivate::implementation(message);
+    QMessageContentContainerPrivate* container = QMessagePrivate::containerImplementation(message);
+
+    if (container->_attachments.isEmpty()) {
+        QMessageContentContainerId existingBodyId(message.bodyId());
+        if (existingBodyId == QMessageContentContainerPrivate::bodyContentId()) {
+            // The body content is in the message itself - move it to become the first attachment
+            QMessageContentContainer newBody(message);
+            QMessageContentContainerPrivate::implementation(newBody)->setDerivedMessage(0);
+
+            container->setContentType("multipart", "mixed", "");
+            privateMessage->_bodyId = container->prependContent(newBody);
+        } else {
+            // This message is now multipart
+            container->setContentType("multipart", "mixed", "");
+        }
+
+        container->_available = true;
+    }
+
+    container->appendContent(attachment);
+
+    bool haveAttachments = !container->_attachments.isEmpty();
+    message.setStatus(QMessage::HasAttachments,haveAttachments);
+
+    privateMessage->_modified = true;
+}
+
+bool ModestEngine::addMessage(QMessage &message)
+{
+    QString modestFolder;
+    ModestStringMap senderInfo;
+    ModestStringMap recipients;
+    ModestStringMap messageData;
+    ModestStringMapList attachments;
+    ModestStringMapList images;
+    uint priority = 0;
+    ModestStringMap headers;
+
+    qDebug() << __PRETTY_FUNCTION__;
+
+    senderInfo = getModestSenderInfo (message);
+    recipients = getModestRecipients (message);
+    messageData = getModestMessageData (message);
+    attachments = getModestAttachments (message);
+    images = getModestImages (message);
+    priority = getModestPriority (message);
+    headers = getModestHeaders (message);
+
+    QString accountName;
+    if (message.parentFolderId().isValid()) {
+        modestFolder = modestFolderIdFromFolderId (message.parentFolderId());
+        accountName = modestAccountIdFromFolderId(message.parentFolderId());
+    } else {
+        modestFolder = modestFolderIdFromStandardFolder(message.standardFolder());
+        if (message.standardFolder() == QMessage::DraftsFolder) {
+            accountName = "local_folders";
+        } else {
+            accountName = modestAccountIdFromAccountId(message.parentAccountId());
+        }
+    }
+    senderInfo["account-name"] = accountName;
+
+    QDBusPendingCall pendingCall = m_QtmPluginDBusInterface->asyncCall (
+            "AddMessage",
+            QVariant::fromValue (modestFolder),
+            QVariant::fromValue (senderInfo),
+            QVariant::fromValue (recipients),
+            QVariant::fromValue (messageData),
+            QVariant::fromValue (attachments),
+            QVariant::fromValue (images),
+            priority,
+            QVariant::fromValue (headers));
+
+    if (pendingCall.isError()) {
+        qWarning() << "DBus call failed! " << pendingCall.error();
+        return false;
+    }
+
+    QDBusPendingCallWatcher pendingCallWatcher(pendingCall);
+    pendingCallWatcher.waitForFinished();
+    QDBusMessage msg = pendingCallWatcher.reply();
+    if (msg.type() == QDBusMessage::ErrorMessage) {
+        qWarning() << "Failed to add message via modest: " << msg.errorMessage();
+        return false;
+    }
+
+    QMessagePrivate* privateMessage = QMessagePrivate::implementation(message);
+    QString messageId;
+    if (message.parentFolderId().isValid()) {
+        messageId = message.parentFolderId().toString()+"/"+msg.arguments()[0].toString();
+    } else if (accountName == "local_folders") {
+        messageId = message.parentAccountId().toString()+
+                    "&maildir&"+modestFolder+"/"+msg.arguments()[0].toString();
+    } else {
+        messageId = message.parentAccountId().toString()+"&"+
+                    accountEmailProtocolAsString(message.parentAccountId())+
+                    "&"+modestFolder+"/"+msg.arguments()[0].toString();
+    }
+    privateMessage->_id = QMessageId(messageId);
+
     return true;
 }
 
+bool ModestEngine::updateMessage(QMessage &message)
+{
+    Q_UNUSED(message) // TODO:
+
+    return false;
+}
+
+bool ModestEngine::removeMessage(const QMessageId &id, QMessageManager::RemovalOption option)
+{
+    Q_UNUSED(option) // TODO:
+
+    QMessage msg = message(id, false);
+    QMessagePrivate* privateMessage = QMessagePrivate::implementation(msg);
+    if (privateMessage->_url.isEmpty()) {
+        return false;
+    } else {
+        m_ModestDBusInterface->call(MODEST_DBUS_METHOD_DELETE_MESSAGE,
+                                    privateMessage->_url);
+        // Make sure that there will instant notification about removed message
+        notification(id, ModestEngine::Removed);
+    }
+    return true;
+}
+
+bool ModestEngine::filterMessage(const QMessage& message, QMessageFilterPrivate::SortedMessageFilterList filterList, int start) const
+{
+    if (filterList.count() > start) {
+        for (int j=start; j < filterList.count(); j++) {
+            QMessageFilterPrivate* pf = QMessageFilterPrivate::implementation(filterList[j]);
+            if (!pf->filter(message)) {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+QMessageIdList ModestEngine::queryMessagesSync(const QMessageFilter &filter, const QMessageSortOrder &sortOrder,
+                                               uint limit, uint offset, bool &isFiltered, bool &isSorted) const
+{
+    QMessageIdList ids;
+
+    QMessageServicePrivate* privateService = QMessageServicePrivate::implementation(m_service);
+    if (privateService->queryMessages(m_service, filter, sortOrder, limit, offset,
+                                      QMessageServicePrivate::EnginesToCallModest)) {
+        QObject::connect(&m_service, SIGNAL(stateChanged(QMessageService::State)),
+                         this, SLOT(stateChanged(QMessageService::State)));
+
+        m_eventLoop.exec();
+
+        isSorted = m_isSorted;
+        isFiltered = m_isFiltered;
+        ids = m_ids;
+        m_ids.clear();
+    }
+
+    return ids;
+}
+
+QMessageIdList ModestEngine::queryMessagesSync(const QMessageFilter &filter, const QString &body,
+                                               QMessageDataComparator::MatchFlags matchFlags,
+                                               const QMessageSortOrder &sortOrder, uint limit, uint offset,
+                                               bool &isFiltered, bool &isSorted) const
+{
+    QMessageIdList ids;
+
+    QMessageServicePrivate* privateService = QMessageServicePrivate::implementation(m_service);
+    if (privateService->queryMessages(m_service, filter, body, matchFlags,
+                                      sortOrder, limit, offset,
+                                      QMessageServicePrivate::EnginesToCallModest)) {
+        QObject::connect(&m_service, SIGNAL(stateChanged(QMessageService::State)),
+                         this, SLOT(stateChanged(QMessageService::State)));
+
+        m_eventLoop.exec();
+
+        isSorted = m_isSorted;
+        isFiltered = m_isFiltered;
+        ids = m_ids;
+        m_ids.clear();
+    }
+
+    return ids;
+}
+
+int ModestEngine::countMessagesSync(const QMessageFilter &filter) const
+{
+    int count;
+
+    QMessageServicePrivate* privateService = QMessageServicePrivate::implementation(m_service);
+    if (privateService->countMessages(m_service, filter, QMessageServicePrivate::EnginesToCallModest)) {
+        QObject::connect(&m_service, SIGNAL(stateChanged(QMessageService::State)),
+                         this, SLOT(stateChanged(QMessageService::State)));
+
+        m_eventLoop.exec();
+
+        count = m_count;
+    }
+
+    return count;
+}
+
+void ModestEngine::stateChanged(QMessageService::State newState)
+{
+    if (newState == QMessageService::FinishedState) {
+        QMessageServicePrivate* privateService = QMessageServicePrivate::implementation(m_service);
+
+        m_ids = privateService->_ids;
+        m_isSorted = privateService->_sorted;
+        m_isFiltered = privateService->_filtered;
+        m_count = privateService->_count;
+
+        m_eventLoop.quit();
+    }
+}
+
+bool ModestEngine::queryMessages(QMessageService& messageService, const QMessageFilter &filter, const QMessageSortOrder &sortOrder, uint limit, uint offset) const
+{
+    return queryMessages(messageService, filter, QString(), 0, sortOrder, limit, offset);
+}
+
 bool ModestEngine::countMessages(QMessageService& messageService, const QMessageFilter &filter)
 {
+    m_pendingMessageQueries.append(MessageQueryInfo());
+
+    MessageQueryInfo &queryInfo = m_pendingMessageQueries[m_pendingMessageQueries.count()-1];
+
+    queryInfo.filter = filter;
+    queryInfo.limit = 0;
+    queryInfo.offset = 0;
+    queryInfo.privateService = QMessageServicePrivate::implementation(messageService);
+    queryInfo.currentFilterListIndex = 0;
+    queryInfo.handledFiltersCount = 0;
+    queryInfo.isQuery = false;
+    queryInfo.returnWithSingleShot = false;
+
+    if (!startQueryingAndFilteringMessages(m_pendingMessageQueries[m_pendingMessageQueries.count()-1])) {
+        QMessageServicePrivate::implementation(messageService)->setFinished(false);
+        m_pendingMessageQueries.removeAt(m_pendingMessageQueries.count()-1);
+        return false;
+    }
+
+    return true;
+}
+
+bool ModestEngine::queryMessages(QMessageService& messageService, const QMessageFilter &filter, const QString &body,
+                                 QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder,
+                                 uint limit, uint offset) const
+{
+    m_pendingMessageQueries.append(MessageQueryInfo());
+
+    MessageQueryInfo &queryInfo = m_pendingMessageQueries[m_pendingMessageQueries.count()-1];
+
+    queryInfo.body = body;
+    queryInfo.matchFlags = matchFlags;
+    queryInfo.filter = filter;
+    queryInfo.sortOrder = sortOrder;
+    queryInfo.limit = limit;
+    queryInfo.offset = offset;
+    queryInfo.privateService = QMessageServicePrivate::implementation(messageService);
+    queryInfo.currentFilterListIndex = 0;
+    queryInfo.handledFiltersCount = 0;
+    queryInfo.isQuery = true;
+    queryInfo.returnWithSingleShot = false;
+
+    if (!startQueryingAndFilteringMessages(m_pendingMessageQueries[m_pendingMessageQueries.count()-1])) {
+        QMessageServicePrivate::implementation(messageService)->setFinished(false);
+        m_pendingMessageQueries.removeAt(m_pendingMessageQueries.count()-1);
+        return false;
+    }
+
+    return true;
+}
+
+bool ModestEngine::startQueryingAndFilteringMessages(MessageQueryInfo &msgQueryInfo) const
+{
+    QMessageFilterPrivate* pf = QMessageFilterPrivate::implementation(msgQueryInfo.filter);
+    if (pf->_filterList.count() == 0) {
+        if ((pf->_field == QMessageFilterPrivate::None) &&
+            (pf->_filterList.count() == 0) &&
+            (pf->_notFilter)) {
+            // There is only one filter: empty ~QMessageFilter()
+            // => return empty QMessageIdList
+            msgQueryInfo.ids.clear();
+            msgQueryInfo.returnWithSingleShot = true;
+            QTimer::singleShot(0, (ModestEngine*)this, SLOT(returnQueryResultsSlot()));
+            return true;
+        } else {
+            // One single filter to be handled
+            QMessageFilter newFilter;
+            QMessageFilterPrivate* pfNew = QMessageFilterPrivate::implementation(newFilter);
+            pfNew->_filterList.append(QMessageFilterPrivate::SortedMessageFilterList());
+            pfNew->_filterList[0] << msgQueryInfo.filter;
+            msgQueryInfo.filter = newFilter;
+        }
+    }
+
+    return queryAndFilterMessages(msgQueryInfo);
+}
+
+void ModestEngine::returnQueryResultsSlot()
+{
+    for (int i=m_pendingMessageQueries.count()-1; i >= 0; i--) {
+        if (m_pendingMessageQueries[i].returnWithSingleShot) {
+            if (m_pendingMessageQueries[i].isQuery) {
+                m_pendingMessageQueries[i].privateService->messagesFound(m_pendingMessageQueries[i].ids, true, true);
+            } else {
+                m_pendingMessageQueries[i].privateService->messagesCounted(m_pendingMessageQueries[i].ids.count());
+            }
+            m_pendingMessageQueries.removeAt(i);
+        }
+    }
+}
+
+bool ModestEngine::queryAndFilterMessages(MessageQueryInfo &msgQueryInfo) const
+{
+    QStringList accountIds;
+    QStringList folderUris;
+    QDateTime startTimeStamp;
+    QDateTime endTimeStamp;
+    QDateTime startReceptionTimeStamp;
+    QDateTime endReceptionTimeStamp;
+
+    QMessageFilterPrivate* pf = QMessageFilterPrivate::implementation(msgQueryInfo.filter);
+
+    // Filters have been sorted into matrix of filters:
+    // - there is AND operation between every filter in one row
+    // - there is OR operation between every row
+    // => Every row can be handled individually
+    // => Final result set can be created by combining result sets
+    //    from individual row based queries
+    QMessageFilterPrivate::SortedMessageFilterList filters = pf->_filterList[msgQueryInfo.currentFilterListIndex];
+
+    msgQueryInfo.realAccountId = QString();
+
+    int handledFiltersCount = 0;
+    pf = QMessageFilterPrivate::implementation(filters[handledFiltersCount]);
+    if ((filters.count() == 1) &&
+        (pf->_field == QMessageFilterPrivate::None) &&
+        (pf->_filterList.count() == 0)) {
+        if (pf->_notFilter) {
+            // There is only one filter: empty ~QMessageFilter()
+            // => this query results empty QMessageIdList
+            // => Skip to next query round
+            int index = -1;
+            for (int i=0; i < m_pendingMessageQueries.count(); i++) {
+                if (m_pendingMessageQueries[i].queryId == msgQueryInfo.queryId) {
+                    index = i;
+                    break;
+                }
+            }
+            if (index >= 0) {
+                handleQueryFinished(index);
+            }
+            return true;
+        } else {
+            // There is only one filter: empty QMessageFilter()
+            // => return all messages
+            handledFiltersCount++;
+        }
+    }
+
+    bool handled = true;
+    while (handledFiltersCount < filters.count() && handled) {
+        handled = false;
+        pf = QMessageFilterPrivate::implementation(filters[handledFiltersCount]);
+        switch (pf->_field) {
+        case QMessageFilterPrivate::Id:
+            break;
+        case QMessageFilterPrivate::ParentAccountId:
+            {
+            if (pf->_comparatorType == QMessageFilterPrivate::Equality) {
+                if (accountIds.count()) {
+                    // Only one account/one query can be used
+                    break;
+                }
+                QMessageDataComparator::EqualityComparator cmp(static_cast<QMessageDataComparator::EqualityComparator>(pf->_comparatorValue));
+                if (cmp == QMessageDataComparator::Equal) {
+                    if (pf->_value.toString().length() > 0) {
+                        accountIds.append(modestAccountIdFromAccountId(pf->_value.toString()));
+                        msgQueryInfo.realAccountId = pf->_value.toString();
+                        handled = true;
+                    }
+                }
+            }
+            break;
+        }
+        case QMessageFilterPrivate::ParentFolderId:
+            {
+            if (pf->_comparatorType == QMessageFilterPrivate::Equality) {
+                QMessageDataComparator::EqualityComparator cmp(static_cast<QMessageDataComparator::EqualityComparator>(pf->_comparatorValue));
+                if (cmp == QMessageDataComparator::Equal) {
+                    if (pf->_value.toString().length() > 0) {
+                        folderUris.append(modestFolderIdFromFolderId(pf->_value.toString()));
+                        if (accountIds.count() == 0) {
+                            accountIds.append(modestAccountIdFromFolderId(pf->_value.toString()));
+
+                            // Note: Even though local folders belong to "local_folders" account
+                            //       inside Modest, local folders can belong to any "real"
+                            //       POP3 or IMAP account in Qt Mobility Messaging side
+                            //       <=> Qt Mobility Messaging does not have "Local Folders"
+                            //           account
+                            // If folder is local folder, "local_folders" accountId will be
+                            // added to accountIds list to enable correct filtering inside
+                            // Modest Plugin
+                            accountIds.append("local_folders");
+
+                            // realAccountId will contain id of Qt Mobility Messaging account
+                            // (AccountId can be found from the beginning of folderId string)
+                            // <=> realAccountId will not ever be "local_folders"
+                            msgQueryInfo.realAccountId = accountIdFromFolderId(pf->_value.toString()).toString();
+                        }
+                        handled = true;
+                    }
+                }
+            }
+            break;
+            }
+        case QMessageFilterPrivate::AncestorFolderIds:
+            break;
+        case QMessageFilterPrivate::Type:
+            break;
+        case QMessageFilterPrivate::StandardFolder:
+            if (pf->_comparatorType == QMessageFilterPrivate::Equality) {
+                QMessageDataComparator::EqualityComparator cmp(static_cast<QMessageDataComparator::EqualityComparator>(pf->_comparatorValue));
+                if (cmp == QMessageDataComparator::Equal) {
+                    QMessage::StandardFolder standardFolder = static_cast<QMessage::StandardFolder>(pf->_value.toInt());
+                    if (standardFolder == QMessage::SentFolder) {
+                        folderUris.append("sent");
+                        if (accountIds.count() == 0) {
+                            accountIds.append("local_folders");
+                        }
+                    }
+                    handled = true;
+                }
+            }
+            break;
+        case QMessageFilterPrivate::ParentAccountIdFilter:
+            break;
+        case QMessageFilterPrivate::ParentFolderIdFilter:
+            break;
+        case QMessageFilterPrivate::TimeStamp:
+            {
+            if (pf->_comparatorType == QMessageFilterPrivate::Equality) {
+                QMessageDataComparator::EqualityComparator cmp(static_cast<QMessageDataComparator::EqualityComparator>(pf->_comparatorValue));
+                if (cmp == QMessageDataComparator::Equal) {
+                    endTimeStamp = pf->_value.toDateTime();
+                    startTimeStamp = pf->_value.toDateTime();
+                    handled = true;
+                }
+            }
+            if (pf->_comparatorType == QMessageFilterPrivate::Relation) {
+                QMessageDataComparator::RelationComparator cmp(static_cast<QMessageDataComparator::RelationComparator>(pf->_comparatorValue));
+                if (cmp == QMessageDataComparator::LessThan) {
+                    endTimeStamp = pf->_value.toDateTime();
+                    handled = true;
+                } else if (cmp == QMessageDataComparator::LessThanEqual) {
+                    endTimeStamp = pf->_value.toDateTime();
+                    handled = true;
+                } else if (cmp == QMessageDataComparator::GreaterThan) {
+                    startTimeStamp = pf->_value.toDateTime();
+                    handled = true;
+                } if (cmp == QMessageDataComparator::GreaterThanEqual) {
+                    startTimeStamp = pf->_value.toDateTime();
+                    handled = true;
+                }
+            }
+            break;
+            }
+        case QMessageFilterPrivate::ReceptionTimeStamp:
+            {
+            if (pf->_comparatorType == QMessageFilterPrivate::Equality) {
+                QMessageDataComparator::EqualityComparator cmp(static_cast<QMessageDataComparator::EqualityComparator>(pf->_comparatorValue));
+                if (cmp == QMessageDataComparator::Equal) {
+                    endReceptionTimeStamp = pf->_value.toDateTime();
+                    startReceptionTimeStamp = pf->_value.toDateTime();
+                    handled = true;
+                }
+            }
+            if (pf->_comparatorType == QMessageFilterPrivate::Relation) {
+                QMessageDataComparator::RelationComparator cmp(static_cast<QMessageDataComparator::RelationComparator>(pf->_comparatorValue));
+                if (cmp == QMessageDataComparator::LessThan) {
+                    endReceptionTimeStamp = pf->_value.toDateTime();
+                    handled = true;
+                } else if (cmp == QMessageDataComparator::LessThanEqual) {
+                    endReceptionTimeStamp = pf->_value.toDateTime();
+                    handled = true;
+                } else if (cmp == QMessageDataComparator::GreaterThan) {
+                    startReceptionTimeStamp = pf->_value.toDateTime();
+                    handled = true;
+                } if (cmp == QMessageDataComparator::GreaterThanEqual) {
+                    startReceptionTimeStamp = pf->_value.toDateTime();
+                    handled = true;
+                }
+            }
+            break;
+            }
+        case QMessageFilterPrivate::Sender:
+            break;
+        case QMessageFilterPrivate::Recipients:
+            break;
+        case QMessageFilterPrivate::Subject:
+            break;
+        case QMessageFilterPrivate::Status:
+            break;
+        case QMessageFilterPrivate::Priority:
+            break;
+        case QMessageFilterPrivate::Size:
+            break;
+        case QMessageFilterPrivate::None:
+            break;
+        }
+        handledFiltersCount++;
+    }
+
+    msgQueryInfo.handledFiltersCount = 0; // Do filtering also for filters which has been handled above
+
+    return searchMessages(msgQueryInfo, accountIds, folderUris, msgQueryInfo.body, startTimeStamp,
+                          endTimeStamp, startReceptionTimeStamp, endReceptionTimeStamp);
+}
+
+bool ModestEngine::searchMessages(MessageQueryInfo &msgQueryInfo, const QStringList& accountIds,
+                                  const QStringList& folderUris, const QString& body,
+                                  const QDateTime& startTimeStamp, const QDateTime& endTimeStamp,
+                                  const QDateTime& startReceptionTimeStamp, const QDateTime& endReceptionTimeStamp) const
+{
+    Q_UNUSED(body) //TODO: Body search
+
+    qulonglong sDate = 0;
+    if (startTimeStamp.isValid() && startReceptionTimeStamp.isValid()) {
+        if (startTimeStamp < startReceptionTimeStamp) {
+            sDate = startTimeStamp.toTime_t();
+        } else {
+            sDate = startReceptionTimeStamp.toTime_t();
+        }
+    } else {
+        if (startTimeStamp.isValid()) {
+            sDate = startTimeStamp.toTime_t();
+        } else if (startReceptionTimeStamp.isValid()) {
+            sDate = startReceptionTimeStamp.toTime_t();
+        }
+    }
+
+
+    qulonglong eDate = 0;
+    if (endTimeStamp.isValid() && endReceptionTimeStamp.isValid()) {
+        if (endTimeStamp > endReceptionTimeStamp) {
+            eDate = endTimeStamp.toTime_t();
+        } else {
+            eDate = endReceptionTimeStamp.toTime_t();
+        }
+    } else {
+        if (endTimeStamp.isValid()) {
+            eDate = endTimeStamp.toTime_t();
+        } else if (endReceptionTimeStamp.isValid()) {
+            eDate = endReceptionTimeStamp.toTime_t();
+        }
+    }
+
+    if (m_pendingMessageQueries.count() == 1) {
+        // This is the first query in pending queries queue
+        // => connect to signals
+        m_QtmPluginDBusInterface->connection().connect(MODESTENGINE_QTM_PLUGIN_NAME,
+                                                       MODESTENGINE_QTM_PLUGIN_PATH,
+                                                       MODESTENGINE_QTM_PLUGIN_NAME,
+                                                       "HeadersReceived",
+                                                       (ModestEngine*)this,
+                                                       SLOT(searchMessagesHeadersReceivedSlot(QDBusMessage)));
+
+        m_QtmPluginDBusInterface->connection().connect(MODESTENGINE_QTM_PLUGIN_NAME,
+                                                       MODESTENGINE_QTM_PLUGIN_PATH,
+                                                       MODESTENGINE_QTM_PLUGIN_NAME,
+                                                       "HeadersFetched",
+                                                       (ModestEngine*)this,
+                                                       SLOT(searchMessagesHeadersFetchedSlot(QDBusMessage)));
+    }
+
+    QDBusMessage reply = m_QtmPluginDBusInterface->call("GetHeaders",
+                                                        accountIds,
+                                                        folderUris,
+                                                        sDate,
+                                                        eDate,
+                                                        false);
+    if (reply.type() != QDBusMessage::ErrorMessage) {
+        m_messageCache.clear();
+        msgQueryInfo.queryId = reply.arguments().takeFirst().toInt();
+    } else {
+        // Request failed
+        int index = -1;
+        for (int i=0; i < m_pendingMessageQueries.count(); i++) {
+            if (m_pendingMessageQueries[i].queryId == msgQueryInfo.queryId) {
+                index = i;
+                break;
+            }
+        }
+        if (index > -1) {
+            m_pendingMessageQueries.removeAt(index);
+        }
+        msgQueryInfo.privateService->setFinished(false);
+
+        if (m_pendingMessageQueries.count() == 0) {
+            // This was last query in pending queries queue
+            // => Disconnect from "GetHeaders" request related DBus signals
+            // Note: Disconnecting signals is done to optimize signal handling
+            //       <=> Disconnecting prevents unnecessary handling of signals
+            //           which have been sent from other applications using
+            //           Qt Mobility Messaging API
+            m_QtmPluginDBusInterface->connection().disconnect(MODESTENGINE_QTM_PLUGIN_NAME,
+                                                              MODESTENGINE_QTM_PLUGIN_PATH,
+                                                              MODESTENGINE_QTM_PLUGIN_NAME,
+                                                              "HeadersReceived",
+                                                              (ModestEngine*)this,
+                                                              SLOT(searchMessagesHeadersReceivedSlot(QDBusMessage)));
+
+            m_QtmPluginDBusInterface->connection().disconnect(MODESTENGINE_QTM_PLUGIN_NAME,
+                                                              MODESTENGINE_QTM_PLUGIN_PATH,
+                                                              MODESTENGINE_QTM_PLUGIN_NAME,
+                                                              "HeadersFetched",
+                                                              (ModestEngine*)this,
+                                                              SLOT(searchMessagesHeadersFetchedSlot(QDBusMessage)));
+        }
+        return false;
+    }
+
     return true;
 }
 
+void ModestEngine::searchMessagesHeadersReceivedSlot(QDBusMessage msg)
+{
+    QList<QVariant> arguments = msg.arguments();
+    int queryId = arguments.takeFirst().toInt();
+
+    int index = -1;
+    for (int i=0; i < m_pendingMessageQueries.count(); i++) {
+        if (m_pendingMessageQueries[i].queryId == queryId) {
+            index = i;
+            break;
+        }
+    }
+    if (index == -1) {
+        // Received DBus Message is not reply for the DBus query
+        // that was sent from this process/instance of modest engine
+        // => Continue waiting
+        return;
+    }
+
+    MessageQueryInfo &queryInfo = m_pendingMessageQueries[index];
+
+    QString reportedAccountId = arguments.takeFirst().toString();
+    QString accountId;
+    if (!queryInfo.realAccountId.isEmpty()) {
+        // Search was done to Modest "local_folders" account
+        // => Correct Qt Mobility Messaging AccountId
+        //    can be taken realAccountId field
+        // => Transform Messaging AccountId to Modest accountId
+        //    by removing "MO_" from the beginning of accountId string
+        accountId = queryInfo.realAccountId;
+        accountId.remove(0,3);
+    } else {
+        accountId = reportedAccountId.remove("_store");
+    }
+
+    QString folderId = arguments.takeFirst().toString();
+    QVariant variant = arguments.takeFirst();
+    QDBusArgument argument = variant.value<QDBusArgument>();
+    QList<QMap<QString, QVariant> > messages;
+    argument >> messages;
+
+    QMessageFilterPrivate::SortedMessageFilterList filters;
+    int firstUnhandledFilterIndex = 0;
+
+    QMessageFilterPrivate* pf = QMessageFilterPrivate::implementation(queryInfo.filter);
+    if (pf->_filterList.count() == 0) {
+        filters.append(queryInfo.filter);
+    } else {
+        if (queryInfo.handledFiltersCount < pf->_filterList[queryInfo.currentFilterListIndex].count()) {
+            filters = pf->_filterList[queryInfo.currentFilterListIndex];
+        }
+    }
+    firstUnhandledFilterIndex = queryInfo.handledFiltersCount;
+
+    for (int i=0; i < messages.count(); i++) {
+        MessagingModestMessage modestMessage;
+        modestMessage.accountId = accountId;
+        modestMessage.folderId = folderId;
+        modestMessage.dateReceived = 0;
+        modestMessage.dateSent = 0;
+        modestMessage.size = 0;
+        modestMessage.flags = MessagingModestMessageNotDefined;
+        modestMessage.priority = MessagingModestMessagePriorityDefined;
+        QMapIterator<QString, QVariant> j(messages[i]);
+        while (j.hasNext()) {
+            j.next();
+            if (j.key() == "url") {
+                modestMessage.url = j.value().toString();
+            } else if (j.key() == "message-uid") {
+                modestMessage.id = j.value().toString();
+            } else if (j.key() == "from") {
+                modestMessage.from = j.value().toString();
+            } else if (j.key() == "to") {
+                modestMessage.to = j.value().toString();
+            } else if (j.key() == "cc") {
+                modestMessage.cc = j.value().toString();
+            } else if (j.key() == "bcc") {
+                modestMessage.bcc = j.value().toString();
+            } else if (j.key() == "replyto") {
+                modestMessage.replyTo = j.value().toString();
+            } else if (j.key() == "subject") {
+                modestMessage.subject = j.value().toString();
+            } else if (j.key() == "date-received") {
+                modestMessage.dateReceived = j.value().toLongLong();
+            } else if (j.key() == "date-sent") {
+                modestMessage.dateSent = j.value().toLongLong();
+            } else if (j.key() == "size") {
+                modestMessage.size = j.value().toLongLong();
+            } else if (j.key() == "flags") {
+                modestMessage.flags = static_cast<MessagingModestMessageFlags>(j.value().toUInt());
+            } else if (j.key() == "priority") {
+                modestMessage.priority = static_cast<MessagingModestMessagePriority>(j.value().toUInt());
+            }
+        }
+
+        QMessage message = messageFromModestMessage(modestMessage);
+        if (reportedAccountId == "local_folders") {
+            QMessagePrivate* privateMessage = QMessagePrivate::implementation(message);
+            QString id = privateMessage->_id.toString();
+            QString newProtocol = "maildir";
+            replaceProtocol(id, newProtocol);
+            privateMessage->_id = QMessageId(id);
+            id = privateMessage->_parentFolderId.toString();
+            replaceProtocol(id, newProtocol);
+            privateMessage->_parentFolderId = QMessageFolderId(id);
+        }
+        if (filterMessage(message, filters, 0)) {
+            if (!queryInfo.ids.contains(message.id())) {
+                if (m_messageCache.size() < maxCacheSize) {
+                    m_messageCache.insert(message.id().toString(), message);
+                }
+                queryInfo.ids.append(message.id());
+            }
+        }
+    }
+}
+
+void ModestEngine::searchMessagesHeadersFetchedSlot(QDBusMessage msg)
+{
+    QList<QVariant> arguments = msg.arguments();
+    int queryId = arguments.takeFirst().toInt();
+
+    int index = -1;
+    for (int i=0; i < m_pendingMessageQueries.count(); i++) {
+        if (m_pendingMessageQueries[i].queryId == queryId) {
+            index = i;
+            break;
+        }
+    }
+    if (index == -1) {
+        // Received DBus Message is not reply for the DBus query
+        // that was sent from this process/instance of modest engine
+        // => Continue waiting
+        return;
+    }
+
+    handleQueryFinished(index);
+}
+
+void ModestEngine::handleQueryFinished(int index) const
+{
+    MessageQueryInfo &queryInfo = m_pendingMessageQueries[index];
+
+    queryInfo.currentFilterListIndex++;
+    QMessageFilterPrivate* pf = QMessageFilterPrivate::implementation(queryInfo.filter);
+    if (queryInfo.currentFilterListIndex < pf->_filterList.count()) {
+        if (queryAndFilterMessages(queryInfo)) {
+            // Continue searching
+            return;
+        }
+    }
+
+    MessagingHelper::orderMessages(queryInfo.ids, queryInfo.sortOrder);
+    MessagingHelper::applyOffsetAndLimitToMessageIdList(queryInfo.ids, queryInfo.limit, queryInfo.offset);
+
+    // Search finished
+    if (queryInfo.isQuery) {
+        queryInfo.privateService->messagesFound(queryInfo.ids, true, true);
+    } else {
+        queryInfo.privateService->messagesCounted(queryInfo.ids.count());
+    }
+    m_pendingMessageQueries.removeAt(index);
+
+    if (m_pendingMessageQueries.count() == 0) {
+        // This was last query in pending queries queue
+        // => Disconnect from "GetHeaders" request related DBus signals
+        // Note: Disconnecting signals is done to optimize signal handling
+        //       <=> Disconnecting prevents unnecessary handling of signals
+        //           which have been sent from other applications using
+        //           Qt Mobility Messaging API
+        m_QtmPluginDBusInterface->connection().disconnect(MODESTENGINE_QTM_PLUGIN_NAME,
+                                                          MODESTENGINE_QTM_PLUGIN_PATH,
+                                                          MODESTENGINE_QTM_PLUGIN_NAME,
+                                                          "HeadersReceived",
+                                                          (ModestEngine*)this,
+                                                          SLOT(searchMessagesHeadersReceivedSlot(QDBusMessage)));
+
+        m_QtmPluginDBusInterface->connection().disconnect(MODESTENGINE_QTM_PLUGIN_NAME,
+                                                          MODESTENGINE_QTM_PLUGIN_PATH,
+                                                          MODESTENGINE_QTM_PLUGIN_NAME,
+                                                          "HeadersFetched",
+                                                          (ModestEngine*)this,
+                                                          SLOT(searchMessagesHeadersFetchedSlot(QDBusMessage)));
+    }
+}
+
+void
+ModestEngine::sendEmailCallEnded(QDBusPendingCallWatcher *watcher)
+{
+    if (watcher->isError ()) {
+        // TODO: Emit a failure
+        qWarning() << "Failed to send email via modest: " << watcher->error();
+    } else {
+        // TODO: Emit a success (or put to outbox)
+        qDebug() << "Message should be outboxed now...";
+    }
+}
+
+void
+ModestEngine::addMessageCallEnded(QDBusPendingCallWatcher *watcher)
+{
+    QDBusPendingReply<QString> reply = *watcher;
+    if (reply.isError ()) {
+        // TODO: Emit a failure
+        qWarning() << "Failed to add message via modest: " << reply.error();
+    } else {
+        QString id = reply.argumentAt<0>();
+        // TODO: Emit a success ... with message's id?
+        qDebug() << "Message with id" << id << "should be added now";
+    }
+}
+
+void ModestEngine::folderUpdatedSlot(QDBusMessage msg)
+{
+    QList<QVariant> arguments = msg.arguments();
+    QString modestAccountId = arguments.takeFirst().toString();
+    QString modestFolderId = arguments.takeFirst().toString();
+    QMessageFolderId updatedFolderId;
+
+    if (modestAccountId == "local_folders") {
+        updatedFolderId = QMessageFolderId("MO_LOCAL&maildir&"+modestFolderId);
+    } else {
+        QMessageAccountId accountId = QMessageAccountId("MO_"+escapeString(modestAccountId));
+        QString protocol = accountEmailProtocolAsString(accountId);
+        if ((protocol == "pop") && (modestFolderId == "INBOX")) {
+            modestFolderId = "cache";
+        }
+        updatedFolderId = QMessageFolderId(accountId.toString()+"&"+protocol+"&"+modestFolderId);
+    }
+
+    int messagesPerAccount = 5;
+    QDBusPendingCall pendingCall = m_ModestDBusInterface->asyncCall(MODEST_DBUS_METHOD_GET_UNREAD_MESSAGES,
+                                                                    messagesPerAccount);
+    QDBusPendingCallWatcher* pendingCallWatcher = new QDBusPendingCallWatcher(pendingCall);
+    pendingCallWatcher->setProperty("folderId", updatedFolderId.toString());
+    connect(pendingCallWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+            this, SLOT(pendingGetUnreadMessagesFinishedSlot(QDBusPendingCallWatcher*)));
+}
+
+void ModestEngine::pendingGetUnreadMessagesFinishedSlot(QDBusPendingCallWatcher* pendingCallWatcher)
+{
+    QDBusMessage msg = pendingCallWatcher->reply();
+    QVariant variant = msg.arguments().takeFirst();
+    QDBusArgument argument = variant.value<QDBusArgument>();
+    QList<ModestAccountsUnreadMessagesDBusStruct> accountsWithUnreadMessages;
+    argument >> accountsWithUnreadMessages;
+
+    bool setOnlyDates = false;
+    if (pendingCallWatcher->property("setOnlyDates").isValid()) {
+        setOnlyDates = true;
+    }
+    QMessageFolderId folderId;
+    if (pendingCallWatcher->property("folderId").isValid()) {
+        folderId = QMessageFolderId(pendingCallWatcher->property("folderId").toString());
+    }
+
+    for (int i=0; i < accountsWithUnreadMessages.count(); i++) {
+        QDateTime newLatestTimeStamp;
+        QDateTime latestTimeStamp = accountsLatestTimestamp.take(accountsWithUnreadMessages[i].accountId);
+        for (int j=0; j < accountsWithUnreadMessages[i].unreadMessages.count(); j++) {
+            ModestUnreadMessageDBusStruct unreadMessage = accountsWithUnreadMessages[i].unreadMessages[j];
+            QDateTime time = QDateTime::fromTime_t(unreadMessage.timeStamp);
+            if (time > newLatestTimeStamp) {
+                newLatestTimeStamp = time;
+            }
+            if (!setOnlyDates) {
+                if (time > latestTimeStamp) {
+                    searchNewMessages(unreadMessage.subject, QString(), time, time, MODEST_DBUS_SEARCH_SUBJECT, 0);
+                }
+            }
+        }
+        if (newLatestTimeStamp.isValid()) {
+            accountsLatestTimestamp.remove(accountsWithUnreadMessages[i].accountId);
+            accountsLatestTimestamp.insert(accountsWithUnreadMessages[i].accountId, newLatestTimeStamp);
+        } else {
+            accountsLatestTimestamp.insert(accountsWithUnreadMessages[i].accountId, QDateTime::currentDateTime());
+        }
+    }
+}
+
+void ModestEngine::searchNewMessages(const QString& searchString, const QString& folderToSearch,
+                                  const QDateTime& startDate, const QDateTime& endDate,
+                                  int searchflags, uint minimumMessageSize) const
+{
+    qlonglong sDate = 0;
+    if (startDate.isValid()) {
+        sDate = startDate.toTime_t();
+    }
+    qlonglong eDate = 0;
+    if (endDate.isValid()) {
+        eDate = endDate.toTime_t();
+    }
+
+    QDBusInterface interface(MODEST_DBUS_SERVICE, MODEST_DBUS_OBJECT, MODEST_DBUS_IFACE);
+    QDBusPendingCall pendingCall = interface.asyncCall(MODEST_DBUS_METHOD_SEARCH,
+                                                       searchString,
+                                                       folderToSearch,
+                                                       sDate,
+                                                       eDate,
+                                                       searchflags,
+                                                       minimumMessageSize);
+    QDBusPendingCallWatcher* pendingCallWatcher = new QDBusPendingCallWatcher(pendingCall);
+    connect(pendingCallWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+            this, SLOT(pendingSearchFinishedSlot(QDBusPendingCallWatcher*)));
+}
+
+void ModestEngine::pendingSearchFinishedSlot(QDBusPendingCallWatcher* pendingCallWatcher)
+{
+    QDBusMessage msg = pendingCallWatcher->reply();
+    QVariant variant = msg.arguments().takeFirst();
+    QDBusArgument argument = variant.value<QDBusArgument>();
+    QList<ModestMessage> messages;
+    argument >> messages;
+
+    for (int i=0; i < messages.count(); i++) {
+        notification(messageIdFromModestMessageId(messages[i].id), ModestEngine::Added);
+    }
+}
+
+void ModestEngine::messageReadChangedSlot(QDBusMessage msg)
+{
+    QString changedMessageId = msg.arguments().takeFirst().toString();
+    notification(messageIdFromModestMessageId(changedMessageId), ModestEngine::Updated);
+}
+
+QMessageManager::NotificationFilterId ModestEngine::registerNotificationFilter(QMessageStorePrivate& messageStore,
+                                                                               const QMessageFilter &filter,
+                                                                               QMessageManager::NotificationFilterId id)
+{
+    m_messageStore = &messageStore;
+
+    int filterId = id;
+    if (filterId == 0) {
+        filterId = ++m_filterId;
+    }
+    m_filters.insert(filterId, filter);
+    return filterId;
+}
+
+void ModestEngine::unregisterNotificationFilter(QMessageManager::NotificationFilterId notificationFilterId)
+{
+    m_filters.remove(notificationFilterId);
+}
+
+QByteArray ModestEngine::getMimePart (const QMessageId &id, const QString &attachmentId)
+{
+    QByteArray result;
+
+    QString modestAccountId = modestAccountIdFromMessageId(id);
+    QString modestFolderId  = modestFolderIdFromMessageId(id);
+    QString modestMessageId = modestMessageIdFromMessageId(id);
+
+    QString filePath, mimeType;
+    int mimeSize = -1;
+    bool expunge = false, isAttachment = false;
+
+    QDBusPendingReply<QString, QString, int, bool, bool> reply =
+            m_QtmPluginDBusInterface->asyncCall(
+                    "GetMimePart",
+                    QVariant::fromValue(modestAccountId),
+                    QVariant::fromValue(modestFolderId),
+                    QVariant::fromValue(modestMessageId),
+                    QVariant::fromValue(attachmentId));
+
+    reply.waitForFinished();
+
+    if (reply.isError()) {
+        qWarning () << reply.error();
+        return result;
+    }
+
+    filePath = reply.argumentAt<0>();
+    mimeType = reply.argumentAt<1>();
+    mimeSize = reply.argumentAt<2>();
+    isAttachment = reply.argumentAt<3>();
+    expunge = reply.argumentAt<4>();
+
+    if (filePath.isEmpty()) {
+        qWarning() << "Received empty file path!";
+        return result;
+    }
+
+    QFile file(filePath);
+
+    if (file.open(QIODevice::ReadWrite) == false) {
+        qWarning() << "Failed to open file" << filePath << ": "
+                << file.error();
+        return result;
+    }
+
+    result = file.readAll();
+
+    if (expunge) {
+        file.remove();
+    } else {
+        file.close();
+    }
+
+    return result;
+}
+
+void ModestEngine::notification(const QMessageId& messageId, NotificationType notificationType) const
+{
+    QMessageId realMessageId = messageId;
+
+    if (notificationType == ModestEngine::Removed) {
+        // Make sure that there will not be many Removed notifications
+        // in a row for a same message
+        QString modestMessageId = modestMessageIdFromMessageId(messageId);
+        if (!m_latestRemoveNotifications.contains(modestMessageId)) {
+            if (m_latestRemoveNotifications.count() > 10) {
+                // Remove oldest notification from the beginning of the list
+                m_latestRemoveNotifications.removeFirst();
+            }
+            // Append new notification
+            m_latestRemoveNotifications.append(modestMessageId);
+        } else {
+            return;
+        }
+    }
+
+    QMessageManager::NotificationFilterIdSet matchingFilters;
+
+    // Copy the filter map to protect against modification during traversal
+    QMap<int, QMessageFilter> filters(m_filters);
+    QMap<int, QMessageFilter>::const_iterator it = filters.begin(), end = filters.end();
+    QMessage message;
+    bool messageRetrieved = false;
+    for ( ; it != end; ++it) {
+        const QMessageFilter &filter(it.value());
+
+        if (!messageRetrieved) {
+            QString modestAccountId = modestAccountIdFromMessageId(messageId);
+            QString modestFolderId = modestFolderIdFromMessageId(messageId);
+            QString modestMessageId = modestMessageIdFromMessageId(messageId);
+
+            MessagingModestMessage modestMessage = messageFromModest(modestAccountId,
+                                                                     modestFolderId,
+                                                                     modestMessageId);
+
+            if (modestMessage.accountId.isEmpty()) {
+                return;
+            }
+
+            if (modestMessage.flags & MessagingModestMessageDeleted) {
+                notificationType = ModestEngine::Removed;
+            }
+            if (modestMessage.size == 0) {
+                notificationType = ModestEngine::Removed;
+            }
+
+            message = messageFromModestMessage(modestMessage);
+            realMessageId =message.id();
+            messageRetrieved = true;
+        }
+
+        if (filter.isEmpty()) {
+            // Empty filter matches to all messages
+            matchingFilters.insert(it.key());
+        } else {
+            if (message.type() == QMessage::NoType) {
+                continue;
+            }
+            QMessageFilterPrivate* privateMessageFilter = QMessageFilterPrivate::implementation(filter);
+            if (privateMessageFilter->filter(message)) {
+                matchingFilters.insert(it.key());
+            }
+        }
+    }
+
+    if (matchingFilters.count() > 0) {
+        if (notificationType == ModestEngine::Added) {
+            m_messageStore->messageNotification(QMessageStorePrivate::Added, realMessageId, matchingFilters);
+        } else if (notificationType == ModestEngine::Updated) {
+            m_messageStore->messageNotification(QMessageStorePrivate::Updated, realMessageId, matchingFilters);
+        } else if (notificationType == ModestEngine::Removed) {
+            m_messageStore->messageNotification(QMessageStorePrivate::Removed, realMessageId, matchingFilters);
+        }
+    }
+}
+
+QMessageAccountId ModestEngine::accountIdFromModestMessageId(const QString& modestMessageId) const
+{
+    // Modest messageId format is following:
+    //   <email protocol>://<username>@<hostname>:<port>...
+    QMessageAccountId accountId;
+
+    int usernameBegin = modestMessageId.indexOf("//")+2;
+    int usernameEnd = modestMessageId.indexOf("@");
+    QString username = QUrl::fromPercentEncoding(modestMessageId.mid(usernameBegin, usernameEnd-usernameBegin).toUtf8());
+    int hostnameBegin = usernameEnd+1;
+    int hostnameEnd = modestMessageId.indexOf(':',hostnameBegin);
+    QString hostname = QUrl::fromPercentEncoding(modestMessageId.mid(hostnameBegin, hostnameEnd-hostnameBegin).toUtf8());
+
+    foreach (QMessageAccount value, iAccounts) {
+        QMessageAccountId accId = value.id();
+        if ((accountUsername(accId) == username) &&
+            (accountHostname(accId) == hostname)) {
+            accountId = accId;
+        }
+    }
+
+    if (!accountId.isValid()) {
+        if (modestMessageId.left(modestMessageId.indexOf(':')) == "maildir") {
+            accountId = QMessageAccountId("MO_LOCAL");
+        }
+    }
+
+    return accountId;
+}
+
+QMessageFolderId ModestEngine::folderIdFromModestMessageId(const QString& modestMessageId,
+                                                           const QMessageAccountId accountId) const
+{
+    // Modest messageId format is following:
+    //   <email protocol>://<username>@<hostname>:<port>...
+    QMessageFolderId folderId;
+    QString folderIdAsString;
+
+    if (!accountId.isValid()) {
+        folderIdAsString = accountIdFromModestMessageId(modestMessageId).toString();
+    } else {
+        folderIdAsString = accountId.toString();
+    }
+
+    int protocolEnd = modestMessageId.indexOf(':');
+    QString protocol = modestMessageId.left(protocolEnd);
+    folderIdAsString += "&" + protocol;
+    if (protocol == "pop") {
+        folderIdAsString += "&cache";
+    } else if (protocol == "imap") {
+        int pathBegin = modestMessageId.indexOf('/',modestMessageId.lastIndexOf(':'))+1;
+        int pathEnd = modestMessageId.lastIndexOf('/');
+        folderIdAsString += "&" + modestMessageId.mid(pathBegin, pathEnd-pathBegin);
+    } else if (protocol == "maildir") {
+        int pathBegin = modestMessageId.indexOf('#')+1;
+        int pathEnd = modestMessageId.lastIndexOf('/');
+        folderIdAsString += "&" + modestMessageId.mid(pathBegin, pathEnd-pathBegin);
+    }
+    folderId = QMessageFolderId(QUrl::fromPercentEncoding(folderIdAsString.toUtf8()));
+
+    return folderId;
+}
+
+QString ModestEngine::modestAccountIdFromAccountId(const QMessageAccountId& accountId) const
+{
+    // Just remove "MO_" prefix from the beginning of id string
+    return accountId.toString().remove(0,3);
+}
+
+QString ModestEngine::modestFolderIdFromFolderId(const QMessageFolderId& folderId) const
+{
+    QString modestFolderId;
+
+    QString folderIdString = folderId.toString();
+    int protocolBegin = folderIdString.indexOf('&');
+    int protocolEnd = folderIdString.lastIndexOf('&');
+
+    modestFolderId = folderIdString.mid(protocolEnd+1);
+    QString protocol = folderIdString.mid(protocolBegin+1,protocolEnd-protocolBegin-1);
+    if ((protocol == "pop") && (modestFolderId == "cache")) {
+        modestFolderId = "INBOX";
+    }
+
+    return modestFolderId;
+}
+
+QString ModestEngine::modestFolderUriFromFolderId(const QMessageFolderId& folderId) const
+{
+    Q_UNUSED(folderId) //TODO:
+    return QString();
+}
+
+QString ModestEngine::modestAccountIdFromMessageId(const QMessageId& messageId,
+                                                   bool checkProtocol) const
+{
+    QString id = messageId.toString();
+    int protocolBegin = id.indexOf('&');
+    int protocolEnd = id.lastIndexOf('&');
+    QString protocol = id.mid(protocolBegin+1,protocolEnd-protocolBegin-1);
+    if (checkProtocol && protocol == "maildir") {
+        return "local_folders";
+    }
+
+    return unescapeString(id.left(protocolBegin).remove(0,3));
+}
+
+QMessageAccountId ModestEngine::accountIdFromFolderId(const QMessageFolderId& folderId) const
+{
+    QString id = folderId.toString();
+    int protocolBegin = id.indexOf('&');
+    return QMessageAccountId(id.left(protocolBegin));
+}
+
+QMessageAccountId ModestEngine::accountIdFromMessageId(const QMessageId& messageId) const
+{
+    QString id = messageId.toString();
+    int protocolBegin = id.indexOf('&');
+    return QMessageAccountId(id.left(protocolBegin));
+}
+
+QString ModestEngine::modestAccountIdFromFolderId(const QMessageFolderId& folderId,
+                                                  bool checkProtocol) const
+{
+    QString id = folderId.toString();
+    int protocolBegin = id.indexOf('&');
+    int protocolEnd = id.lastIndexOf('&');
+    QString protocol = id.mid(protocolBegin+1,protocolEnd-protocolBegin-1);
+    if (checkProtocol && protocol == "maildir") {
+        return "local_folders";
+    }
+
+    return unescapeString(id.left(protocolBegin).remove(0,3));
+}
+
+QString ModestEngine::modestFolderIdFromMessageId(const QMessageId& messageId) const
+{
+    QString id = messageId.toString();
+
+    int protocolBegin = id.indexOf('&');
+    int protocolEnd = id.lastIndexOf('&');
+    int folderEnd = id.lastIndexOf('/');
+
+    QString protocol = id.mid(protocolBegin+1,protocolEnd-protocolBegin-1);
+    id = id.mid(protocolEnd+1,folderEnd-protocolEnd-1);
+    if ((protocol == "pop") && (id == "cache")) {
+        id = "INBOX";
+    }
+
+    return id;
+}
+
+void ModestEngine::replaceProtocol(QString& id, const QString& newProtocol) const
+{
+    int protocolBegin = id.indexOf('&');
+    int protocolEnd = id.lastIndexOf('&');
+    id.remove(protocolBegin+1,protocolEnd-protocolBegin-1);
+    id.insert(protocolBegin+1, newProtocol);
+}
+
+QMessageAccountId ModestEngine::realAccountId(const MessagingModestMessage& modestMessage) const
+{
+    QMessageAccountId accountId;
+
+    if (modestMessage.accountId == "local_folders") {
+        QString accountIdString;
+        // Message is in local foldar, but message can be linked
+        // to actual account using 'From', 'To', 'Cc' or 'Bcc' fields
+        foreach (QMessageAccount value, iAccounts) {
+            QMessageAccountPrivate* privAccount = QMessageAccountPrivate::implementation(value);
+            if (modestMessage.from.contains(privAccount->_address.addressee())) {
+                accountIdString = value.id().toString();
+                break;
+            } else if (modestMessage.to.contains(privAccount->_address.addressee())) {
+                accountIdString = value.id().toString();
+                break;
+            } else if (modestMessage.cc.contains(privAccount->_address.addressee())) {
+                accountIdString = value.id().toString();
+                break;
+            } else if (modestMessage.bcc.contains(privAccount->_address.addressee())) {
+                accountIdString = value.id().toString();
+                break;
+            }
+        }
+        if (!accountIdString.isEmpty()) {
+            accountId = QMessageAccountId(accountIdString);
+        }
+    } else {
+        accountId = accountIdFromModestAccountId(modestMessage.accountId);
+    }
+
+    return accountId;
+}
+
+QString ModestEngine::modestMessageIdFromMessageId(const QMessageId& messageId) const
+{
+    QString id = messageId.toString();
+    return id.mid(id.lastIndexOf('/')+1);
+}
+
+QMessageAccountId ModestEngine::accountIdFromModestAccountId(const QString& accountId) const
+{
+    // Just add "MO_" prefix to the beginning of id string & escape created Id
+    return QMessageAccountId(escapeString("MO_"+accountId));
+}
+
+QMessageFolderId ModestEngine::folderIdFromModestFolderId(const QMessageAccountId& accountId,
+                                                          bool isLocalFolder,
+                                                          const QString& modestFolderId) const
+{
+    // Format: <accountId>&<email protocol>&<Modest folderId>
+    QMessageFolderId folderId;
+
+    if (isLocalFolder) {
+         folderId = QMessageFolderId(accountId.toString()+"&maildir&"+modestFolderId);
+    } else {
+        QString protocol = accountEmailProtocolAsString(accountId);
+        if ((protocol == "pop") && (modestFolderId == "INBOX")) {
+            folderId = QMessageFolderId(accountId.toString()+"&"+protocol+"&cache");
+        } else {
+            folderId = QMessageFolderId(accountId.toString()+"&"+protocol+"&"+modestFolderId);
+        }
+    }
+
+    return folderId;
+}
+
+QMessageId ModestEngine::messageIdFromModestMessageId(const QString& messageId) const
+{
+    QString messageIdString = folderIdFromModestMessageId(messageId).toString();
+    int idPartBegin = messageId.lastIndexOf('/');
+    messageIdString += messageId.mid(idPartBegin, idPartBegin-messageId.length());
+    return QMessageId(messageIdString);
+}
+
+QMessageId ModestEngine::messageIdFromModestMessageFilePath(const QString& messageFilePath) const
+{
+    QString messageIdString;
+
+    QString filePath = messageFilePath;
+    QString localRootFolder = this->localRootFolder();
+    if (filePath.startsWith(localRootFolder)) {
+        messageIdString = "MO_LOCAL&maildir&";
+        filePath.remove(0,localRootFolder.length()+1);
+        filePath.remove("/cur");
+        messageIdString += filePath.left(filePath.lastIndexOf('!'));
+    } else {
+        foreach (QMessageAccount value, iAccounts) {
+            QMessageAccountId accountId = value.id();
+            QString rootFolder = accountRootFolder(accountId);
+            if (filePath.startsWith(rootFolder)) {
+                QString protocol = accountEmailProtocolAsString(accountId);
+                messageIdString = accountId.toString()+"&"+protocol+"&";
+                filePath.remove(0,rootFolder.length()+1);
+                filePath.remove("/subfolders");
+                messageIdString += filePath.left(filePath.lastIndexOf('.'));
+                if (protocol == "pop") {
+                    QDir dir(messageFilePath);
+                    dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
+                    QFileInfoList dirs = dir.entryInfoList();
+                    if (dirs.count() > 0) {
+                        QString fileName = dirs[0].fileName();
+                        // Remove folder that contains actual message
+                        messageIdString = messageIdString.left(messageIdString.lastIndexOf('/')+1);
+                        // Add message name
+                        messageIdString = messageIdString+fileName;
+                    }
+                }
+            }
+        }
+    }
+
+    return QMessageId(messageIdString);
+}
+
+QString ModestEngine::unescapeString(const QString& string)
+{
+    QString unescapedString;
+
+    QByteArray str = string.toUtf8();
+    gchar* unescaped_string = gconf_unescape_key(str.data(), str.length());
+    unescapedString = QString::fromUtf8(unescaped_string);
+    g_free(unescaped_string);
+
+    return unescapedString;
+}
+
+QString ModestEngine::escapeString(const QString& string)
+{
+    QString escapedString;
+
+    QByteArray str = unescapeString(string).toUtf8();
+    gchar* escaped_string = gconf_escape_key(str.data(), str.length());
+    escapedString = QString::fromUtf8(escaped_string);
+    g_free(escaped_string);
+
+    return escapedString;
+}
+
+INotifyWatcher::INotifyWatcher()
+{
+    // Initialize inotify instance
+    // => returned file descriptor is associated with
+    //    a new inotify event queue
+    // O_CLOEXEC flag makes sure that file descriptor
+    //           is closed if execution is transfered
+    //           from this process to a new program
+    //           (Check more info from 'execve' documentation)
+#ifdef IN_CLOEXEC
+    m_inotifyFileDescriptor = inotify_init1(IN_CLOEXEC);
+#else
+    m_inotifyFileDescriptor = inotify_init();
+    if (m_inotifyFileDescriptor >= 0) {
+        ::fcntl(m_inotifyFileDescriptor, F_SETFD, FD_CLOEXEC);
+    }
+#endif
+    if (m_inotifyFileDescriptor >= 0) {
+        // Change thread affinity for this object to this
+        // thread.
+        // => Event processing (for this objects events) will
+        //    be done in this thread
+        moveToThread(this);
+    }
+}
+
+INotifyWatcher::~INotifyWatcher()
+{
+    // Tell the thread's event loop to exit
+    // => thread returns from the call to exec()
+    exit();
+
+    // Wait until this thread has finished execution
+    // <=> waits until thread returns from run()
+    wait();
+
+    clear();
+
+    // Close file descriptor that's referring to inotify instance
+    // => The underlying inotify object and its resources are freed
+    ::close(m_inotifyFileDescriptor);
+}
+
+void INotifyWatcher::clear()
+{
+    // Remove all watches from inotify instance watch list
+    QMapIterator<int, QString> i(m_dirs);
+    while (i.hasNext()) {
+        inotify_rm_watch(m_inotifyFileDescriptor, i.next().key());
+    }
+    m_dirs.clear();
+
+    QMapIterator<int, QString> j(m_files);
+    while (j.hasNext()) {
+        inotify_rm_watch(m_inotifyFileDescriptor, j.next().key());
+    }
+    m_files.clear();
+}
+
+void INotifyWatcher::run()
+{
+    // Start listening inotify
+    QSocketNotifier socketNotifier(m_inotifyFileDescriptor, QSocketNotifier::Read, this);
+    connect(&socketNotifier, SIGNAL(activated(int)), SLOT(notifySlot()));
+
+    // Enter the thread event loop
+    (void) exec();
+}
+
+int INotifyWatcher::addFile(const QString& path, uint eventsToWatch)
+{
+    int watchDescriptor = 0;
+    QMutexLocker locker(&m_mutex);
+
+    if (m_inotifyFileDescriptor >= 0) {
+        int watchDescriptor = 0;
+        if (eventsToWatch == 0) {
+            watchDescriptor = inotify_add_watch(m_inotifyFileDescriptor,
+                                                QFile::encodeName(path),
+                                                0 | IN_ATTRIB
+                                                  | IN_MODIFY
+                                                  | IN_MOVE
+                                                  | IN_MOVE_SELF
+                                                  | IN_DELETE_SELF);
+        } else {
+            watchDescriptor = inotify_add_watch(m_inotifyFileDescriptor,
+                                                QFile::encodeName(path),
+                                                eventsToWatch);
+        }
+        if (watchDescriptor > 0) {
+            m_files.insert(watchDescriptor, path);
+        } else {
+            watchDescriptor = 0;
+        }
+    }
+
+    // Start thread (if thread is not already running)
+    start();
+
+    return watchDescriptor;
+}
+
+int INotifyWatcher::addDirectory(const QString& path, uint eventsToWatch)
+{
+    int watchDescriptor = 0;
+    QMutexLocker locker(&m_mutex);
+
+    if (m_inotifyFileDescriptor >= 0) {
+        int watchDescriptor = 0;
+        if (eventsToWatch == 0) {
+            watchDescriptor = inotify_add_watch(m_inotifyFileDescriptor,
+                                                QFile::encodeName(path),
+                                                0 | IN_ATTRIB
+                                                  | IN_MOVE
+                                                  | IN_CREATE
+                                                  | IN_DELETE
+                                                  | IN_DELETE_SELF);
+        } else {
+            watchDescriptor = inotify_add_watch(m_inotifyFileDescriptor,
+                                                QFile::encodeName(path),
+                                                eventsToWatch);
+        }
+        if (watchDescriptor > 0) {
+            m_dirs.insert(watchDescriptor, path);
+        } else {
+            watchDescriptor = 0;
+        }
+    }
+
+    // Start thread (if thread is not already running)
+    start();
+
+    return watchDescriptor;
+}
+
+QStringList INotifyWatcher::directories() const
+{
+    return m_dirs.values();
+}
+
+QStringList INotifyWatcher::files() const
+{
+    return m_dirs.values();
+}
+
+void INotifyWatcher::notifySlot()
+{
+    QMutexLocker locker(&m_mutex);
+
+    int bufferSize = 0;
+    ioctl(m_inotifyFileDescriptor, FIONREAD, (char*) &bufferSize);
+    QVarLengthArray<char, 4096> buffer(bufferSize);
+    bufferSize = read(m_inotifyFileDescriptor, buffer.data(), bufferSize);
+    const char* at = buffer.data();
+    const char* const end = at + bufferSize;
+
+    QMap<int, INotifyEvent> eventsForWatchedFile;
+    QMap<QString, INotifyEvent> eventsForFileInWatchedDirectory;
+    while (at < end) {
+        const inotify_event *event = reinterpret_cast<const inotify_event *>(at);
+        if (m_files.contains(event->wd)) {
+            // File event handling
+            if (eventsForWatchedFile.contains(event->wd)) {
+                // There is already unhandled event for this file in queue
+                // => Mask is ORed to existing event
+                eventsForWatchedFile[event->wd].mask |= event->mask;
+            } else {
+                // There is no event for this file in queue
+                // => New event is created
+                INotifyEvent inotifyEvent;
+                inotifyEvent.watchDescriptor = event->wd;
+                inotifyEvent.mask = event->mask;
+                inotifyEvent.fileName = QString::fromAscii(event->name, event->len);
+                eventsForWatchedFile.insert(event->wd, inotifyEvent);
+            }
+        } else {
+            // Directory event handling
+            QString changeForFileInDirectory = QString::fromAscii(event->name, event->len);
+            // Remove unnecessary postfix (starting with '!') from the file name
+            changeForFileInDirectory = changeForFileInDirectory.left(changeForFileInDirectory.lastIndexOf('!'));
+            if (!changeForFileInDirectory.isEmpty()) {
+                QString eventId = QString::number(event->wd)+changeForFileInDirectory;
+                if (eventsForFileInWatchedDirectory.contains(eventId)) {
+                    // There is already unhandled event for this file in queue
+                    // => Mask is ORed to existing event
+                    eventsForFileInWatchedDirectory[eventId].mask |= event->mask;
+                } else {
+                    // There is no event for this file in queue
+                    // => New event is created
+                    INotifyEvent inotifyEvent;
+                    inotifyEvent.watchDescriptor = event->wd;
+                    inotifyEvent.mask = event->mask;
+                    inotifyEvent.fileName = QString::fromAscii(event->name, event->len);
+                    eventsForFileInWatchedDirectory.insert(eventId, inotifyEvent);
+                }
+            }
+        }
+        at += sizeof(inotify_event) + event->len;
+    }
+
+    QMap<int, INotifyEvent>::const_iterator it = eventsForWatchedFile.constBegin();
+    while (it != eventsForWatchedFile.constEnd()) {
+        INotifyEvent event = *it;
+        QString file = m_files.value(event.watchDescriptor);
+        if (!file.isEmpty()) {
+            emit fileChanged(event.watchDescriptor, file, event.mask);
+        }
+        ++it;
+    }
+
+    QMap<QString, INotifyEvent>::const_iterator jt = eventsForFileInWatchedDirectory.constBegin();
+    while (jt != eventsForFileInWatchedDirectory.constEnd()) {
+        INotifyEvent event = *jt;
+        QString file = m_dirs.value(event.watchDescriptor)+"/"+event.fileName;
+        emit fileChanged(event.watchDescriptor, file, event.mask);
+        ++jt;
+    }
+}
+
+ModestStringMap ModestEngine::getModestSenderInfo(QMessage &message)
+{
+    QMessageAddress address;
+    ModestStringMap senderInfo;
+    QMessageAccountId accountId;
+    QString value;
+
+    accountId = message.parentAccountId();
+    if (accountId.isValid() == false) {
+        qWarning () << "Account ID is invalid";
+        return ModestStringMap();
+    }
+
+    senderInfo["account-name"] = unescapeString(modestAccountIdFromAccountId(accountId));
+
+    QMessageAccount messageAccount = account(accountId);
+    QMessageAccountPrivate* privAccount = QMessageAccountPrivate::implementation(messageAccount);
+    address = privAccount->_address;
+    value = address.addressee();
+
+    if (value.isEmpty() == false && value.isNull() == false) {
+        senderInfo["from"] = value;
+    }
+
+    return senderInfo;
+}
+
+ModestStringMap ModestEngine::getModestRecipients(QMessage &message)
+{
+    QMessageAddressList addresses;
+    QMessageAddress address;
+    ModestStringMap recipients;
+    QString value;
+
+    addresses = message.to();
+    value.clear();
+    for (int i = 0; i < addresses.length(); i++) {
+        address = addresses[i];
+
+        if (value.isEmpty()) {
+            value = address.addressee();
+        } else {
+            value.append (",");
+            value.append (address.addressee());
+        }
+    }
+
+    if (value.isEmpty() == false && value.isNull() == false) {
+        recipients["to"] = value;
+    }
+
+    addresses = message.cc();
+    value.clear();
+    for (int i = 0; i < addresses.length(); i++) {
+        address = addresses[i];
+
+        if (value.isEmpty()) {
+            value = address.addressee();
+        } else {
+            value.append (",");
+            value.append (address.addressee());
+        }
+    }
+
+    if (value.isEmpty() == false && value.isNull() == false) {
+        recipients["cc"] = value;
+    }
+
+    addresses = message.bcc();
+    value.clear();
+    for (int i = 0; i < addresses.length(); i++) {
+        address = addresses[i];
+
+        if (value.isEmpty()) {
+            value = address.addressee();
+        } else {
+            value.append (",");
+            value.append (address.addressee());
+        }
+    }
+
+    if (value.isEmpty() == false && value.isNull() == false) {
+        recipients["bcc"] = value;
+    }
+
+    return recipients;
+}
+
+ModestStringMap ModestEngine::getModestMessageData(QMessage &message)
+{
+    QMessageContentContainerId bodyId;
+    QMessageContentContainer body;
+    ModestStringMap messageData;
+    QString value;
+
+    value = message.subject();
+
+    if (value.isEmpty() == false && value.isNull() == false) {
+        messageData["subject"] = value;
+    }
+
+    bodyId = message.bodyId();
+    if (bodyId.isValid()) {
+        body = message.find (bodyId);
+    } else {
+        body = message;
+    }
+
+    value = body.contentType();
+
+    if (value == "text") {
+        QString key, data;
+        bool hasContent = false;
+
+        value = body.contentSubType();
+
+        if ((hasContent = body.isContentAvailable()) == true) {
+            data = body.textContent();
+        }
+
+        if (value == "plain") {
+            key = "plain-body";
+        } else if (value == "html") {
+            key = "html-body";
+        }
+
+        if (key.isEmpty() == false && key.isNull() == false && hasContent) {
+            messageData[key] = data;
+        }
+    }
+
+    return messageData;
+}
+
+ModestStringMapList ModestEngine::getModestAttachments(QMessage &message)
+{
+    QMessageContentContainerIdList attachmentIds;
+    ModestStringMapList attachments;
+    QMessage::StatusFlags messageStatus;
+    QString value;
+
+    messageStatus = message.status();
+
+    if (messageStatus & QMessage::HasAttachments) {
+        attachmentIds = message.attachmentIds();
+
+        foreach (QMessageContentContainerId identifier, attachmentIds) {
+            ModestStringMap attachmentData;
+            QMessageContentContainer attachmentCont;
+
+            if (identifier.isValid() == false) continue;
+
+            attachmentCont = message.find (identifier);
+
+            if (attachmentCont.isContentAvailable () == false) continue;
+
+            attachmentData.clear();
+
+            value = attachmentCont.contentType();
+
+            if (value.isEmpty() == false) {
+                value.append("/");
+                value.append (attachmentCont.contentSubType());
+                attachmentData["mime-type"] = value;
+
+                qDebug() << "mime-type: " << value;
+            }
+
+            value = QMessageContentContainerPrivate::attachmentFilename (
+                attachmentCont);
+
+            if (value.isEmpty() == false) {
+                attachmentData["filename"] = value;
+                qDebug() << "filename: " << value;
+            }
+
+            qDebug() << "Charset: " << attachmentCont.contentCharset();
+            qDebug() << "Headers: " << attachmentCont.headerFields();
+
+            if (attachmentData.isEmpty() == false) {
+                attachmentData["content-id"] = identifier.toString();
+                attachments.append (attachmentData);
+            }
+        }
+    }
+
+    return attachments;
+}
+
+ModestStringMapList ModestEngine::getModestImages(QMessage &message)
+{
+    Q_UNUSED(message);
+    // Don't know if this even makes sense. Modest expects inlined images
+    // to be in a separate list, but that doesn't make much sense?
+    return ModestStringMapList();
+}
+
+uint ModestEngine::getModestPriority(QMessage &message)
+{
+    uint priority = 0;
+
+    switch (message.priority()) {
+    case QMessage::HighPriority:
+        priority = MODESTENGINE_HIGH_PRIORITY;
+        break;
+
+    default:
+    case QMessage::NormalPriority:
+        priority = MODESTENGINE_NORMAL_PRIORITY;
+        break;
+
+    case QMessage::LowPriority:
+        priority = MODESTENGINE_LOW_PRIORITY;
+        break;
+    }
+
+    return priority;
+}
+
+ModestStringMap ModestEngine::getModestHeaders(QMessage &message)
+{
+    Q_UNUSED(message);
+    return ModestStringMap(); // stub
+}
+
+#include "moc_modestengine_maemo_p.cpp"
 
 QTM_END_NAMESPACE