|
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 } |