commands/sms/smswatch.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // smswatch.cpp
       
     2 // 
       
     3 // Copyright (c) 2008 - 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 #include "smswatch.h"
       
    14 #include <gsmumsg.h>
       
    15 #include <gsmubuf.h>
       
    16 #include <smsustrm.h>
       
    17 #include "sms.h"
       
    18 
       
    19 // __TEST_MODE__ provides a dummy autometric command
       
    20 //#define __TEST_MODE__
       
    21 
       
    22 #undef ASSERT
       
    23 #define ASSERT(x) if (!(x)) { iParent.Printf(_L8("Assertion failed at line %d: " #x "\r\n"), __LINE__); PanicMe(__LINE__); }
       
    24 
       
    25 // local static method definitions
       
    26 static void PanicMe(TInt aError)
       
    27 	 {
       
    28 	 _LIT(KSmsWatcherPanic, "AmSms");
       
    29 	 User::Panic(KSmsWatcherPanic, aError);	 
       
    30 	 }
       
    31 
       
    32 //
       
    33 // CSmsWatcher
       
    34 //
       
    35 CSmsWatcher* CSmsWatcher::NewL(CCmdSms& aParent)
       
    36 	{
       
    37 	CSmsWatcher* self = new (ELeave) CSmsWatcher(aParent);
       
    38 	CleanupStack::PushL(self);
       
    39 	self->ConstructL();
       
    40 	CleanupStack::Pop();
       
    41 	return self;
       
    42 	}
       
    43 
       
    44 CSmsWatcher::CSmsWatcher(CCmdSms& aParent)
       
    45 	: CActive(CActive::EPriorityStandard), iParent(aParent), iState(ESmsListenIdle)
       
    46 	{
       
    47 	CActiveScheduler::Add(this);
       
    48 	}
       
    49 
       
    50 CSmsWatcher::~CSmsWatcher()
       
    51 	{
       
    52 	Cancel();
       
    53 	delete iMessage;
       
    54 	iCommand.Close();
       
    55 	if (iSocket.SubSessionHandle() > 0)
       
    56 		iSocket.Close();
       
    57 	if (iSocketServer.Handle() > 0)
       
    58 		iSocketServer.Close();
       
    59 	}
       
    60 
       
    61 void CSmsWatcher::ConstructL()
       
    62 	{
       
    63 	// connect to the sms socket
       
    64 	User::LeaveIfError(iSocketServer.Connect());
       
    65 	User::LeaveIfError(iSocket.Open(iSocketServer,KSMSAddrFamily,KSockDatagram,KSMSDatagramProtocol));
       
    66 	iSmsAddr.SetSmsAddrFamily(ESmsAddrMatchText);
       
    67 	_LIT8(KShebang, "#!");
       
    68 	iSmsAddr.SetTextMatch(KShebang());
       
    69 	User::LeaveIfError(iSocket.Bind(iSmsAddr));
       
    70 	}
       
    71 
       
    72 void CSmsWatcher::DoCancel()
       
    73 	{
       
    74 	switch(iState)
       
    75 		{
       
    76 		case ESmsListenReadSms:
       
    77 		case ESmsListenProcessSms:
       
    78 		case ESmsListenIdle: // This could happen when signalling failure via KIoctlReadMessageFailed
       
    79 			iSocket.CancelIoctl();
       
    80 			break;
       
    81 		default:
       
    82 			PanicMe(__LINE__);
       
    83 		}
       
    84 	}
       
    85 
       
    86 
       
    87 void CSmsWatcher::RunL()
       
    88 	{
       
    89 	iErrorMessage.Zero();
       
    90 	if (iStatus.Int() < 0)
       
    91 		{
       
    92 		iErrorMessage.AppendFormat(_L("Error reported from CSmsWatcher::RunL"));
       
    93 		User::Leave(iStatus.Int()); // process any errors elsewhere
       
    94 		}
       
    95 	
       
    96 	switch(iState)
       
    97 		{
       
    98 		case ESmsListenReadSms:
       
    99 			ReadSmsAndRespondToStackL(); // inform the stack we've got the sms
       
   100 			break;
       
   101 		
       
   102 		case ESmsListenProcessSms:
       
   103 			ProcessCommandL(); // process the contents of the sms
       
   104 			WaitForMessage(); // Start listening for another message (RunError will call it if ProcessCommandL leaves)
       
   105 			break;
       
   106 #ifdef __TEST_MODE__
       
   107 		case ESmsListenTestMode:
       
   108 			{
       
   109 			// a test mode skipping reception & decoding of an autometric sms
       
   110 			//_LIT(KTestMsg, "!#AUTOMETRIC;d:0243261943;?");
       
   111 			_LIT(KTestMsg, "#!fshell\ninfoprint \"hello world!\"\n");
       
   112 			ParseBufferL(KTestMsg, _L("012345678"));
       
   113 			}
       
   114 			break;
       
   115 #endif
       
   116 		case ESmsListenIdle:
       
   117 			//CompleteWatch(KErrCompletion); // indicate an error with a prior event
       
   118 			break;
       
   119 		
       
   120 		default:
       
   121 			PanicMe(KErrUnknown); // design fault
       
   122 			break;
       
   123 		}
       
   124 	}
       
   125 
       
   126 //
       
   127 // CSmsWatcher::RunError
       
   128 // handle any probs with the state machine 
       
   129 //
       
   130 TInt CSmsWatcher::RunError(TInt aError)
       
   131 	{
       
   132 	switch (iState)
       
   133 		{
       
   134 		case ESmsListenProcessSms:
       
   135 			// Problem such as bad message - log it and carry on
       
   136 			if (iErrorMessage.Length())
       
   137 				{
       
   138 				iParent.PrintError(aError, iErrorMessage);
       
   139 				}
       
   140 			else
       
   141 				{
       
   142 				iParent.PrintError(aError, _L("Error when processing SMS"));
       
   143 				}
       
   144 			WaitForMessage(); // Start listening for another message
       
   145 		break;
       
   146 		
       
   147 		case ESmsListenReadSms:
       
   148 			{
       
   149 			// inform the stack we've failed to retrieve the sms. Likely due to OOM when calling PrepBuffersL
       
   150 			iSocket.Ioctl(KIoctlReadMessageFailed, iStatus, &iIoctlResult, KSolSmsProv);
       
   151 			SetActive();
       
   152 			iState = ESmsListenIdle;
       
   153 			}
       
   154 		break;
       
   155 		
       
   156 		default:
       
   157 			PanicMe(__LINE__); // design fault
       
   158 		break;
       
   159 		};
       
   160 	return KErrNone;
       
   161 	}
       
   162 
       
   163 //
       
   164 // CSmsWatcher::WaitForMessage
       
   165 // posts an async. read against the sms socket waiting for an incoming sms
       
   166 //
       
   167 void CSmsWatcher::WaitForMessage()
       
   168 	{
       
   169 	ASSERT(!IsActive());
       
   170 
       
   171 #ifndef __TEST_MODE__
       
   172 	iIoctlResult = KSockSelectRead;
       
   173 	ASSERT(iSocket.SubSessionHandle() > 0);
       
   174 	iSocket.Ioctl(KIOctlSelect, iStatus, &iIoctlResult, KSOLSocket);
       
   175 	iState = ESmsListenReadSms;
       
   176 #else
       
   177 	TRequestStatus* status = &iStatus;
       
   178 	*status = KRequestPending;
       
   179 	User::RequestComplete(status, KErrNone);
       
   180 	iState = ESmsListenTestMode;
       
   181 #endif
       
   182 	SetActive();
       
   183 	}
       
   184 
       
   185 //
       
   186 // CSmsWatcher::ReadSmsAndRespondToStackL
       
   187 // retrieve the sms and inform the stack whether we've got it
       
   188 //
       
   189 void CSmsWatcher::ReadSmsAndRespondToStackL()
       
   190 	{
       
   191 	// prep. buffers used to hold the message
       
   192 	PrepBuffersL();
       
   193 	
       
   194 	// retrieve the sms from the stack
       
   195 	RSmsSocketReadStream readstream1(iSocket);
       
   196 	CleanupClosePushL(readstream1);
       
   197 	iMessage->InternalizeL(readstream1);
       
   198 	CleanupStack::PopAndDestroy();
       
   199 	
       
   200 	// inform the stack we've got the sms
       
   201 	iSocket.Ioctl(KIoctlReadMessageSucceeded, iStatus, &iIoctlResult, KSolSmsProv);
       
   202 	iState = ESmsListenProcessSms;
       
   203 	SetActive();
       
   204 	}
       
   205 
       
   206 //
       
   207 // CSmsWatcher::ProcessCommandL
       
   208 // having captured the sms that contains the command, slurp it out & process any instructions contained therein
       
   209 //
       
   210 void CSmsWatcher::ProcessCommandL()
       
   211 	{
       
   212 	ASSERT(iMessage);
       
   213 	ASSERT(iCommand.Length() == 0);
       
   214 	const TInt length = iMessage->Buffer().Length();
       
   215 	iCommand.CreateL(length);
       
   216 	iMessage->Buffer().Extract(iCommand, 0, length);
       
   217 	TPtrC address = iMessage->ToFromAddress();
       
   218 	ParseBufferL(iCommand, address);
       
   219 	}
       
   220 
       
   221 //
       
   222 // CSmsWatcher::PrepBuffersL
       
   223 // trash the old buffer data, replace with virgin ones
       
   224 //
       
   225 void CSmsWatcher::PrepBuffersL()
       
   226 	{
       
   227 	delete iMessage;
       
   228 	iMessage = NULL;
       
   229 	iCommand.Close();
       
   230 	CSmsBuffer* buffer = CSmsBuffer::NewL();
       
   231 	CleanupStack::PushL(buffer);
       
   232 	iMessage = CSmsMessage::NewL(iParent.Fs(), CSmsPDU::ESmsDeliver, buffer);
       
   233 	CleanupStack::Pop(buffer); // iMessage takes ownership
       
   234 	}
       
   235 
       
   236 //
       
   237 // CSmsWatcher::ParseInstructionsL
       
   238 // interpret the instructions received OTA
       
   239 // eg: "#!fshell\necho Hello!\n"
       
   240 //
       
   241 void CSmsWatcher::ParseBufferL(const TDesC& aInstruction, const TDesC& aSenderAddress)
       
   242 	{
       
   243 	TBool accept = EFalse;
       
   244 	RPointerArray<HBufC>& matchStrings = iParent.MatchStrings();
       
   245 	if (matchStrings.Count()==0)
       
   246 		{
       
   247 		accept = ETrue;
       
   248 		}
       
   249 	else
       
   250 		{
       
   251 		for (TInt i=0; i<matchStrings.Count(); ++i)
       
   252 			{
       
   253 			Printf(_L("Sender %S matches %S: "), &aSenderAddress, matchStrings[i]);
       
   254 			if (aSenderAddress.Match(*matchStrings[i])!=KErrNotFound)
       
   255 				{
       
   256 				accept = ETrue;
       
   257 				}
       
   258 			}
       
   259 		}
       
   260 		
       
   261 	if (!accept)
       
   262 		{
       
   263 		iErrorMessage.Zero();
       
   264 		iErrorMessage.AppendFormat(_L("Rejecting SMS from %S: did not match authorised sender"), &aSenderAddress);
       
   265 		User::Leave(KErrAccessDenied);
       
   266 		}
       
   267 	
       
   268 	
       
   269 	if (aInstruction.MatchF(_L("#!fshell*")) == 0 || aInstruction.MatchF(_L("#!perl*")) == 0)
       
   270 		{
       
   271 		CSmsShellCommand* command = CSmsShellCommand::NewL(iParent, aInstruction, aSenderAddress);
       
   272 		command->StartL();		
       
   273 		}
       
   274 	else
       
   275 		{
       
   276 		TPtrC firstLine(aInstruction);
       
   277 		TInt pos = firstLine.Find(_L("\n"));
       
   278 		if (pos!=KErrNotFound)
       
   279 			{
       
   280 			firstLine.Set(firstLine.Left(pos));
       
   281 			if ((firstLine.Length()>0)&&(firstLine[firstLine.Length()-1]=='\r'))
       
   282 				{
       
   283 				firstLine.Set(firstLine.Left(firstLine.Length()-1));
       
   284 				}
       
   285 			}
       
   286 		iErrorMessage.Zero();
       
   287 		iErrorMessage.AppendFormat(_L("Unhandled shebang command from %S: %S"), &aSenderAddress, &firstLine);
       
   288 		User::Leave(KErrArgument);
       
   289 		}
       
   290 	}
       
   291 
       
   292 //
       
   293 // CSmsWatcher::Message
       
   294 // 
       
   295 const TDesC& CSmsWatcher::Message()
       
   296 	{
       
   297 	return iCommand;
       
   298 	}