emailservices/nmailagent/src/nmmailagent.cpp
changeset 20 ecc8def7944a
parent 18 578830873419
child 23 2dc6caa42ec3
--- a/emailservices/nmailagent/src/nmmailagent.cpp	Fri Apr 16 14:51:52 2010 +0300
+++ b/emailservices/nmailagent/src/nmmailagent.cpp	Mon May 03 12:23:15 2010 +0300
@@ -19,7 +19,8 @@
 #include "nmmailagent.h"
 
 // CONSTS
-const int maxUnreadCount = 1; // 1 is enough
+const int NmAgentMaxUnreadCount = 1; // 1 is enough
+const int NmAgentIndicatorNotSet = -1;
 
 
 /*!
@@ -28,80 +29,88 @@
     \brief Main class for receiving email events and passing them to the HbIndicator
 */
 
-/*!
-    Creates list of folder paths where plug-ins can be loaded from.
-    \return folder path list.
-*/
-QStringList NmMailAgent::pluginFolders()
-{
-    const QString nmPluginPath("resource/plugins");
-    QStringList pluginDirectories;
-    QFileInfoList driveList = QDir::drives();
-
-    foreach(const QFileInfo &driveInfo, driveList) {
-        QString pluginDirectory =
-            driveInfo.absolutePath() + nmPluginPath;
-
-        if (QFileInfo(pluginDirectory).exists()) {
-            pluginDirectories.append(pluginDirectory);
-        }
-    }
-
-    return pluginDirectories;
-}
-
 NmMailboxInfo::NmMailboxInfo()
 {
     mId = 0;
+    mIndicatorIndex = NmAgentIndicatorNotSet;
     mSyncState = SyncComplete;
     mConnectState = Disconnected;
     mUnreadMails = 0;
+    mOutboxMails = 0;
+    mInboxFolderId = 0;
+    mOutboxFolderId = 0;
+    mInboxCreatedMessages = 0;
+    mInboxChangedMessages = 0;
+    mInboxDeletedMessages = 0;
     mActive = false;
 }
 
 NmMailAgent::NmMailAgent() :
- mAdapter(NULL),
- mActiveIndicators(0)
+ mPluginFactory(NULL),
+ mSendingState(false)
 {
     NMLOG("NmMailAgent::NmMailAgent");
 }
 
 /*!
+    Delayed start
+*/
+void NmMailAgent::delayedStart()
+{
+	NMLOG("NmMailAgent::delayedStart");
+	if (!init()) {
+		// Initialisation failed. Quit the agent.
+		QCoreApplication::exit(1);
+	}
+}
+
+/*!
     Initialise the agent. \return true if succesfully started.
 */
 bool NmMailAgent::init()
 {
-    if (!loadAdapter()) {
-        // Failed to load NmFrameworkAdapter
+	NMLOG("NmMailAgent::init");
+    mPluginFactory = NmDataPluginFactory::instance();
+    if (!mPluginFactory) {
+        NMLOG("NmMailAgent::init PluginFactory not created");
         return false;
     }
 
-    // Start listening events
-    connect(mAdapter, SIGNAL(mailboxEvent(NmMailboxEvent, const QList<NmId>&)),
-        this, SLOT(handleMailboxEvent(NmMailboxEvent, const QList<NmId> &)));
+    QList<QObject*> *plugins = mPluginFactory->pluginInstances();
+
+    foreach (QObject *plugin, *plugins) {
+    	if (plugin) {
+			// Start listening events
+			connect(plugin, SIGNAL(mailboxEvent(NmMailboxEvent, const QList<NmId>&)),
+				this, SLOT(handleMailboxEvent(NmMailboxEvent, const QList<NmId> &)),
+				Qt::UniqueConnection);
 
-    connect(mAdapter, SIGNAL(messageEvent(
-            NmMessageEvent, const NmId &, const QList<NmId> &, const NmId&)),
-        this, SLOT(handleMessageEvent(
-            NmMessageEvent, const NmId &, const QList<NmId> &, const NmId&)));
+			connect(plugin, SIGNAL(messageEvent(
+					NmMessageEvent, const NmId &, const QList<NmId> &, const NmId&)),
+				this, SLOT(handleMessageEvent(
+					NmMessageEvent, const NmId &, const QList<NmId> &, const NmId&)),
+				Qt::UniqueConnection);
 
-    connect(mAdapter, SIGNAL(syncStateEvent(NmSyncState, const NmId)),
-        this, SLOT(handleSyncStateEvent(NmSyncState, const NmId)));
+			connect(plugin, SIGNAL(syncStateEvent(NmSyncState, const NmOperationCompletionEvent&)),
+				this, SLOT(handleSyncStateEvent(NmSyncState, const NmOperationCompletionEvent&)),
+				Qt::UniqueConnection);
 
-    connect(mAdapter, SIGNAL(connectionEvent(NmConnectState, const NmId)),
-        this, SLOT(handleConnectionEvent(NmConnectState, const NmId)));
+			connect(plugin, SIGNAL(connectionEvent(NmConnectState, const NmId)),
+				this, SLOT(handleConnectionEvent(NmConnectState, const NmId)),
+				Qt::UniqueConnection);
+    	}
+    }
 
     // load all current mailboxes
     initMailboxStatus();
 
-    updateStatus();
     return true;
 }
 
 NmMailAgent::~NmMailAgent()
 {
-    delete mAdapter;
     qDeleteAll(mMailboxes);
+    NmDataPluginFactory::releaseInstance(mPluginFactory);
 }
 
 /*!
@@ -111,17 +120,37 @@
 {
     NMLOG("NmMailAgent::initMailboxStatus");
     QList<NmMailbox*> mailboxes;
-    mAdapter->listMailboxes(mailboxes);
-    foreach (const NmMailbox* mailbox, mailboxes) {
-        if (mailbox) {
-            NmMailboxInfo *mailboxInfo = createMailboxInfo(*mailbox);
-            if (mailboxInfo) {
-                mailboxInfo->mUnreadMails = getUnreadCount(mailbox->id(),maxUnreadCount);
-                updateMailboxActivity(mailbox->id(), isMailboxActive(*mailboxInfo));
+    QList<QObject*> *plugins = mPluginFactory->pluginInstances();
+
+    foreach(QObject* pluginObject, *plugins) {
+        NmDataPluginInterface *plugin =
+            mPluginFactory->interfaceInstance(pluginObject);
+        if (plugin) {
+            plugin->listMailboxes(mailboxes);
+        }
+
+        // Add the indicators
+        // Must be made in reverse order to show them properly in
+        // HbIndicator menu
+        QListIterator<NmMailbox *> i(mailboxes);
+        i.toBack();
+        while (i.hasPrevious()) {
+            const NmMailbox *mailbox = i.previous();
+            if (mailbox) {
+                NmMailboxInfo *mailboxInfo = createMailboxInfo(*mailbox,plugin);
+                if (mailboxInfo) {
+                    mailboxInfo->mUnreadMails = getUnreadCount(mailbox->id(),NmAgentMaxUnreadCount);
+                    mailboxInfo->mOutboxMails = getOutboxCount(mailbox->id());
+
+                    // Create indicator for visible mailboxes
+                    updateMailboxState(mailbox->id(),
+                        isMailboxActive(*mailboxInfo),
+                        false);
+                }
             }
         }
+        qDeleteAll(mailboxes);
     }
-    qDeleteAll(mailboxes);
 }
 
 /*!
@@ -135,109 +164,115 @@
     NMLOG("NmMailAgent::getUnreadCount");
     int count(0);
 
-    // get inbox folder ID
-    NmId inboxId = mAdapter->getStandardFolderId(
-            mailboxId, NmFolderInbox );
+    NmDataPluginInterface *plugin = mPluginFactory->interfaceInstance(mailboxId);
 
-    // get list of messages in inbox
-    QList<NmMessageEnvelope*> messageList;
-    mAdapter->listMessages(mailboxId, inboxId, messageList);
+    if (plugin) {
+		// get inbox folder ID
+		NmId inboxId = plugin->getStandardFolderId(
+				mailboxId, NmFolderInbox );
+
+		// get list of messages in inbox
+		QList<NmMessageEnvelope*> messageList;
+		plugin->listMessages(mailboxId, inboxId, messageList);
 
-    foreach (const NmMessageEnvelope* envelope, messageList) {
-        // if the message is not read, it is "unread"
-        if (!envelope->isRead()) {
-            count++;
+		foreach (const NmMessageEnvelope* envelope, messageList) {
+			// if the message is not read, it is "unread"
+			if (!envelope->isRead()) {
+				count++;
 
-            // No more unread mails are needed
-            if (count >= maxCount) {
-                break;
-            }
-        }
+				// No more unread mails are needed
+				if (count >= maxCount) {
+					break;
+				}
+			}
+		}
+		qDeleteAll(messageList);
     }
-	qDeleteAll(messageList);
 	NMLOG(QString("NmMailAgent::getUnreadCount count=%1").arg(count));
 
     return count;
 }
 
 /*!
-    Load NmFrameworkAdapter from plugins.
-    \return true if adapter is loaded succesfully.
+    Get mailbox count in outbox folder
+    \param mailboxId id of the mailbox
+    \param maxCount max number of outbox mails that is needed
+    \return number of mails in the outbox
 */
-bool NmMailAgent::loadAdapter()
+int NmMailAgent::getOutboxCount(const NmId &mailboxId)
 {
-    QStringList directories(pluginFolders());
+    NMLOG("NmMailAgent::getOutboxCount");
+    int count(0);
+
+    NmDataPluginInterface *plugin = mPluginFactory->interfaceInstance(mailboxId);
 
-     foreach (const QString &pluginPath, directories) {
-         QPluginLoader *loader =
-             new QPluginLoader(pluginPath + "/nmframeworkadapter.qtplugin");
-         if (loader) {
-             mAdapter = static_cast<NmFrameworkAdapter *>(loader->instance());
-             if (mAdapter) {
-                 return true;
-             }
-         }
-     }
-     NMLOG("NmMailAgent::loadAdapter failed");
-     return false;
+    if (plugin) {
+		// get outbox folder ID
+		NmId outboxId = plugin->getStandardFolderId( mailboxId, NmFolderOutbox );
+
+		// get list of messages in outbox
+		QList<NmMessageEnvelope*> messageList;
+		plugin->listMessages(mailboxId, outboxId, messageList);
+		count = messageList.count();
+		qDeleteAll(messageList);
+    }
+    NMLOG(QString("NmMailAgent::getOutboxCount count=%1").arg(count));
+
+    return count;
 }
 
 /*!
-    Update the mailbox visibility
+    Update the mailbox visibility and status
     \param mailboxId id of the mailbox
     \param active visibility state of the mailbox
+    \param refreshAlways true when the indicator should be always updated
     \return true if the mailbox state was changed
 */
-bool NmMailAgent::updateMailboxActivity(const NmId &mailboxId, bool active)
+bool NmMailAgent::updateMailboxState(const NmId &mailboxId,
+    bool active, bool refreshAlways)
 {
+    // Update the global sending state
+    mSendingState = false;
+    foreach (NmMailboxInfo *mailboxInfo, mMailboxes) {
+        if (mailboxInfo->mOutboxMails>0) {
+            mSendingState = true;
+            break;
+        }
+    }
+
     NmMailboxInfo *mailboxInfo = getMailboxInfo(mailboxId);
     bool changed = false;
-    if (mailboxInfo->mActive != active) {
+    if (mailboxInfo->mActive != active ||
+        refreshAlways) {
         mailboxInfo->mActive = active;
         changed = true;
         if (active) {
-            // Mailbox becomes active again. Move to the bottom of the list.
-            mMailboxes.removeAll(mailboxInfo);
-            mMailboxes.append(mailboxInfo);
+            // Mailbox is not yet assigned to any indicator
+            if (mailboxInfo->mIndicatorIndex < 0) {
+                mailboxInfo->mIndicatorIndex = getIndicatorIndex();
+            }
+
+            updateIndicator(true,*mailboxInfo);
+        }
+        else {
+            // Indicator not anymore active. Release it.
+            if (mailboxInfo->mIndicatorIndex>=0) {
+                updateIndicator(false,*mailboxInfo);
+                mailboxInfo->mIndicatorIndex = NmAgentIndicatorNotSet;
+            }
         }
     }
     return changed;
 }
 
 /*!
-    Updates status according to current information
-*/
-void NmMailAgent::updateStatus()
-{
-    NMLOG("NmMailAgent::updateStatus");
-
-    int activeIndicators = 0;
-
-    // Update the indicators
-    foreach (NmMailboxInfo *mailboxInfo, mMailboxes) {
-        // Show only active mailboxes
-        if (mailboxInfo->mActive) {
-            updateIndicator(activeIndicators,true,*mailboxInfo);
-            activeIndicators++;
-        }
-    }
-
-    // Hide the indicator that are not needed anymore
-    for (int i=activeIndicators;i<mActiveIndicators;i++) {
-        NmMailboxInfo mailboxInfo;
-        updateIndicator(i,false,mailboxInfo);
-    }
-    mActiveIndicators = activeIndicators;
-}
-
-/*!
     Check if the mailbox indicator should be active, according to current state
     \param mailboxInfo information of the mailbox
     \return true if indicator should be now active
 */
 bool NmMailAgent::isMailboxActive(const NmMailboxInfo& mailboxInfo)
 {
-    if (mailboxInfo.mUnreadMails>0) {
+    if (mailboxInfo.mUnreadMails>0 || mailboxInfo.mOutboxMails>0) {
         return true;
     }
     return false;
@@ -250,14 +285,15 @@
     \param mailboxInfo information of the mailbox
     \return true if indicator was updated with no errors
 */
-bool NmMailAgent::updateIndicator(int mailboxIndex, bool active,
+bool NmMailAgent::updateIndicator(bool active,
     const NmMailboxInfo& mailboxInfo)
 {
     NMLOG(QString("NmMailAgent::updateIndicator index=%1 active=%2 unread=%3").
-        arg(mailboxIndex).arg(active).arg(mailboxInfo.mUnreadMails));
+        arg(mailboxInfo.mIndicatorIndex).arg(active).arg(mailboxInfo.mUnreadMails));
 
     bool ok = false;
-    QString name = QString("com.nokia.nmail.indicatorplugin_")+mailboxIndex+"/1.0";
+    QString name = QString("com.nokia.nmail.indicatorplugin_%1/1.0").
+        arg(mailboxInfo.mIndicatorIndex);
 
     QList<QVariant> list;
     list.append(mailboxInfo.mId.id());
@@ -265,6 +301,8 @@
     list.append(mailboxInfo.mUnreadMails);
     list.append(mailboxInfo.mSyncState);
     list.append(mailboxInfo.mConnectState);
+    list.append(mailboxInfo.mOutboxMails);
+    list.append(mSendingState);
 
     HbIndicator indicator;
     if (active) {
@@ -277,31 +315,59 @@
 }
 
 /*!
+    Get next free indicator index, starting from 0
+    @return index of the indicator that is available
+ */
+int NmMailAgent::getIndicatorIndex()
+{
+    int index = 0;
+    bool found(false);
+    do {
+        found = false;
+        foreach (NmMailboxInfo *mailbox, mMailboxes) {
+            if (mailbox->mIndicatorIndex == index &&
+                mailbox->mActive) {
+                found = true;
+                index++;
+            }
+        }
+    }
+    while( found );
+    return index;
+}
+
+/*!
     Received from NmFrameworkAdapter mailboxEvent signal
     \sa NmFrameworkAdapter
 */
 void NmMailAgent::handleMailboxEvent(NmMailboxEvent event, const QList<NmId> &mailboxIds)
 {
     NMLOG(QString("NmMailAgent::handleMailboxEvent %1").arg(event));
-    bool updateNeeded(false);
 
     switch(event) {
         case NmMailboxCreated:
             foreach (NmId mailboxId, mailboxIds) {
                 getMailboxInfo(mailboxId); // create a new mailbox if needed
-                updateNeeded = true;
             }
             break;
         case NmMailboxChanged:
+
             // Mailbox name may have been changed
             foreach (NmId mailboxId, mailboxIds) {
                 NmMailboxInfo *mailboxInfo = getMailboxInfo(mailboxId);
                 NmMailbox *mailbox(NULL);
-                mAdapter->getMailboxById(mailboxId,mailbox);
+                NmDataPluginInterface *plugin = mPluginFactory->interfaceInstance(mailboxId);
+                if (plugin) {
+					plugin->getMailboxById(mailboxId,mailbox);
+                }
                 if (mailbox && mailboxInfo) {
                     if(mailbox->name() != mailboxInfo->mName) {
                         mailboxInfo->mName = mailbox->name();
-                        updateNeeded = true;
+
+                        if (mailboxInfo->mActive) {
+                            // Update the status of the mailbox
+                            updateMailboxState(mailboxId, true, true);
+                        }
                     }
                 }
                 delete mailbox;
@@ -309,23 +375,18 @@
             break;
         case NmMailboxDeleted:
             foreach (NmId mailboxId, mailboxIds) {
-                if (removeMailboxInfo(mailboxId)) {
-                    updateNeeded = true;
-                }
+                // Will hide also the indicator
+                removeMailboxInfo(mailboxId);
             }
             break;
         default:
             break;
     }
-
-    if (updateNeeded) {
-        updateStatus();
-    }
 }
 
 /*!
     Received from NmFrameworkAdapter messageEvent signal
-    \sa NmFrameWorkAdapter
+    \sa NmFrameworkAdapter
 */
 void NmMailAgent::handleMessageEvent(
             NmMessageEvent event,
@@ -334,56 +395,114 @@
             const NmId& mailboxId)
 {
     NMLOG(QString("NmMailAgent::handleMessageEvent %1 %2").arg(event).arg(mailboxId.id()));
-    Q_UNUSED(folderId);
-    Q_UNUSED(messageIds);
+    bool updateNeeded = false;
 
     switch (event) {
+        case NmMessageCreated: {
+            NmMailboxInfo *mailboxInfo = getMailboxInfo(mailboxId);
+            
+            if (folderId==mailboxInfo->mInboxFolderId) {
+                mailboxInfo->mInboxCreatedMessages++;
+            }
+            
+            // When created a new mail in the outbox, we are in sending state
+            if (mailboxInfo->mOutboxFolderId == folderId) {
+                // The first mail created in the outbox
+                if (mailboxInfo->mOutboxMails <= 0) {
+                    updateNeeded = true;
+                }
+                mailboxInfo->mOutboxMails += messageIds.count();
+            }
+            break;
+        }
         case NmMessageChanged: {
             NmMailboxInfo *mailboxInfo = getMailboxInfo(mailboxId);
+            
+            if (folderId==mailboxInfo->mInboxFolderId) {
+                mailboxInfo->mInboxChangedMessages++;
+            }
+            
             // If not currently syncronizing the mailbox, this may mean
             // that a message was read/unread
             if (mailboxInfo && mailboxInfo->mSyncState==SyncComplete) {
-                // check the unread status here again
-                mailboxInfo->mUnreadMails = getUnreadCount(mailboxId,maxUnreadCount);
-                if(updateMailboxActivity(mailboxId, isMailboxActive(*mailboxInfo))) {
-                    updateStatus();
-                }
+                // check the unread status again
+                mailboxInfo->mUnreadMails = getUnreadCount(mailboxId,NmAgentMaxUnreadCount);
+                updateNeeded = true;
             }
 			break;
 		}
+        case NmMessageDeleted: {
+            NmMailboxInfo *mailboxInfo = getMailboxInfo(mailboxId);
+
+            if (folderId==mailboxInfo->mInboxFolderId) {
+                mailboxInfo->mInboxDeletedMessages++;
+            }
+            
+            // Deleted mails from the outbox
+            if (mailboxInfo->mOutboxFolderId == folderId) {
+                mailboxInfo->mOutboxMails -= messageIds.count();
+
+                // Sanity check for the outbox count
+                if (mailboxInfo->mOutboxMails < 0) {
+                    mailboxInfo->mOutboxMails = 0;
+                }
+
+                // The last mail was now deleted
+                if (mailboxInfo->mOutboxMails == 0) {
+                    updateNeeded = true;
+                }
+            }
+            break;
+        }
         default:
             break;
     }
 
-    // Do not perform an update here, just in handleSyncState
+    if (updateNeeded) {
+        NmMailboxInfo *mailboxInfo = getMailboxInfo(mailboxId);
+        updateMailboxState(mailboxId,
+            isMailboxActive(*mailboxInfo), true /* force refresh */);
+    }
 }
 
 /*!
     Received from NmFrameworkAdapter syncStateEvent signal
-    \sa NmFrameWorkAdapter
+    \sa NmFrameworkAdapter
 */
 void NmMailAgent::handleSyncStateEvent(
             NmSyncState state,
-            const NmId mailboxId)
+            const NmOperationCompletionEvent &event)
 {
-    NMLOG(QString("NmMailAgent::handleSyncStateEvent %1 %2").arg(state).arg(mailboxId.id()));
-    NmMailboxInfo *info = getMailboxInfo(mailboxId);
+    NMLOG(QString("NmMailAgent::handleSyncStateEvent %1 %2").arg(state).arg(event.mMailboxId.id()));
+    NmMailboxInfo *info = getMailboxInfo(event.mMailboxId);
     if (info) {
         info->mSyncState = state;
+        
+        if (state==Synchronizing) {
+            // Reset counters when sync is started
+            info->mInboxCreatedMessages = 0;
+            info->mInboxChangedMessages = 0;
+            info->mInboxDeletedMessages = 0;
+        } 
+        else if (state==SyncComplete) {
+            // Check the unread status here again
+            info->mUnreadMails = getUnreadCount(event.mMailboxId,NmAgentMaxUnreadCount);
 
-        if (state==SyncComplete) {
-            // check the unread status here again
-            info->mUnreadMails = getUnreadCount(mailboxId,maxUnreadCount);
-            if(updateMailboxActivity(mailboxId, isMailboxActive(*info))) {
-                updateStatus();
-            }
+            // Refresh the indicator if messages created or changed
+            NMLOG(QString(" created=%1, changed=%1, deleted=%1").
+                arg(info->mInboxCreatedMessages).
+                arg(info->mInboxChangedMessages).
+                arg(info->mInboxDeletedMessages));
+            bool refresh = (info->mInboxCreatedMessages > 0) || (info->mInboxChangedMessages > 0);
+
+            updateMailboxState(event.mMailboxId, isMailboxActive(*info), refresh);
         }
     }
 }
 
 /*!
     Received from NmFrameworkAdapter connectionState signal
-    \sa NmFrameWorkAdapter
+    \sa NmFrameworkAdapter
 */
 void NmMailAgent::handleConnectionEvent(NmConnectState state, const NmId mailboxId)
 {
@@ -393,7 +512,6 @@
         // Connecting, Connected, Disconnecting, Disconnected
         mailboxInfo->mConnectState = state;
     }
-    updateStatus();
 }
 
 /*!
@@ -405,6 +523,11 @@
     bool found = false;
     foreach (NmMailboxInfo *mailbox, mMailboxes) {
         if (mailbox->mId == id) {
+            // Hide the indicator too
+            if(mailbox->mIndicatorIndex>=0) {
+                updateIndicator(false,*mailbox);
+            }
+
             found = true;
             mMailboxes.removeAll(mailbox);
         }
@@ -420,18 +543,23 @@
 {
     // get information of the mailbox
     NmMailbox *mailbox = NULL;
-    mAdapter->getMailboxById(id, mailbox);
-    if (mailbox) {
-        return createMailboxInfo(*mailbox);
+    NmMailboxInfo *info = NULL;
+    NmDataPluginInterface *plugin = mPluginFactory->interfaceInstance(id);
+    if (plugin) {
+        plugin->getMailboxById(id, mailbox);
+        if (mailbox) {
+            info = createMailboxInfo(*mailbox,plugin);
+        }
     }
-    return NULL;
+
+    return info;
 }
 
 /*!
     Create a new mailbox info with given parameters
     \return new mailbox info object
 */
-NmMailboxInfo *NmMailAgent::createMailboxInfo(const NmMailbox& mailbox)
+NmMailboxInfo *NmMailAgent::createMailboxInfo(const NmMailbox& mailbox,NmDataPluginInterface *plugin)
 {
     NmMailboxInfo *mailboxInfo = new NmMailboxInfo();
     mailboxInfo->mId = mailbox.id();
@@ -440,7 +568,16 @@
     mMailboxes.append(mailboxInfo);
 
     // Subscribe to get all mailbox events
-    mAdapter->subscribeMailboxEvents(mailboxInfo->mId);
+    plugin->subscribeMailboxEvents(mailboxInfo->mId);
+
+    // get inbox folder ID
+    mailboxInfo->mInboxFolderId = plugin->getStandardFolderId(
+        mailbox.id(), NmFolderInbox );
+
+    // get outbox folder ID
+    mailboxInfo->mOutboxFolderId = plugin->getStandardFolderId(
+        mailbox.id(), NmFolderOutbox );
+
     return mailboxInfo;
 }