diff -r 000000000000 -r 7f656887cf89 commands/sms/smswatch.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commands/sms/smswatch.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,298 @@ +// smswatch.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 "smswatch.h" +#include +#include +#include +#include "sms.h" + +// __TEST_MODE__ provides a dummy autometric command +//#define __TEST_MODE__ + +#undef ASSERT +#define ASSERT(x) if (!(x)) { iParent.Printf(_L8("Assertion failed at line %d: " #x "\r\n"), __LINE__); PanicMe(__LINE__); } + +// local static method definitions +static void PanicMe(TInt aError) + { + _LIT(KSmsWatcherPanic, "AmSms"); + User::Panic(KSmsWatcherPanic, aError); + } + +// +// CSmsWatcher +// +CSmsWatcher* CSmsWatcher::NewL(CCmdSms& aParent) + { + CSmsWatcher* self = new (ELeave) CSmsWatcher(aParent); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +CSmsWatcher::CSmsWatcher(CCmdSms& aParent) + : CActive(CActive::EPriorityStandard), iParent(aParent), iState(ESmsListenIdle) + { + CActiveScheduler::Add(this); + } + +CSmsWatcher::~CSmsWatcher() + { + Cancel(); + delete iMessage; + iCommand.Close(); + if (iSocket.SubSessionHandle() > 0) + iSocket.Close(); + if (iSocketServer.Handle() > 0) + iSocketServer.Close(); + } + +void CSmsWatcher::ConstructL() + { + // connect to the sms socket + User::LeaveIfError(iSocketServer.Connect()); + User::LeaveIfError(iSocket.Open(iSocketServer,KSMSAddrFamily,KSockDatagram,KSMSDatagramProtocol)); + iSmsAddr.SetSmsAddrFamily(ESmsAddrMatchText); + _LIT8(KShebang, "#!"); + iSmsAddr.SetTextMatch(KShebang()); + User::LeaveIfError(iSocket.Bind(iSmsAddr)); + } + +void CSmsWatcher::DoCancel() + { + switch(iState) + { + case ESmsListenReadSms: + case ESmsListenProcessSms: + case ESmsListenIdle: // This could happen when signalling failure via KIoctlReadMessageFailed + iSocket.CancelIoctl(); + break; + default: + PanicMe(__LINE__); + } + } + + +void CSmsWatcher::RunL() + { + iErrorMessage.Zero(); + if (iStatus.Int() < 0) + { + iErrorMessage.AppendFormat(_L("Error reported from CSmsWatcher::RunL")); + User::Leave(iStatus.Int()); // process any errors elsewhere + } + + switch(iState) + { + case ESmsListenReadSms: + ReadSmsAndRespondToStackL(); // inform the stack we've got the sms + break; + + case ESmsListenProcessSms: + ProcessCommandL(); // process the contents of the sms + WaitForMessage(); // Start listening for another message (RunError will call it if ProcessCommandL leaves) + break; +#ifdef __TEST_MODE__ + case ESmsListenTestMode: + { + // a test mode skipping reception & decoding of an autometric sms + //_LIT(KTestMsg, "!#AUTOMETRIC;d:0243261943;?"); + _LIT(KTestMsg, "#!fshell\ninfoprint \"hello world!\"\n"); + ParseBufferL(KTestMsg, _L("012345678")); + } + break; +#endif + case ESmsListenIdle: + //CompleteWatch(KErrCompletion); // indicate an error with a prior event + break; + + default: + PanicMe(KErrUnknown); // design fault + break; + } + } + +// +// CSmsWatcher::RunError +// handle any probs with the state machine +// +TInt CSmsWatcher::RunError(TInt aError) + { + switch (iState) + { + case ESmsListenProcessSms: + // Problem such as bad message - log it and carry on + if (iErrorMessage.Length()) + { + iParent.PrintError(aError, iErrorMessage); + } + else + { + iParent.PrintError(aError, _L("Error when processing SMS")); + } + WaitForMessage(); // Start listening for another message + break; + + case ESmsListenReadSms: + { + // inform the stack we've failed to retrieve the sms. Likely due to OOM when calling PrepBuffersL + iSocket.Ioctl(KIoctlReadMessageFailed, iStatus, &iIoctlResult, KSolSmsProv); + SetActive(); + iState = ESmsListenIdle; + } + break; + + default: + PanicMe(__LINE__); // design fault + break; + }; + return KErrNone; + } + +// +// CSmsWatcher::WaitForMessage +// posts an async. read against the sms socket waiting for an incoming sms +// +void CSmsWatcher::WaitForMessage() + { + ASSERT(!IsActive()); + +#ifndef __TEST_MODE__ + iIoctlResult = KSockSelectRead; + ASSERT(iSocket.SubSessionHandle() > 0); + iSocket.Ioctl(KIOctlSelect, iStatus, &iIoctlResult, KSOLSocket); + iState = ESmsListenReadSms; +#else + TRequestStatus* status = &iStatus; + *status = KRequestPending; + User::RequestComplete(status, KErrNone); + iState = ESmsListenTestMode; +#endif + SetActive(); + } + +// +// CSmsWatcher::ReadSmsAndRespondToStackL +// retrieve the sms and inform the stack whether we've got it +// +void CSmsWatcher::ReadSmsAndRespondToStackL() + { + // prep. buffers used to hold the message + PrepBuffersL(); + + // retrieve the sms from the stack + RSmsSocketReadStream readstream1(iSocket); + CleanupClosePushL(readstream1); + iMessage->InternalizeL(readstream1); + CleanupStack::PopAndDestroy(); + + // inform the stack we've got the sms + iSocket.Ioctl(KIoctlReadMessageSucceeded, iStatus, &iIoctlResult, KSolSmsProv); + iState = ESmsListenProcessSms; + SetActive(); + } + +// +// CSmsWatcher::ProcessCommandL +// having captured the sms that contains the command, slurp it out & process any instructions contained therein +// +void CSmsWatcher::ProcessCommandL() + { + ASSERT(iMessage); + ASSERT(iCommand.Length() == 0); + const TInt length = iMessage->Buffer().Length(); + iCommand.CreateL(length); + iMessage->Buffer().Extract(iCommand, 0, length); + TPtrC address = iMessage->ToFromAddress(); + ParseBufferL(iCommand, address); + } + +// +// CSmsWatcher::PrepBuffersL +// trash the old buffer data, replace with virgin ones +// +void CSmsWatcher::PrepBuffersL() + { + delete iMessage; + iMessage = NULL; + iCommand.Close(); + CSmsBuffer* buffer = CSmsBuffer::NewL(); + CleanupStack::PushL(buffer); + iMessage = CSmsMessage::NewL(iParent.Fs(), CSmsPDU::ESmsDeliver, buffer); + CleanupStack::Pop(buffer); // iMessage takes ownership + } + +// +// CSmsWatcher::ParseInstructionsL +// interpret the instructions received OTA +// eg: "#!fshell\necho Hello!\n" +// +void CSmsWatcher::ParseBufferL(const TDesC& aInstruction, const TDesC& aSenderAddress) + { + TBool accept = EFalse; + RPointerArray& matchStrings = iParent.MatchStrings(); + if (matchStrings.Count()==0) + { + accept = ETrue; + } + else + { + for (TInt i=0; iStartL(); + } + else + { + TPtrC firstLine(aInstruction); + TInt pos = firstLine.Find(_L("\n")); + if (pos!=KErrNotFound) + { + firstLine.Set(firstLine.Left(pos)); + if ((firstLine.Length()>0)&&(firstLine[firstLine.Length()-1]=='\r')) + { + firstLine.Set(firstLine.Left(firstLine.Length()-1)); + } + } + iErrorMessage.Zero(); + iErrorMessage.AppendFormat(_L("Unhandled shebang command from %S: %S"), &aSenderAddress, &firstLine); + User::Leave(KErrArgument); + } + } + +// +// CSmsWatcher::Message +// +const TDesC& CSmsWatcher::Message() + { + return iCommand; + }