Tidied iocli exports, build macro tweaks.
Removed 4 overloads of CCommandBase::RunCommand[L] that are no longer used at all, and changed one more to not be exported as it's only used internally to iocli.dll.
fixed builds on platforms that don't support btrace or any form of tracing.
// 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 <gsmumsg.h>
#include <gsmubuf.h>
#include <smsustrm.h>
#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<HBufC>& matchStrings = iParent.MatchStrings();
if (matchStrings.Count()==0)
{
accept = ETrue;
}
else
{
for (TInt i=0; i<matchStrings.Count(); ++i)
{
Printf(_L("Sender %S matches %S: "), &aSenderAddress, matchStrings[i]);
if (aSenderAddress.Match(*matchStrings[i])!=KErrNotFound)
{
accept = ETrue;
}
}
}
if (!accept)
{
iErrorMessage.Zero();
iErrorMessage.AppendFormat(_L("Rejecting SMS from %S: did not match authorised sender"), &aSenderAddress);
User::Leave(KErrAccessDenied);
}
if (aInstruction.MatchF(_L("#!fshell*")) == 0 || aInstruction.MatchF(_L("#!perl*")) == 0)
{
CSmsShellCommand* command = CSmsShellCommand::NewL(iParent, aInstruction, aSenderAddress);
command->StartL();
}
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;
}