|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "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 * Initial Contributors: |
|
9 * Nokia Corporation - initial contribution. |
|
10 * |
|
11 * Contributors: |
|
12 * Description : |
|
13 * |
|
14 */ |
|
15 |
|
16 #include "cmgwcommandhandler.h" |
|
17 #include <mmretrieve.h> |
|
18 #include <mmlist.h> |
|
19 #include <exterror.h> |
|
20 |
|
21 #include "atmisccmdpluginconsts.h" |
|
22 #include "debug.h" |
|
23 |
|
24 const TUint KEOT = 26; // End of Transmission |
|
25 const TUint KESC = 27; // Escape |
|
26 |
|
27 const TUint8 KSCATonBitMask = 0x70; |
|
28 const TUint8 KSCANpiBitMask = 0x0F; |
|
29 |
|
30 CCMGWCommandHandler* CCMGWCommandHandler::NewL(MATMiscCmdPlugin* aCallback, TAtCommandParser& aATCmdParser, RMobilePhone& aPhone) |
|
31 { |
|
32 TRACE_FUNC_ENTRY |
|
33 CCMGWCommandHandler* self = new (ELeave) CCMGWCommandHandler(aCallback, aATCmdParser, aPhone); |
|
34 CleanupStack::PushL(self); |
|
35 self->ConstructL(); |
|
36 CleanupStack::Pop(self); |
|
37 TRACE_FUNC_EXIT |
|
38 return self; |
|
39 } |
|
40 |
|
41 CCMGWCommandHandler::CCMGWCommandHandler(MATMiscCmdPlugin* aCallback, TAtCommandParser& aATCmdParser, RMobilePhone& aPhone) : |
|
42 CATCmdAsyncBase(aCallback, aATCmdParser, aPhone), |
|
43 iEntryPckg(iEntry) |
|
44 { |
|
45 TRACE_FUNC_ENTRY |
|
46 TRACE_FUNC_EXIT |
|
47 } |
|
48 |
|
49 void CCMGWCommandHandler::ConstructL() |
|
50 { |
|
51 TRACE_FUNC_ENTRY |
|
52 iReply.CreateL(KDefaultCmdBufLength); |
|
53 iTPDU.CreateL(KDefaultCmdBufLength); |
|
54 |
|
55 User::LeaveIfError( iMobileSmsMessaging.Open(iPhone) ); |
|
56 |
|
57 TInt err = iMobileSmsStore.Open(iMobileSmsMessaging, KETelIccSmsStore); |
|
58 if (err != KErrNone) |
|
59 { |
|
60 iState = ECMGWStateSimStoreNotSupported; |
|
61 } |
|
62 iRetrieveMobilePhoneSmspList = CRetrieveMobilePhoneSmspList::NewL(iMobileSmsMessaging); |
|
63 |
|
64 TRACE_FUNC_EXIT |
|
65 } |
|
66 |
|
67 CCMGWCommandHandler::~CCMGWCommandHandler() |
|
68 { |
|
69 TRACE_FUNC_ENTRY |
|
70 Cancel(); |
|
71 delete iRetrieveMobilePhoneSmspList; |
|
72 delete iMobilePhoneSmspList; |
|
73 iMobileSmsStore.Close(); |
|
74 iMobileSmsMessaging.Close(); |
|
75 iReply.Close(); |
|
76 iTPDU.Close(); |
|
77 TRACE_FUNC_EXIT |
|
78 } |
|
79 |
|
80 /** |
|
81 * Set message format |
|
82 * 0: PDU mode |
|
83 * 1: Text mode - not supported |
|
84 */ |
|
85 void CCMGWCommandHandler::SetMessageFormat(TInt aFormat) |
|
86 { |
|
87 TRACE_FUNC_ENTRY |
|
88 if (aFormat == 0 || aFormat == 1) |
|
89 { |
|
90 iMsgFormat = aFormat; |
|
91 } |
|
92 Trace(_L("Message format: %d"), iMsgFormat); |
|
93 TRACE_FUNC_ENTRY |
|
94 } |
|
95 |
|
96 void CCMGWCommandHandler::HandleCommand(const TDesC8& aCmd, RBuf8& /*aReply*/, TBool /*aReplyNeeded*/) |
|
97 { |
|
98 TRACE_FUNC_ENTRY |
|
99 |
|
100 if (iMsgFormat == 1 || iState == ECMGWStateSimStoreNotSupported ) |
|
101 { |
|
102 // Reply "ERROR" if text mode is set |
|
103 // Reply "ERROR" if SIM store is not supported |
|
104 iCallback->CreateReplyAndComplete( EReplyTypeError ); |
|
105 TRACE_FUNC_EXIT |
|
106 return; |
|
107 } |
|
108 |
|
109 TInt err = KErrNone; |
|
110 |
|
111 TAtCommandParser::TCommandHandlerType cmdHandlerType = iATCmdParser.CommandHandlerType(); |
|
112 |
|
113 switch (cmdHandlerType) |
|
114 { |
|
115 case (TAtCommandParser::ECmdHandlerTypeTest): |
|
116 { |
|
117 iCallback->CreateReplyAndComplete( EReplyTypeOk ); |
|
118 break; |
|
119 } |
|
120 case (TAtCommandParser::ECmdHandlerTypeSet): |
|
121 { |
|
122 switch(iState) |
|
123 { |
|
124 case ECMGWStateIdle: |
|
125 { |
|
126 // Parse parameters |
|
127 err = ParseParameters(); |
|
128 if (err == KErrNone) |
|
129 { |
|
130 Trace(_L("Parse parameters OK.")); |
|
131 Trace(_L("Length = %d"), iTPDULength); |
|
132 Trace(_L("stat = %d"), iTPDUStat); |
|
133 |
|
134 iTPDU.Zero(); |
|
135 iState = ECMGWStateEditMode; |
|
136 iCallback->CreateReplyAndComplete( EReplyTypeEditor ); |
|
137 } |
|
138 else |
|
139 { |
|
140 // Syntax error |
|
141 Trace(_L("Syntax error. err = %d"), err); |
|
142 iState = ECMGWStateIdle; |
|
143 iCallback->CreateReplyAndComplete(EReplyTypeError); |
|
144 } |
|
145 break; |
|
146 } |
|
147 case ECMGWStateEditMode: // Edit state |
|
148 { |
|
149 HandleEditModeCommand(aCmd); |
|
150 break; |
|
151 } |
|
152 default: // Other states |
|
153 { |
|
154 Cancel(); |
|
155 iCallback->CreateReplyAndComplete( EReplyTypeError ); |
|
156 } |
|
157 } |
|
158 break; |
|
159 } |
|
160 default: |
|
161 { |
|
162 iCallback->CreateReplyAndComplete( EReplyTypeError ); |
|
163 break; |
|
164 } |
|
165 } |
|
166 |
|
167 TRACE_FUNC_EXIT |
|
168 } |
|
169 |
|
170 void CCMGWCommandHandler::HandleEditModeCommand( const TDesC8& aCmd ) |
|
171 { |
|
172 TRACE_FUNC_ENTRY |
|
173 |
|
174 TInt err = KErrNone; |
|
175 TUint8 cmdCharVal = 0; |
|
176 if (aCmd.Length()) |
|
177 { |
|
178 cmdCharVal = aCmd[0]; |
|
179 } |
|
180 |
|
181 switch ( cmdCharVal ) |
|
182 { |
|
183 case KEOT: // End of Transmission: Now write the message |
|
184 { |
|
185 // Extract SCA fro PDU |
|
186 err = ExtractSCA(); |
|
187 if (err == KErrNotFound) |
|
188 { |
|
189 // SCA not provided by client |
|
190 if (iMobileSmspEntry.iServiceCentre.iTelNumber.Length() == 0) |
|
191 { |
|
192 // Retrieve SMS parameter list |
|
193 iRetrieveMobilePhoneSmspList->Start(iStatus); |
|
194 iState = ECMGWStateRetrieveSCA; |
|
195 SetActive(); |
|
196 } |
|
197 else |
|
198 { |
|
199 // Got the SCA from SIM params already - self complete |
|
200 iServiceCentre = iMobileSmspEntry.iServiceCentre; |
|
201 |
|
202 TRequestStatus* status = &iStatus; |
|
203 User::RequestComplete(status, KErrNone); |
|
204 iState = ECMGWStatePreparePDU; |
|
205 SetActive(); |
|
206 } |
|
207 } |
|
208 else if( err == KErrNone ) |
|
209 { |
|
210 // Got the SCA from client (in iService Centre) - self complete |
|
211 TRequestStatus* status = &iStatus; |
|
212 User::RequestComplete(status, KErrNone); |
|
213 iState = ECMGWStatePreparePDU; |
|
214 SetActive(); |
|
215 } |
|
216 else |
|
217 { |
|
218 // Extract SCA failed |
|
219 iState = ECMGWStateIdle; |
|
220 iCallback->CreateCMSReplyAndComplete(KErrGsmSMSInvalidPDUModeParameter); |
|
221 } |
|
222 break; |
|
223 } |
|
224 case KESC: // Escape |
|
225 { |
|
226 iState = ECMGWStateIdle; |
|
227 iCallback->CreateReplyAndComplete( EReplyTypeOk ); |
|
228 break; |
|
229 } |
|
230 default: // Still entering PDU data |
|
231 { |
|
232 iTPDU.Append( aCmd ); |
|
233 iCallback->CreateReplyAndComplete( EReplyTypeEditor ); |
|
234 break; |
|
235 } |
|
236 } |
|
237 |
|
238 TRACE_FUNC_EXIT |
|
239 } |
|
240 |
|
241 void CCMGWCommandHandler::RunL() |
|
242 { |
|
243 TRACE_FUNC_ENTRY |
|
244 |
|
245 iReply.Zero(); |
|
246 TInt err = iStatus.Int(); |
|
247 Trace(_L("State = %d, err = %d"), iState, err); |
|
248 |
|
249 if (err == KErrNone) |
|
250 { |
|
251 switch (iState) |
|
252 { |
|
253 case ECMGWStateRetrieveSCA: |
|
254 { |
|
255 // Got SCA from SIM params - update iServiceCentre |
|
256 iMobilePhoneSmspList = iRetrieveMobilePhoneSmspList->RetrieveListL(); |
|
257 iMobileSmspEntry = iMobilePhoneSmspList->GetEntryL(0); |
|
258 iServiceCentre = iMobileSmspEntry.iServiceCentre; |
|
259 |
|
260 // Complete self to send PDU in next state |
|
261 TRequestStatus* status = &iStatus; |
|
262 User::RequestComplete(status, KErrNone); |
|
263 iState = ECMGWStatePreparePDU; |
|
264 SetActive(); |
|
265 } |
|
266 break; |
|
267 case ECMGWStatePreparePDU: |
|
268 { |
|
269 // Create an SMS entry from PDU |
|
270 iEntry.iServiceCentre = iServiceCentre; |
|
271 |
|
272 err = CreateSmsEntry(); |
|
273 if (err == KErrNone) |
|
274 { |
|
275 Trace(_L("Create SMS entry OK.")); |
|
276 Trace(_L("Service center: %S"), |
|
277 &iEntry.iServiceCentre.iTelNumber); |
|
278 Trace(_L("Type of number: %d"), |
|
279 iEntry.iServiceCentre.iTypeOfNumber); |
|
280 Trace(_L("Number plan: %d"), |
|
281 iEntry.iServiceCentre.iNumberPlan); |
|
282 Trace(_L("Message status: %d"), iEntry.iMsgStatus); |
|
283 |
|
284 // Start to write PDU |
|
285 iEntry.iIndex = -1; |
|
286 iMobileSmsStore.Write(iStatus, iEntryPckg); |
|
287 iState = ECMGWStateWritePDU; |
|
288 SetActive(); |
|
289 } |
|
290 else |
|
291 { |
|
292 // Create failed |
|
293 iState = ECMGWStateIdle; |
|
294 iCallback->CreateCMSReplyAndComplete(KErrGsmSMSInvalidPDUModeParameter); |
|
295 } |
|
296 break; |
|
297 } |
|
298 case ECMGWStateWritePDU: |
|
299 { |
|
300 Trace(_L("Write successful. Index = %d"), iEntry.iIndex); |
|
301 |
|
302 iReply.Append(KCRLF); |
|
303 iReply.Append(KAtCMGW); |
|
304 iReply.AppendNum(iEntry.iIndex); |
|
305 iState = ECMGWStateIdle; |
|
306 iCallback->CreateReplyAndComplete(EReplyTypeOk, iReply); |
|
307 } |
|
308 break; |
|
309 default: |
|
310 iState = ECMGWStateIdle; |
|
311 iCallback->CreateReplyAndComplete(EReplyTypeError); |
|
312 break; |
|
313 } |
|
314 } |
|
315 else |
|
316 { |
|
317 iState = ECMGWStateIdle; |
|
318 iCallback->CreateCMSReplyAndComplete(err); |
|
319 } |
|
320 |
|
321 TRACE_FUNC_EXIT |
|
322 } |
|
323 |
|
324 TInt CCMGWCommandHandler::RunError(TInt aError) |
|
325 { |
|
326 TRACE_FUNC_ENTRY |
|
327 |
|
328 delete iMobilePhoneSmspList; |
|
329 iMobilePhoneSmspList = NULL; |
|
330 iState = ECMGWStateIdle; |
|
331 iCallback->CreateCMSReplyAndComplete(aError); |
|
332 |
|
333 TRACE_FUNC_EXIT |
|
334 return KErrNone; |
|
335 } |
|
336 |
|
337 void CCMGWCommandHandler::DoCancel() |
|
338 { |
|
339 TRACE_FUNC_ENTRY |
|
340 |
|
341 switch (iState) |
|
342 { |
|
343 case ECMGWStateRetrieveSCA: |
|
344 { |
|
345 iRetrieveMobilePhoneSmspList->Cancel(); |
|
346 break; |
|
347 } |
|
348 case ECMGWStateWritePDU: |
|
349 { |
|
350 iMobileSmsStore.CancelAsyncRequest(EMobilePhoneStoreWrite); |
|
351 break; |
|
352 } |
|
353 } |
|
354 iState = ECMGWStateIdle; |
|
355 |
|
356 TRACE_FUNC_EXIT |
|
357 } |
|
358 /** |
|
359 * Parse parameters of +CMGW=<length>,<stat> |
|
360 */ |
|
361 TInt CCMGWCommandHandler::ParseParameters() |
|
362 { |
|
363 TRACE_FUNC_ENTRY |
|
364 |
|
365 TInt ret = KErrNone; |
|
366 iTPDULength = 0; |
|
367 iTPDUStat = 0; // default value |
|
368 TInt otherParams = 0; |
|
369 // Get length |
|
370 TInt retLength = iATCmdParser.NextIntParam(iTPDULength); |
|
371 // Get status |
|
372 TInt retStat = iATCmdParser.NextIntParam(iTPDUStat); |
|
373 // Get other parameters |
|
374 TInt retOther = iATCmdParser.NextIntParam(otherParams); |
|
375 // syntax error happens if |
|
376 // a)there is no param 1 |
|
377 // b)there are 3 params |
|
378 // c)param 2 is not 0,1,2 or 3 |
|
379 TBool noParam1 = (retLength != KErrNone); |
|
380 TBool badParam2 = (retStat == KErrGeneral); |
|
381 TBool tooManyParams = (retOther != KErrNotFound); |
|
382 |
|
383 if (noParam1 || badParam2 || tooManyParams) |
|
384 { |
|
385 ret = KErrArgument; |
|
386 } |
|
387 else |
|
388 { |
|
389 switch (iTPDUStat) |
|
390 { |
|
391 case 0: |
|
392 // to receive unread message |
|
393 iMessageStatus = RMobileSmsStore::EStoredMessageUnread; |
|
394 break; |
|
395 case 1: |
|
396 // to receive read message |
|
397 iMessageStatus = RMobileSmsStore::EStoredMessageRead; |
|
398 break; |
|
399 case 2: |
|
400 // Unsent is not supported in this version |
|
401 ret = KErrNotSupported; |
|
402 break; |
|
403 case 3: |
|
404 // Sent is not supported in this version |
|
405 ret = KErrNotSupported; |
|
406 break; |
|
407 default: |
|
408 ret = KErrArgument; |
|
409 break; |
|
410 } |
|
411 iEntry.iMsgStatus = iMessageStatus; |
|
412 } |
|
413 |
|
414 TRACE_FUNC_EXIT |
|
415 return ret; |
|
416 } |
|
417 |
|
418 /** |
|
419 * Create an SMS entry from the PDU string |
|
420 */ |
|
421 TInt CCMGWCommandHandler::CreateSmsEntry() |
|
422 { |
|
423 TRACE_FUNC_ENTRY |
|
424 |
|
425 TInt err = KErrNone; |
|
426 |
|
427 // Check the length |
|
428 if (iTPDU.Length() != (iSCALength+iTPDULength+1)*2) |
|
429 { |
|
430 TRACE_FUNC_EXIT |
|
431 return KErrArgument; |
|
432 } |
|
433 |
|
434 RBuf8 buf; |
|
435 err = buf.Create(iTPDULength); |
|
436 if (err != KErrNone) |
|
437 { |
|
438 TRACE_FUNC_EXIT |
|
439 return err; |
|
440 } |
|
441 // Convert to binary format |
|
442 for(TInt i=(iSCALength+1)*2; i< iTPDU.Length(); i+=2) |
|
443 { |
|
444 TLex8 lex(iTPDU.Mid(i, 2)); |
|
445 TUint8 val = 0; |
|
446 err = lex.Val(val, EHex); |
|
447 if (err != KErrNone) |
|
448 { |
|
449 buf.Close(); |
|
450 TRACE_FUNC_EXIT |
|
451 return err; |
|
452 } |
|
453 buf.Append(val); |
|
454 } |
|
455 iEntry.iMsgData.Copy(buf); |
|
456 |
|
457 buf.Close(); |
|
458 TRACE_FUNC_EXIT |
|
459 return KErrNone; |
|
460 } |
|
461 |
|
462 /** |
|
463 * Extract the SMS service center address from the head of PDU string |
|
464 */ |
|
465 TInt CCMGWCommandHandler::ExtractSCA() |
|
466 { |
|
467 TRACE_FUNC_ENTRY |
|
468 |
|
469 TInt err = KErrNone; |
|
470 TLex8 lex; |
|
471 RMobilePhone::TMobileAddress sca; |
|
472 // SCA length |
|
473 lex.Assign(iTPDU.Left(2)); |
|
474 err = lex.Val(iSCALength, EHex); |
|
475 if (err != KErrNone) |
|
476 { |
|
477 TRACE_FUNC_EXIT |
|
478 return err; |
|
479 } |
|
480 TInt length = iTPDU.Length(); |
|
481 if (iSCALength == 0) |
|
482 { |
|
483 // Service center is not found in PDU |
|
484 err = KErrNotFound; |
|
485 } |
|
486 else if (iSCALength > (length-2)/2) |
|
487 { |
|
488 // Service certer length error |
|
489 err = KErrArgument; |
|
490 } |
|
491 else |
|
492 { |
|
493 // SCA is given |
|
494 // Parse SCA TON and NPI |
|
495 TUint8 val = 0; |
|
496 lex.Assign(iTPDU.Mid(2,2)); |
|
497 err = lex.Val(val, EHex); |
|
498 if (err != KErrNone) |
|
499 { |
|
500 TRACE_FUNC_EXIT |
|
501 return err; |
|
502 } |
|
503 TUint8 ton = (val&KSCATonBitMask)>>4; |
|
504 TUint8 npi = val&KSCANpiBitMask; |
|
505 switch (ton) // TON |
|
506 { |
|
507 case 0: // 000 |
|
508 sca.iTypeOfNumber = RMobilePhone::EUnknownNumber; |
|
509 break; |
|
510 case 1: // 001 |
|
511 sca.iTypeOfNumber = RMobilePhone::EInternationalNumber; |
|
512 sca.iTelNumber.Append('+'); |
|
513 break; |
|
514 case 2: // 010 |
|
515 sca.iTypeOfNumber = RMobilePhone::ENationalNumber; |
|
516 break; |
|
517 default: |
|
518 // CMCC doesn't support other types |
|
519 TRACE_FUNC_EXIT |
|
520 return KErrArgument; |
|
521 } |
|
522 switch (npi) // NPI |
|
523 { |
|
524 case 0: // 0000 |
|
525 sca.iNumberPlan = RMobilePhone::EUnknownNumberingPlan; |
|
526 break; |
|
527 case 1: // 0001 |
|
528 sca.iNumberPlan = RMobilePhone::EIsdnNumberPlan; |
|
529 break; |
|
530 default: |
|
531 // CMCC doesn't support other number plans |
|
532 TRACE_FUNC_EXIT |
|
533 return KErrArgument; |
|
534 } |
|
535 // Extract SCA number |
|
536 for (TInt i=4; i<(iSCALength+1)*2; i+=2) |
|
537 { |
|
538 sca.iTelNumber.Append(iTPDU[i+1]); |
|
539 sca.iTelNumber.Append(iTPDU[i]); |
|
540 } |
|
541 if(sca.iTelNumber[sca.iTelNumber.Length()-1] == 'F' |
|
542 || sca.iTelNumber[sca.iTelNumber.Length()-1] == 'f') |
|
543 { |
|
544 sca.iTelNumber.Delete(sca.iTelNumber.Length()-1, 1); |
|
545 } |
|
546 iServiceCentre = sca; |
|
547 } |
|
548 TRACE_FUNC_EXIT |
|
549 return err; |
|
550 } |
|
551 |
|
552 |