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