--- /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 <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;
+ }