commands/sms/smsevent.cpp
changeset 0 7f656887cf89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/sms/smsevent.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,303 @@
+// smsevent.cpp
+// 
+// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "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:
+// Accenture - Initial contribution
+//
+
+#include "smsevent.h"
+#include "sms.h"
+
+_LIT(KInternationlDialDirectIndicator,	"+");
+
+//
+// CSmsEventBase
+//
+CSmsEventBase::CSmsEventBase(CCmdSms& aObserver):
+CActive(CActive::EPriorityStandard), iObserver(aObserver)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+//
+// CSmsEventDial
+//
+CSmsEventDial* CSmsEventDial::NewL(CCmdSms& aObserver, RCall::TTelNumberC& aTelNumber)
+	{
+	CSmsEventDial* self = new (ELeave) CSmsEventDial(aObserver);
+	CleanupStack::PushL(self);
+	self->ConstructL(aTelNumber);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CSmsEventDial::CSmsEventDial(CCmdSms& aObserver):
+CSmsEventBase(aObserver), iState(ESmsEventNetworkIdle)
+	{
+	}
+
+CSmsEventDial::~CSmsEventDial()
+	{
+	Cancel();
+	iTimeout.Cancel();
+	iTimeout.Close();
+	if (iCall.SubSessionHandle() > 0)
+		iCall.Close(); // should also force a hangup on the call object if it's active
+	if (iLine.SubSessionHandle() > 0)
+		iLine.Close();
+	if (iPhone.SubSessionHandle() > 0)
+		iPhone.Close();
+	if (iTelServer.Handle() > 0)
+		iTelServer.Close();
+	}
+
+void CSmsEventDial::ConstructL(RCall::TTelNumberC& aTelNumber)
+	{
+	// timeout timer 
+	iTimeout.CreateLocal();
+	
+	// capture the number to dial
+	iNumber.iTypeOfNumber = RMobilePhone::ENationalNumber;
+	iNumber.iNumberPlan = RMobilePhone::EIsdnNumberPlan;
+	iNumber.iTelNumber.Copy(aTelNumber);
+	
+	// check if there's a '+' at the front of the number
+	if (aTelNumber.MatchC(KInternationlDialDirectIndicator) == 0)
+		iNumber.iTypeOfNumber = RMobilePhone::EInternationalNumber;
+	
+	// connect to ETel. Note we're assuming the TSY has been loaded already
+	RTelServer::TPhoneInfo phoneInfo;
+	User::LeaveIfError(iTelServer.Connect());
+	User::LeaveIfError(iTelServer.GetPhoneInfo(0, phoneInfo));
+	
+	// open the first phone object
+	User::LeaveIfError(iPhone.Open(iTelServer, phoneInfo.iName));
+	
+	// find the voice line & open it
+	TInt lines = 0;
+	RPhone::TLineInfo lineInfo;
+	User::LeaveIfError(iPhone.EnumerateLines(lines));
+	if (lines <= 0)
+		User::Leave(KErrNotSupported);
+	for (TInt ii = 0 ; ii < lines ; ii++)
+		{
+		User::LeaveIfError(iPhone.GetLineInfo(ii, lineInfo));
+		if (lineInfo.iLineCapsFlags & RLine::KCapsVoice)
+			{
+			// found our voice line
+			if (lineInfo.iStatus > RCall::EStatusIdle)
+				User::Leave(KErrInUse);
+			User::LeaveIfError(iLine.Open(iPhone, lineInfo.iName));
+			break;
+			}
+		}
+	if (iLine.SubSessionHandle() <= 0)
+		User::Leave(KErrNotFound);
+	
+	// create a voice call (note it's not currently active)
+	User::LeaveIfError(iCall.OpenNewCall(iLine, iCallName));
+	}
+
+//
+// CSmsEventDial::StartL
+// start the dial-out procedure, beginning
+// with a check of the network, line/call status
+//
+void CSmsEventDial::StartL()
+	{
+	User::LeaveIfError(iLine.GetMobileLineStatus(iCallStatus));
+	if (iCallStatus > RMobileCall::EStatusIdle)
+		User::Leave(KErrInUse);
+	
+	// some product tsy implementations can't handle a dial request immediately following receiving an sms. so we wait a little bit..5 seconds in fact
+	iTimeout.After(iStatus, 5000000);
+	SetActive();
+	iState = ESmsEventDial;
+	}
+
+void CSmsEventDial::RunL()
+	{
+	User::LeaveIfError(iStatus.Int()); // process the error elsewhere
+	switch (iState)
+		{
+		case ESmsEventDial:
+			{
+			// dial the number
+			iCall.Dial(iStatus, iNumber.iTelNumber);
+			SetActive();
+			iState = ESmsEventStatusChange;
+			}
+		break;
+				
+		case ESmsEventWatchStatus:
+		case ESmsEventStatusChange:
+			{
+			User::LeaveIfError(iCall.GetMobileCallStatus(iCallStatus));
+			if (iCallStatus > RMobileCall::EStatusIdle)
+				{
+				// keep the call going until it drops
+				iCall.NotifyMobileCallStatusChange(iStatus, iCallStatus);
+				SetActive();
+				iState = ESmsEventWatchStatus;
+				return;
+				}
+			}
+		break;
+		
+		default:
+		break;
+		};
+	}
+
+//
+// CSmsEventDial::RunError
+// inform the observer we hit a prob. with execution of the dial state machine
+//
+TInt CSmsEventDial::RunError(TInt /*aError*/)
+	{
+	//TODO iObserver.EventComplete(aError); 
+	return KErrNone;
+	}
+
+void CSmsEventDial::DoCancel()
+	{
+	switch (iState)
+		{
+		case ESmsEventDial:
+			iTimeout.Cancel();
+		break;
+		
+		case ESmsEventStatusChange:
+			iCall.DialCancel();
+		break;
+		
+		case ESmsEventWatchStatus:
+			iCall.NotifyStatusChangeCancel();			
+		break;
+		
+		default:
+		break;
+		};
+	}
+
+CSmsShellCommand* CSmsShellCommand::NewL(CCmdSms& aObserver, const TDesC& aCommandText, const TDesC& aSenderAddress)
+	{
+	CSmsShellCommand* self = new(ELeave) CSmsShellCommand(aObserver);
+	CleanupStack::PushL(self);
+	self->ConstructL(aCommandText, aSenderAddress);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CSmsShellCommand::CSmsShellCommand(CCmdSms& aObserver)
+	: CSmsEventBase(aObserver)
+	{
+	}
+
+void CSmsShellCommand::ConstructL(const TDesC& aCommandText, const TDesC& aSenderAddress)
+	{
+	iSmsSender.CreateL(aSenderAddress);
+	// Set up environment for script
+	iScriptEnv = CEnvironment::NewL(iObserver.Env());
+	_LIT(KSmsSenderEnvironmentVariable, "SMS_SENDER");
+	iScriptEnv->SetL(KSmsSenderEnvironmentVariable, iSmsSender);
+
+	const TDesC* scriptName = NULL;
+	_LIT(KFshellName, "C:\\shared\\fshellscript%d.script");
+	_LIT(KPerlName, "C:\\shared\\perlscript%d.pl");
+	if (aCommandText.MatchF(_L("#!fshell*")) == 0)
+		{
+		iExeName = _L("fshell.exe");
+		scriptName = &KFshellName;
+		}
+	else if (aCommandText.MatchF(_L("#!perl*")) == 0)
+		{
+		iExeName = _L("perl.exe");
+		scriptName = &KPerlName;
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}	
+	
+	RBuf8 buf;
+	CleanupClosePushL(buf);
+	buf.CreateL(aCommandText.Length());
+	buf.Copy(aCommandText);
+
+	RFile scriptFile;
+	CleanupClosePushL(scriptFile);
+	TInt nonce = 0;
+	iObserver.Fs().MkDirAll(*scriptName);
+	TInt err = KErrNone;
+	do {
+		iScriptFile.Format(*scriptName, nonce);
+		nonce++;
+		err = scriptFile.Create(iObserver.Fs(), iScriptFile, EFileShareAny|EFileWrite);
+		} while (err == KErrAlreadyExists);
+	User::LeaveIfError(scriptFile.Write(buf));
+	CleanupStack::PopAndDestroy(2, &buf);
+	}
+
+void CSmsShellCommand::StartL()
+	{
+	iProcess.CreateL(iExeName, iScriptFile, iObserver.IoSession(), iObserver.Stdin(), iObserver.Stdout(), iObserver.Stderr(), *iScriptEnv);
+	iProcess.Run(iStatus);
+	SetActive();
+	}
+
+void CSmsShellCommand::DoCancel()
+	{
+	iProcess.Process().LogonCancel(iStatus);
+	}
+
+CSmsShellCommand::~CSmsShellCommand()
+	{
+	Cancel();
+	iProcess.Close();
+	if (!iObserver.Debug())
+		{
+		iObserver.Fs().Delete(iScriptFile);
+		}
+	delete iScriptEnv;
+	iSmsSender.Close();
+	}
+
+void CSmsShellCommand::RunL()
+	{
+	TExitType exitType = iProcess.Process().ExitType();
+	TInt exitReason = iProcess.Process().ExitReason();
+	TBool ok = exitType == EExitKill && exitReason == 0;
+	if (ok)
+		{
+		iObserver.Printf(_L("Script from %S completed ok.\r\n"), &iSmsSender);
+		}
+	else
+		{
+		TInt err = exitReason;
+		if (err >= 0) err = KErrGeneral;
+		switch (iProcess.Process().ExitType())
+			{
+			case EExitKill:
+				iObserver.PrintError(err, _L("Script %S failed, returned %d"), &iScriptFile, exitReason);
+				break;
+			case EExitTerminate:
+				iObserver.PrintError(err, _L("Script %S terminated with %d"), &iScriptFile, exitReason);
+				break;
+			case EExitPanic:
+				{
+				TExitCategoryName cat = iProcess.Process().ExitCategory();
+				iObserver.PrintError(err, _L("Script %S panicked with %S %d"), &iScriptFile, &cat, exitReason);
+				break;
+				}
+			default:
+				break;
+			}
+		}
+	delete this;
+	}