messagingfw/biomsgfw/BIOCSRC/BIOOP.CPP
changeset 0 8e480a14352b
child 44 7c176670643f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/biomsgfw/BIOCSRC/BIOOP.CPP	Mon Jan 18 20:36:02 2010 +0200
@@ -0,0 +1,460 @@
+// Copyright (c) 2004-2009 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:
+// This class contains the parsing and processing of BIO messages.
+// This functionality was originally carried out in the BIO Server MTM but
+// has been moved to the Client MTM for reasons of capability. Potentially,
+// BIO parsers may need additional capabilities for their processing and it would
+// be difficult to ensure that the Message Server (and all other server MTMs) had
+// the same capabilities.  By moving the processing to the Client MTM it is only 
+// the client UI app that needs the additional capabilities.
+// Parsing and processing of a message is initiated by calling StartCommandL().
+// The command function can be one of the following:
+// KBiosMtmParse - just parse the message
+// KBiosMtmParseThenProcess - parse the message and then process it
+// KBiosMtmProcess - just process the mesage (must have been parsed previously)
+// Parsing a message involves finding the relevant BIO parser, loading it and then calling
+// ParseL() on the parser.
+// Processing a message involves finding the relevant BIO parser, loading it and then
+// calling ProcessL() on the parser.
+// To avoid unresponsiveness, a parse-then-process command is carried out in two steps.
+// The parsing is carried out first and then the AO is set up so the processing is
+// carried out in a separate RunL().
+// Both the parser ParseL() and parser ProcessL() are asynchronous methods.
+// 
+//
+
+#include <e32uid.h>   	
+#include <msvstd.h>
+#include <biodb.h>		// bio database
+#include <biouids.h>	// contains panic codes
+#include <txtrich.h>
+#include <txtfmlyr.h>
+
+#include "BIOSCMDS.H"
+#include "regpsdll.h"   // Parser Registry - used to load the parser
+#include "bsp.h"		// CBaseScriptParser, CBaseScriptParser2
+#include "BIOOP.H"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <biomessageuids.h>
+#include "tmsvbioinfo.h"
+#endif
+
+// panic text
+_LIT(KBioOpPanic, "BIOO");
+	
+CBIOOperation* CBIOOperation::NewL(RFs aRFs, CMsvSession& aSession, CBIODatabase* aBDB, TRequestStatus& aCompletionStatus)
+	{
+	CBIOOperation* self=new(ELeave) CBIOOperation(aRFs, aSession, aBDB, aCompletionStatus);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+CBIOOperation::CBIOOperation(RFs aRFs, CMsvSession& aSession, CBIODatabase* aBDB, TRequestStatus& aCompletionStatus)
+: CMsvOperation(aSession, EPriorityStandard, aCompletionStatus), 
+iFs(aRFs), iBioDatabase(aBDB), iInOperation(EFalse)
+	{
+	}
+
+	
+void CBIOOperation::ConstructL()
+//
+// 2nd phase construction
+//
+	{
+	// initiallise progress
+	iProgress.iBioState = TBioProgress::EBiosWaiting;
+
+	// create msv entry
+	iCurrentEntry = CMsvEntry::NewL(iMsvSession, KMsvRootIndexEntryIdValue, TMsvSelectionOrdering());
+	
+	// add active object
+	CActiveScheduler::Add(this);
+	}
+
+
+CBIOOperation::~CBIOOperation()
+	{
+	Cancel();
+	delete iParser;
+	delete iCurrentEntry;
+	delete iRegisteredParserDll;
+	delete iMessageBody;
+	}
+
+
+void CBIOOperation::StartCommand(const CMsvEntrySelection& aSelection, TInt aCommand, TRequestStatus& aStatus)
+//
+// BIOServer specific commands
+//
+	{
+	__ASSERT_DEBUG(iBioOperationState == EBiooWaiting, User::Panic(KBioOpPanic, KBIOMessageOperationNotInactive));
+	__ASSERT_ALWAYS(aSelection.Count() >= 1, User::Panic(KBioOpPanic, KBIOMessageNotFound));
+	
+	// to notify caller on completion
+	iReportStatus = &aStatus;
+	aStatus = KRequestPending;
+
+	TMsvId service;
+	TMsvEntry entry;
+
+	TInt error = iMsvSession.GetEntry(aSelection.At(0), service, entry);
+
+	iMtm = entry.iMtm;   
+	iService = entry.iServiceId; 
+
+	// perform the command, no need to go on if we already got an error
+	if (error == KErrNone)
+		{
+		switch (aCommand)
+			{
+		case KBiosMtmParse:
+			TRAP(error, ParseL(aSelection, EFalse));
+			break;
+		case KBiosMtmParseThenProcess:
+			TRAP(error, ParseL(aSelection, ETrue));
+			break;
+		case KBiosMtmProcess:
+			TRAP(error, ProcessL(aSelection));
+			break;
+		default:
+			error = KErrNotSupported;
+			break;
+			}
+		};
+	
+	// check for errors	
+	if (error != KErrNone)
+		{
+		// complete
+		iStatus = KRequestPending;
+		TRequestStatus* stat = &iStatus;
+		SetActive();
+		User::RequestComplete(stat, error);
+		}
+	}
+
+
+void CBIOOperation::DoCancel()
+//
+// Cancel
+//
+	{
+	if (iParser)
+		iParser->Cancel();
+	iInOperation = EFalse;
+	User::RequestComplete(iReportStatus, KErrCancel);
+	}
+
+
+void CBIOOperation::RunL()
+//
+// Active object RunL
+//
+	{
+	TInt error = iStatus.Int();
+	if (error == KErrNone)
+		{
+		switch (iBioOperationState)
+			{
+		case EBiooParsing:
+			{
+			iCurrentEntry->SetEntryL(iCurrentMsvId);
+
+			if (iBioOperationOperation == EBioParseAndProcess)
+				{
+				iBioOperationState = EBiooWaiting;
+				ProcessL();
+				}
+			else
+				{
+				iBioOperationState = EBiooComplete;
+				}
+			break;
+			}
+		case EBiooProcessing:
+			iBioOperationState = EBiooComplete;
+		case EBiooCreating:
+		case EBiooWaiting:
+		default:
+			break;
+			}
+		}
+
+	if (iBioOperationState == EBiooComplete || error != KErrNone)
+		{
+		RunError(error);
+		}
+	}
+
+
+TInt CBIOOperation::RunError(TInt aError)
+	{
+	// also called with aError == KErrNone
+	TMsvEntry entry = iCurrentEntry->Entry();
+	entry.SetReadOnly(ETrue);
+	TInt error = KErrNone;
+	TRAP(error,iCurrentEntry->ChangeL(entry));
+		
+	iBioOperationState = EBiooWaiting;
+	iInOperation = EFalse;
+	iProgress.iErrorCode = aError;
+		
+	User::RequestComplete(iReportStatus, aError);
+	
+	return error;
+	}
+
+
+void CBIOOperation::ParseL(const CMsvEntrySelection& aSelection, TBool aCommit)
+	{
+	// parse and process?
+	iBioOperationOperation = aCommit ? EBioParseAndProcess : EBioParseOnly;
+
+	// set context
+    iCurrentMsvId = aSelection[0];
+	iCurrentEntry->SetEntryL(iCurrentMsvId);
+
+	// check if it's alreadly parsed
+	// iMtmData3 == 0 => not yet parsed
+	// iMtmData3 == 1 => parsed
+	// iMtmData3 == 2 => processed
+	if (iCurrentEntry->Entry().MtmData3()==EBioMsgNotParsed)
+		{
+		// put in check that it's a valid SMS/smart message	
+		StartParserL();
+		}
+	else if (iCurrentEntry->Entry().MtmData3()==EBioMsgParsed || 
+			 iCurrentEntry->Entry().MtmData3()==EBioMsgProcessed)
+		{
+		iStatus = KRequestPending;
+		TRequestStatus* ps = &iStatus;
+		SetActive();
+		User::RequestComplete(ps, KErrNone);
+		iProgress.iBioState = TBioProgress::EBiosCreating;
+
+		if (iBioOperationOperation == EBioParseAndProcess)
+			{
+			iBioOperationState = EBiooParsing;
+			CreateParserL();
+			}
+		else
+			{
+			iBioOperationState = EBiooComplete;
+			}
+		}
+	else
+		{
+		User::Leave(KErrCorrupt);
+		}
+	iInOperation = ETrue;
+	}
+
+
+void CBIOOperation::CreateParserL()
+	{
+
+	// get bio type uid from message	
+	TUid parserUid;
+	parserUid.iUid = iCurrentEntry->Entry().iBioType;
+
+	// check if we already have a parser and if it's the correct one
+	if ((iParser != NULL) && (parserUid != iParser->ParserUid()))
+		{
+		// first delete the old parser before creating the new one
+		delete iParser;
+		iParser = NULL;
+		}
+		
+	if (iParser == NULL)
+		{	
+	  	// create the local variables 
+		if (parserUid.iUid == 0)
+			User::Leave(KBspSmartMessageNoParserDefined);
+		
+		// get parser filename for loading
+		TFileName parserDllName(iBioDatabase->GetBioParserNameL(parserUid));
+		
+		// create dll registry
+		delete iRegisteredParserDll;
+		iRegisteredParserDll = NULL;
+		iRegisteredParserDll = CRegisteredParserDll::NewL(parserDllName);
+
+		// get handle to dll		
+		RLibrary parserlibrary;
+		User::LeaveIfError(iRegisteredParserDll->GetLibrary(iFs, parserlibrary));
+
+		// create a typedef so that we can make a call to the dll to create a parser.
+		typedef CBaseScriptParser2* (*NewParserL)(CRegisteredParserDll& registeredparserdll, CMsvEntry& aEntry, RFs& aFs);
+		
+		// entry point for NewL function found at ordinal 1
+		TLibraryFunction libFunc = parserlibrary.Lookup(1);
+		
+		// check that we found the entry point
+		if (libFunc == NULL) 
+			User::Leave(KErrBadLibraryEntryPoint) ;
+
+		// create a function pointer to NewL
+		NewParserL pFunc = (NewParserL)libFunc;  
+		CBaseScriptParser2* parser(NULL);
+	
+		TInt refcount = iRegisteredParserDll->DllRefCount();
+		TRAPD(ret, parser = ((*pFunc)(*iRegisteredParserDll, *iCurrentEntry, iFs)));
+
+	    // unload the library if allocation failed and refcount == 1
+		if ((ret != KErrNone) && (iRegisteredParserDll->DllRefCount() == refcount))
+			iRegisteredParserDll->ReleaseLibrary();
+		
+		// leave if error
+		User::LeaveIfError(ret);
+		iParser = parser;
+		}
+	}
+
+
+void CBIOOperation::StartParserL()
+//
+// We have a parser parse the message (fire up the parser)
+//
+	{
+	__ASSERT_DEBUG(iBioOperationState == EBiooWaiting, User::Panic(KBioOpPanic, KBIOMessageOperationNotInactive));
+	
+	// get the msg body
+	ExtractMessageBodyL();
+
+	// create parser
+	CreateParserL();
+
+	// set the entry and start the parser (parser takes ownership of entry)
+    // make sure it points to the message
+    iCurrentEntry->SetEntryL(iCurrentMsvId);
+
+	// make the entry editable
+	TMsvEntry entry(iCurrentEntry->Entry());
+	entry.SetReadOnly(EFalse);
+	iCurrentEntry->ChangeL(entry);
+	
+	// parse 
+	iParser->ParseL(iStatus, *iMessageBody);
+	SetActive();
+	
+	iBioOperationState = EBiooParsing;
+	iProgress.iBioState = TBioProgress::EBiosParsing;
+	}
+
+
+void CBIOOperation::ExtractMessageBodyL()
+//
+// Get the message body
+//
+	{
+	// build a CRichText object to read in message body
+	CParaFormatLayer* paraFormatLayer = CParaFormatLayer::NewL();
+    CleanupStack::PushL(paraFormatLayer);
+    CCharFormatLayer* charFormatLayer = CCharFormatLayer::NewL();
+    CleanupStack::PushL(charFormatLayer);
+    CRichText* richText = CRichText::NewL(paraFormatLayer, charFormatLayer);
+    CleanupStack::PushL(richText);
+
+	// get store holding message body
+    CMsvStore* store = iCurrentEntry->ReadStoreL();
+	CleanupStack::PushL(store);
+
+	// check for message body
+    if (!store->HasBodyTextL())
+    	User::Leave(KErrNotFound);
+	
+    // extract the body text
+    store->RestoreBodyTextL(*richText);
+    
+    // create buffer to hold body text
+	TInt messageLength = richText->DocumentLength();
+	if (iMessageBody)
+		{
+		delete iMessageBody;
+		iMessageBody = NULL;
+		}
+	iMessageBody = HBufC::NewL(messageLength);
+
+	// read in message body
+	TPtr messDes = iMessageBody->Des();
+	TInt length = messDes.Length();
+	while (length < messageLength)
+		{
+		TPtrC desc = richText->Read(length, messageLength-length);
+		messDes.Append(desc);
+		length+=desc.Length();
+		}
+	CleanupStack::PopAndDestroy(4, paraFormatLayer); // store, text, charFormatLayer, paraFormatLayer
+	}
+
+
+void CBIOOperation::ProcessL(const CMsvEntrySelection& aSelection)
+//
+// successfully parsed the message - do the settings
+//
+	{
+	// set operation
+	iBioOperationOperation = EBioProcess;
+
+	// get the id of the bio message
+    iCurrentMsvId = aSelection[0];
+	iCurrentEntry->SetEntryL(iCurrentMsvId);
+
+	CreateParserL();
+
+	iInOperation = ETrue;
+	ProcessL();
+	}
+	
+	
+void CBIOOperation::ProcessL()
+//
+// successfully parsed the message - do the settings
+//
+	{
+	__ASSERT_DEBUG(iBioOperationState == EBiooWaiting, User::Panic(KBioOpPanic, KBIOMessageOperationNotInactive));
+
+	if (iInOperation == EFalse)
+		User::Leave(KErrDisconnected);
+	
+	__ASSERT_ALWAYS(iParser != NULL, User::Panic(KBioOpPanic, KBIOMessageNoParserCreated));
+	iProgress.iBioState = TBioProgress::EBiosProcessing;
+	
+	// make entry readable so we can change things
+	TMsvEntry entry = iCurrentEntry->Entry();
+	if (entry.ReadOnly())
+		{
+		entry.SetReadOnly(EFalse);
+		iCurrentEntry->ChangeL(entry);
+		}
+
+	// start to process message
+	iParser->ProcessL(iStatus);
+	SetActive();
+	
+	iBioOperationState = EBiooProcessing;
+	}
+	
+	
+const TDesC8& CBIOOperation::ProgressL()
+//
+// get progress information
+//
+	{
+	iProgressBuf = TBioProgressBuf(iProgress);
+	return iProgressBuf;
+	}