harvesterplugins/messaging/email/qtemailfetcher/qtemailfetcher.cpp
changeset 2 208a4ba3894c
child 3 6832643895f7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/harvesterplugins/messaging/email/qtemailfetcher/qtemailfetcher.cpp	Mon May 03 12:32:15 2010 +0300
@@ -0,0 +1,249 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Utility class for fetching email.
+*
+*/
+
+#include "qtemailfetcher.h"
+#include <csearchdocument.h>
+#include <cpixmaindefs.h>
+//#include <QThread> //If we happen to use QThread::yieldCurrentThread()
+
+//Symbian specific details; picked up from cemailplugin.cpp. 
+//Refactor it to cpixmaindefs.h
+_LIT(KMsgBaseAppClassGeneric, "root msg email");
+
+_LIT(KMsgSubject, "Subject");
+_LIT(KMsgRecipients, "Recipients");
+_LIT(KMsgBody, "Body");
+_LIT(KMimeTypeField, CPIX_MIMETYPE_FIELD);
+_LIT(KMimeTypeMsg, "Messages");
+
+//------------------------------------------------------------------------------
+QEmailFetcher::QEmailFetcher( MEmailItemObserver& aObserver )
+    :iEmailObserver( aObserver ), 
+     iEmailEventNotifier( NULL ),
+     iEmailService( NULL ),
+     iMailBoxListings( NULL ), 
+     iMailFolderList( NULL ),
+     iEnvelopeListing( NULL )
+    {
+    }
+
+//------------------------------------------------------------------------------
+QEmailFetcher::~QEmailFetcher()
+    {
+    delete iEmailEventNotifier;
+    delete iEmailService;
+    delete iMailBoxListings;
+    delete iMailFolderList;
+    }
+
+//------------------------------------------------------------------------------
+QEmailFetcher* QEmailFetcher::newInstance( MEmailItemObserver& aObserver ){
+    QEmailFetcher* emailFetcher = NULL;
+    
+    //Leak free init.
+    try{
+        QEmailFetcher* emailFetcher = new QEmailFetcher( aObserver );
+        //Uncomment 'this' once the actual APIs are ready.
+        emailFetcher->iEmailService = new NmEmailService( emailFetcher );
+        emailFetcher->iEmailEventNotifier =  new NmEventNotifier( emailFetcher );
+        emailFetcher->iMailBoxListings = new NmMailboxListing( emailFetcher );
+    }catch(...){ //cleanup.
+        delete emailFetcher; 
+        delete emailFetcher->iEmailService;
+        delete emailFetcher->iEmailEventNotifier;
+        delete emailFetcher->iMailBoxListings;
+        emailFetcher->iEmailService = NULL;
+        emailFetcher->iEmailEventNotifier = NULL;
+        emailFetcher->iMailBoxListings = NULL;
+        throw; //rethrow the exception to caller.
+    }
+    initialize( emailFetcher ); //Do the rest of the init.
+    return emailFetcher; //returns only if not null.
+}
+
+//------------------------------------------------------------------------------
+void QEmailFetcher::initialize( QEmailFetcher* aThis ){
+    //The use of 'aThis' is because the current function is static.
+    connect( aThis->iEmailService, SIGNAL(initialized(bool)), 
+             aThis, SLOT(emailServiceIntialized(bool)) );
+    aThis->iEmailService->initialise();
+    aThis->connect( aThis->iEmailEventNotifier, 
+                    SIGNAL(messageEvent(MessageEvent, quint64, quint64, QList<quint64>)),
+                    aThis, 
+                    SLOT(handleMessageEvent(MessageEvent, quint64, quint64, QList<quint64>)) );
+}
+
+//------------------------------------------------------------------------------
+void QEmailFetcher::emailServiceIntialized(bool aAllOk){
+    if( aAllOk ){
+        connect( iMailBoxListings, SIGNAL(mailboxesListed(int)), this, SLOT(handleMailboxesListed(int)) );
+    }
+}
+
+//------------------------------------------------------------------------------
+void QEmailFetcher::StartHarvesting(){
+    iMailBoxListings->start();
+}
+
+//------------------------------------------------------------------------------
+namespace {
+
+// Taken from qt/src/corelib/kernel/qcore_symbian_p.cpp, as recomended in
+// http://qt.nokia.com/files/pdf/whitepaper-using-qt-and-symbian-c-together, page 34.
+// URL last accessed on April 6th, 2010.
+
+// Returned TPtrC is valid as long as the given parameter is valid and unmodified
+static inline TPtrC qt_QString2TPtrC( const QString& string )
+{
+    return TPtrC16(static_cast<const TUint16*>(string.utf16()), string.length());
+}
+
+//------------------------------------------------------------------------------
+// TODO Remove this code if qt_QString2TPtrC works.
+// TODO If this function is used, remember to release memory.
+// Ownership with caller.
+//HBufC* qt_QString2HBufC(const QString& aString)
+//{
+//    HBufC *buffer;
+//#ifdef QT_NO_UNICODE
+//    TPtrC8 ptr(reinterpret_cast<const TUint8*>(aString.toLocal8Bit().constData()));
+//#else
+//    TPtrC16 ptr(qt_QString2TPtrC(aString));
+//#endif
+//    buffer = q_check_ptr(HBufC::New(ptr.Length()));
+//    buffer->Des().Copy(ptr);
+//    return buffer;
+//}
+
+//------------------------------------------------------------------------------
+//Private free function creates CSearchDocument from EMailMessageEnvelope.
+CSearchDocument* getSearchDocument( const NmMessageEnvelope& aEnvelope ){
+    QList<NmEmailAddress> toList;
+    //Need to cast away const-ness since the get method is unfortunately not const.
+    const_cast<NmMessageEnvelope&>(aEnvelope).getToRecipients( toList );
+
+    //We need ALL the recipients in a SINGLE field.
+    QString recipients = "";
+    for( int i=0; i<toList.length(); i++ )
+        recipients += toList.at( i ).displayName() + " "; //or should we get address?
+
+    NmMessageBody body;
+    //Cast away const-ness since the get method is unfortunately not const.
+    //Returns void. Cannot check for success/failure.
+    const_cast<NmMessageEnvelope&>(aEnvelope).getPlainTextBody( body ); 
+    QString msgBody = body.content();
+
+    CSearchDocument* doc = 0;
+    QT_TRAP_THROWING(
+    //Use qt_Qstring2TPtrC since we are working with <b>const</b> EmailMessageEnvelope.
+    doc = CSearchDocument::NewL( qt_QString2TPtrC( QString().setNum( aEnvelope.id() ) ), 
+                                 KMsgBaseAppClassGeneric );
+    doc->AddFieldL( KMimeTypeField, KMimeTypeMsg, CDocumentField::EStoreYes | CDocumentField::EIndexUnTokenized);
+    doc->AddFieldL( KMsgSubject, qt_QString2TPtrC( aEnvelope.subject() ), CDocumentField::EStoreYes | CDocumentField::EIndexTokenized );
+    doc->AddFieldL( KMsgRecipients, qt_QString2TPtrC( recipients ), CDocumentField::EStoreYes | CDocumentField::EIndexTokenized );
+    doc->AddFieldL( KMsgBody, qt_QString2TPtrC( msgBody ), CDocumentField::EStoreYes | CDocumentField::EIndexTokenized );
+    //TODO: What should go in here?
+    doc->AddExcerptL( KNullDesC );
+    );
+    return doc;
+}
+} //anonymous namespace
+
+//------------------------------------------------------------------------------
+//Options to make async (like other plugins' Asynchronizer):
+//1. Use http://doc.trolltech.com/4.6/qtimer.html and connect timeout() signal to something?
+//Downside: 
+//Have to save the state of the function and resume. Achievable via static members. 
+//Remeber to reset counters.
+//2. Use timer; unlike above, have handleMailboxesListed() simply trigger a  
+//Timer controlled function.
+//3. Use QThread::currentThread()->yieldCurrentThread();
+//Downside: Not tested.
+//4. As recommended by the email API documentation, use SingleShotTimer:
+//QTimer::singleShot(nsecs,nmFolderListing,SLOT(start());
+//
+//Recommendation: Use option 4.
+
+void QEmailFetcher::handleMailboxesListed(int aCount){
+    QList<NmMailbox> mailBoxes;
+    if( aCount>0 && iMailBoxListings->getMailboxes( mailBoxes ) ){
+        for( int i=0; i<aCount; i++ ){
+            //Already set to NULL in constructor, so safe to call delete first time.
+            delete iMailFolderList; iMailFolderList = NULL;
+            iMailFolderList = new NmFolderListing( this, mailBoxes.at( i ).id() );
+            connect( iMailFolderList, SIGNAL(foldersListed()), this, SLOT(mailFoldersListed()) );
+            const int waitForSeconds = 30; //TODO Move this constant out of here if needed elsewhere
+            QTimer::singleShot( waitForSeconds, iMailFolderList, SLOT( start()) );
+        }
+    }
+}
+
+//------------------------------------------------------------------------------
+void QEmailFetcher::mailFoldersListed(int aCount){
+    if( aCount == NmFolderListing::FolderListingFailed ) return; //silently.
+    QList<NmFolder> folders;
+    if ( aCount && iMailFolderList->getFolders( folders ) ) {
+        for( int i=0; i<aCount; i++ ){
+            //Already set to NULL in constructor, so safe to call delete first time.
+            delete iEnvelopeListing; iEnvelopeListing = NULL; 
+            iEnvelopeListing = new NmEnvelopeListing( this, folders.at( i ).id(), 0 );
+            connect(iEnvelopeListing, SIGNAL(envelopesListed(int)),this,SLOT(processMessages(int)));
+            iEnvelopeListing->start();
+        }
+    }
+}
+
+//------------------------------------------------------------------------------
+void QEmailFetcher::processMessages(int aCount){
+    if( aCount == NmMailboxListing::MailboxListingFailed ) return; //silently.
+    QList<NmMessageEnvelope> envelopes;
+    if ( aCount > 0 && iEnvelopeListing->getEnvelopes(envelopes) ) {
+        for( int i=0; i<envelopes.count(); i++ ) {
+        const NmMessageEnvelope &envelope = envelopes.at( i );
+        //Create document and call back observer.
+        QT_TRAP_THROWING( iEmailObserver.HandleDocumentL( getSearchDocument( envelope ), ECPixAddAction ) );
+        }
+    }
+}
+
+//------------------------------------------------------------------------------
+void QEmailFetcher::handleMessageEvent( const MessageEvent aEvent, quint64 aMailboxId, quint64 aFolderId, QList<quint64> aMessageList){
+    NmMessageEnvelope envelope;
+    const int messageCount = aMessageList.count();
+    if( messageCount>0 ){
+    if( aEvent == MessageCreated || aEvent == MessageChanged ){
+        for( int i=0; i<messageCount; i++ ){
+            if( iEmailService->getEnvelope( aMailboxId, aFolderId, aMessageList.at( i ), envelope ) ){
+                QT_TRAP_THROWING( 
+                   iEmailObserver.HandleDocumentL( getSearchDocument( envelope ), 
+                           //Doing this simply avoids *duplicate* code for update action.
+                           aEvent == MessageCreated ? ECPixAddAction : ECPixUpdateAction ) );
+            }
+        }
+    }
+    else if( aEvent == MessageDeleted ) {
+        //TODO We can do better. For delete, we dont have to create full document. Just the ID should be enough.
+        //We can have another function called getPartialSearchDocument so deletes will be faster.
+        for( int i=0; i<messageCount; i++ ){
+            if( iEmailService->getEnvelope( aMailboxId, aFolderId, aMessageList.at( i ), envelope ) ){
+                QT_TRAP_THROWING( 
+                iEmailObserver.HandleDocumentL( getSearchDocument( envelope ), ECPixRemoveAction ) );
+            }
+        }
+    }
+    }
+}