src/messaging/modestengine_maemo.cpp
changeset 0 876b1a06bc25
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 #include "modestengine_maemo_p.h"
       
    42 #include "maemohelpers_p.h"
       
    43 #include "qmessage_p.h"
       
    44 #include "qmessageaccount.h"
       
    45 #include "qmessageaccount_p.h"
       
    46 #include "qmessageaccountfilter.h"
       
    47 #include "qmessageaccountfilter_p.h"
       
    48 #include "qmessagefolder_p.h"
       
    49 #include "qmessagestore_p.h"
       
    50 #include "qmessageservice_maemo_p.h"
       
    51 #include "qmessagecontentcontainer_maemo_p.h"
       
    52 #include <QUrl>
       
    53 #include <QtDBus>
       
    54 #include <QFileSystemWatcher>
       
    55 #include <QTimer>
       
    56 
       
    57 #include <dbus/dbus.h>
       
    58 #include <QDebug>
       
    59 
       
    60 #include </usr/include/libmodest-dbus-client-1.0/libmodest-dbus-client/libmodest-dbus-api.h>
       
    61 #include </usr/include/sys/inotify.h>
       
    62 #include </usr/include/sys/ioctl.h>
       
    63 #include </usr/include/sys/fcntl.h>
       
    64 
       
    65 // Marshall the ModestStringMap data into a D-Bus argument
       
    66 QDBusArgument &operator<<(QDBusArgument &argument,
       
    67                           const QtMobility::ModestStringMap &map)
       
    68 {
       
    69     QtMobility::ModestStringMap::const_iterator iter;
       
    70 
       
    71     argument.beginMap (QVariant::String, QVariant::String);
       
    72     for (iter = map.constBegin(); iter != map.constEnd(); iter++) {
       
    73         argument.beginMapEntry();
       
    74         argument << iter.key() << iter.value();
       
    75         argument.endMapEntry();
       
    76     }
       
    77     argument.endMap();
       
    78 
       
    79     return argument;
       
    80 }
       
    81 
       
    82 // Retrieve the ModestStringMap data from the D-Bus argument
       
    83 const QDBusArgument &operator>>(const QDBusArgument &argument,
       
    84                                 QtMobility::ModestStringMap &map)
       
    85 {
       
    86     map.clear();
       
    87 
       
    88     argument.beginMap();
       
    89     while (!argument.atEnd()) {
       
    90         QString key, value;
       
    91         argument.beginMapEntry();
       
    92         argument >> key >> value;
       
    93         argument.endMapEntry();
       
    94         map[key] = value;
       
    95     }
       
    96     argument.endMap();
       
    97 
       
    98     return argument;
       
    99 }
       
   100 
       
   101 QDBusArgument &operator<<(QDBusArgument &argument,
       
   102                           const QtMobility::ModestUnreadMessageDBusStruct &unreadMessage)
       
   103 {
       
   104     argument.beginStructure();
       
   105     argument << unreadMessage.timeStamp;
       
   106     argument << unreadMessage.subject;
       
   107     argument.endStructure();
       
   108     return argument;
       
   109 }
       
   110 
       
   111 const QDBusArgument &operator>>(const QDBusArgument &argument,
       
   112                                 QtMobility::ModestUnreadMessageDBusStruct &unreadMessage)
       
   113 {
       
   114     argument.beginStructure();
       
   115     argument >> unreadMessage.timeStamp;
       
   116     argument >> unreadMessage.subject;
       
   117     argument.endStructure();
       
   118     return argument;
       
   119 }
       
   120 
       
   121 QDBusArgument &operator<<(QDBusArgument &argument,
       
   122                           const QtMobility::ModestAccountsUnreadMessagesDBusStruct &unreadMessages)
       
   123 {
       
   124     argument.beginStructure();
       
   125     argument << unreadMessages.accountId;
       
   126     argument << unreadMessages.accountName;
       
   127     argument << unreadMessages.accountProtocol;
       
   128     argument << unreadMessages.unreadCount;
       
   129     argument << unreadMessages.unreadMessages;
       
   130     argument.endStructure();
       
   131     return argument;
       
   132 }
       
   133 
       
   134 const QDBusArgument &operator>>(const QDBusArgument &argument,
       
   135                                 QtMobility::ModestAccountsUnreadMessagesDBusStruct &unreadMessages)
       
   136 {
       
   137     argument.beginStructure();
       
   138     argument >> unreadMessages.accountId;
       
   139     argument >> unreadMessages.accountName;
       
   140     argument >> unreadMessages.accountProtocol;
       
   141     argument >> unreadMessages.unreadCount;
       
   142     argument >> unreadMessages.unreadMessages;
       
   143     argument.endStructure();
       
   144     return argument;
       
   145 }
       
   146 
       
   147 QDBusArgument &operator<<(QDBusArgument &argument, const QtMobility::ModestMessage &message)
       
   148 {
       
   149     argument.beginStructure();
       
   150     argument << message.id;
       
   151     argument << message.subject;
       
   152     argument << message.folder;
       
   153     argument << message.sender;
       
   154     argument << message.size;
       
   155     argument << message.hasAttachment;
       
   156     argument << message.isUnread;
       
   157     argument << message.timeStamp;
       
   158     argument.endStructure();
       
   159     return argument;
       
   160 }
       
   161 
       
   162 const QDBusArgument &operator>>(const QDBusArgument &argument, QtMobility::ModestMessage &message)
       
   163 {
       
   164     argument.beginStructure();
       
   165     argument >> message.id;
       
   166     argument >> message.subject;
       
   167     argument >> message.folder;
       
   168     argument >> message.sender;
       
   169     argument >> message.size;
       
   170     argument >> message.hasAttachment;
       
   171     argument >> message.isUnread;
       
   172     argument >> message.timeStamp;
       
   173     argument.endStructure();
       
   174     return argument;
       
   175 }
       
   176 
       
   177 QDBusArgument &operator<<(QDBusArgument &argument, const QtMobility::MessagingModestMimePart &mimePart)
       
   178 {
       
   179     argument.beginStructure();
       
   180     argument << mimePart.mimeType;
       
   181     argument << mimePart.isAttachment;
       
   182     argument << mimePart.fileName;
       
   183     argument << mimePart.contentId;
       
   184     argument.endStructure();
       
   185     return argument;
       
   186 }
       
   187 
       
   188 const QDBusArgument &operator>>(const QDBusArgument &argument, QtMobility::MessagingModestMimePart &mimePart)
       
   189 {
       
   190     argument.beginStructure();
       
   191     argument >> mimePart.mimeType;
       
   192     argument >> mimePart.isAttachment;
       
   193     argument >> mimePart.fileName;
       
   194     argument >> mimePart.contentId;
       
   195     argument.endStructure();
       
   196     return argument;
       
   197 }
       
   198 
       
   199 QDBusArgument &operator<<(QDBusArgument &argument, const QtMobility::MessagingModestFolder &folder)
       
   200 {
       
   201     argument.beginStructure();
       
   202     argument << folder.parentAccountId;
       
   203     argument << folder.parentFolderId;
       
   204     argument << folder.modestId;
       
   205     argument << static_cast<uint>(folder.type);
       
   206     argument << folder.localizedName;
       
   207     argument.endStructure();
       
   208     return argument;
       
   209 }
       
   210 
       
   211 const QDBusArgument &operator>>(const QDBusArgument &argument, QtMobility::MessagingModestFolder &folder)
       
   212 {
       
   213     argument.beginStructure();
       
   214 
       
   215     argument >> folder.parentAccountId;
       
   216     QByteArray str = folder.parentAccountId.toUtf8();
       
   217     gchar* escaped_string = gconf_escape_key(str.data(), str.length());
       
   218     folder.parentAccountId = QString::fromUtf8(escaped_string);
       
   219     g_free(escaped_string);
       
   220 
       
   221     argument >> folder.parentFolderId;
       
   222     argument >> folder.modestId;
       
   223 
       
   224     uint type;
       
   225     argument >> type;
       
   226     folder.type = static_cast<QtMobility::MessagingModestFolderType>(type);
       
   227 
       
   228     argument >> folder.localizedName;
       
   229     argument.endStructure();
       
   230     return argument;
       
   231 }
       
   232 
       
   233 QTM_BEGIN_NAMESPACE
       
   234 
       
   235 /* configuration key definitions for modest */
       
   236 #define MODESTENGINE_ACCOUNT_NAMESPACE         "/apps/modest/accounts"
       
   237 #define MODESTENGINE_SERVER_ACCOUNT_NAMESPACE  "/apps/modest/server_accounts"
       
   238 #define MODESTENGINE_DEFAULT_ACCOUNT           "/apps/modest/default_account"
       
   239 #define MODESTENGINE_ACCOUNT_ENABLED           "enabled"
       
   240 #define MODESTENGINE_ACCOUNT_DISPLAY_NAME      "display_name"
       
   241 #define MODESTENGINE_ACCOUNT_FULLNAME          "fullname"
       
   242 #define MODESTENGINE_ACCOUNT_EMAIL             "email"
       
   243 #define MODESTENGINE_ACCOUNT_STORE_ACCOUNT     "store_account"
       
   244 #define MODESTENGINE_ACCOUNT_TRANSPORT_ACCOUNT "transport_account"
       
   245 #define MODESTENGINE_ACCOUNT_PROTOCOL          "proto"
       
   246 #define MODESTENGINE_ACCOUNT_USERNAME          "username"
       
   247 #define MODESTENGINE_ACCOUNT_HOSTNAME          "hostname"
       
   248 #define MODESTENGINE_ACCOUNT_PORT              "port"
       
   249 
       
   250 // The modest engine has a new plugin, we need service names for it
       
   251 #define MODESTENGINE_QTM_PLUGIN_PATH           "/com/nokia/Qtm/Modest/Plugin"
       
   252 #define MODESTENGINE_QTM_PLUGIN_NAME           "com.nokia.Qtm.Modest.Plugin"
       
   253 
       
   254 typedef enum {
       
   255     MODEST_DBUS_SEARCH_SUBJECT   = (1 << 0),
       
   256     MODEST_DBUS_SEARCH_SENDER    = (1 << 1),
       
   257     MODEST_DBUS_SEARCH_RECIPIENT = (1 << 2),
       
   258     MODEST_DBUS_SEARCH_SIZE      = (1 << 3),
       
   259     MODEST_DBUS_SEARCH_BODY      = (1 << 6)
       
   260 } ModestDBusSearchFlags;
       
   261 
       
   262 // Specific priority settings to translate to modest priorities
       
   263 #define MODESTENGINE_HIGH_PRIORITY             2
       
   264 #define MODESTENGINE_NORMAL_PRIORITY           0
       
   265 #define MODESTENGINE_LOW_PRIORITY              1
       
   266 
       
   267 Q_GLOBAL_STATIC(ModestEngine,modestEngine);
       
   268 
       
   269 ModestEngine::ModestEngine()
       
   270  : m_queryIds(0)
       
   271 {
       
   272     qWarning() << "ModestEngine::ModestEngine Starting to initialize";
       
   273     g_type_init();
       
   274     m_gconfclient = gconf_client_get_default();
       
   275     if (!m_gconfclient) {
       
   276         qWarning("qtmessaging: could not get gconf client");
       
   277     } else {
       
   278         updateEmailAccounts();
       
   279     }
       
   280 
       
   281     qWarning() << "ModestEngine::ModestEngine Connecting to Modest DBus Interface";
       
   282     // Setup DBus Interface for Modest
       
   283     m_ModestDBusInterface = new QDBusInterface(MODEST_DBUS_SERVICE,
       
   284                                                MODEST_DBUS_OBJECT,
       
   285                                                MODEST_DBUS_IFACE,
       
   286                                                QDBusConnection::sessionBus(),
       
   287                                                this);
       
   288     if (m_ModestDBusInterface->isValid()) {
       
   289         qWarning() << "ModestEngine::ModestEngine Connected to Modest DBus Interface";
       
   290     } else {
       
   291         qWarning() << "ModestEngine::ModestEngine Unable to connect to Modest DBus Interface";
       
   292     }
       
   293 
       
   294     // Get notifications of Incoming Messages
       
   295     m_ModestDBusInterface->connection().connect(MODEST_DBUS_SERVICE,
       
   296                                                 MODEST_DBUS_OBJECT,
       
   297                                                 MODEST_DBUS_IFACE,
       
   298                                                 MODEST_DBUS_SIGNAL_FOLDER_UPDATED,
       
   299                                                 this, SLOT(folderUpdatedSlot(QDBusMessage)));
       
   300 
       
   301     // Get notifications of message Read/Unread state changes
       
   302     m_ModestDBusInterface->connection().connect(MODEST_DBUS_SERVICE,
       
   303                                                 MODEST_DBUS_OBJECT,
       
   304                                                 MODEST_DBUS_IFACE,
       
   305                                                 MODEST_DBUS_SIGNAL_MSG_READ_CHANGED,
       
   306                                                this, SLOT(messageReadChangedSlot(QDBusMessage)));
       
   307 
       
   308     qWarning() << "ModestEngine::ModestEngine Connecting to Qt Mobility Modest Plugin DBus Interface";
       
   309     // Setup Qt Mobility Modest Plugin based DBus Interface for Modest
       
   310     m_QtmPluginDBusInterface = new QDBusInterface(MODESTENGINE_QTM_PLUGIN_NAME,
       
   311                                                   MODESTENGINE_QTM_PLUGIN_PATH,
       
   312                                                   MODESTENGINE_QTM_PLUGIN_NAME,
       
   313                                                   QDBusConnection::sessionBus(),
       
   314                                                   this);
       
   315 
       
   316     if (m_QtmPluginDBusInterface->isValid()) {
       
   317         qWarning() << "ModestEngine::ModestEngine Connected to Qt Mobility Modest Plugin DBus Interface";
       
   318     } else {
       
   319         qWarning() << "ModestEngine::ModestEngine Unable to connect to Qt Mobility Modest Plugin DBus Interface";
       
   320     }
       
   321 
       
   322     qDBusRegisterMetaType< ModestStringMap >();
       
   323     qDBusRegisterMetaType< ModestStringMapList >();
       
   324 
       
   325     qRegisterMetaType<INotifyWatcher::FileNotification>();
       
   326 
       
   327     qRegisterMetaType<ModestUnreadMessageDBusStruct>();
       
   328     qRegisterMetaType<ModestAccountsUnreadMessagesDBusStruct>();
       
   329     qDBusRegisterMetaType<ModestMessage>();
       
   330 
       
   331     qRegisterMetaType<MessagingModestMimePart>();
       
   332 
       
   333     qRegisterMetaType<MessagingModestFolder>();
       
   334 
       
   335 
       
   336     connect(&m_MailFoldersWatcher, SIGNAL(fileChanged(int, QString, uint)),
       
   337             this, SLOT(fileChangedSlot(int, QString, uint)));
       
   338 
       
   339     watchAllKnownEmailFolders();
       
   340 
       
   341     // Get latest messages from each account
       
   342     // => This ensures that notifications of all incoming messages will be sent
       
   343     int messagesPerAccount = 1;
       
   344     QDBusPendingCall pendingCall = m_ModestDBusInterface->asyncCall(MODEST_DBUS_METHOD_GET_UNREAD_MESSAGES,
       
   345                                                                     messagesPerAccount);
       
   346     QDBusPendingCallWatcher* pendingCallWatcher = new QDBusPendingCallWatcher(pendingCall);
       
   347     pendingCallWatcher->setProperty("setOnlyDates", true);
       
   348     connect(pendingCallWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
       
   349             this, SLOT(pendingGetUnreadMessagesFinishedSlot(QDBusPendingCallWatcher*)));
       
   350 
       
   351     QList<MessagingModestFolder> modestFolders;
       
   352     foldersFromModest(modestFolders);
       
   353     if (modestFolders.count() > 0) {
       
   354         for (int i=0; i < modestFolders.count(); i++) {
       
   355             if (modestFolders[i].type == MessagingModestFolderTypeInbox && modestFolders[i].parentAccountId != "local_folders") {
       
   356                 QMessageAccountId accountId = accountIdFromModestAccountId(modestFolders[i].parentAccountId);
       
   357                 if (accountExists(accountId)) {
       
   358                     QString id = accountId.toString()+"&"+accountEmailProtocolAsString(accountId)+"&"+modestFolders[i].modestId;
       
   359                     startObservingModestFolder(id);
       
   360                 }
       
   361             }
       
   362         }
       
   363     }
       
   364 
       
   365     qWarning() << "ModestEngine::ModestEngine Initialized successfully";
       
   366 }
       
   367 
       
   368 ModestEngine::~ModestEngine()
       
   369 {
       
   370     g_object_unref(m_gconfclient);
       
   371     m_gconfclient=NULL;
       
   372 
       
   373     if (m_observed_folders.count()) {
       
   374         for (int i = m_observed_folders.count()-1; i >= 0; i--) {
       
   375             stopObservingModestFolder(m_observed_folders[i]);
       
   376         }
       
   377     }
       
   378 }
       
   379 
       
   380 ModestEngine* ModestEngine::instance()
       
   381 {
       
   382     return modestEngine();
       
   383 }
       
   384 
       
   385 MessagingModestMessage ModestEngine::messageFromModest(const QString& accountId, const QString &folderId, const QString& messageId) const
       
   386 {
       
   387     MessagingModestMessage modestMessage;
       
   388 
       
   389     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
   390         return modestMessage;
       
   391     }
       
   392 
       
   393     QDBusPendingCall pendingCall = m_QtmPluginDBusInterface->asyncCall("GetMessage",
       
   394                                                                        accountId,
       
   395                                                                        folderId,
       
   396                                                                        messageId);
       
   397     QDBusPendingCallWatcher pendingCallWatcher(pendingCall);
       
   398     pendingCallWatcher.waitForFinished();
       
   399 
       
   400     QDBusMessage msg = pendingCallWatcher.reply();
       
   401 
       
   402     if (msg.type() == QDBusMessage::ReplyMessage) {
       
   403         modestMessage.id = messageId;
       
   404         modestMessage.accountId = accountId;
       
   405         modestMessage.folderId = folderId;
       
   406         modestMessage.url = msg.arguments()[0].toString();
       
   407         modestMessage.mimeType = msg.arguments()[1].toString();
       
   408         modestMessage.from = msg.arguments()[2].toString();
       
   409         modestMessage.to = msg.arguments()[3].toString();
       
   410         modestMessage.cc = msg.arguments()[4].toString();
       
   411         modestMessage.bcc = msg.arguments()[5].toString();
       
   412         modestMessage.replyTo = msg.arguments()[6].toString();
       
   413         modestMessage.subject = msg.arguments()[7].toString();
       
   414         modestMessage.dateReceived = msg.arguments()[8].toLongLong();
       
   415         modestMessage.dateSent = msg.arguments()[9].toLongLong();
       
   416         modestMessage.size = msg.arguments()[10].toLongLong();
       
   417         modestMessage.flags = static_cast<MessagingModestMessageFlags>(msg.arguments()[11].toUInt());
       
   418         modestMessage.priority = static_cast<MessagingModestMessagePriority>(msg.arguments()[12].toUInt());
       
   419 
       
   420         QVariant variant = msg.arguments()[13];
       
   421         QDBusArgument argument = variant.value<QDBusArgument>();
       
   422         argument >> modestMessage.mimeParts;
       
   423     } else {
       
   424         modestMessage.dateReceived = 0;
       
   425         modestMessage.dateSent = 0;
       
   426         modestMessage.size = 0;
       
   427         modestMessage.flags = MessagingModestMessageNotDefined;
       
   428         modestMessage.priority = MessagingModestMessagePriorityNotDefined;
       
   429     }
       
   430 
       
   431     return modestMessage;
       
   432 }
       
   433 
       
   434 void ModestEngine::updateEmailAccounts() const
       
   435 {
       
   436     iDefaultEmailAccountId = QMessageAccountId();
       
   437     iAccounts.clear();
       
   438 
       
   439     GSList *accounts;
       
   440     GError *error = NULL;
       
   441 
       
   442     accounts = gconf_client_all_dirs(m_gconfclient, MODESTENGINE_ACCOUNT_NAMESPACE, &error);
       
   443     if (error) {
       
   444 #ifdef MESSAGING_DEBUG
       
   445         qDebug("qtmessaging: failed to list '%s': '%s'", MODESTENGINE_ACCOUNT_NAMESPACE, error->message);
       
   446 #endif
       
   447         g_error_free(error);
       
   448     } else {
       
   449         gchar *default_account_id = gconf_client_get_string(m_gconfclient, MODESTENGINE_DEFAULT_ACCOUNT, &error);
       
   450         if (error) {
       
   451             qWarning("qtmessaging: failed to get '%s': %s", MODESTENGINE_DEFAULT_ACCOUNT, error->message);
       
   452             g_error_free(error);
       
   453         }
       
   454 
       
   455         const size_t prefix_len = strlen(MODESTENGINE_ACCOUNT_NAMESPACE) + 1;
       
   456 
       
   457         GSList *iter = accounts;
       
   458         while (iter) {
       
   459             if (!(iter->data)) {
       
   460                 iter = iter->next;
       
   461                 continue;
       
   462             }
       
   463 
       
   464             const gchar* account_key = (const gchar*)iter->data;
       
   465             // account_key = /apps/modest/server_accounts/<account id>
       
   466             // => take account id from account_key & unescape account id
       
   467             gchar* unescaped_account_id = gconf_unescape_key(account_key+prefix_len, strlen(account_key)-prefix_len);
       
   468 
       
   469             gboolean account_ok = FALSE;
       
   470             // Check if account is enabled
       
   471             if (account_key) {
       
   472                 gchar* key = g_strconcat(account_key, "/", MODESTENGINE_ACCOUNT_ENABLED, NULL);
       
   473                 account_ok = gconf_client_get_bool(m_gconfclient, key, NULL);
       
   474                 g_free(key);
       
   475             }
       
   476 
       
   477             // Check if account store is defined
       
   478             if (account_ok) {
       
   479                 gchar* key = g_strconcat(account_key, "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
       
   480                 gchar* server_account_name = gconf_client_get_string(m_gconfclient, key, NULL);
       
   481                 if (server_account_name) {
       
   482                     gchar* escaped_server_account_name = gconf_escape_key(server_account_name, strlen(server_account_name));
       
   483                     g_free(server_account_name);
       
   484                     gchar* store_account_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_server_account_name, NULL);
       
   485                     if (!gconf_client_dir_exists(m_gconfclient, store_account_key, NULL)) {
       
   486                         account_ok = FALSE;
       
   487                     }
       
   488                     g_free(store_account_key);
       
   489                     g_free(escaped_server_account_name);
       
   490                 }
       
   491                 g_free(key);
       
   492             }
       
   493 
       
   494             // Check if account transport is defined
       
   495             if (account_ok) {
       
   496                 gchar* key = g_strconcat(account_key, "/", MODESTENGINE_ACCOUNT_TRANSPORT_ACCOUNT, NULL);
       
   497                 gchar* server_account_name = gconf_client_get_string(m_gconfclient, key, NULL);
       
   498                 if (server_account_name) {
       
   499                     gchar* escaped_server_account_name = gconf_escape_key(server_account_name, strlen(server_account_name));
       
   500                     g_free(server_account_name);
       
   501                     gchar* transport_account_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_server_account_name, NULL);
       
   502                     if (!gconf_client_dir_exists(m_gconfclient, transport_account_key, NULL)) {
       
   503                         account_ok = FALSE;
       
   504                     }
       
   505                     g_free(transport_account_key);
       
   506                     g_free(escaped_server_account_name);
       
   507                 }
       
   508                 g_free(key);
       
   509             }
       
   510 
       
   511             if (account_ok) {
       
   512                 gchar* escaped_account_id = gconf_escape_key(unescaped_account_id, strlen(unescaped_account_id));
       
   513                 QString accountId = "MO_"+QString::fromUtf8(escaped_account_id);
       
   514                 g_free(escaped_account_id);
       
   515 
       
   516                 gchar* name_key = g_strconcat(account_key, "/", MODESTENGINE_ACCOUNT_DISPLAY_NAME, NULL);
       
   517                 gchar* account_name = gconf_client_get_string(m_gconfclient, name_key, NULL);
       
   518                 QString accountName = QString::fromUtf8(account_name);
       
   519                 g_free(account_name);
       
   520                 g_free(name_key);
       
   521 
       
   522                 gchar* email_key = g_strconcat(account_key, "/", MODESTENGINE_ACCOUNT_EMAIL, NULL);
       
   523                 gchar* email = gconf_client_get_string(m_gconfclient, email_key, NULL);
       
   524                 QString accountAddress = QString::fromUtf8(email);
       
   525                 g_free(email);
       
   526                 g_free(email_key);
       
   527 
       
   528                 QMessageAccount account = QMessageAccountPrivate::from(QMessageAccountId(accountId),
       
   529                                                                        accountName,
       
   530                                                                        QMessageAddress(QMessageAddress::Email, accountAddress),
       
   531                                                                        QMessage::Email);
       
   532                 iAccounts.insert(accountId, account);
       
   533 
       
   534                 // Check if newly added account is default account
       
   535                 if (default_account_id) {
       
   536                     if (!strncmp(default_account_id, unescaped_account_id, strlen(default_account_id))) {
       
   537                         iDefaultEmailAccountId = accountId;
       
   538                     }
       
   539                 }
       
   540             }
       
   541 
       
   542             g_free(unescaped_account_id);
       
   543             g_free(iter->data);
       
   544             iter->data = NULL;
       
   545             iter = g_slist_next(iter);
       
   546         }
       
   547         // strings were freed in while loop
       
   548         // => it's enough to just free accounts list
       
   549         g_slist_free(accounts);
       
   550         g_free(default_account_id);
       
   551     }
       
   552 }
       
   553 
       
   554 QMessageAccountIdList ModestEngine::queryAccounts(const QMessageAccountFilter &filter, const QMessageAccountSortOrder &sortOrder,
       
   555                                                   uint limit, uint offset, bool &isFiltered, bool &isSorted) const
       
   556 {
       
   557     Q_UNUSED(sortOrder)
       
   558     Q_UNUSED(limit)
       
   559     Q_UNUSED(offset)
       
   560 
       
   561     QMessageAccountIdList accountIds;
       
   562 
       
   563     if (!m_QtmPluginDBusInterface->isValid()) {
       
   564         return accountIds;
       
   565     }
       
   566 
       
   567     updateEmailAccounts();
       
   568     foreach (QMessageAccount value, iAccounts) {
       
   569         accountIds.append(value.id());
       
   570     }
       
   571 
       
   572     MessagingHelper::filterAccounts(accountIds, filter);
       
   573     isFiltered = true;
       
   574 
       
   575     isSorted = false;
       
   576 
       
   577     return accountIds;
       
   578 }
       
   579 
       
   580 int ModestEngine::countAccounts(const QMessageAccountFilter &filter) const
       
   581 {
       
   582     bool isFiltered, isSorted;
       
   583     return queryAccounts(filter, QMessageAccountSortOrder(), 0, 0, isFiltered, isSorted).count();
       
   584 }
       
   585 
       
   586 QMessageAccount ModestEngine::account(const QMessageAccountId &id) const
       
   587 {
       
   588     updateEmailAccounts();
       
   589     return iAccounts[id.toString()];
       
   590 }
       
   591 
       
   592 QMessageAccountId ModestEngine::defaultAccount() const
       
   593 {
       
   594     updateEmailAccounts();
       
   595     return iDefaultEmailAccountId;
       
   596 }
       
   597 
       
   598 QFileInfoList ModestEngine::localFolders() const
       
   599 {
       
   600     QDir dir(localRootFolder());
       
   601     dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
       
   602     QFileInfoList fileInfoList = dir.entryInfoList();
       
   603     appendLocalSubFolders(fileInfoList, 0);
       
   604     return fileInfoList;
       
   605 }
       
   606 
       
   607 void ModestEngine::appendLocalSubFolders(QFileInfoList& fileInfoList, int startIndex) const
       
   608 {
       
   609     int endIndex = fileInfoList.count();
       
   610     for (int i=startIndex; i < endIndex; i++) {
       
   611         QDir dir(fileInfoList[i].absoluteFilePath());
       
   612         if (dir.exists()) {
       
   613             dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
       
   614             QFileInfoList dirs = dir.entryInfoList();
       
   615             for (int j = 0; j < dirs.count(); j++) {
       
   616                 QString fileName = dirs[j].fileName();
       
   617                 if (fileName != "cur" && fileName != "new" && fileName != "tmp") {
       
   618                     fileInfoList.append(dirs[j]);
       
   619                 }
       
   620             }
       
   621         }
       
   622     }
       
   623     if (fileInfoList.count() > endIndex) {
       
   624         appendLocalSubFolders(fileInfoList, endIndex);
       
   625     }
       
   626 }
       
   627 
       
   628 void ModestEngine::appendIMAPSubFolders(QFileInfoList& fileInfoList, int startIndex) const
       
   629 {
       
   630     int endIndex = fileInfoList.count();
       
   631     for (int i=startIndex; i < endIndex; i++) {
       
   632         QDir dir(fileInfoList[i].absoluteFilePath()+QString("/subfolders"));
       
   633         if (dir.exists()) {
       
   634             dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
       
   635             fileInfoList.append(dir.entryInfoList());
       
   636         }
       
   637     }
       
   638     if (fileInfoList.count() > endIndex) {
       
   639         appendIMAPSubFolders(fileInfoList, endIndex);
       
   640     }
       
   641 }
       
   642 
       
   643 QString ModestEngine::localRootFolder() const
       
   644 {
       
   645     return QDir::home().absolutePath()+QString("/.modest/local_folders");
       
   646 }
       
   647 
       
   648 QString ModestEngine::accountRootFolder(QMessageAccountId& accountId) const
       
   649 {
       
   650     QString modestAccountId = escapeString(modestAccountIdFromAccountId(accountId));
       
   651 
       
   652     QString userName;
       
   653     QString hostName;
       
   654     QString port;
       
   655     QString protocol;
       
   656 
       
   657     gchar* store_account_key = g_strconcat(MODESTENGINE_ACCOUNT_NAMESPACE, "/", modestAccountId.toUtf8().data(), "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
       
   658     gchar* store_account_name = gconf_client_get_string(m_gconfclient, store_account_key, NULL);
       
   659     g_free(store_account_key);
       
   660     gchar* escaped_store_account_name = gconf_escape_key(store_account_name, strlen(store_account_name));
       
   661     g_free(store_account_name);
       
   662 
       
   663     gchar* username_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_USERNAME, NULL);
       
   664     gchar* account_username = gconf_client_get_string(m_gconfclient, username_key, NULL);
       
   665     userName = QString::fromUtf8(account_username);
       
   666     g_free(account_username);
       
   667     g_free(username_key);
       
   668 
       
   669     gchar* hostname_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_HOSTNAME, NULL);
       
   670     gchar* account_hostname = gconf_client_get_string(m_gconfclient, hostname_key, NULL);
       
   671     hostName = QString::fromUtf8(account_hostname);
       
   672     g_free(account_hostname);
       
   673     g_free(hostname_key);
       
   674 
       
   675     gchar* port_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_PORT, NULL);
       
   676     gint account_port = gconf_client_get_int(m_gconfclient, port_key, NULL);
       
   677     port = QString::number(account_port);
       
   678     g_free(port_key);
       
   679 
       
   680     gchar* protocol_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_PROTOCOL, NULL);
       
   681     gchar* account_protocol = gconf_client_get_string(m_gconfclient, protocol_key, NULL);
       
   682     protocol = QString::fromUtf8(account_protocol);
       
   683     g_free(account_protocol);
       
   684     g_free(protocol_key);
       
   685 
       
   686     g_free(escaped_store_account_name);
       
   687 
       
   688     if (protocol == "pop") {
       
   689         return QDir::home().absolutePath()+"/.modest/cache/mail/"+protocol+"/"+userName+"__"+hostName+"_"+port;
       
   690     } else if (protocol == "imap") {
       
   691         return QDir::home().absolutePath()+"/.modest/cache/mail/"+protocol+"/"+userName+"__"+hostName+"_"+port+"/folders";
       
   692     }
       
   693     return QString();
       
   694 }
       
   695 
       
   696 QFileInfoList ModestEngine::accountFolders(QMessageAccountId& accountId) const
       
   697 {
       
   698     QFileInfoList fileInfoList;
       
   699 
       
   700     EmailProtocol protocol = accountEmailProtocol(accountId);
       
   701 
       
   702     if (protocol == ModestEngine::EmailProtocolPop3) {
       
   703         QFileInfo fileInfo = QFileInfo(accountRootFolder(accountId)+"/cache");
       
   704         fileInfoList.append(fileInfo);
       
   705     } else if (protocol == ModestEngine::EmailProtocolIMAP) {
       
   706         QDir dir(accountRootFolder(accountId));
       
   707         dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
       
   708         fileInfoList = dir.entryInfoList();
       
   709         appendIMAPSubFolders(fileInfoList, 0);
       
   710     }
       
   711 
       
   712     return fileInfoList;
       
   713 }
       
   714 
       
   715 ModestEngine::EmailProtocol ModestEngine::accountEmailProtocol(QMessageAccountId& accountId) const
       
   716 {
       
   717     EmailProtocol protocol = EmailProtocolUnknown;
       
   718 
       
   719     QString modestAccountId = escapeString(modestAccountIdFromAccountId(accountId));
       
   720 
       
   721     gchar* store_account_key = g_strconcat(MODESTENGINE_ACCOUNT_NAMESPACE, "/", modestAccountId.toUtf8().data(), "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
       
   722     gchar* store_account_name = gconf_client_get_string(m_gconfclient, store_account_key, NULL);
       
   723     g_free(store_account_key);
       
   724     gchar* escaped_store_account_name = gconf_escape_key(store_account_name, strlen(store_account_name));
       
   725     g_free(store_account_name);
       
   726 
       
   727     gchar* protocol_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_PROTOCOL, NULL);
       
   728     gchar* account_protocol = gconf_client_get_string(m_gconfclient, protocol_key, NULL);
       
   729     if (QString("pop") == account_protocol) {
       
   730         protocol = EmailProtocolPop3;
       
   731     } else if (QString("imap") == account_protocol) {
       
   732         protocol = EmailProtocolIMAP;
       
   733     }
       
   734     g_free(account_protocol);
       
   735     g_free(protocol_key);
       
   736 
       
   737     g_free(escaped_store_account_name);
       
   738 
       
   739     return protocol;
       
   740 }
       
   741 
       
   742 bool ModestEngine::accountExists(const QMessageAccountId& accountId) const
       
   743 {
       
   744     bool retVal = false;
       
   745 
       
   746     QString modestAccountId = escapeString(modestAccountIdFromAccountId(accountId));
       
   747     gchar* account_key = g_strconcat(MODESTENGINE_ACCOUNT_NAMESPACE, "/", modestAccountId.toUtf8().data(), NULL);
       
   748     retVal = gconf_client_dir_exists(m_gconfclient, account_key, NULL);
       
   749     g_free(account_key);
       
   750 
       
   751     return retVal;
       
   752 }
       
   753 
       
   754 QString ModestEngine::accountEmailProtocolAsString(const QMessageAccountId& accountId) const
       
   755 {
       
   756     QString protocol;
       
   757 
       
   758     QString modestAccountId = escapeString(modestAccountIdFromAccountId(accountId));
       
   759 
       
   760     gchar* store_account_key = g_strconcat(MODESTENGINE_ACCOUNT_NAMESPACE, "/", modestAccountId.toUtf8().data(), "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
       
   761     gchar* store_account_name = gconf_client_get_string(m_gconfclient, store_account_key, NULL);
       
   762     g_free(store_account_key);
       
   763     gchar* escaped_store_account_name = gconf_escape_key(store_account_name, strlen(store_account_name));
       
   764     g_free(store_account_name);
       
   765 
       
   766     gchar* protocol_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_PROTOCOL, NULL);
       
   767     gchar* account_protocol = gconf_client_get_string(m_gconfclient, protocol_key, NULL);
       
   768     protocol = QString::fromUtf8(account_protocol);
       
   769     g_free(account_protocol);
       
   770     g_free(protocol_key);
       
   771 
       
   772     g_free(escaped_store_account_name);
       
   773 
       
   774     return protocol;
       
   775 }
       
   776 
       
   777 QString ModestEngine::accountUsername(QMessageAccountId& accountId) const
       
   778 {
       
   779     QString username;
       
   780 
       
   781     QString modestAccountId = escapeString(modestAccountIdFromAccountId(accountId));
       
   782 
       
   783     gchar* store_account_key = g_strconcat(MODESTENGINE_ACCOUNT_NAMESPACE, "/", modestAccountId.toUtf8().data(), "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
       
   784     gchar* store_account_name = gconf_client_get_string(m_gconfclient, store_account_key, NULL);
       
   785     g_free(store_account_key);
       
   786     gchar* escaped_store_account_name = gconf_escape_key(store_account_name, strlen(store_account_name));
       
   787     g_free(store_account_name);
       
   788 
       
   789     gchar* username_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_USERNAME, NULL);
       
   790     gchar* account_username = gconf_client_get_string(m_gconfclient, username_key, NULL);
       
   791     username = QString::fromUtf8(account_username);
       
   792     g_free(account_username);
       
   793     g_free(username_key);
       
   794 
       
   795     g_free(escaped_store_account_name);
       
   796 
       
   797     return username;
       
   798 }
       
   799 
       
   800 QString ModestEngine::accountHostname(QMessageAccountId& accountId) const
       
   801 {
       
   802     QString host;
       
   803 
       
   804     QString modestAccountId = escapeString(modestAccountIdFromAccountId(accountId));
       
   805 
       
   806     gchar* store_account_key = g_strconcat(MODESTENGINE_ACCOUNT_NAMESPACE, "/", modestAccountId.toUtf8().data(), "/", MODESTENGINE_ACCOUNT_STORE_ACCOUNT, NULL);
       
   807     gchar* store_account_name = gconf_client_get_string(m_gconfclient, store_account_key, NULL);
       
   808     g_free(store_account_key);
       
   809     gchar* escaped_store_account_name = gconf_escape_key(store_account_name, strlen(store_account_name));
       
   810     g_free(store_account_name);
       
   811 
       
   812     gchar* host_key = g_strconcat(MODESTENGINE_SERVER_ACCOUNT_NAMESPACE, "/", escaped_store_account_name, "/", MODESTENGINE_ACCOUNT_HOSTNAME, NULL);
       
   813     gchar* account_host = gconf_client_get_string(m_gconfclient, host_key, NULL);
       
   814     host = QString::fromUtf8(account_host);
       
   815     g_free(account_host);
       
   816     g_free(host_key);
       
   817 
       
   818     g_free(escaped_store_account_name);
       
   819 
       
   820     return host;
       
   821 }
       
   822 
       
   823 void ModestEngine::foldersFromModest(QList<MessagingModestFolder>& folders) const
       
   824 {
       
   825     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
   826         return;
       
   827     }
       
   828 
       
   829     QDBusPendingCall pendingCall = m_QtmPluginDBusInterface->asyncCall("GetFolders");
       
   830     QDBusPendingCallWatcher pendingCallWatcher(pendingCall);
       
   831     pendingCallWatcher.waitForFinished();
       
   832 
       
   833     QDBusMessage msg = pendingCallWatcher.reply();
       
   834 
       
   835     if (msg.type() == QDBusMessage::ReplyMessage) {
       
   836         QVariant variant = msg.arguments()[0];
       
   837         QDBusArgument argument = variant.value<QDBusArgument>();
       
   838         argument >> folders;
       
   839     }
       
   840 }
       
   841 
       
   842 QMessageFolderIdList ModestEngine::queryFolders(const QMessageFolderFilter &filter, const QMessageFolderSortOrder &sortOrder,
       
   843                                                 uint limit, uint offset, bool &isFiltered, bool &isSorted) const
       
   844 {
       
   845     Q_UNUSED(sortOrder)
       
   846     Q_UNUSED(limit)
       
   847     Q_UNUSED(offset)
       
   848 
       
   849     QMessageFolderIdList folderIds;
       
   850 
       
   851     if (!m_QtmPluginDBusInterface->isValid()) {
       
   852         return folderIds;
       
   853     }
       
   854 
       
   855     updateEmailAccounts();
       
   856 
       
   857     if (iAccounts.isEmpty()) {
       
   858         return folderIds;
       
   859     }
       
   860 
       
   861     m_folderCache.clear();
       
   862 
       
   863     QList<MessagingModestFolder> modestFolders;
       
   864     foldersFromModest(modestFolders);
       
   865 
       
   866     if (modestFolders.count() > 0) {
       
   867         foreach (QMessageAccount value, iAccounts) {
       
   868             QMessageAccountId accountId = value.id();
       
   869             // Add folder to cache
       
   870             QString modestAccountId = modestAccountIdFromAccountId(accountId);
       
   871             for (int j=0; j < modestFolders.count(); j++) {
       
   872                 if (modestFolders[j].parentAccountId == modestAccountId) {
       
   873                     MessagingModestFolder folder = modestFolders[j];
       
   874                     QString id = accountId.toString()+"&"+accountEmailProtocolAsString(accountId)+"&"+folder.modestId;
       
   875                     folder.id = id;
       
   876                     m_folderCache.insert(id, folder);
       
   877 
       
   878                     folderIds.append(QMessageFolderId(id));
       
   879                 }
       
   880             }
       
   881             for (int j=0; j < modestFolders.count(); j++) {
       
   882                 if (modestFolders[j].parentAccountId == "local_folders") {
       
   883                     MessagingModestFolder folder = modestFolders[j];
       
   884                     QString id = accountId.toString()+"&"+"maildir"+"&"+folder.modestId;
       
   885                     folder.id = id;
       
   886                     m_folderCache.insert(id, folder);
       
   887 
       
   888                     folderIds.append(QMessageFolderId(id));
       
   889                 }
       
   890             }
       
   891         }
       
   892     } else {
       
   893         QFileInfoList localFolders = this->localFolders();
       
   894         QString localRootFolder = this->localRootFolder();
       
   895 
       
   896         foreach (QMessageAccount value, iAccounts) {
       
   897             QMessageAccountId accountId = value.id();
       
   898             QString rootFolder = accountRootFolder(accountId);
       
   899             QFileInfoList folders = this->accountFolders(accountId);
       
   900 
       
   901             for (int i=0; i < folders.count(); i++) {
       
   902                 QString filePath = folders[i].absoluteFilePath();
       
   903                 QString modestId = filePath.right(filePath.size()-rootFolder.size()-1);
       
   904                 modestId = modestId.remove("/subfolders");
       
   905                 QString id = accountId.toString()+"&"+accountEmailProtocolAsString(accountId)+"&"+modestId;
       
   906                 folderIds.append(QMessageFolderId(id));
       
   907 
       
   908                 // Add folder to cache
       
   909                 MessagingModestFolder folder;
       
   910                 folder.id = id;
       
   911                 folder.modestId = modestId;
       
   912                 if (modestId.lastIndexOf('/') == -1) {
       
   913                     // Folder does not have subfolders
       
   914                     folder.name = modestId;
       
   915                     if ((accountEmailProtocolAsString(accountId) == "pop") && (folder.name == "cache")) {
       
   916                         folder.name = "Inbox";
       
   917                     }
       
   918                 } else {
       
   919                     // Folder has subfolders
       
   920                     folder.name = modestId.right(modestId.length()-modestId.lastIndexOf('/')-1);
       
   921                     folder.parentFolderId = modestId.left(modestId.lastIndexOf('/'));
       
   922                 }
       
   923                 folder.parentAccountId = modestAccountIdFromAccountId(accountId);
       
   924                 folder.type = MessagingModestFolderTypeUnknown;
       
   925                 m_folderCache.insert(id, folder);
       
   926             }
       
   927 
       
   928             // Each account sees local folders as account folders
       
   929             for (int i=0; i < localFolders.count(); i++) {
       
   930                 QString filePath = localFolders[i].absoluteFilePath();
       
   931                 QString modestId = filePath.right(filePath.size()-localRootFolder.size()-1);
       
   932                 QString id = accountId.toString()+"&"+"maildir"+"&"+modestId;
       
   933                 folderIds.append(QMessageFolderId(id));
       
   934 
       
   935                 // Add folder to cache
       
   936                 MessagingModestFolder folder;
       
   937                 folder.id = id;
       
   938                 folder.modestId = modestId;
       
   939                 if (modestId.lastIndexOf('/') == -1) {
       
   940                     // Folder does not have subfolders
       
   941                     folder.name = modestId;
       
   942                     if ((accountEmailProtocolAsString(accountId) == "pop") && (folder.name == "cache")) {
       
   943                         folder.name = "Inbox";
       
   944                     }
       
   945                 } else {
       
   946                     // Folder has subfolders
       
   947                     folder.name = modestId.right(modestId.length()-modestId.lastIndexOf('/')-1);
       
   948                     folder.parentFolderId = modestId.left(modestId.lastIndexOf('/'));
       
   949                 }
       
   950                 folder.parentAccountId = "local_folders";
       
   951                 folder.type = MessagingModestFolderTypeUnknown;
       
   952                 m_folderCache.insert(id, folder);
       
   953             }
       
   954         }
       
   955     }
       
   956 
       
   957     MessagingHelper::filterFolders(folderIds, filter);
       
   958     isFiltered = true;
       
   959     isSorted = false;
       
   960     return folderIds;
       
   961 }
       
   962 
       
   963 int ModestEngine::countFolders(const QMessageFolderFilter &filter) const
       
   964 {
       
   965     bool isFiltered, isSorted;
       
   966     return queryFolders(filter, QMessageFolderSortOrder(), 0, 0, isFiltered, isSorted).count();
       
   967 }
       
   968 
       
   969 QMessageFolder ModestEngine::folder(const QMessageFolderId &id) const
       
   970 {
       
   971     QMessageFolder folder;
       
   972 
       
   973     QString idString = id.toString();
       
   974     if (m_folderCache.contains(idString)) {
       
   975         MessagingModestFolder modestFolder = m_folderCache.value(idString);
       
   976         int endOfAccountId = idString.indexOf('&');
       
   977         QString accountId = idString.left(endOfAccountId);
       
   978         QString folderPath = idString.right(idString.length()-idString.lastIndexOf('&')-1);
       
   979         QMessageFolderId parentId;
       
   980         QString name;
       
   981         if (folderPath.lastIndexOf('/') != -1) {
       
   982             // Folder has subfolders
       
   983             parentId = idString.left(idString.lastIndexOf('/'));
       
   984         }
       
   985 
       
   986         if (modestFolder.localizedName.isEmpty()) {
       
   987             folder = QMessageFolderPrivate::from(id,
       
   988                                                  QMessageAccountId(accountId),
       
   989                                                  parentId,
       
   990                                                  modestFolder.name,
       
   991                                                  folderPath);
       
   992         } else {
       
   993             folder = QMessageFolderPrivate::from(id,
       
   994                                                  QMessageAccountId(accountId),
       
   995                                                  parentId,
       
   996                                                  modestFolder.localizedName,
       
   997                                                  folderPath);
       
   998         }
       
   999     }
       
  1000 
       
  1001     return folder;
       
  1002 }
       
  1003 
       
  1004 bool ModestEngine::startObservingModestFolder(const QMessageFolderId& folderId) const
       
  1005 {
       
  1006     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
  1007         return false;
       
  1008     }
       
  1009 
       
  1010     if (!m_observed_folders.contains(folderId)) {
       
  1011         QDBusPendingCall pendingCall = m_QtmPluginDBusInterface->asyncCall("AddFolderObserver",
       
  1012                                                                            QVariant::fromValue(modestAccountIdFromFolderId(folderId)),
       
  1013                                                                            QVariant::fromValue(modestFolderIdFromFolderId(folderId)));
       
  1014         QDBusPendingCallWatcher pendingCallWatcher(pendingCall);
       
  1015         pendingCallWatcher.waitForFinished();
       
  1016 
       
  1017         QDBusMessage msg = pendingCallWatcher.reply();
       
  1018 
       
  1019         if (msg.type() == QDBusMessage::ReplyMessage) {
       
  1020             if (m_observed_folders.count() == 0) {
       
  1021                 m_QtmPluginDBusInterface->connection().connect(MODESTENGINE_QTM_PLUGIN_NAME,
       
  1022                                                                MODESTENGINE_QTM_PLUGIN_PATH,
       
  1023                                                                MODESTENGINE_QTM_PLUGIN_NAME,
       
  1024                                                                "FolderContentsChanged",
       
  1025                                                                (ModestEngine*)this,
       
  1026                                                                SLOT(modestFolderContentsChangedSlot(QDBusMessage)));
       
  1027             }
       
  1028 
       
  1029             m_observed_folders.append(folderId);
       
  1030 
       
  1031             return true;
       
  1032         }
       
  1033     } else {
       
  1034         return true;
       
  1035     }
       
  1036 
       
  1037     return false;
       
  1038 }
       
  1039 
       
  1040 bool ModestEngine::stopObservingModestFolder(const QMessageFolderId& folderId) const
       
  1041 {
       
  1042     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
  1043         return false;
       
  1044     }
       
  1045 
       
  1046     if (m_observed_folders.contains(folderId)) {
       
  1047         QDBusPendingCall pendingCall = m_QtmPluginDBusInterface->asyncCall("RemoveFolderObserver",
       
  1048                                                                            QVariant::fromValue(modestAccountIdFromFolderId(folderId)),
       
  1049                                                                            QVariant::fromValue(modestFolderIdFromFolderId(folderId)));
       
  1050         QDBusPendingCallWatcher pendingCallWatcher(pendingCall);
       
  1051         pendingCallWatcher.waitForFinished();
       
  1052 
       
  1053         QDBusMessage msg = pendingCallWatcher.reply();
       
  1054 
       
  1055         if (msg.type() == QDBusMessage::ReplyMessage) {
       
  1056             m_observed_folders.removeOne(folderId);
       
  1057 
       
  1058             if (m_observed_folders.count() == 0) {
       
  1059                 m_QtmPluginDBusInterface->connection().disconnect(MODESTENGINE_QTM_PLUGIN_NAME,
       
  1060                                                                   MODESTENGINE_QTM_PLUGIN_PATH,
       
  1061                                                                   MODESTENGINE_QTM_PLUGIN_NAME,
       
  1062                                                                   "FolderContentsChanged",
       
  1063                                                                   (ModestEngine*)this,
       
  1064                                                                   SLOT(modestFolderContentsChangedSlot(QDBusMessage)));
       
  1065             }
       
  1066 
       
  1067             return true;
       
  1068         }
       
  1069     }
       
  1070 
       
  1071     return false;
       
  1072 }
       
  1073 
       
  1074 void ModestEngine::modestFolderContentsChangedSlot(QDBusMessage msg)
       
  1075 {
       
  1076     QList<QVariant> arguments = msg.arguments();
       
  1077 
       
  1078     QString modestAccountId = arguments.takeFirst().toString();
       
  1079     QString modestFolderId = arguments.takeFirst().toString();
       
  1080     QMessageAccountId accountId = accountIdFromModestAccountId(modestAccountId);
       
  1081     QString protocol = accountEmailProtocolAsString(accountId);
       
  1082     if ((protocol == "pop") && (modestFolderId == "INBOX")) {
       
  1083         modestFolderId = "cache";
       
  1084     }
       
  1085     QString folderId = accountId.toString()+"&"+accountEmailProtocolAsString(accountId)+"&"+modestFolderId;
       
  1086 
       
  1087     qlonglong change = arguments.takeFirst().toLongLong();
       
  1088     QVariant variant = arguments.takeFirst();
       
  1089     QList<QString> messageIds = variant.toStringList();
       
  1090     if (change == 4) { // Headers added
       
  1091         for (int i = 0; i < messageIds.count(); i++) {
       
  1092             QMessageId messageId = folderId+"/"+messageIds[i];
       
  1093             notification(messageId, ModestEngine::Added);
       
  1094         }
       
  1095     }/* else if (change == 8) { // Headers removed
       
  1096         for (int i = 0; i < messageIds.count(); i++) {
       
  1097             QMessageId messageId = folderId+"/"+messageIds[i];
       
  1098             notification(messageId, ModestEngine::Removed);
       
  1099         }
       
  1100     }*/
       
  1101 }
       
  1102 
       
  1103 void ModestEngine::watchAllKnownEmailFolders()
       
  1104 {
       
  1105     QFileInfoList localFolders = this->localFolders();
       
  1106 
       
  1107     // Changes in local Email folders can be monitored using directory
       
  1108     // monitoring. <=> All messages are stored as individual files.
       
  1109     for (int i=0; i < localFolders.count(); i++) {
       
  1110         m_MailFoldersWatcher.addDirectory(localFolders[i].absoluteFilePath()+"/cur", IN_MOVED_TO | IN_DELETE);
       
  1111     }
       
  1112 
       
  1113     // Monitor changes also in root folder to see if new folders are added
       
  1114     m_MailFoldersWatcher.addDirectory(localRootFolder(), IN_CREATE);
       
  1115 
       
  1116     // Changes in remote Email folders must be monitored using file monitoring.
       
  1117     // That's because message headers are stored into summary.mmap file (and summary.mmap
       
  1118     // file maybe the only place that contains message information).
       
  1119     // => summary.mmap files will be monitored
       
  1120     foreach (QMessageAccount value, iAccounts) {
       
  1121         QMessageAccountId accountId = value.id();
       
  1122         QString rootFolder = accountRootFolder(accountId);
       
  1123         EmailProtocol protocol = accountEmailProtocol(accountId);
       
  1124         QFileInfoList folders = this->accountFolders(accountId);
       
  1125 
       
  1126         for (int i=0; i < folders.count(); i++) {
       
  1127             if (protocol == ModestEngine::EmailProtocolPop3) {
       
  1128                 QString folder = folders[i].absoluteFilePath();
       
  1129                 m_MailFoldersWatcher.addDirectory(folder, IN_CREATE);
       
  1130             } else if (protocol == ModestEngine::EmailProtocolIMAP) {
       
  1131                 m_MailFoldersWatcher.addDirectory(folders[i].absoluteFilePath(), IN_MOVED_TO | IN_DELETE);
       
  1132             }
       
  1133         }
       
  1134 
       
  1135     }
       
  1136 }
       
  1137 
       
  1138 void ModestEngine::fileChangedSlot(int watchDescriptor, QString filePath, uint events)
       
  1139 {
       
  1140     Q_UNUSED(watchDescriptor)
       
  1141 
       
  1142     if (events & IN_CREATE) {
       
  1143         if (QFileInfo(filePath).isDir()) {
       
  1144             // New directory was added
       
  1145             // => Start watching new folder
       
  1146             QString newDirPath = QString(filePath.toUtf8());
       
  1147             m_MailFoldersWatcher.addDirectory(newDirPath + "/cur");
       
  1148         }
       
  1149     }
       
  1150 
       
  1151     int filenameBegin = filePath.lastIndexOf('/')+1;
       
  1152     QString fileName = filePath.mid(filenameBegin,filePath.lastIndexOf('.')-filenameBegin);
       
  1153     if (!fileName.endsWith("summary")) {
       
  1154         if (events & (IN_MOVED_TO | IN_CREATE)) {
       
  1155             if (events != (IN_MOVED_TO | IN_MOVED_FROM)) {
       
  1156                 // Wait a moment to make sure that Modest has finished adding message
       
  1157                 QEventLoop eventLoop;
       
  1158                 QTimer::singleShot(100, &eventLoop, SLOT(quit()));
       
  1159                 eventLoop.exec();
       
  1160                 notification(messageIdFromModestMessageFilePath(filePath), ModestEngine::Added);
       
  1161             }
       
  1162         } else if (events & IN_DELETE) {
       
  1163             notification(messageIdFromModestMessageFilePath(filePath), ModestEngine::Removed);
       
  1164         }
       
  1165     }
       
  1166 }
       
  1167 
       
  1168 bool ModestEngine::sendEmail(QMessage &message)
       
  1169 {
       
  1170     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
  1171         return false;
       
  1172     }
       
  1173 
       
  1174     ModestStringMap senderInfo;
       
  1175     ModestStringMap recipients;
       
  1176     ModestStringMap messageData;
       
  1177     ModestStringMapList attachments;
       
  1178     ModestStringMapList images;
       
  1179     uint priority = 0;
       
  1180     ModestStringMap headers;
       
  1181 
       
  1182     senderInfo = getModestSenderInfo(message);
       
  1183 
       
  1184     if (senderInfo.isEmpty()) {
       
  1185         return false;
       
  1186     }
       
  1187 
       
  1188     recipients = getModestRecipients(message);
       
  1189 
       
  1190     if (recipients.isEmpty()) {
       
  1191         return false;
       
  1192     }
       
  1193 
       
  1194     messageData = getModestMessageData(message);
       
  1195     attachments = getModestAttachments(message);
       
  1196     images = getModestImages(message);
       
  1197     priority = getModestPriority(message);
       
  1198     headers = getModestHeaders(message);
       
  1199 
       
  1200     qDebug() << "Sending D-BUS message";
       
  1201 
       
  1202     QDBusPendingCall call = m_QtmPluginDBusInterface->asyncCall (
       
  1203             "SendEmail",
       
  1204             QVariant::fromValue (senderInfo),
       
  1205             QVariant::fromValue (recipients),
       
  1206             QVariant::fromValue (messageData),
       
  1207             QVariant::fromValue (attachments),
       
  1208             QVariant::fromValue (images),
       
  1209             priority,
       
  1210             QVariant::fromValue (headers));
       
  1211 
       
  1212     qDebug() << "Message sent";
       
  1213 
       
  1214     if (call.isError()) {
       
  1215         qWarning() << "Call failed! " << call.error();
       
  1216         return false;
       
  1217     }
       
  1218 
       
  1219     QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher (call, this);
       
  1220 
       
  1221     connect (watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
       
  1222              this, SLOT(sendEmailCallEnded(QDBusPendingCallWatcher*)));
       
  1223 
       
  1224     return true;
       
  1225 }
       
  1226 
       
  1227 bool ModestEngine::composeEmail(const QMessage &message)
       
  1228 {
       
  1229     QString mailString("mailto:");
       
  1230     QList<QMessageAddress> list(message.to());
       
  1231     if (!list.empty()){
       
  1232         for (int i = 0; i < list.size(); ++i) {
       
  1233             if (i == 0) {
       
  1234                 mailString += list.at(i).addressee();
       
  1235             } else {
       
  1236                 mailString += QString("%2C%20");
       
  1237                 mailString += list.at(i).addressee();
       
  1238             }
       
  1239         }
       
  1240     }
       
  1241 
       
  1242     bool firstParameter = true;
       
  1243 
       
  1244     QString subject = message.subject();
       
  1245     if (!subject.isEmpty()) {
       
  1246         if (firstParameter) {
       
  1247             mailString += QString("?");
       
  1248             firstParameter = false;
       
  1249         } else {
       
  1250             mailString += QString("&");
       
  1251         }
       
  1252         mailString += QString("subject=");
       
  1253         mailString += subject;
       
  1254     }
       
  1255 
       
  1256     QString body = message.textContent();
       
  1257     if (!body.isEmpty()) {
       
  1258         if (firstParameter) {
       
  1259             mailString += QString("?");
       
  1260             firstParameter = false;
       
  1261         } else {
       
  1262             mailString += QString("&");
       
  1263         }
       
  1264         mailString += QString("body=");
       
  1265         mailString += QString(body);
       
  1266     }
       
  1267 
       
  1268     QUrl url(mailString);
       
  1269 
       
  1270     QDBusInterface dbusif(MODEST_DBUS_SERVICE, MODEST_DBUS_OBJECT, MODEST_DBUS_IFACE);
       
  1271     QDBusMessage msg = dbusif.call(MODEST_DBUS_METHOD_MAIL_TO, url.toString());
       
  1272 
       
  1273     return true;
       
  1274 }
       
  1275 
       
  1276 bool ModestEngine::showMessage(const QMessageId &id)
       
  1277 {
       
  1278     QMessage msg = message(id, false);
       
  1279     QMessagePrivate* privateMessage = QMessagePrivate::implementation(msg);
       
  1280     if (privateMessage->_url.isEmpty()) {
       
  1281         return false;
       
  1282     } else {
       
  1283         m_ModestDBusInterface->call(MODEST_DBUS_METHOD_OPEN_MESSAGE,
       
  1284                                     privateMessage->_url);
       
  1285     }
       
  1286     return true;
       
  1287 }
       
  1288 
       
  1289 bool ModestEngine::exportUpdates(const QMessageAccountId &id)
       
  1290 {
       
  1291     Q_UNUSED(id) // Modest does not offer Account specific updates
       
  1292 
       
  1293     m_ModestDBusInterface->call(MODEST_DBUS_METHOD_SEND_RECEIVE);
       
  1294     return true;
       
  1295 }
       
  1296 
       
  1297 QMessage ModestEngine::message(const QMessageId &id, bool useCache) const
       
  1298 {
       
  1299     if (useCache) {
       
  1300         QMessage message = m_messageCache.value(id.toString());
       
  1301         if (message.type() != QMessage::NoType) {
       
  1302             return message;
       
  1303         }
       
  1304     }
       
  1305 
       
  1306     QString modestAccountId = modestAccountIdFromMessageId(id);
       
  1307     QString modestFolderId = modestFolderIdFromMessageId(id);
       
  1308     QString modestMessageId = modestMessageIdFromMessageId(id);
       
  1309 
       
  1310     MessagingModestMessage modestMessage = messageFromModest(modestAccountId,
       
  1311                                                              modestFolderId,
       
  1312                                                              modestMessageId);
       
  1313 
       
  1314     if (modestMessage.flags & MessagingModestMessageDeleted) {
       
  1315         return QMessage();
       
  1316     }
       
  1317 
       
  1318     if (modestMessage.accountId.isEmpty()) {
       
  1319         return QMessage();
       
  1320     }
       
  1321 
       
  1322     return messageFromModestMessage(modestMessage, accountIdFromMessageId(id));
       
  1323 }
       
  1324 
       
  1325 QMessage::StandardFolder ModestEngine::standardFolderFromModestFolderId(const QString& modestFolderId) const
       
  1326 {
       
  1327     if (!QString::compare(modestFolderId, "INBOX", Qt::CaseInsensitive)) {
       
  1328         return QMessage::InboxFolder;
       
  1329     } else if (!QString::compare(modestFolderId, "drafts", Qt::CaseInsensitive)) {
       
  1330         return QMessage::DraftsFolder;
       
  1331     } else if (!QString::compare(modestFolderId, "sent", Qt::CaseInsensitive)) {
       
  1332         return QMessage::SentFolder;
       
  1333     }
       
  1334 
       
  1335     return QMessage::DraftsFolder;
       
  1336 }
       
  1337 
       
  1338 QString ModestEngine::modestFolderIdFromStandardFolder(QMessage::StandardFolder standardFolder) const
       
  1339 {
       
  1340     switch (standardFolder) {
       
  1341     case QMessage::InboxFolder:  return "INBOX";
       
  1342     case QMessage::DraftsFolder: return "drafts";
       
  1343     case QMessage::SentFolder:   return "sent";
       
  1344     case QMessage::OutboxFolder: return "outbox";
       
  1345     case QMessage::TrashFolder:  return "thrash";
       
  1346     }
       
  1347     return "drafts";
       
  1348 }
       
  1349 
       
  1350 QMessage ModestEngine::messageFromModestMessage(const MessagingModestMessage& modestMessage,
       
  1351                                                 QMessageAccountId accountId) const
       
  1352 {
       
  1353     QMessage message;
       
  1354     QMessagePrivate* privateMessage = QMessagePrivate::implementation(message);
       
  1355     QMessageContentContainerPrivate* container = QMessagePrivate::containerImplementation(message);
       
  1356 
       
  1357     // Type
       
  1358     message.setType(QMessage::Email);
       
  1359 
       
  1360     // Parent Account Id
       
  1361     QMessageAccountId parentAccountId;
       
  1362     if (accountId.isValid()) {
       
  1363         parentAccountId = accountId;
       
  1364     } else {
       
  1365         parentAccountId = realAccountId(modestMessage);
       
  1366     }
       
  1367     message.setParentAccountId(parentAccountId);
       
  1368 
       
  1369     // Parent Folder Id
       
  1370     QMessageFolderId folderId;
       
  1371     if (modestMessage.accountId == "local_folders") {
       
  1372         folderId = folderIdFromModestFolderId(parentAccountId, true, modestMessage.folderId);
       
  1373     } else {
       
  1374         // Since Message is not in local folder, message status can be set to Incoming
       
  1375         privateMessage->_status = privateMessage->_status | QMessage::Incoming;
       
  1376         folderId = folderIdFromModestFolderId(parentAccountId, false, modestMessage.folderId);
       
  1377     }
       
  1378     privateMessage->_parentFolderId = folderId;
       
  1379 
       
  1380     // Message Id
       
  1381     QMessageId messageId = QMessageId(folderId.toString()+"/"+modestMessage.id);
       
  1382     privateMessage->_id = messageId;
       
  1383 
       
  1384     // Dates
       
  1385     message.setDate(QDateTime::fromTime_t(modestMessage.dateSent));
       
  1386     message.setReceivedDate(QDateTime::fromTime_t(modestMessage.dateReceived));
       
  1387 
       
  1388     // Priority
       
  1389     switch (modestMessage.priority) {
       
  1390     case QtMobility::MessagingModestMessageHighPriority:
       
  1391         message.setPriority(QMessage::HighPriority);
       
  1392         break;
       
  1393     case QtMobility::MessagingModestMessageNormalPriority:
       
  1394         message.setPriority(QMessage::NormalPriority);
       
  1395         break;
       
  1396     case QtMobility::MessagingModestMessageLowPriority:
       
  1397         message.setPriority(QMessage::LowPriority);
       
  1398         break;
       
  1399     }
       
  1400 
       
  1401     // Message MIME type
       
  1402     QString fullMimeType = modestMessage.mimeType;
       
  1403     int slashIndex = fullMimeType.indexOf('/');
       
  1404     QByteArray mimeType = fullMimeType.left(slashIndex).toAscii();
       
  1405     QByteArray mimeSubType = fullMimeType.mid(slashIndex+1).toAscii();
       
  1406     container->_type = mimeType.data();
       
  1407     container->_subType = mimeSubType.data();
       
  1408 
       
  1409     // Standard Folder
       
  1410     QMessagePrivate::setStandardFolder(message,
       
  1411                                        standardFolderFromModestFolderId(modestMessage.folderId));
       
  1412 
       
  1413     // Body & Attachments handling
       
  1414     for (int i=0; i < modestMessage.mimeParts.count(); i++) {
       
  1415         if (!modestMessage.mimeParts[i].isAttachment) {
       
  1416             // Body
       
  1417             QByteArray fullMimeType = modestMessage.mimeParts[i].mimeType.toUtf8();
       
  1418             QString contentId = modestMessage.mimeParts[i].contentId;
       
  1419             QByteArray fileName = modestMessage.mimeParts[i].fileName.toAscii();
       
  1420 
       
  1421             QByteArray mainType("text");
       
  1422             QByteArray subType("plain");
       
  1423             QByteArray charset;
       
  1424 
       
  1425             int index = fullMimeType.indexOf("/");
       
  1426             if (index != -1) {
       
  1427                 mainType = fullMimeType.left(index).trimmed();
       
  1428 
       
  1429                 subType = fullMimeType.mid(index + 1).trimmed();
       
  1430                 index = subType.indexOf(";");
       
  1431                 if (index != -1) {
       
  1432                     QString remainder = subType.mid(index + 1);
       
  1433                     subType = subType.left(index).trimmed();
       
  1434 
       
  1435                     QRegExp charsetPattern("charset=(\\S+)");
       
  1436                     index = charsetPattern.indexIn(remainder);
       
  1437                     if (index != -1) {
       
  1438                         charset = charsetPattern.cap(1).toLatin1().toUpper();
       
  1439                     }
       
  1440                 }
       
  1441             }
       
  1442 
       
  1443             if (charset.isEmpty()) {
       
  1444                 charset = "UTF-8";
       
  1445             }
       
  1446 
       
  1447             // Accept only text type Body
       
  1448             if (mainType.toLower() == "text") {
       
  1449                 QMessageContentContainerId existingBodyId(message.bodyId());
       
  1450                 if (existingBodyId.isValid()) {
       
  1451                     if (existingBodyId == QMessageContentContainerPrivate::bodyContentId()) {
       
  1452                         // The body content is in the message itself
       
  1453                         container->_containingMessageId = messageId.toString();
       
  1454                         container->_attachmentId = contentId;
       
  1455                         container->_name = fileName;
       
  1456                         container->_type = mainType;
       
  1457                         container->_subType = subType;
       
  1458                         container->_charset = charset;
       
  1459                         container->_size = 0;
       
  1460                         container->_available = true;
       
  1461                     } else {
       
  1462                         // The body content is in the first attachment
       
  1463                         QMessageContentContainerPrivate *attachmentContainer(QMessageContentContainerPrivate::implementation(*container->attachment(existingBodyId)));
       
  1464                         attachmentContainer->_containingMessageId = messageId.toString();
       
  1465                         attachmentContainer->_attachmentId = contentId;
       
  1466                         attachmentContainer->_name = fileName;
       
  1467                         attachmentContainer->_type = mainType;
       
  1468                         attachmentContainer->_subType = subType;
       
  1469                         attachmentContainer->_charset = charset;
       
  1470                         attachmentContainer->_size = 0;
       
  1471                         attachmentContainer->_available = true;
       
  1472                     }
       
  1473                 } else {
       
  1474                     if (container->_attachments.isEmpty()) {
       
  1475                         // Put the content directly into the message
       
  1476                         container->_containingMessageId = messageId.toString();
       
  1477                         container->_attachmentId = contentId;
       
  1478                         container->_name = fileName;
       
  1479                         container->_type = mainType;
       
  1480                         container->_subType = subType;
       
  1481                         container->_charset = charset;
       
  1482                         container->_size = 0;
       
  1483                         container->_available = true;
       
  1484                         privateMessage->_bodyId = QMessageContentContainerPrivate::bodyContentId();
       
  1485                     } else {
       
  1486                         // Add the body as the first attachment
       
  1487                         QMessageContentContainer newBody;
       
  1488                         QMessageContentContainerPrivate *attachmentContainer = QMessageContentContainerPrivate::implementation(newBody);
       
  1489                         attachmentContainer->_containingMessageId = messageId.toString();
       
  1490                         attachmentContainer->_attachmentId = contentId;
       
  1491                         attachmentContainer->_name = fileName;
       
  1492                         attachmentContainer->_type = mainType;
       
  1493                         attachmentContainer->_subType = subType;
       
  1494                         attachmentContainer->_charset = charset;
       
  1495                         attachmentContainer->_size = 0;
       
  1496                         attachmentContainer->_available = true;
       
  1497                         privateMessage->_bodyId = container->prependContent(newBody);
       
  1498                     }
       
  1499                 }
       
  1500             }
       
  1501         } else {
       
  1502             // Attachment
       
  1503             QString fullMimeType = modestMessage.mimeParts[i].mimeType;
       
  1504             QString contentId = modestMessage.mimeParts[i].contentId;
       
  1505             int slashIndex = fullMimeType.indexOf('/');
       
  1506             QByteArray mimeType = fullMimeType.left(slashIndex).toAscii();
       
  1507             QByteArray mimeSubType = fullMimeType.mid(slashIndex+1).toAscii();
       
  1508             // TODO: Attachment size
       
  1509             QByteArray fileName = modestMessage.mimeParts[i].fileName.toAscii();
       
  1510             fileName = fileName.mid(fileName.lastIndexOf('/')+1);
       
  1511             QString msgId = messageId.toString();
       
  1512             QMessageContentContainer attachment =
       
  1513                     QMessageContentContainerPrivate::from(msgId,
       
  1514                                                           contentId,
       
  1515                                                           fileName,
       
  1516                                                           mimeType,
       
  1517                                                           mimeSubType,
       
  1518                                                           0);
       
  1519             appendAttachmentToMessage(message, attachment);
       
  1520         }
       
  1521     }
       
  1522 
       
  1523     // From
       
  1524     if (modestMessage.from.size() > 0) {
       
  1525         message.setFrom(QMessageAddress(QMessageAddress::Email, modestMessage.from));
       
  1526         QMessagePrivate::setSenderName(message, modestMessage.from);
       
  1527     }
       
  1528 
       
  1529     // To
       
  1530     if (modestMessage.to.size() > 0) {
       
  1531         QMessageAddressList toAddresses;
       
  1532         foreach (const QString &element, modestMessage.to.split(",", QString::SkipEmptyParts)) {
       
  1533             QMessageAddress addr;
       
  1534             addr.setType(QMessageAddress::Email);
       
  1535             addr.setAddressee(element.trimmed());
       
  1536             toAddresses.append(addr);
       
  1537         }
       
  1538         message.setTo(toAddresses);
       
  1539     }
       
  1540 
       
  1541     // Cc
       
  1542     if (modestMessage.cc.size() > 0) {
       
  1543         QMessageAddressList ccAddresses;
       
  1544         foreach (const QString &element, modestMessage.cc.split(",", QString::SkipEmptyParts)) {
       
  1545             QMessageAddress addr;
       
  1546             addr.setType(QMessageAddress::Email);
       
  1547             addr.setAddressee(element.trimmed());
       
  1548             ccAddresses.append(addr);
       
  1549         }
       
  1550         message.setCc(ccAddresses);
       
  1551     }
       
  1552 
       
  1553     // Bcc
       
  1554     if (modestMessage.bcc.size() > 0) {
       
  1555         QMessageAddressList bccAddresses;
       
  1556         foreach (const QString &element, modestMessage.bcc.split(",", QString::SkipEmptyParts)) {
       
  1557             QMessageAddress addr;
       
  1558             addr.setType(QMessageAddress::Email);
       
  1559             addr.setAddressee(element.trimmed());
       
  1560             bccAddresses.append(addr);
       
  1561         }
       
  1562         message.setBcc(bccAddresses);
       
  1563     }
       
  1564 
       
  1565     // Subject
       
  1566     message.setSubject(modestMessage.subject);
       
  1567 
       
  1568     // Size
       
  1569     privateMessage->_size = modestMessage.size;
       
  1570 
       
  1571     // Read Status
       
  1572     if (modestMessage.flags & MessagingModestMessageSeen) {
       
  1573         privateMessage->_status = privateMessage->_status | QMessage::Read;
       
  1574     }
       
  1575 
       
  1576     // Attachments Status
       
  1577     if (modestMessage.flags & MessagingModestMessageAttachments) {
       
  1578         privateMessage->_status = privateMessage->_status | QMessage::HasAttachments;
       
  1579     }
       
  1580 
       
  1581     // Modest specific url
       
  1582     privateMessage->_url = modestMessage.url;
       
  1583 
       
  1584     // Modified flag
       
  1585     privateMessage->_modified = false;
       
  1586 
       
  1587     return message;
       
  1588 }
       
  1589 
       
  1590 void ModestEngine::appendAttachmentToMessage(QMessage& message, QMessageContentContainer& attachment) const
       
  1591 {
       
  1592     QMessagePrivate* privateMessage = QMessagePrivate::implementation(message);
       
  1593     QMessageContentContainerPrivate* container = QMessagePrivate::containerImplementation(message);
       
  1594 
       
  1595     if (container->_attachments.isEmpty()) {
       
  1596         QMessageContentContainerId existingBodyId(message.bodyId());
       
  1597         if (existingBodyId == QMessageContentContainerPrivate::bodyContentId()) {
       
  1598             // The body content is in the message itself - move it to become the first attachment
       
  1599             QMessageContentContainer newBody(message);
       
  1600             QMessageContentContainerPrivate::implementation(newBody)->setDerivedMessage(0);
       
  1601 
       
  1602             container->setContentType("multipart", "mixed", "");
       
  1603             privateMessage->_bodyId = container->prependContent(newBody);
       
  1604         } else {
       
  1605             // This message is now multipart
       
  1606             container->setContentType("multipart", "mixed", "");
       
  1607         }
       
  1608 
       
  1609         container->_available = true;
       
  1610     }
       
  1611 
       
  1612     container->appendContent(attachment);
       
  1613 
       
  1614     bool haveAttachments = !container->_attachments.isEmpty();
       
  1615     message.setStatus(QMessage::HasAttachments,haveAttachments);
       
  1616 
       
  1617     privateMessage->_modified = true;
       
  1618 }
       
  1619 
       
  1620 bool ModestEngine::addMessage(QMessage &message)
       
  1621 {
       
  1622     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
  1623         return false;
       
  1624     }
       
  1625 
       
  1626     QString modestFolder;
       
  1627     ModestStringMap senderInfo;
       
  1628     ModestStringMap recipients;
       
  1629     ModestStringMap messageData;
       
  1630     ModestStringMapList attachments;
       
  1631     ModestStringMapList images;
       
  1632     uint priority = 0;
       
  1633     ModestStringMap headers;
       
  1634 
       
  1635     qDebug() << __PRETTY_FUNCTION__;
       
  1636 
       
  1637     senderInfo = getModestSenderInfo (message);
       
  1638     recipients = getModestRecipients (message);
       
  1639     messageData = getModestMessageData (message);
       
  1640     attachments = getModestAttachments (message);
       
  1641     images = getModestImages (message);
       
  1642     priority = getModestPriority (message);
       
  1643     headers = getModestHeaders (message);
       
  1644 
       
  1645     QString accountName;
       
  1646     if (message.parentFolderId().isValid()) {
       
  1647         modestFolder = modestFolderIdFromFolderId (message.parentFolderId());
       
  1648         accountName = modestAccountIdFromFolderId(message.parentFolderId());
       
  1649     } else {
       
  1650         modestFolder = modestFolderIdFromStandardFolder(message.standardFolder());
       
  1651         if (message.standardFolder() == QMessage::DraftsFolder) {
       
  1652             accountName = "local_folders";
       
  1653         } else {
       
  1654             accountName = modestAccountIdFromAccountId(message.parentAccountId());
       
  1655         }
       
  1656     }
       
  1657     senderInfo["account-name"] = accountName;
       
  1658 
       
  1659     QList<QVariant> arguments;
       
  1660     arguments << modestFolder;
       
  1661     arguments << QVariant::fromValue(senderInfo);
       
  1662     arguments << QVariant::fromValue(recipients);
       
  1663     arguments << QVariant::fromValue(messageData);
       
  1664     arguments << QVariant::fromValue(attachments);
       
  1665     arguments << QVariant::fromValue(images);
       
  1666     arguments << priority;
       
  1667     arguments << QVariant::fromValue(headers);
       
  1668 
       
  1669     QDBusPendingCall pendingCall = m_QtmPluginDBusInterface->asyncCallWithArgumentList("AddMessage",
       
  1670                                                                                        arguments);
       
  1671 
       
  1672     if (pendingCall.isError()) {
       
  1673         qWarning() << "DBus call failed! " << pendingCall.error();
       
  1674         return false;
       
  1675     }
       
  1676 
       
  1677     QDBusPendingCallWatcher pendingCallWatcher(pendingCall);
       
  1678     pendingCallWatcher.waitForFinished();
       
  1679     QDBusMessage msg = pendingCallWatcher.reply();
       
  1680     if (msg.type() == QDBusMessage::ErrorMessage) {
       
  1681         qWarning() << "Failed to add message via modest: " << msg.errorMessage();
       
  1682         return false;
       
  1683     }
       
  1684 
       
  1685     QMessagePrivate* privateMessage = QMessagePrivate::implementation(message);
       
  1686     QString messageId;
       
  1687     if (message.parentFolderId().isValid()) {
       
  1688         messageId = message.parentFolderId().toString()+"/"+msg.arguments()[0].toString();
       
  1689     } else if (accountName == "local_folders") {
       
  1690         messageId = message.parentAccountId().toString()+
       
  1691                     "&maildir&"+modestFolder+"/"+msg.arguments()[0].toString();
       
  1692     } else {
       
  1693         messageId = message.parentAccountId().toString()+"&"+
       
  1694                     accountEmailProtocolAsString(message.parentAccountId())+
       
  1695                     "&"+modestFolder+"/"+msg.arguments()[0].toString();
       
  1696     }
       
  1697     privateMessage->_id = QMessageId(messageId);
       
  1698 
       
  1699     // Use update functionality to set Priority & Read status
       
  1700     // <=> Modest Plugin can not set Priority & Read status
       
  1701     //     immediately after message creation in add call
       
  1702     updateMessage(message);
       
  1703 
       
  1704     return true;
       
  1705 }
       
  1706 
       
  1707 bool ModestEngine::updateMessage(QMessage &message)
       
  1708 {
       
  1709     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
  1710         return false;
       
  1711     }
       
  1712 
       
  1713     if (!message.id().isValid()) {
       
  1714         return false;
       
  1715     }
       
  1716 
       
  1717     QString modestAccountId = modestAccountIdFromMessageId(message.id());
       
  1718     QString modestFolderId  = modestFolderIdFromMessageId(message.id());
       
  1719     QString modestMessageId = modestMessageIdFromMessageId(message.id());
       
  1720 
       
  1721     QString modestFolder;
       
  1722     ModestStringMap senderInfo;
       
  1723     ModestStringMap recipients;
       
  1724     ModestStringMap messageData;
       
  1725     ModestStringMapList attachments;
       
  1726     ModestStringMapList images;
       
  1727     uint priority = 0;
       
  1728     ModestStringMap headers;
       
  1729 
       
  1730     qDebug() << __PRETTY_FUNCTION__;
       
  1731 
       
  1732     // Only read status & priority can be updated using Modest
       
  1733     if (message.status() & QMessage::Read) {
       
  1734         messageData["read"] = "";
       
  1735     }
       
  1736     priority = getModestPriority (message);
       
  1737 
       
  1738     QList<QVariant> arguments;
       
  1739     arguments << QVariant::fromValue(modestAccountId);
       
  1740     arguments << QVariant::fromValue(modestFolderId);
       
  1741     arguments << QVariant::fromValue(modestMessageId);
       
  1742     arguments << QVariant::fromValue(senderInfo);
       
  1743     arguments << QVariant::fromValue(recipients);
       
  1744     arguments << QVariant::fromValue(messageData);
       
  1745     arguments << QVariant::fromValue(attachments);
       
  1746     arguments << QVariant::fromValue(images);
       
  1747     arguments << priority;
       
  1748     arguments << QVariant::fromValue(headers);
       
  1749 
       
  1750     QDBusPendingCall pendingCall = m_QtmPluginDBusInterface->asyncCallWithArgumentList("UpdateMessage",
       
  1751                                                                                        arguments);
       
  1752 
       
  1753     if (pendingCall.isError()) {
       
  1754         qWarning() << "DBus call failed! " << pendingCall.error();
       
  1755         return false;
       
  1756     }
       
  1757 
       
  1758     QDBusPendingCallWatcher pendingCallWatcher(pendingCall);
       
  1759     pendingCallWatcher.waitForFinished();
       
  1760     QDBusMessage msg = pendingCallWatcher.reply();
       
  1761     if (msg.type() == QDBusMessage::ErrorMessage) {
       
  1762         qWarning() << "Failed to update message via modest: " << msg.errorMessage();
       
  1763         return false;
       
  1764     }
       
  1765 
       
  1766     return true;
       
  1767 }
       
  1768 
       
  1769 bool ModestEngine::removeMessage(const QMessageId &id, QMessageManager::RemovalOption option)
       
  1770 {
       
  1771     Q_UNUSED(option) // TODO:
       
  1772 
       
  1773     QMessage msg = message(id, false);
       
  1774     QMessagePrivate* privateMessage = QMessagePrivate::implementation(msg);
       
  1775     if (privateMessage->_url.isEmpty()) {
       
  1776         return false;
       
  1777     } else {
       
  1778         m_ModestDBusInterface->call(MODEST_DBUS_METHOD_DELETE_MESSAGE,
       
  1779                                     privateMessage->_url);
       
  1780         // Make sure that there will instant notification about removed message
       
  1781         notification(id, ModestEngine::Removed);
       
  1782     }
       
  1783     return true;
       
  1784 }
       
  1785 
       
  1786 bool ModestEngine::filterMessage(const QMessage& message, QMessageFilterPrivate::SortedMessageFilterList filterList, int start) const
       
  1787 {
       
  1788     if (filterList.count() > start) {
       
  1789         for (int j=start; j < filterList.count(); j++) {
       
  1790             QMessageFilterPrivate* pf = QMessageFilterPrivate::implementation(filterList[j]);
       
  1791             if (!pf->filter(message)) {
       
  1792                 return false;
       
  1793             }
       
  1794         }
       
  1795     }
       
  1796     return true;
       
  1797 }
       
  1798 
       
  1799 QMessageIdList ModestEngine::queryMessagesSync(const QMessageFilter &filter, const QMessageSortOrder &sortOrder,
       
  1800                                                uint limit, uint offset, bool &isFiltered, bool &isSorted) const
       
  1801 {
       
  1802     QMessageIdList ids;
       
  1803 
       
  1804     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
  1805         return ids;
       
  1806     }
       
  1807 
       
  1808     QMessageServicePrivate* privateService = QMessageServicePrivate::implementation(m_service);
       
  1809     if (privateService->queryMessages(m_service, filter, sortOrder, limit, offset,
       
  1810                                       QMessageServicePrivate::EnginesToCallModest)) {
       
  1811         QObject::connect(&m_service, SIGNAL(stateChanged(QMessageService::State)),
       
  1812                          this, SLOT(stateChanged(QMessageService::State)));
       
  1813 
       
  1814         m_eventLoop.exec();
       
  1815 
       
  1816         isSorted = m_isSorted;
       
  1817         isFiltered = m_isFiltered;
       
  1818         ids = m_ids;
       
  1819         m_ids.clear();
       
  1820     }
       
  1821 
       
  1822     return ids;
       
  1823 }
       
  1824 
       
  1825 QMessageIdList ModestEngine::queryMessagesSync(const QMessageFilter &filter, const QString &body,
       
  1826                                                QMessageDataComparator::MatchFlags matchFlags,
       
  1827                                                const QMessageSortOrder &sortOrder, uint limit, uint offset,
       
  1828                                                bool &isFiltered, bool &isSorted) const
       
  1829 {
       
  1830     QMessageIdList ids;
       
  1831 
       
  1832     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
  1833         return ids;
       
  1834     }
       
  1835 
       
  1836     QMessageServicePrivate* privateService = QMessageServicePrivate::implementation(m_service);
       
  1837     if (privateService->queryMessages(m_service, filter, body, matchFlags,
       
  1838                                       sortOrder, limit, offset,
       
  1839                                       QMessageServicePrivate::EnginesToCallModest)) {
       
  1840         QObject::connect(&m_service, SIGNAL(stateChanged(QMessageService::State)),
       
  1841                          this, SLOT(stateChanged(QMessageService::State)));
       
  1842 
       
  1843         m_eventLoop.exec();
       
  1844 
       
  1845         isSorted = m_isSorted;
       
  1846         isFiltered = m_isFiltered;
       
  1847         ids = m_ids;
       
  1848         m_ids.clear();
       
  1849     }
       
  1850 
       
  1851     return ids;
       
  1852 }
       
  1853 
       
  1854 int ModestEngine::countMessagesSync(const QMessageFilter &filter) const
       
  1855 {
       
  1856     int count;
       
  1857 
       
  1858     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
  1859         return 0;
       
  1860     }
       
  1861 
       
  1862     QMessageServicePrivate* privateService = QMessageServicePrivate::implementation(m_service);
       
  1863     if (privateService->countMessages(m_service, filter, QMessageServicePrivate::EnginesToCallModest)) {
       
  1864         QObject::connect(&m_service, SIGNAL(stateChanged(QMessageService::State)),
       
  1865                          this, SLOT(stateChanged(QMessageService::State)));
       
  1866 
       
  1867         m_eventLoop.exec();
       
  1868 
       
  1869         count = m_count;
       
  1870     }
       
  1871 
       
  1872     return count;
       
  1873 }
       
  1874 
       
  1875 void ModestEngine::stateChanged(QMessageService::State newState)
       
  1876 {
       
  1877     if (newState == QMessageService::FinishedState) {
       
  1878         QMessageServicePrivate* privateService = QMessageServicePrivate::implementation(m_service);
       
  1879 
       
  1880         m_ids = privateService->_ids;
       
  1881         m_isSorted = privateService->_sorted;
       
  1882         m_isFiltered = privateService->_filtered;
       
  1883         m_count = privateService->_count;
       
  1884 
       
  1885         m_eventLoop.quit();
       
  1886     }
       
  1887 }
       
  1888 
       
  1889 bool ModestEngine::queryMessages(QMessageService& messageService, const QMessageFilter &filter, const QMessageSortOrder &sortOrder, uint limit, uint offset) const
       
  1890 {
       
  1891     return queryMessages(messageService, filter, QString(), 0, sortOrder, limit, offset);
       
  1892 }
       
  1893 
       
  1894 bool ModestEngine::countMessages(QMessageService& messageService, const QMessageFilter &filter)
       
  1895 {
       
  1896     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
  1897         return false;
       
  1898     }
       
  1899 
       
  1900     m_pendingMessageQueries.append(MessageQueryInfo());
       
  1901 
       
  1902     MessageQueryInfo &queryInfo = m_pendingMessageQueries[m_pendingMessageQueries.count()-1];
       
  1903 
       
  1904     queryInfo.filter = filter;
       
  1905     queryInfo.limit = 0;
       
  1906     queryInfo.offset = 0;
       
  1907     queryInfo.privateService = QMessageServicePrivate::implementation(messageService);
       
  1908     queryInfo.currentFilterListIndex = 0;
       
  1909     queryInfo.handledFiltersCount = 0;
       
  1910     queryInfo.isQuery = false;
       
  1911     queryInfo.returnWithSingleShot = false;
       
  1912 
       
  1913     if (!startQueryingAndFilteringMessages(m_pendingMessageQueries[m_pendingMessageQueries.count()-1])) {
       
  1914         QMessageServicePrivate::implementation(messageService)->setFinished(false);
       
  1915         m_pendingMessageQueries.removeAt(m_pendingMessageQueries.count()-1);
       
  1916         return false;
       
  1917     }
       
  1918 
       
  1919     return true;
       
  1920 }
       
  1921 
       
  1922 bool ModestEngine::queryMessages(QMessageService& messageService, const QMessageFilter &filter, const QString &body,
       
  1923                                  QMessageDataComparator::MatchFlags matchFlags, const QMessageSortOrder &sortOrder,
       
  1924                                  uint limit, uint offset) const
       
  1925 {
       
  1926     if (!m_QtmPluginDBusInterface->isValid() || iAccounts.isEmpty()) {
       
  1927         return false;
       
  1928     }
       
  1929 
       
  1930     m_pendingMessageQueries.append(MessageQueryInfo());
       
  1931 
       
  1932     MessageQueryInfo &queryInfo = m_pendingMessageQueries[m_pendingMessageQueries.count()-1];
       
  1933 
       
  1934     queryInfo.body = body;
       
  1935     queryInfo.matchFlags = matchFlags;
       
  1936     queryInfo.filter = filter;
       
  1937     queryInfo.sortOrder = sortOrder;
       
  1938     queryInfo.limit = limit;
       
  1939     queryInfo.offset = offset;
       
  1940     queryInfo.privateService = QMessageServicePrivate::implementation(messageService);
       
  1941     queryInfo.currentFilterListIndex = 0;
       
  1942     queryInfo.handledFiltersCount = 0;
       
  1943     queryInfo.isQuery = true;
       
  1944     queryInfo.returnWithSingleShot = false;
       
  1945 
       
  1946     if (!startQueryingAndFilteringMessages(m_pendingMessageQueries[m_pendingMessageQueries.count()-1])) {
       
  1947         m_pendingMessageQueries.removeAt(m_pendingMessageQueries.count()-1);
       
  1948         if (m_pendingMessageQueries.count() == 0) {
       
  1949             // This was last query in pending queries queue
       
  1950             // => Disconnect from "GetHeaders" request related DBus signals
       
  1951             // Note: Disconnecting signals is done to optimize signal handling
       
  1952             //       <=> Disconnecting prevents unnecessary handling of signals
       
  1953             //           which have been sent from other applications using
       
  1954             //           Qt Mobility Messaging API
       
  1955             m_QtmPluginDBusInterface->connection().disconnect(MODESTENGINE_QTM_PLUGIN_NAME,
       
  1956                                                               MODESTENGINE_QTM_PLUGIN_PATH,
       
  1957                                                               MODESTENGINE_QTM_PLUGIN_NAME,
       
  1958                                                               "HeadersReceived",
       
  1959                                                               (ModestEngine*)this,
       
  1960                                                               SLOT(searchMessagesHeadersReceivedSlot(QDBusMessage)));
       
  1961 
       
  1962             m_QtmPluginDBusInterface->connection().disconnect(MODESTENGINE_QTM_PLUGIN_NAME,
       
  1963                                                               MODESTENGINE_QTM_PLUGIN_PATH,
       
  1964                                                               MODESTENGINE_QTM_PLUGIN_NAME,
       
  1965                                                               "HeadersFetched",
       
  1966                                                               (ModestEngine*)this,
       
  1967                                                               SLOT(searchMessagesHeadersFetchedSlot(QDBusMessage)));
       
  1968         }
       
  1969         return false;
       
  1970     }
       
  1971 
       
  1972     return true;
       
  1973 }
       
  1974 
       
  1975 bool ModestEngine::startQueryingAndFilteringMessages(MessageQueryInfo &msgQueryInfo) const
       
  1976 {
       
  1977     QMessageFilterPrivate* pf = QMessageFilterPrivate::implementation(msgQueryInfo.filter);
       
  1978     if (pf->_filterList.count() == 0) {
       
  1979         if ((pf->_field == QMessageFilterPrivate::None) &&
       
  1980             (pf->_filterList.count() == 0) &&
       
  1981             (pf->_notFilter)) {
       
  1982             // There is only one filter: empty ~QMessageFilter()
       
  1983             // => return empty QMessageIdList
       
  1984             msgQueryInfo.ids.clear();
       
  1985             msgQueryInfo.returnWithSingleShot = true;
       
  1986             QTimer::singleShot(0, (ModestEngine*)this, SLOT(returnQueryResultsSlot()));
       
  1987             return true;
       
  1988         } else {
       
  1989             // One single filter to be handled
       
  1990             QMessageFilter newFilter;
       
  1991             QMessageFilterPrivate* pfNew = QMessageFilterPrivate::implementation(newFilter);
       
  1992             pfNew->_filterList.append(QMessageFilterPrivate::SortedMessageFilterList());
       
  1993             pfNew->_filterList[0] << msgQueryInfo.filter;
       
  1994             msgQueryInfo.filter = newFilter;
       
  1995         }
       
  1996     }
       
  1997 
       
  1998     return queryAndFilterMessages(msgQueryInfo);
       
  1999 }
       
  2000 
       
  2001 void ModestEngine::returnQueryResultsSlot()
       
  2002 {
       
  2003     for (int i=m_pendingMessageQueries.count()-1; i >= 0; i--) {
       
  2004         if (m_pendingMessageQueries[i].returnWithSingleShot) {
       
  2005             if (m_pendingMessageQueries[i].isQuery) {
       
  2006                 m_pendingMessageQueries[i].privateService->messagesFound(m_pendingMessageQueries[i].ids, true, true);
       
  2007             } else {
       
  2008                 m_pendingMessageQueries[i].privateService->messagesCounted(m_pendingMessageQueries[i].ids.count());
       
  2009             }
       
  2010             m_pendingMessageQueries.removeAt(i);
       
  2011         }
       
  2012     }
       
  2013 }
       
  2014 
       
  2015 bool ModestEngine::queryAndFilterMessages(MessageQueryInfo &msgQueryInfo) const
       
  2016 {
       
  2017     QStringList accountIds;
       
  2018     QStringList folderUris;
       
  2019     QDateTime startTimeStamp;
       
  2020     QDateTime endTimeStamp;
       
  2021     QDateTime startReceptionTimeStamp;
       
  2022     QDateTime endReceptionTimeStamp;
       
  2023 
       
  2024     QMessageFilterPrivate* pf = QMessageFilterPrivate::implementation(msgQueryInfo.filter);
       
  2025 
       
  2026     // Filters have been sorted into matrix of filters:
       
  2027     // - there is AND operation between every filter in one row
       
  2028     // - there is OR operation between every row
       
  2029     // => Every row can be handled individually
       
  2030     // => Final result set can be created by combining result sets
       
  2031     //    from individual row based queries
       
  2032     QMessageFilterPrivate::SortedMessageFilterList filters = pf->_filterList[msgQueryInfo.currentFilterListIndex];
       
  2033 
       
  2034     msgQueryInfo.realAccountId = QString();
       
  2035 
       
  2036     int handledFiltersCount = 0;
       
  2037     pf = QMessageFilterPrivate::implementation(filters[handledFiltersCount]);
       
  2038     if ((filters.count() == 1) &&
       
  2039         (pf->_field == QMessageFilterPrivate::None) &&
       
  2040         (pf->_filterList.count() == 0)) {
       
  2041         if (pf->_notFilter) {
       
  2042             // There is only one filter: empty ~QMessageFilter()
       
  2043             // => this query results empty QMessageIdList
       
  2044             // => Skip to next query round
       
  2045             int index = -1;
       
  2046             for (int i=0; i < m_pendingMessageQueries.count(); i++) {
       
  2047                 if (m_pendingMessageQueries[i].queryId == msgQueryInfo.queryId) {
       
  2048                     index = i;
       
  2049                     break;
       
  2050                 }
       
  2051             }
       
  2052             if (index >= 0) {
       
  2053                 handleQueryFinished(index);
       
  2054             }
       
  2055             return true;
       
  2056         } else {
       
  2057             // There is only one filter: empty QMessageFilter()
       
  2058             // => return all messages
       
  2059             handledFiltersCount++;
       
  2060         }
       
  2061     }
       
  2062 
       
  2063     bool handled = true;
       
  2064     while (handledFiltersCount < filters.count() && handled) {
       
  2065         handled = false;
       
  2066         pf = QMessageFilterPrivate::implementation(filters[handledFiltersCount]);
       
  2067         switch (pf->_field) {
       
  2068         case QMessageFilterPrivate::Id:
       
  2069             break;
       
  2070         case QMessageFilterPrivate::ParentAccountId:
       
  2071             {
       
  2072             if (pf->_comparatorType == QMessageFilterPrivate::Equality) {
       
  2073                 if (accountIds.count()) {
       
  2074                     // Only one account/one query can be used
       
  2075                     break;
       
  2076                 }
       
  2077                 QMessageDataComparator::EqualityComparator cmp(static_cast<QMessageDataComparator::EqualityComparator>(pf->_comparatorValue));
       
  2078                 if (cmp == QMessageDataComparator::Equal) {
       
  2079                     if (pf->_value.toString().length() > 0) {
       
  2080                         accountIds.append(modestAccountIdFromAccountId(pf->_value.toString()));
       
  2081                         // Local folders are not account specific
       
  2082                         // => Make sure that account specific messages are searched from local_folders account
       
  2083                         accountIds.append("local_folders");
       
  2084                         handled = true;
       
  2085                     }
       
  2086                 }
       
  2087             }
       
  2088             break;
       
  2089         }
       
  2090         case QMessageFilterPrivate::ParentFolderId:
       
  2091             {
       
  2092             if (pf->_comparatorType == QMessageFilterPrivate::Equality) {
       
  2093                 QMessageDataComparator::EqualityComparator cmp(static_cast<QMessageDataComparator::EqualityComparator>(pf->_comparatorValue));
       
  2094                 if (cmp == QMessageDataComparator::Equal) {
       
  2095                     if (pf->_value.toString().length() > 0) {
       
  2096                         folderUris.append(modestFolderIdFromFolderId(pf->_value.toString()));
       
  2097                         if (accountIds.count() == 0) {
       
  2098                             accountIds.append(modestAccountIdFromFolderId(pf->_value.toString()));
       
  2099 
       
  2100                             // Note: Even though local folders belong to "local_folders" account
       
  2101                             //       inside Modest, local folders can belong to any "real"
       
  2102                             //       POP3 or IMAP account in Qt Mobility Messaging side
       
  2103                             //       <=> Qt Mobility Messaging does not have "Local Folders"
       
  2104                             //           account
       
  2105                             // If folder is local folder, "local_folders" accountId will be
       
  2106                             // added to accountIds list to enable correct filtering inside
       
  2107                             // Modest Plugin
       
  2108                             accountIds.append("local_folders");
       
  2109 
       
  2110                             // realAccountId will contain id of Qt Mobility Messaging account
       
  2111                             // (AccountId can be found from the beginning of folderId string)
       
  2112                             // <=> realAccountId will not ever be "local_folders"
       
  2113                             msgQueryInfo.realAccountId = accountIdFromFolderId(pf->_value.toString()).toString();
       
  2114                         }
       
  2115                         handled = true;
       
  2116                     }
       
  2117                 }
       
  2118             }
       
  2119             break;
       
  2120             }
       
  2121         case QMessageFilterPrivate::AncestorFolderIds:
       
  2122             break;
       
  2123         case QMessageFilterPrivate::Type:
       
  2124             break;
       
  2125         case QMessageFilterPrivate::StandardFolder:
       
  2126             if (pf->_comparatorType == QMessageFilterPrivate::Equality) {
       
  2127                 QMessageDataComparator::EqualityComparator cmp(static_cast<QMessageDataComparator::EqualityComparator>(pf->_comparatorValue));
       
  2128                 if (cmp == QMessageDataComparator::Equal) {
       
  2129                     QMessage::StandardFolder standardFolder = static_cast<QMessage::StandardFolder>(pf->_value.toInt());
       
  2130                     if (standardFolder == QMessage::SentFolder) {
       
  2131                         // Possible "real" accountIds can be ignored in this phase
       
  2132                         // because messages are searched from "local_folders" account
       
  2133                         // <=> Actual account filtering is done when search from Modest
       
  2134                         //     has finished
       
  2135                         accountIds.clear();
       
  2136 
       
  2137                         accountIds.append("local_folders");
       
  2138                         folderUris.append("sent");
       
  2139                     } else if (standardFolder == QMessage::DraftsFolder) {
       
  2140                         // Possible "real" accountIds can be ignored in this phase
       
  2141                         // because messages are searched from "local_folders" account
       
  2142                         // <=> Actual account filtering is done when search from Modest
       
  2143                         //     has finished
       
  2144                         accountIds.clear();
       
  2145 
       
  2146                         accountIds.append("local_folders");
       
  2147                         folderUris.append("drafts");
       
  2148                     }
       
  2149                     handled = true;
       
  2150                 }
       
  2151             }
       
  2152             break;
       
  2153         case QMessageFilterPrivate::ParentAccountIdFilter:
       
  2154             break;
       
  2155         case QMessageFilterPrivate::ParentFolderIdFilter:
       
  2156             break;
       
  2157         case QMessageFilterPrivate::TimeStamp:
       
  2158             {
       
  2159             if (pf->_comparatorType == QMessageFilterPrivate::Equality) {
       
  2160                 QMessageDataComparator::EqualityComparator cmp(static_cast<QMessageDataComparator::EqualityComparator>(pf->_comparatorValue));
       
  2161                 if (cmp == QMessageDataComparator::Equal) {
       
  2162                     endTimeStamp = pf->_value.toDateTime();
       
  2163                     startTimeStamp = pf->_value.toDateTime();
       
  2164                     handled = true;
       
  2165                 }
       
  2166             }
       
  2167             if (pf->_comparatorType == QMessageFilterPrivate::Relation) {
       
  2168                 QMessageDataComparator::RelationComparator cmp(static_cast<QMessageDataComparator::RelationComparator>(pf->_comparatorValue));
       
  2169                 if (cmp == QMessageDataComparator::LessThan) {
       
  2170                     endTimeStamp = pf->_value.toDateTime();
       
  2171                     handled = true;
       
  2172                 } else if (cmp == QMessageDataComparator::LessThanEqual) {
       
  2173                     endTimeStamp = pf->_value.toDateTime();
       
  2174                     handled = true;
       
  2175                 } else if (cmp == QMessageDataComparator::GreaterThan) {
       
  2176                     startTimeStamp = pf->_value.toDateTime();
       
  2177                     handled = true;
       
  2178                 } if (cmp == QMessageDataComparator::GreaterThanEqual) {
       
  2179                     startTimeStamp = pf->_value.toDateTime();
       
  2180                     handled = true;
       
  2181                 }
       
  2182             }
       
  2183             break;
       
  2184             }
       
  2185         case QMessageFilterPrivate::ReceptionTimeStamp:
       
  2186             {
       
  2187             if (pf->_comparatorType == QMessageFilterPrivate::Equality) {
       
  2188                 QMessageDataComparator::EqualityComparator cmp(static_cast<QMessageDataComparator::EqualityComparator>(pf->_comparatorValue));
       
  2189                 if (cmp == QMessageDataComparator::Equal) {
       
  2190                     endReceptionTimeStamp = pf->_value.toDateTime();
       
  2191                     startReceptionTimeStamp = pf->_value.toDateTime();
       
  2192                     handled = true;
       
  2193                 }
       
  2194             }
       
  2195             if (pf->_comparatorType == QMessageFilterPrivate::Relation) {
       
  2196                 QMessageDataComparator::RelationComparator cmp(static_cast<QMessageDataComparator::RelationComparator>(pf->_comparatorValue));
       
  2197                 if (cmp == QMessageDataComparator::LessThan) {
       
  2198                     endReceptionTimeStamp = pf->_value.toDateTime();
       
  2199                     handled = true;
       
  2200                 } else if (cmp == QMessageDataComparator::LessThanEqual) {
       
  2201                     endReceptionTimeStamp = pf->_value.toDateTime();
       
  2202                     handled = true;
       
  2203                 } else if (cmp == QMessageDataComparator::GreaterThan) {
       
  2204                     startReceptionTimeStamp = pf->_value.toDateTime();
       
  2205                     handled = true;
       
  2206                 } if (cmp == QMessageDataComparator::GreaterThanEqual) {
       
  2207                     startReceptionTimeStamp = pf->_value.toDateTime();
       
  2208                     handled = true;
       
  2209                 }
       
  2210             }
       
  2211             break;
       
  2212             }
       
  2213         case QMessageFilterPrivate::Sender:
       
  2214             break;
       
  2215         case QMessageFilterPrivate::Recipients:
       
  2216             break;
       
  2217         case QMessageFilterPrivate::Subject:
       
  2218             break;
       
  2219         case QMessageFilterPrivate::Status:
       
  2220             break;
       
  2221         case QMessageFilterPrivate::Priority:
       
  2222             break;
       
  2223         case QMessageFilterPrivate::Size:
       
  2224             break;
       
  2225         case QMessageFilterPrivate::None:
       
  2226             break;
       
  2227         }
       
  2228         handledFiltersCount++;
       
  2229     }
       
  2230 
       
  2231     msgQueryInfo.handledFiltersCount = 0; // Do filtering also for filters which has been handled above
       
  2232 
       
  2233     return searchMessages(msgQueryInfo, accountIds, folderUris, msgQueryInfo.body, startTimeStamp,
       
  2234                           endTimeStamp, startReceptionTimeStamp, endReceptionTimeStamp);
       
  2235 }
       
  2236 
       
  2237 bool ModestEngine::searchMessages(MessageQueryInfo &msgQueryInfo, const QStringList& accountIds,
       
  2238                                   const QStringList& folderUris, const QString& body,
       
  2239                                   const QDateTime& startTimeStamp, const QDateTime& endTimeStamp,
       
  2240                                   const QDateTime& startReceptionTimeStamp, const QDateTime& endReceptionTimeStamp) const
       
  2241 {
       
  2242     Q_UNUSED(body) //TODO: Body search
       
  2243 
       
  2244     qulonglong sDate = 0;
       
  2245     if (startTimeStamp.isValid() && startReceptionTimeStamp.isValid()) {
       
  2246         if (startTimeStamp < startReceptionTimeStamp) {
       
  2247             sDate = startTimeStamp.toTime_t();
       
  2248         } else {
       
  2249             sDate = startReceptionTimeStamp.toTime_t();
       
  2250         }
       
  2251     } else {
       
  2252         if (startTimeStamp.isValid()) {
       
  2253             sDate = startTimeStamp.toTime_t();
       
  2254         } else if (startReceptionTimeStamp.isValid()) {
       
  2255             sDate = startReceptionTimeStamp.toTime_t();
       
  2256         }
       
  2257     }
       
  2258 
       
  2259 
       
  2260     qulonglong eDate = 0;
       
  2261     if (endTimeStamp.isValid() && endReceptionTimeStamp.isValid()) {
       
  2262         if (endTimeStamp > endReceptionTimeStamp) {
       
  2263             eDate = endTimeStamp.toTime_t();
       
  2264         } else {
       
  2265             eDate = endReceptionTimeStamp.toTime_t();
       
  2266         }
       
  2267     } else {
       
  2268         if (endTimeStamp.isValid()) {
       
  2269             eDate = endTimeStamp.toTime_t();
       
  2270         } else if (endReceptionTimeStamp.isValid()) {
       
  2271             eDate = endReceptionTimeStamp.toTime_t();
       
  2272         }
       
  2273     }
       
  2274 
       
  2275     if (m_pendingMessageQueries.count() == 1) {
       
  2276         // This is the first query in pending queries queue
       
  2277         // => connect to signals
       
  2278         m_QtmPluginDBusInterface->connection().connect(MODESTENGINE_QTM_PLUGIN_NAME,
       
  2279                                                        MODESTENGINE_QTM_PLUGIN_PATH,
       
  2280                                                        MODESTENGINE_QTM_PLUGIN_NAME,
       
  2281                                                        "HeadersReceived",
       
  2282                                                        (ModestEngine*)this,
       
  2283                                                        SLOT(searchMessagesHeadersReceivedSlot(QDBusMessage)));
       
  2284 
       
  2285         m_QtmPluginDBusInterface->connection().connect(MODESTENGINE_QTM_PLUGIN_NAME,
       
  2286                                                        MODESTENGINE_QTM_PLUGIN_PATH,
       
  2287                                                        MODESTENGINE_QTM_PLUGIN_NAME,
       
  2288                                                        "HeadersFetched",
       
  2289                                                        (ModestEngine*)this,
       
  2290                                                        SLOT(searchMessagesHeadersFetchedSlot(QDBusMessage)));
       
  2291     }
       
  2292 
       
  2293     QDBusMessage reply = m_QtmPluginDBusInterface->call("GetHeaders",
       
  2294                                                         accountIds,
       
  2295                                                         folderUris,
       
  2296                                                         sDate,
       
  2297                                                         eDate,
       
  2298                                                         false);
       
  2299     if (reply.type() != QDBusMessage::ErrorMessage) {
       
  2300         m_messageCache.clear();
       
  2301         msgQueryInfo.queryId = reply.arguments().takeFirst().toInt();
       
  2302     } else {
       
  2303         return false;
       
  2304     }
       
  2305 
       
  2306     return true;
       
  2307 }
       
  2308 
       
  2309 void ModestEngine::searchMessagesHeadersReceivedSlot(QDBusMessage msg)
       
  2310 {
       
  2311     QList<QVariant> arguments = msg.arguments();
       
  2312     int queryId = arguments.takeFirst().toInt();
       
  2313 
       
  2314     int index = -1;
       
  2315     for (int i=0; i < m_pendingMessageQueries.count(); i++) {
       
  2316         if (m_pendingMessageQueries[i].queryId == queryId) {
       
  2317             index = i;
       
  2318             break;
       
  2319         }
       
  2320     }
       
  2321     if (index == -1) {
       
  2322         // Received DBus Message is not reply for the DBus query
       
  2323         // that was sent from this process/instance of modest engine
       
  2324         // => Continue waiting
       
  2325         return;
       
  2326     }
       
  2327 
       
  2328     MessageQueryInfo &queryInfo = m_pendingMessageQueries[index];
       
  2329 
       
  2330     QString reportedAccountId = arguments.takeFirst().toString();
       
  2331     QString accountId;
       
  2332     if (!queryInfo.realAccountId.isEmpty()) {
       
  2333         // Search was done to Modest "local_folders" account
       
  2334         // => Correct Qt Mobility Messaging AccountId
       
  2335         //    can be taken realAccountId field
       
  2336         // => Transform Messaging AccountId to Modest accountId
       
  2337         //    by removing "MO_" from the beginning of accountId string
       
  2338         accountId = queryInfo.realAccountId;
       
  2339         accountId.remove(0,3);
       
  2340     } else {
       
  2341         accountId = reportedAccountId.remove("_store");
       
  2342     }
       
  2343 
       
  2344     QString folderId = arguments.takeFirst().toString();
       
  2345     QVariant variant = arguments.takeFirst();
       
  2346     QDBusArgument argument = variant.value<QDBusArgument>();
       
  2347     QList<QMap<QString, QVariant> > messages;
       
  2348     argument >> messages;
       
  2349 
       
  2350     QMessageFilterPrivate::SortedMessageFilterList filters;
       
  2351     int firstUnhandledFilterIndex = 0;
       
  2352 
       
  2353     QMessageFilterPrivate* pf = QMessageFilterPrivate::implementation(queryInfo.filter);
       
  2354     if (pf->_filterList.count() == 0) {
       
  2355         filters.append(queryInfo.filter);
       
  2356     } else {
       
  2357         if (queryInfo.handledFiltersCount < pf->_filterList[queryInfo.currentFilterListIndex].count()) {
       
  2358             filters = pf->_filterList[queryInfo.currentFilterListIndex];
       
  2359         }
       
  2360     }
       
  2361     firstUnhandledFilterIndex = queryInfo.handledFiltersCount;
       
  2362 
       
  2363     for (int i=0; i < messages.count(); i++) {
       
  2364         MessagingModestMessage modestMessage;
       
  2365         modestMessage.accountId = accountId;
       
  2366         modestMessage.folderId = folderId;
       
  2367         modestMessage.dateReceived = 0;
       
  2368         modestMessage.dateSent = 0;
       
  2369         modestMessage.size = 0;
       
  2370         modestMessage.flags = MessagingModestMessageNotDefined;
       
  2371         modestMessage.priority = MessagingModestMessagePriorityNotDefined;
       
  2372 
       
  2373         QMapIterator<QString, QVariant> j(messages[i]);
       
  2374         while (j.hasNext()) {
       
  2375             j.next();
       
  2376             if (j.key() == "url") {
       
  2377                 modestMessage.url = j.value().toString();
       
  2378             } else if (j.key() == "message-uid") {
       
  2379                 modestMessage.id = j.value().toString();
       
  2380             } else if (j.key() == "from") {
       
  2381                 modestMessage.from = j.value().toString();
       
  2382             } else if (j.key() == "to") {
       
  2383                 modestMessage.to = j.value().toString();
       
  2384             } else if (j.key() == "cc") {
       
  2385                 modestMessage.cc = j.value().toString();
       
  2386             } else if (j.key() == "bcc") {
       
  2387                 modestMessage.bcc = j.value().toString();
       
  2388             } else if (j.key() == "replyto") {
       
  2389                 modestMessage.replyTo = j.value().toString();
       
  2390             } else if (j.key() == "subject") {
       
  2391                 modestMessage.subject = j.value().toString();
       
  2392             } else if (j.key() == "date-received") {
       
  2393                 modestMessage.dateReceived = j.value().toLongLong();
       
  2394             } else if (j.key() == "date-sent") {
       
  2395                 modestMessage.dateSent = j.value().toLongLong();
       
  2396             } else if (j.key() == "size") {
       
  2397                 modestMessage.size = j.value().toLongLong();
       
  2398             } else if (j.key() == "flags") {
       
  2399                 qlonglong flags = j.value().toUInt();
       
  2400                 qlonglong priority = flags & MessagingModestMessageHasPriority;
       
  2401                 modestMessage.priority = static_cast<MessagingModestMessagePriority>(priority);
       
  2402                 modestMessage.flags = static_cast<MessagingModestMessageFlags>(flags);
       
  2403             }
       
  2404         }
       
  2405 
       
  2406         QMessage message = messageFromModestMessage(modestMessage);
       
  2407         if (reportedAccountId == "local_folders") {
       
  2408             QMessagePrivate* privateMessage = QMessagePrivate::implementation(message);
       
  2409             QString id = privateMessage->_id.toString();
       
  2410             QString newProtocol = "maildir";
       
  2411             replaceProtocol(id, newProtocol);
       
  2412             privateMessage->_id = QMessageId(id);
       
  2413             id = privateMessage->_parentFolderId.toString();
       
  2414             replaceProtocol(id, newProtocol);
       
  2415             privateMessage->_parentFolderId = QMessageFolderId(id);
       
  2416         }
       
  2417         if (filterMessage(message, filters, 0)) {
       
  2418             if (!queryInfo.ids.contains(message.id())) {
       
  2419                 if (m_messageCache.size() < maxCacheSize) {
       
  2420                     m_messageCache.insert(message.id().toString(), message);
       
  2421                 }
       
  2422                 queryInfo.ids.append(message.id());
       
  2423             }
       
  2424         }
       
  2425     }
       
  2426 }
       
  2427 
       
  2428 void ModestEngine::searchMessagesHeadersFetchedSlot(QDBusMessage msg)
       
  2429 {
       
  2430     QList<QVariant> arguments = msg.arguments();
       
  2431     int queryId = arguments.takeFirst().toInt();
       
  2432 
       
  2433     int index = -1;
       
  2434     for (int i=0; i < m_pendingMessageQueries.count(); i++) {
       
  2435         if (m_pendingMessageQueries[i].queryId == queryId) {
       
  2436             index = i;
       
  2437             break;
       
  2438         }
       
  2439     }
       
  2440     if (index == -1) {
       
  2441         // Received DBus Message is not reply for the DBus query
       
  2442         // that was sent from this process/instance of modest engine
       
  2443         // => Continue waiting
       
  2444         return;
       
  2445     }
       
  2446 
       
  2447     handleQueryFinished(index);
       
  2448 }
       
  2449 
       
  2450 void ModestEngine::handleQueryFinished(int index) const
       
  2451 {
       
  2452     MessageQueryInfo &queryInfo = m_pendingMessageQueries[index];
       
  2453 
       
  2454     queryInfo.currentFilterListIndex++;
       
  2455     QMessageFilterPrivate* pf = QMessageFilterPrivate::implementation(queryInfo.filter);
       
  2456     if (queryInfo.currentFilterListIndex < pf->_filterList.count()) {
       
  2457         if (queryAndFilterMessages(queryInfo)) {
       
  2458             // Continue searching
       
  2459             return;
       
  2460         }
       
  2461     }
       
  2462 
       
  2463     MessagingHelper::orderMessages(queryInfo.ids, queryInfo.sortOrder);
       
  2464     MessagingHelper::applyOffsetAndLimitToMessageIdList(queryInfo.ids, queryInfo.limit, queryInfo.offset);
       
  2465 
       
  2466     // Search finished
       
  2467     if (queryInfo.isQuery) {
       
  2468         queryInfo.privateService->messagesFound(queryInfo.ids, true, true);
       
  2469     } else {
       
  2470         queryInfo.privateService->messagesCounted(queryInfo.ids.count());
       
  2471     }
       
  2472     m_pendingMessageQueries.removeAt(index);
       
  2473 
       
  2474     if (m_pendingMessageQueries.count() == 0) {
       
  2475         // This was last query in pending queries queue
       
  2476         // => Disconnect from "GetHeaders" request related DBus signals
       
  2477         // Note: Disconnecting signals is done to optimize signal handling
       
  2478         //       <=> Disconnecting prevents unnecessary handling of signals
       
  2479         //           which have been sent from other applications using
       
  2480         //           Qt Mobility Messaging API
       
  2481         m_QtmPluginDBusInterface->connection().disconnect(MODESTENGINE_QTM_PLUGIN_NAME,
       
  2482                                                           MODESTENGINE_QTM_PLUGIN_PATH,
       
  2483                                                           MODESTENGINE_QTM_PLUGIN_NAME,
       
  2484                                                           "HeadersReceived",
       
  2485                                                           (ModestEngine*)this,
       
  2486                                                           SLOT(searchMessagesHeadersReceivedSlot(QDBusMessage)));
       
  2487 
       
  2488         m_QtmPluginDBusInterface->connection().disconnect(MODESTENGINE_QTM_PLUGIN_NAME,
       
  2489                                                           MODESTENGINE_QTM_PLUGIN_PATH,
       
  2490                                                           MODESTENGINE_QTM_PLUGIN_NAME,
       
  2491                                                           "HeadersFetched",
       
  2492                                                           (ModestEngine*)this,
       
  2493                                                           SLOT(searchMessagesHeadersFetchedSlot(QDBusMessage)));
       
  2494     }
       
  2495 }
       
  2496 
       
  2497 void
       
  2498 ModestEngine::sendEmailCallEnded(QDBusPendingCallWatcher *watcher)
       
  2499 {
       
  2500     if (watcher->isError ()) {
       
  2501         // TODO: Emit a failure
       
  2502         qWarning() << "Failed to send email via modest: " << watcher->error();
       
  2503     } else {
       
  2504         // TODO: Emit a success (or put to outbox)
       
  2505         qDebug() << "Message should be outboxed now...";
       
  2506     }
       
  2507 }
       
  2508 
       
  2509 void
       
  2510 ModestEngine::addMessageCallEnded(QDBusPendingCallWatcher *watcher)
       
  2511 {
       
  2512     QDBusPendingReply<QString> reply = *watcher;
       
  2513     if (reply.isError ()) {
       
  2514         // TODO: Emit a failure
       
  2515         qWarning() << "Failed to add message via modest: " << reply.error();
       
  2516     } else {
       
  2517         QString id = reply.argumentAt<0>();
       
  2518         // TODO: Emit a success ... with message's id?
       
  2519         qDebug() << "Message with id" << id << "should be added now";
       
  2520     }
       
  2521 }
       
  2522 
       
  2523 void ModestEngine::folderUpdatedSlot(QDBusMessage msg)
       
  2524 {
       
  2525     QList<QVariant> arguments = msg.arguments();
       
  2526     QString modestAccountId = arguments.takeFirst().toString();
       
  2527     QString modestFolderId = arguments.takeFirst().toString();
       
  2528     QMessageFolderId updatedFolderId;
       
  2529 
       
  2530     if (modestAccountId == "local_folders") {
       
  2531         updatedFolderId = QMessageFolderId("MO_LOCAL&maildir&"+modestFolderId);
       
  2532     } else {
       
  2533         QMessageAccountId accountId = QMessageAccountId("MO_"+escapeString(modestAccountId));
       
  2534         QString protocol = accountEmailProtocolAsString(accountId);
       
  2535         if ((protocol == "pop") && (modestFolderId == "INBOX")) {
       
  2536             modestFolderId = "cache";
       
  2537         }
       
  2538         updatedFolderId = QMessageFolderId(accountId.toString()+"&"+protocol+"&"+modestFolderId);
       
  2539     }
       
  2540 
       
  2541     int messagesPerAccount = 5;
       
  2542     QDBusPendingCall pendingCall = m_ModestDBusInterface->asyncCall(MODEST_DBUS_METHOD_GET_UNREAD_MESSAGES,
       
  2543                                                                     messagesPerAccount);
       
  2544     QDBusPendingCallWatcher* pendingCallWatcher = new QDBusPendingCallWatcher(pendingCall);
       
  2545     pendingCallWatcher->setProperty("folderId", updatedFolderId.toString());
       
  2546     connect(pendingCallWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
       
  2547             this, SLOT(pendingGetUnreadMessagesFinishedSlot(QDBusPendingCallWatcher*)));
       
  2548 }
       
  2549 
       
  2550 void ModestEngine::pendingGetUnreadMessagesFinishedSlot(QDBusPendingCallWatcher* pendingCallWatcher)
       
  2551 {
       
  2552     if (pendingCallWatcher->isError()) {
       
  2553         return;
       
  2554     }
       
  2555 
       
  2556     QDBusMessage msg = pendingCallWatcher->reply();
       
  2557     if (msg.arguments().count() == 0) {
       
  2558         return;
       
  2559     }
       
  2560 
       
  2561     QVariant variant = msg.arguments().takeFirst();
       
  2562     QDBusArgument argument = variant.value<QDBusArgument>();
       
  2563     QList<ModestAccountsUnreadMessagesDBusStruct> accountsWithUnreadMessages;
       
  2564     argument >> accountsWithUnreadMessages;
       
  2565 
       
  2566     bool setOnlyDates = false;
       
  2567     if (pendingCallWatcher->property("setOnlyDates").isValid()) {
       
  2568         setOnlyDates = true;
       
  2569     }
       
  2570     QMessageFolderId folderId;
       
  2571     if (pendingCallWatcher->property("folderId").isValid()) {
       
  2572         folderId = QMessageFolderId(pendingCallWatcher->property("folderId").toString());
       
  2573     }
       
  2574 
       
  2575     for (int i=0; i < accountsWithUnreadMessages.count(); i++) {
       
  2576         QDateTime newLatestTimeStamp;
       
  2577         QDateTime latestTimeStamp = accountsLatestTimestamp.take(accountsWithUnreadMessages[i].accountId);
       
  2578         for (int j=0; j < accountsWithUnreadMessages[i].unreadMessages.count(); j++) {
       
  2579             ModestUnreadMessageDBusStruct unreadMessage = accountsWithUnreadMessages[i].unreadMessages[j];
       
  2580             QDateTime time = QDateTime::fromTime_t(unreadMessage.timeStamp);
       
  2581             if (time > newLatestTimeStamp) {
       
  2582                 newLatestTimeStamp = time;
       
  2583             }
       
  2584             if (!setOnlyDates) {
       
  2585                 if (time > latestTimeStamp) {
       
  2586                     searchNewMessages(unreadMessage.subject, QString(), time, time, MODEST_DBUS_SEARCH_SUBJECT, 0);
       
  2587                 }
       
  2588             }
       
  2589         }
       
  2590         if (newLatestTimeStamp.isValid()) {
       
  2591             accountsLatestTimestamp.remove(accountsWithUnreadMessages[i].accountId);
       
  2592             accountsLatestTimestamp.insert(accountsWithUnreadMessages[i].accountId, newLatestTimeStamp);
       
  2593         } else {
       
  2594             accountsLatestTimestamp.insert(accountsWithUnreadMessages[i].accountId, QDateTime::currentDateTime());
       
  2595         }
       
  2596     }
       
  2597 }
       
  2598 
       
  2599 void ModestEngine::searchNewMessages(const QString& searchString, const QString& folderToSearch,
       
  2600                                   const QDateTime& startDate, const QDateTime& endDate,
       
  2601                                   int searchflags, uint minimumMessageSize) const
       
  2602 {
       
  2603     qlonglong sDate = 0;
       
  2604     if (startDate.isValid()) {
       
  2605         sDate = startDate.toTime_t();
       
  2606     }
       
  2607     qlonglong eDate = 0;
       
  2608     if (endDate.isValid()) {
       
  2609         eDate = endDate.toTime_t();
       
  2610     }
       
  2611 
       
  2612     QDBusInterface interface(MODEST_DBUS_SERVICE, MODEST_DBUS_OBJECT, MODEST_DBUS_IFACE);
       
  2613     QDBusPendingCall pendingCall = interface.asyncCall(MODEST_DBUS_METHOD_SEARCH,
       
  2614                                                        searchString,
       
  2615                                                        folderToSearch,
       
  2616                                                        sDate,
       
  2617                                                        eDate,
       
  2618                                                        searchflags,
       
  2619                                                        minimumMessageSize);
       
  2620     QDBusPendingCallWatcher* pendingCallWatcher = new QDBusPendingCallWatcher(pendingCall);
       
  2621     connect(pendingCallWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
       
  2622             this, SLOT(pendingSearchFinishedSlot(QDBusPendingCallWatcher*)));
       
  2623 }
       
  2624 
       
  2625 void ModestEngine::pendingSearchFinishedSlot(QDBusPendingCallWatcher* pendingCallWatcher)
       
  2626 {
       
  2627     if (pendingCallWatcher->isError()) {
       
  2628         return;
       
  2629     }
       
  2630 
       
  2631     QDBusMessage msg = pendingCallWatcher->reply();
       
  2632     if (msg.arguments().count() == 0) {
       
  2633         return;
       
  2634     }
       
  2635 
       
  2636     QVariant variant = msg.arguments().takeFirst();
       
  2637     QDBusArgument argument = variant.value<QDBusArgument>();
       
  2638     QList<ModestMessage> messages;
       
  2639     argument >> messages;
       
  2640 
       
  2641     for (int i=0; i < messages.count(); i++) {
       
  2642         notification(messageIdFromModestMessageId(messages[i].id), ModestEngine::Added);
       
  2643     }
       
  2644 }
       
  2645 
       
  2646 void ModestEngine::messageReadChangedSlot(QDBusMessage msg)
       
  2647 {
       
  2648     QString changedMessageId = msg.arguments().takeFirst().toString();
       
  2649     notification(messageIdFromModestMessageId(changedMessageId), ModestEngine::Updated);
       
  2650 }
       
  2651 
       
  2652 QMessageManager::NotificationFilterId ModestEngine::registerNotificationFilter(QMessageStorePrivate& messageStore,
       
  2653                                                                                const QMessageFilter &filter,
       
  2654                                                                                QMessageManager::NotificationFilterId id)
       
  2655 {
       
  2656     m_messageStore = &messageStore;
       
  2657 
       
  2658     int filterId = id;
       
  2659     if (filterId == 0) {
       
  2660         filterId = ++m_filterId;
       
  2661     }
       
  2662     m_filters.insert(filterId, filter);
       
  2663     return filterId;
       
  2664 }
       
  2665 
       
  2666 void ModestEngine::unregisterNotificationFilter(QMessageManager::NotificationFilterId notificationFilterId)
       
  2667 {
       
  2668     m_filters.remove(notificationFilterId);
       
  2669 }
       
  2670 
       
  2671 QByteArray ModestEngine::getMimePart (const QMessageId &id, const QString &attachmentId)
       
  2672 {
       
  2673     QByteArray result;
       
  2674 
       
  2675     QString modestAccountId = modestAccountIdFromMessageId(id);
       
  2676     QString modestFolderId  = modestFolderIdFromMessageId(id);
       
  2677     QString modestMessageId = modestMessageIdFromMessageId(id);
       
  2678 
       
  2679     QString filePath, mimeType;
       
  2680     int mimeSize = -1;
       
  2681     bool expunge = false, isAttachment = false;
       
  2682 
       
  2683     QDBusPendingReply<QString, QString, int, bool, bool> reply =
       
  2684             m_QtmPluginDBusInterface->asyncCall(
       
  2685                     "GetMimePart",
       
  2686                     QVariant::fromValue(modestAccountId),
       
  2687                     QVariant::fromValue(modestFolderId),
       
  2688                     QVariant::fromValue(modestMessageId),
       
  2689                     QVariant::fromValue(attachmentId));
       
  2690 
       
  2691     reply.waitForFinished();
       
  2692 
       
  2693     if (reply.isError()) {
       
  2694         return result;
       
  2695     }
       
  2696 
       
  2697     filePath = reply.argumentAt<0>();
       
  2698     mimeType = reply.argumentAt<1>();
       
  2699     mimeSize = reply.argumentAt<2>();
       
  2700     isAttachment = reply.argumentAt<3>();
       
  2701     expunge = reply.argumentAt<4>();
       
  2702 
       
  2703     if (filePath.isEmpty()) {
       
  2704         qWarning() << "Received empty file path!";
       
  2705         return result;
       
  2706     }
       
  2707 
       
  2708     QFile file(filePath);
       
  2709 
       
  2710     QIODevice::OpenMode openMode = QIODevice::ReadOnly;
       
  2711     if (expunge) {
       
  2712         openMode = QIODevice::ReadWrite;
       
  2713     }
       
  2714     
       
  2715     if (file.open(openMode) == false) {
       
  2716         qWarning() << "Failed to open file" << filePath << ": "
       
  2717                 << file.errorString();
       
  2718         return result;
       
  2719     }
       
  2720 
       
  2721     result = file.readAll();
       
  2722 
       
  2723     if (expunge) {
       
  2724         file.remove();
       
  2725     } else {
       
  2726         file.close();
       
  2727     }
       
  2728 
       
  2729     return result;
       
  2730 }
       
  2731 
       
  2732 bool ModestEngine::retrieveBody(QMessageService& messageService, const QMessageId &id)
       
  2733 {
       
  2734     if (!id.isValid()) return false;
       
  2735 
       
  2736     QMessage msg = message(id, true);
       
  2737     QMessageContentContainerId attachmentId = msg.bodyId();
       
  2738 
       
  2739     //if (!attachmentId.isValid()) return false;
       
  2740 
       
  2741     return retrieve(messageService, id, attachmentId, &msg);
       
  2742 }
       
  2743 
       
  2744 bool ModestEngine::retrieve(QMessageService& messageService, const QMessageId &id,
       
  2745                             const QMessageContentContainerId &attachmentId, QMessage *msg)
       
  2746 {
       
  2747     QByteArray result;
       
  2748 
       
  2749     if (!id.isValid()) return false;
       
  2750     //if (!attachmentId.isValid()) return false;
       
  2751 
       
  2752     QString modestAccountId = modestAccountIdFromMessageId(id);
       
  2753     QString modestFolderId  = modestFolderIdFromMessageId(id);
       
  2754     QString modestMessageId = modestMessageIdFromMessageId(id);
       
  2755     QString modestAttachmentId;
       
  2756     int opId = -1;
       
  2757 
       
  2758     QMessage message;
       
  2759 
       
  2760     if (msg != 0) {
       
  2761         message = *msg;
       
  2762     } else {
       
  2763         message = this->message(id, true);
       
  2764     }
       
  2765 
       
  2766     QMessageContentContainer cont = message.find(attachmentId);
       
  2767     QMessageContentContainerPrivate *contPrivate = QMessageContentContainerPrivate::implementation(cont);
       
  2768 
       
  2769     if (contPrivate != 0) {
       
  2770         modestAttachmentId = contPrivate->_attachmentId;
       
  2771     }
       
  2772 
       
  2773     if (m_pending_downloads.count() == 0) {
       
  2774         m_QtmPluginDBusInterface->connection().connect(MODESTENGINE_QTM_PLUGIN_NAME,
       
  2775                                                        MODESTENGINE_QTM_PLUGIN_PATH,
       
  2776                                                        MODESTENGINE_QTM_PLUGIN_NAME,
       
  2777                                                        "PartDownloadFinished",
       
  2778                                                        (ModestEngine*)this,
       
  2779                                                        SLOT(mimePartDownloadFinishedSlot(QDBusMessage)));
       
  2780     }
       
  2781 
       
  2782     QDBusPendingReply<int> reply = m_QtmPluginDBusInterface->asyncCall("DownloadMimePart",
       
  2783                                                                         QVariant::fromValue(modestAccountId),
       
  2784                                                                         QVariant::fromValue(modestFolderId),
       
  2785                                                                         QVariant::fromValue(modestMessageId),
       
  2786                                                                         QVariant::fromValue(modestAttachmentId));
       
  2787 
       
  2788     reply.waitForFinished();
       
  2789 
       
  2790     if (reply.isError()) {
       
  2791         if (m_pending_downloads.count() == 0) {
       
  2792             m_QtmPluginDBusInterface->connection().disconnect(MODESTENGINE_QTM_PLUGIN_NAME,
       
  2793                                                               MODESTENGINE_QTM_PLUGIN_PATH,
       
  2794                                                               MODESTENGINE_QTM_PLUGIN_NAME,
       
  2795                                                               "PartDownloadFinished",
       
  2796                                                               (ModestEngine*)this,
       
  2797                                                               SLOT(mimePartDownloadFinishedSlot(QDBusMessage)));
       
  2798         }
       
  2799         return false;
       
  2800     }
       
  2801 
       
  2802     opId = reply.argumentAt<0>();
       
  2803 
       
  2804     QMessageServicePrivate* privateService = QMessageServicePrivate::implementation(messageService);
       
  2805     m_pending_downloads.insert(opId, privateService);
       
  2806 
       
  2807     return true;
       
  2808 }
       
  2809 
       
  2810 void ModestEngine::mimePartDownloadFinishedSlot(QDBusMessage msg)
       
  2811 {
       
  2812     QList<QVariant> arguments = msg.arguments();
       
  2813     int operationId = arguments.takeFirst().toInt();
       
  2814 
       
  2815     if (m_pending_downloads.contains(operationId)) {
       
  2816         QMessageServicePrivate* privateService = m_pending_downloads.take(operationId);
       
  2817 
       
  2818         privateService->_pendingRequestCount--;
       
  2819 
       
  2820         bool success = arguments.takeFirst().toBool();
       
  2821         if (success) {
       
  2822             privateService->setFinished(true);
       
  2823         } else {
       
  2824             privateService->setFinished(false);
       
  2825         }
       
  2826 
       
  2827         if (m_pending_downloads.count() == 0) {
       
  2828             m_QtmPluginDBusInterface->connection().disconnect(MODESTENGINE_QTM_PLUGIN_NAME,
       
  2829                                                               MODESTENGINE_QTM_PLUGIN_PATH,
       
  2830                                                               MODESTENGINE_QTM_PLUGIN_NAME,
       
  2831                                                               "PartDownloadFinished",
       
  2832                                                               (ModestEngine*)this,
       
  2833                                                               SLOT(mimePartDownloadFinishedSlot(QDBusMessage)));
       
  2834         }
       
  2835     }
       
  2836 }
       
  2837 
       
  2838 void ModestEngine::notification(const QMessageId& messageId, NotificationType notificationType) const
       
  2839 {
       
  2840     QMessageId realMessageId = messageId;
       
  2841     QString modestAccountId = modestAccountIdFromMessageId(messageId);
       
  2842     QString modestFolderId = modestFolderIdFromMessageId(messageId);
       
  2843     QString modestMessageId = modestMessageIdFromMessageId(messageId);
       
  2844 
       
  2845     // Make sure that there will not be many Added or Removed notifications
       
  2846     // in a row for the same message
       
  2847     // Make also sure that there will not be updated notification for a
       
  2848     // message that has already been notified to be removed.
       
  2849     QString searchId;
       
  2850     if (notificationType == ModestEngine::Added) {
       
  2851         searchId = "A"+modestAccountId+modestFolderId+modestMessageId;
       
  2852     } else {
       
  2853         searchId = "D"+modestAccountId+modestFolderId+modestMessageId;
       
  2854     }
       
  2855     if (!m_latestAddOrRemoveNotifications.contains(searchId)) {
       
  2856         if ((notificationType == ModestEngine::Added) || (notificationType == ModestEngine::Removed)) {
       
  2857             // Only Added & Removed notification will be checked
       
  2858             if (m_latestAddOrRemoveNotifications.count() > 10) {
       
  2859                 // Remove the oldest notification from the beginning of the list
       
  2860                 m_latestAddOrRemoveNotifications.removeFirst();
       
  2861             }
       
  2862             // Append new notification
       
  2863             m_latestAddOrRemoveNotifications.append(searchId);
       
  2864         }
       
  2865     } else {
       
  2866         // Add or Remove notification for the message was already handled!
       
  2867         // => Skip unwanted notification
       
  2868         return;
       
  2869     }
       
  2870 
       
  2871     QMessageManager::NotificationFilterIdSet matchingFilters;
       
  2872 
       
  2873     // Copy the filter map to protect against modification during traversal
       
  2874     QMap<int, QMessageFilter> filters(m_filters);
       
  2875     QMap<int, QMessageFilter>::const_iterator it = filters.begin(), end = filters.end();
       
  2876     QMessage message;
       
  2877     bool messageRetrieved = false;
       
  2878     for ( ; it != end; ++it) {
       
  2879         const QMessageFilter &filter(it.value());
       
  2880 
       
  2881         if (!messageRetrieved) {
       
  2882             MessagingModestMessage modestMessage = messageFromModest(modestAccountId,
       
  2883                                                                      modestFolderId,
       
  2884                                                                      modestMessageId);
       
  2885 
       
  2886             if (modestMessage.accountId.isEmpty()) {
       
  2887                 return;
       
  2888             }
       
  2889 
       
  2890             if (modestMessage.flags & MessagingModestMessageDeleted) {
       
  2891                 notificationType = ModestEngine::Removed;
       
  2892             }
       
  2893             if (modestMessage.size == 0) {
       
  2894                 notificationType = ModestEngine::Removed;
       
  2895             }
       
  2896 
       
  2897             message = messageFromModestMessage(modestMessage);
       
  2898             realMessageId =message.id();
       
  2899             messageRetrieved = true;
       
  2900         }
       
  2901 
       
  2902         if (filter.isEmpty()) {
       
  2903             // Empty filter matches to all messages
       
  2904             matchingFilters.insert(it.key());
       
  2905         } else {
       
  2906             if (message.type() == QMessage::NoType) {
       
  2907                 continue;
       
  2908             }
       
  2909             QMessageFilterPrivate* privateMessageFilter = QMessageFilterPrivate::implementation(filter);
       
  2910             if (privateMessageFilter->filter(message)) {
       
  2911                 matchingFilters.insert(it.key());
       
  2912             }
       
  2913         }
       
  2914     }
       
  2915 
       
  2916     if (matchingFilters.count() > 0) {
       
  2917         if (notificationType == ModestEngine::Added) {
       
  2918             m_messageStore->messageNotification(QMessageStorePrivate::Added, realMessageId, matchingFilters);
       
  2919         } else if (notificationType == ModestEngine::Updated) {
       
  2920             m_messageStore->messageNotification(QMessageStorePrivate::Updated, realMessageId, matchingFilters);
       
  2921         } else if (notificationType == ModestEngine::Removed) {
       
  2922             m_messageStore->messageNotification(QMessageStorePrivate::Removed, realMessageId, matchingFilters);
       
  2923         }
       
  2924     }
       
  2925 }
       
  2926 
       
  2927 QMessageAccountId ModestEngine::accountIdFromModestMessageId(const QString& modestMessageId) const
       
  2928 {
       
  2929     // Modest messageId format is following:
       
  2930     //   <email protocol>://<username>@<hostname>:<port>...
       
  2931     QMessageAccountId accountId;
       
  2932 
       
  2933     int usernameBegin = modestMessageId.indexOf("//")+2;
       
  2934     int usernameEnd = modestMessageId.indexOf("@");
       
  2935     QString username = QUrl::fromPercentEncoding(modestMessageId.mid(usernameBegin, usernameEnd-usernameBegin).toUtf8());
       
  2936     int hostnameBegin = usernameEnd+1;
       
  2937     int hostnameEnd = modestMessageId.indexOf(':',hostnameBegin);
       
  2938     QString hostname = QUrl::fromPercentEncoding(modestMessageId.mid(hostnameBegin, hostnameEnd-hostnameBegin).toUtf8());
       
  2939 
       
  2940     foreach (QMessageAccount value, iAccounts) {
       
  2941         QMessageAccountId accId = value.id();
       
  2942         if ((accountUsername(accId) == username) &&
       
  2943             (accountHostname(accId) == hostname)) {
       
  2944             accountId = accId;
       
  2945         }
       
  2946     }
       
  2947 
       
  2948     if (!accountId.isValid()) {
       
  2949         if (modestMessageId.left(modestMessageId.indexOf(':')) == "maildir") {
       
  2950             accountId = QMessageAccountId("MO_LOCAL");
       
  2951         }
       
  2952     }
       
  2953 
       
  2954     return accountId;
       
  2955 }
       
  2956 
       
  2957 QMessageFolderId ModestEngine::folderIdFromModestMessageId(const QString& modestMessageId,
       
  2958                                                            const QMessageAccountId accountId) const
       
  2959 {
       
  2960     // Modest messageId format is following:
       
  2961     //   <email protocol>://<username>@<hostname>:<port>...
       
  2962     QMessageFolderId folderId;
       
  2963     QString folderIdAsString;
       
  2964 
       
  2965     if (!accountId.isValid()) {
       
  2966         folderIdAsString = accountIdFromModestMessageId(modestMessageId).toString();
       
  2967     } else {
       
  2968         folderIdAsString = accountId.toString();
       
  2969     }
       
  2970 
       
  2971     int protocolEnd = modestMessageId.indexOf(':');
       
  2972     QString protocol = modestMessageId.left(protocolEnd);
       
  2973     folderIdAsString += "&" + protocol;
       
  2974     if (protocol == "pop") {
       
  2975         folderIdAsString += "&cache";
       
  2976     } else if (protocol == "imap") {
       
  2977         int pathBegin = modestMessageId.indexOf('/',modestMessageId.lastIndexOf(':'))+1;
       
  2978         int pathEnd = modestMessageId.lastIndexOf('/');
       
  2979         folderIdAsString += "&" + modestMessageId.mid(pathBegin, pathEnd-pathBegin);
       
  2980     } else if (protocol == "maildir") {
       
  2981         int pathBegin = modestMessageId.indexOf('#')+1;
       
  2982         int pathEnd = modestMessageId.lastIndexOf('/');
       
  2983         folderIdAsString += "&" + modestMessageId.mid(pathBegin, pathEnd-pathBegin);
       
  2984     }
       
  2985     folderId = QMessageFolderId(QUrl::fromPercentEncoding(folderIdAsString.toUtf8()));
       
  2986 
       
  2987     return folderId;
       
  2988 }
       
  2989 
       
  2990 QString ModestEngine::modestAccountIdFromAccountId(const QMessageAccountId& accountId) const
       
  2991 {
       
  2992     // Just remove "MO_" prefix from the beginning of id string
       
  2993     return accountId.toString().remove(0,3);
       
  2994 }
       
  2995 
       
  2996 QString ModestEngine::modestFolderIdFromFolderId(const QMessageFolderId& folderId) const
       
  2997 {
       
  2998     QString modestFolderId;
       
  2999 
       
  3000     QString folderIdString = folderId.toString();
       
  3001     int protocolBegin = folderIdString.indexOf('&');
       
  3002     int protocolEnd = folderIdString.lastIndexOf('&');
       
  3003 
       
  3004     modestFolderId = folderIdString.mid(protocolEnd+1);
       
  3005     QString protocol = folderIdString.mid(protocolBegin+1,protocolEnd-protocolBegin-1);
       
  3006     if ((protocol == "pop") && (modestFolderId == "cache")) {
       
  3007         modestFolderId = "INBOX";
       
  3008     }
       
  3009 
       
  3010     return modestFolderId;
       
  3011 }
       
  3012 
       
  3013 QString ModestEngine::modestFolderUriFromFolderId(const QMessageFolderId& folderId) const
       
  3014 {
       
  3015     Q_UNUSED(folderId) //TODO:
       
  3016     return QString();
       
  3017 }
       
  3018 
       
  3019 QString ModestEngine::modestAccountIdFromMessageId(const QMessageId& messageId,
       
  3020                                                    bool checkProtocol) const
       
  3021 {
       
  3022     QString id = messageId.toString();
       
  3023     int protocolBegin = id.indexOf('&');
       
  3024     int protocolEnd = id.lastIndexOf('&');
       
  3025     QString protocol = id.mid(protocolBegin+1,protocolEnd-protocolBegin-1);
       
  3026     if (checkProtocol && protocol == "maildir") {
       
  3027         return "local_folders";
       
  3028     }
       
  3029 
       
  3030     return unescapeString(id.left(protocolBegin).remove(0,3));
       
  3031 }
       
  3032 
       
  3033 QMessageAccountId ModestEngine::accountIdFromFolderId(const QMessageFolderId& folderId) const
       
  3034 {
       
  3035     QString id = folderId.toString();
       
  3036     int protocolBegin = id.indexOf('&');
       
  3037     return QMessageAccountId(id.left(protocolBegin));
       
  3038 }
       
  3039 
       
  3040 QMessageAccountId ModestEngine::accountIdFromMessageId(const QMessageId& messageId) const
       
  3041 {
       
  3042     QString id = messageId.toString();
       
  3043     int protocolBegin = id.indexOf('&');
       
  3044     return QMessageAccountId(id.left(protocolBegin));
       
  3045 }
       
  3046 
       
  3047 QString ModestEngine::modestAccountIdFromFolderId(const QMessageFolderId& folderId,
       
  3048                                                   bool checkProtocol) const
       
  3049 {
       
  3050     QString id = folderId.toString();
       
  3051     int protocolBegin = id.indexOf('&');
       
  3052     int protocolEnd = id.lastIndexOf('&');
       
  3053     QString protocol = id.mid(protocolBegin+1,protocolEnd-protocolBegin-1);
       
  3054     if (checkProtocol && protocol == "maildir") {
       
  3055         return "local_folders";
       
  3056     }
       
  3057 
       
  3058     return unescapeString(id.left(protocolBegin).remove(0,3));
       
  3059 }
       
  3060 
       
  3061 QString ModestEngine::modestFolderIdFromMessageId(const QMessageId& messageId) const
       
  3062 {
       
  3063     QString id = messageId.toString();
       
  3064 
       
  3065     int protocolBegin = id.indexOf('&');
       
  3066     int protocolEnd = id.lastIndexOf('&');
       
  3067     int folderEnd = id.lastIndexOf('/');
       
  3068 
       
  3069     QString protocol = id.mid(protocolBegin+1,protocolEnd-protocolBegin-1);
       
  3070     id = id.mid(protocolEnd+1,folderEnd-protocolEnd-1);
       
  3071     if ((protocol == "pop") && (id == "cache")) {
       
  3072         id = "INBOX";
       
  3073     }
       
  3074 
       
  3075     return id;
       
  3076 }
       
  3077 
       
  3078 void ModestEngine::replaceProtocol(QString& id, const QString& newProtocol) const
       
  3079 {
       
  3080     int protocolBegin = id.indexOf('&');
       
  3081     int protocolEnd = id.lastIndexOf('&');
       
  3082     id.remove(protocolBegin+1,protocolEnd-protocolBegin-1);
       
  3083     id.insert(protocolBegin+1, newProtocol);
       
  3084 }
       
  3085 
       
  3086 QMessageAccountId ModestEngine::realAccountId(const MessagingModestMessage& modestMessage) const
       
  3087 {
       
  3088     QMessageAccountId accountId;
       
  3089 
       
  3090     if (modestMessage.accountId == "local_folders") {
       
  3091         QString accountIdString;
       
  3092         // Message is in local foldar, but message can be linked
       
  3093         // to actual account using 'From', 'To', 'Cc' or 'Bcc' fields
       
  3094         foreach (QMessageAccount value, iAccounts) {
       
  3095             QMessageAccountPrivate* privAccount = QMessageAccountPrivate::implementation(value);
       
  3096             if (modestMessage.from.contains(privAccount->_address.addressee())) {
       
  3097                 accountIdString = value.id().toString();
       
  3098                 break;
       
  3099             } else if (modestMessage.to.contains(privAccount->_address.addressee())) {
       
  3100                 accountIdString = value.id().toString();
       
  3101                 break;
       
  3102             } else if (modestMessage.cc.contains(privAccount->_address.addressee())) {
       
  3103                 accountIdString = value.id().toString();
       
  3104                 break;
       
  3105             } else if (modestMessage.bcc.contains(privAccount->_address.addressee())) {
       
  3106                 accountIdString = value.id().toString();
       
  3107                 break;
       
  3108             }
       
  3109         }
       
  3110         if (!accountIdString.isEmpty()) {
       
  3111             accountId = QMessageAccountId(accountIdString);
       
  3112         }
       
  3113     } else {
       
  3114         accountId = accountIdFromModestAccountId(modestMessage.accountId);
       
  3115     }
       
  3116 
       
  3117     return accountId;
       
  3118 }
       
  3119 
       
  3120 QString ModestEngine::modestMessageIdFromMessageId(const QMessageId& messageId) const
       
  3121 {
       
  3122     QString id = messageId.toString();
       
  3123     return id.mid(id.lastIndexOf('/')+1);
       
  3124 }
       
  3125 
       
  3126 QMessageAccountId ModestEngine::accountIdFromModestAccountId(const QString& accountId) const
       
  3127 {
       
  3128     // Just add "MO_" prefix to the beginning of id string & escape created Id
       
  3129     return QMessageAccountId(escapeString("MO_"+accountId));
       
  3130 }
       
  3131 
       
  3132 QMessageFolderId ModestEngine::folderIdFromModestFolderId(const QMessageAccountId& accountId,
       
  3133                                                           bool isLocalFolder,
       
  3134                                                           const QString& modestFolderId) const
       
  3135 {
       
  3136     // Format: <accountId>&<email protocol>&<Modest folderId>
       
  3137     QMessageFolderId folderId;
       
  3138 
       
  3139     if (isLocalFolder) {
       
  3140          folderId = QMessageFolderId(accountId.toString()+"&maildir&"+modestFolderId);
       
  3141     } else {
       
  3142         QString protocol = accountEmailProtocolAsString(accountId);
       
  3143         if ((protocol == "pop") && (modestFolderId == "INBOX")) {
       
  3144             folderId = QMessageFolderId(accountId.toString()+"&"+protocol+"&cache");
       
  3145         } else {
       
  3146             folderId = QMessageFolderId(accountId.toString()+"&"+protocol+"&"+modestFolderId);
       
  3147         }
       
  3148     }
       
  3149 
       
  3150     return folderId;
       
  3151 }
       
  3152 
       
  3153 QMessageId ModestEngine::messageIdFromModestMessageId(const QString& messageId) const
       
  3154 {
       
  3155     QString messageIdString = folderIdFromModestMessageId(messageId).toString();
       
  3156     int idPartBegin = messageId.lastIndexOf('/');
       
  3157     messageIdString += messageId.mid(idPartBegin, idPartBegin-messageId.length());
       
  3158     return QMessageId(messageIdString);
       
  3159 }
       
  3160 
       
  3161 QMessageId ModestEngine::messageIdFromModestMessageFilePath(const QString& messageFilePath) const
       
  3162 {
       
  3163     QString messageIdString;
       
  3164 
       
  3165     QString filePath = messageFilePath;
       
  3166     QString localRootFolder = this->localRootFolder();
       
  3167     if (filePath.startsWith(localRootFolder)) {
       
  3168         messageIdString = "MO_LOCAL&maildir&";
       
  3169         filePath.remove(0,localRootFolder.length()+1);
       
  3170         filePath.remove("/cur");
       
  3171         messageIdString += filePath.left(filePath.lastIndexOf('!'));
       
  3172     } else {
       
  3173         foreach (QMessageAccount value, iAccounts) {
       
  3174             QMessageAccountId accountId = value.id();
       
  3175             QString rootFolder = accountRootFolder(accountId);
       
  3176             if (filePath.startsWith(rootFolder)) {
       
  3177                 QString protocol = accountEmailProtocolAsString(accountId);
       
  3178                 messageIdString = accountId.toString()+"&"+protocol+"&";
       
  3179                 filePath.remove(0,rootFolder.length()+1);
       
  3180                 filePath.remove("/subfolders");
       
  3181                 messageIdString += filePath.left(filePath.lastIndexOf('.'));
       
  3182                 if (protocol == "pop") {
       
  3183                     QDir dir(messageFilePath);
       
  3184                     dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
       
  3185                     QFileInfoList dirs = dir.entryInfoList();
       
  3186                     if (dirs.count() > 0) {
       
  3187                         QString fileName = dirs[0].fileName();
       
  3188                         // Remove folder that contains actual message
       
  3189                         messageIdString = messageIdString.left(messageIdString.lastIndexOf('/')+1);
       
  3190                         // Add message name
       
  3191                         messageIdString = messageIdString+fileName;
       
  3192                     }
       
  3193                 }
       
  3194             }
       
  3195         }
       
  3196     }
       
  3197 
       
  3198     return QMessageId(messageIdString);
       
  3199 }
       
  3200 
       
  3201 QString ModestEngine::unescapeString(const QString& string)
       
  3202 {
       
  3203     QString unescapedString;
       
  3204 
       
  3205     QByteArray str = string.toUtf8();
       
  3206     gchar* unescaped_string = gconf_unescape_key(str.data(), str.length());
       
  3207     unescapedString = QString::fromUtf8(unescaped_string);
       
  3208     g_free(unescaped_string);
       
  3209 
       
  3210     return unescapedString;
       
  3211 }
       
  3212 
       
  3213 QString ModestEngine::escapeString(const QString& string)
       
  3214 {
       
  3215     QString escapedString;
       
  3216 
       
  3217     QByteArray str = unescapeString(string).toUtf8();
       
  3218     gchar* escaped_string = gconf_escape_key(str.data(), str.length());
       
  3219     escapedString = QString::fromUtf8(escaped_string);
       
  3220     g_free(escaped_string);
       
  3221 
       
  3222     return escapedString;
       
  3223 }
       
  3224 
       
  3225 INotifyWatcher::INotifyWatcher()
       
  3226 {
       
  3227     // Initialize inotify instance
       
  3228     // => returned file descriptor is associated with
       
  3229     //    a new inotify event queue
       
  3230     // O_CLOEXEC flag makes sure that file descriptor
       
  3231     //           is closed if execution is transfered
       
  3232     //           from this process to a new program
       
  3233     //           (Check more info from 'execve' documentation)
       
  3234 #ifdef IN_CLOEXEC
       
  3235     m_inotifyFileDescriptor = inotify_init1(IN_CLOEXEC);
       
  3236 #else
       
  3237     m_inotifyFileDescriptor = inotify_init();
       
  3238     if (m_inotifyFileDescriptor >= 0) {
       
  3239         ::fcntl(m_inotifyFileDescriptor, F_SETFD, FD_CLOEXEC);
       
  3240     }
       
  3241 #endif
       
  3242     if (m_inotifyFileDescriptor >= 0) {
       
  3243         // Change thread affinity for this object to this
       
  3244         // thread.
       
  3245         // => Event processing (for this objects events) will
       
  3246         //    be done in this thread
       
  3247         moveToThread(this);
       
  3248     }
       
  3249 }
       
  3250 
       
  3251 INotifyWatcher::~INotifyWatcher()
       
  3252 {
       
  3253     // Tell the thread's event loop to exit
       
  3254     // => thread returns from the call to exec()
       
  3255     exit();
       
  3256 
       
  3257     // Wait until this thread has finished execution
       
  3258     // <=> waits until thread returns from run()
       
  3259     wait();
       
  3260 
       
  3261     clear();
       
  3262 
       
  3263     // Close file descriptor that's referring to inotify instance
       
  3264     // => The underlying inotify object and its resources are freed
       
  3265     ::close(m_inotifyFileDescriptor);
       
  3266 }
       
  3267 
       
  3268 void INotifyWatcher::clear()
       
  3269 {
       
  3270     // Remove all watches from inotify instance watch list
       
  3271     QMapIterator<int, QString> i(m_dirs);
       
  3272     while (i.hasNext()) {
       
  3273         inotify_rm_watch(m_inotifyFileDescriptor, i.next().key());
       
  3274     }
       
  3275     m_dirs.clear();
       
  3276 
       
  3277     QMapIterator<int, QString> j(m_files);
       
  3278     while (j.hasNext()) {
       
  3279         inotify_rm_watch(m_inotifyFileDescriptor, j.next().key());
       
  3280     }
       
  3281     m_files.clear();
       
  3282 }
       
  3283 
       
  3284 void INotifyWatcher::run()
       
  3285 {
       
  3286     // Start listening inotify
       
  3287     QSocketNotifier socketNotifier(m_inotifyFileDescriptor, QSocketNotifier::Read, this);
       
  3288     connect(&socketNotifier, SIGNAL(activated(int)), SLOT(notifySlot()));
       
  3289 
       
  3290     // Enter the thread event loop
       
  3291     (void) exec();
       
  3292 }
       
  3293 
       
  3294 int INotifyWatcher::addFile(const QString& path, uint eventsToWatch)
       
  3295 {
       
  3296     int watchDescriptor = 0;
       
  3297     QMutexLocker locker(&m_mutex);
       
  3298 
       
  3299     if (m_inotifyFileDescriptor >= 0) {
       
  3300         int watchDescriptor = 0;
       
  3301         if (eventsToWatch == 0) {
       
  3302             watchDescriptor = inotify_add_watch(m_inotifyFileDescriptor,
       
  3303                                                 QFile::encodeName(path),
       
  3304                                                 0 | IN_ATTRIB
       
  3305                                                   | IN_MODIFY
       
  3306                                                   | IN_MOVE
       
  3307                                                   | IN_MOVE_SELF
       
  3308                                                   | IN_DELETE_SELF);
       
  3309         } else {
       
  3310             watchDescriptor = inotify_add_watch(m_inotifyFileDescriptor,
       
  3311                                                 QFile::encodeName(path),
       
  3312                                                 eventsToWatch);
       
  3313         }
       
  3314         if (watchDescriptor > 0) {
       
  3315             m_files.insert(watchDescriptor, path);
       
  3316         } else {
       
  3317             watchDescriptor = 0;
       
  3318         }
       
  3319     }
       
  3320 
       
  3321     // Start thread (if thread is not already running)
       
  3322     start();
       
  3323 
       
  3324     return watchDescriptor;
       
  3325 }
       
  3326 
       
  3327 int INotifyWatcher::addDirectory(const QString& path, uint eventsToWatch)
       
  3328 {
       
  3329     int watchDescriptor = 0;
       
  3330     QMutexLocker locker(&m_mutex);
       
  3331 
       
  3332     if (m_inotifyFileDescriptor >= 0) {
       
  3333         int watchDescriptor = 0;
       
  3334         if (eventsToWatch == 0) {
       
  3335             watchDescriptor = inotify_add_watch(m_inotifyFileDescriptor,
       
  3336                                                 QFile::encodeName(path),
       
  3337                                                 0 | IN_ATTRIB
       
  3338                                                   | IN_MOVE
       
  3339                                                   | IN_CREATE
       
  3340                                                   | IN_DELETE
       
  3341                                                   | IN_DELETE_SELF);
       
  3342         } else {
       
  3343             watchDescriptor = inotify_add_watch(m_inotifyFileDescriptor,
       
  3344                                                 QFile::encodeName(path),
       
  3345                                                 eventsToWatch);
       
  3346         }
       
  3347         if (watchDescriptor > 0) {
       
  3348             m_dirs.insert(watchDescriptor, path);
       
  3349         } else {
       
  3350             watchDescriptor = 0;
       
  3351         }
       
  3352     }
       
  3353 
       
  3354     // Start thread (if thread is not already running)
       
  3355     start();
       
  3356 
       
  3357     return watchDescriptor;
       
  3358 }
       
  3359 
       
  3360 QStringList INotifyWatcher::directories() const
       
  3361 {
       
  3362     return m_dirs.values();
       
  3363 }
       
  3364 
       
  3365 QStringList INotifyWatcher::files() const
       
  3366 {
       
  3367     return m_dirs.values();
       
  3368 }
       
  3369 
       
  3370 void INotifyWatcher::notifySlot()
       
  3371 {
       
  3372     QMutexLocker locker(&m_mutex);
       
  3373 
       
  3374     int bufferSize = 0;
       
  3375     ioctl(m_inotifyFileDescriptor, FIONREAD, (char*) &bufferSize);
       
  3376     QVarLengthArray<char, 4096> buffer(bufferSize);
       
  3377     bufferSize = read(m_inotifyFileDescriptor, buffer.data(), bufferSize);
       
  3378     const char* at = buffer.data();
       
  3379     const char* const end = at + bufferSize;
       
  3380 
       
  3381     QMap<int, INotifyEvent> eventsForWatchedFile;
       
  3382     QMap<QString, INotifyEvent> eventsForFileInWatchedDirectory;
       
  3383     while (at < end) {
       
  3384         const inotify_event *event = reinterpret_cast<const inotify_event *>(at);
       
  3385         if (m_files.contains(event->wd)) {
       
  3386             // File event handling
       
  3387             if (eventsForWatchedFile.contains(event->wd)) {
       
  3388                 // There is already unhandled event for this file in queue
       
  3389                 // => Mask is ORed to existing event
       
  3390                 eventsForWatchedFile[event->wd].mask |= event->mask;
       
  3391             } else {
       
  3392                 // There is no event for this file in queue
       
  3393                 // => New event is created
       
  3394                 INotifyEvent inotifyEvent;
       
  3395                 inotifyEvent.watchDescriptor = event->wd;
       
  3396                 inotifyEvent.mask = event->mask;
       
  3397                 inotifyEvent.fileName = QString::fromAscii(event->name, event->len);
       
  3398                 eventsForWatchedFile.insert(event->wd, inotifyEvent);
       
  3399             }
       
  3400         } else {
       
  3401             // Directory event handling
       
  3402             QString changeForFileInDirectory = QString::fromAscii(event->name, event->len);
       
  3403             // Remove unnecessary postfix (starting with '!') from the file name
       
  3404             changeForFileInDirectory = changeForFileInDirectory.left(changeForFileInDirectory.lastIndexOf('!'));
       
  3405             if (!changeForFileInDirectory.isEmpty()) {
       
  3406                 QString eventId = QString::number(event->wd)+changeForFileInDirectory;
       
  3407                 if (eventsForFileInWatchedDirectory.contains(eventId)) {
       
  3408                     // There is already unhandled event for this file in queue
       
  3409                     // => Mask is ORed to existing event
       
  3410                     eventsForFileInWatchedDirectory[eventId].mask |= event->mask;
       
  3411                 } else {
       
  3412                     // There is no event for this file in queue
       
  3413                     // => New event is created
       
  3414                     INotifyEvent inotifyEvent;
       
  3415                     inotifyEvent.watchDescriptor = event->wd;
       
  3416                     inotifyEvent.mask = event->mask;
       
  3417                     inotifyEvent.fileName = QString::fromAscii(event->name, event->len);
       
  3418                     eventsForFileInWatchedDirectory.insert(eventId, inotifyEvent);
       
  3419                 }
       
  3420             }
       
  3421         }
       
  3422         at += sizeof(inotify_event) + event->len;
       
  3423     }
       
  3424 
       
  3425     QMap<int, INotifyEvent>::const_iterator it = eventsForWatchedFile.constBegin();
       
  3426     while (it != eventsForWatchedFile.constEnd()) {
       
  3427         INotifyEvent event = *it;
       
  3428         QString file = m_files.value(event.watchDescriptor);
       
  3429         if (!file.isEmpty()) {
       
  3430             emit fileChanged(event.watchDescriptor, file, event.mask);
       
  3431         }
       
  3432         ++it;
       
  3433     }
       
  3434 
       
  3435     QMap<QString, INotifyEvent>::const_iterator jt = eventsForFileInWatchedDirectory.constBegin();
       
  3436     while (jt != eventsForFileInWatchedDirectory.constEnd()) {
       
  3437         INotifyEvent event = *jt;
       
  3438         QString file = m_dirs.value(event.watchDescriptor)+"/"+event.fileName;
       
  3439         emit fileChanged(event.watchDescriptor, file, event.mask);
       
  3440         ++jt;
       
  3441     }
       
  3442 }
       
  3443 
       
  3444 ModestStringMap ModestEngine::getModestSenderInfo(QMessage &message)
       
  3445 {
       
  3446     QMessageAddress address;
       
  3447     ModestStringMap senderInfo;
       
  3448     QMessageAccountId accountId;
       
  3449     QString value;
       
  3450 
       
  3451     accountId = message.parentAccountId();
       
  3452     if (accountId.isValid() == false) {
       
  3453         qWarning () << "Account ID is invalid";
       
  3454         return ModestStringMap();
       
  3455     }
       
  3456 
       
  3457     senderInfo["account-name"] = unescapeString(modestAccountIdFromAccountId(accountId));
       
  3458 
       
  3459     QMessageAccount messageAccount = account(accountId);
       
  3460     QMessageAccountPrivate* privAccount = QMessageAccountPrivate::implementation(messageAccount);
       
  3461     address = privAccount->_address;
       
  3462     value = address.addressee();
       
  3463 
       
  3464     if (value.isEmpty() == false && value.isNull() == false) {
       
  3465         senderInfo["from"] = value;
       
  3466     }
       
  3467 
       
  3468     return senderInfo;
       
  3469 }
       
  3470 
       
  3471 ModestStringMap ModestEngine::getModestRecipients(QMessage &message)
       
  3472 {
       
  3473     QMessageAddressList addresses;
       
  3474     QMessageAddress address;
       
  3475     ModestStringMap recipients;
       
  3476     QString value;
       
  3477 
       
  3478     addresses = message.to();
       
  3479     value.clear();
       
  3480     for (int i = 0; i < addresses.length(); i++) {
       
  3481         address = addresses[i];
       
  3482 
       
  3483         if (value.isEmpty()) {
       
  3484             value = address.addressee();
       
  3485         } else {
       
  3486             value.append (",");
       
  3487             value.append (address.addressee());
       
  3488         }
       
  3489     }
       
  3490 
       
  3491     if (value.isEmpty() == false && value.isNull() == false) {
       
  3492         recipients["to"] = value;
       
  3493     }
       
  3494 
       
  3495     addresses = message.cc();
       
  3496     value.clear();
       
  3497     for (int i = 0; i < addresses.length(); i++) {
       
  3498         address = addresses[i];
       
  3499 
       
  3500         if (value.isEmpty()) {
       
  3501             value = address.addressee();
       
  3502         } else {
       
  3503             value.append (",");
       
  3504             value.append (address.addressee());
       
  3505         }
       
  3506     }
       
  3507 
       
  3508     if (value.isEmpty() == false && value.isNull() == false) {
       
  3509         recipients["cc"] = value;
       
  3510     }
       
  3511 
       
  3512     addresses = message.bcc();
       
  3513     value.clear();
       
  3514     for (int i = 0; i < addresses.length(); i++) {
       
  3515         address = addresses[i];
       
  3516 
       
  3517         if (value.isEmpty()) {
       
  3518             value = address.addressee();
       
  3519         } else {
       
  3520             value.append (",");
       
  3521             value.append (address.addressee());
       
  3522         }
       
  3523     }
       
  3524 
       
  3525     if (value.isEmpty() == false && value.isNull() == false) {
       
  3526         recipients["bcc"] = value;
       
  3527     }
       
  3528 
       
  3529     return recipients;
       
  3530 }
       
  3531 
       
  3532 ModestStringMap ModestEngine::getModestMessageData(QMessage &message)
       
  3533 {
       
  3534     QMessageContentContainerId bodyId;
       
  3535     QMessageContentContainer body;
       
  3536     ModestStringMap messageData;
       
  3537     QString value;
       
  3538 
       
  3539     value = message.subject();
       
  3540 
       
  3541     if (value.isEmpty() == false && value.isNull() == false) {
       
  3542         messageData["subject"] = value;
       
  3543     }
       
  3544 
       
  3545     bodyId = message.bodyId();
       
  3546     if (bodyId.isValid()) {
       
  3547         body = message.find (bodyId);
       
  3548     } else {
       
  3549         body = message;
       
  3550     }
       
  3551 
       
  3552     value = body.contentType();
       
  3553 
       
  3554     if (value == "text") {
       
  3555         QString key, data;
       
  3556         bool hasContent = false;
       
  3557 
       
  3558         value = body.contentSubType();
       
  3559 
       
  3560         if ((hasContent = body.isContentAvailable()) == true) {
       
  3561             data = body.textContent();
       
  3562         }
       
  3563 
       
  3564         if (value == "plain") {
       
  3565             key = "plain-body";
       
  3566         } else if (value == "html") {
       
  3567             key = "html-body";
       
  3568         }
       
  3569 
       
  3570         if (key.isEmpty() == false && key.isNull() == false && hasContent) {
       
  3571             messageData[key] = data;
       
  3572         }
       
  3573     }
       
  3574 
       
  3575     if (message.status() & QMessage::Read) {
       
  3576         messageData["read"] = "";
       
  3577     }
       
  3578 
       
  3579     return messageData;
       
  3580 }
       
  3581 
       
  3582 ModestStringMapList ModestEngine::getModestAttachments(QMessage &message)
       
  3583 {
       
  3584     QMessageContentContainerIdList attachmentIds;
       
  3585     ModestStringMapList attachments;
       
  3586     QMessage::StatusFlags messageStatus;
       
  3587     QString value;
       
  3588 
       
  3589     messageStatus = message.status();
       
  3590 
       
  3591     if (messageStatus & QMessage::HasAttachments) {
       
  3592         attachmentIds = message.attachmentIds();
       
  3593 
       
  3594         foreach (QMessageContentContainerId identifier, attachmentIds) {
       
  3595             ModestStringMap attachmentData;
       
  3596             QMessageContentContainer attachmentCont;
       
  3597 
       
  3598             if (identifier.isValid() == false) continue;
       
  3599 
       
  3600             attachmentCont = message.find (identifier);
       
  3601 
       
  3602             if (attachmentCont.isContentAvailable () == false) continue;
       
  3603 
       
  3604             attachmentData.clear();
       
  3605 
       
  3606             value = attachmentCont.contentType();
       
  3607 
       
  3608             if (value.isEmpty() == false) {
       
  3609                 value.append("/");
       
  3610                 value.append (attachmentCont.contentSubType());
       
  3611                 attachmentData["mime-type"] = value;
       
  3612 
       
  3613                 qDebug() << "mime-type: " << value;
       
  3614             }
       
  3615 
       
  3616             value = QMessageContentContainerPrivate::attachmentFilename (
       
  3617                 attachmentCont);
       
  3618 
       
  3619             if (value.isEmpty() == false) {
       
  3620                 attachmentData["filename"] = value;
       
  3621                 qDebug() << "filename: " << value;
       
  3622             }
       
  3623 
       
  3624             qDebug() << "Charset: " << attachmentCont.contentCharset();
       
  3625             qDebug() << "Headers: " << attachmentCont.headerFields();
       
  3626 
       
  3627             if (attachmentData.isEmpty() == false) {
       
  3628                 attachmentData["content-id"] = identifier.toString();
       
  3629                 attachments.append (attachmentData);
       
  3630             }
       
  3631         }
       
  3632     }
       
  3633 
       
  3634     return attachments;
       
  3635 }
       
  3636 
       
  3637 ModestStringMapList ModestEngine::getModestImages(QMessage &message)
       
  3638 {
       
  3639     Q_UNUSED(message);
       
  3640     // Don't know if this even makes sense. Modest expects inlined images
       
  3641     // to be in a separate list, but that doesn't make much sense?
       
  3642     return ModestStringMapList();
       
  3643 }
       
  3644 
       
  3645 uint ModestEngine::getModestPriority(QMessage &message)
       
  3646 {
       
  3647     uint priority = 0;
       
  3648 
       
  3649     switch (message.priority()) {
       
  3650     case QMessage::HighPriority:
       
  3651         priority = MODESTENGINE_HIGH_PRIORITY;
       
  3652         break;
       
  3653 
       
  3654     default:
       
  3655     case QMessage::NormalPriority:
       
  3656         priority = MODESTENGINE_NORMAL_PRIORITY;
       
  3657         break;
       
  3658 
       
  3659     case QMessage::LowPriority:
       
  3660         priority = MODESTENGINE_LOW_PRIORITY;
       
  3661         break;
       
  3662     }
       
  3663 
       
  3664     return priority;
       
  3665 }
       
  3666 
       
  3667 ModestStringMap ModestEngine::getModestHeaders(QMessage &message)
       
  3668 {
       
  3669     Q_UNUSED(message);
       
  3670     return ModestStringMap(); // stub
       
  3671 }
       
  3672 
       
  3673 void ModestEngine::clearHeaderCache()
       
  3674 {
       
  3675     m_messageCache.clear();
       
  3676 }
       
  3677 
       
  3678 #include "moc_modestengine_maemo_p.cpp"
       
  3679 
       
  3680 QTM_END_NAMESPACE