|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // AT Command Class for Sms |
|
15 // Also contains member functions used by different ATCommands in the GsmTsy. |
|
16 // |
|
17 // |
|
18 |
|
19 #include "mSLOGGER.H" |
|
20 #include "ATIO.H" |
|
21 #include "ATSTD.H" |
|
22 #include "mSMSSTOR.H" |
|
23 #include "Matstd.h" |
|
24 #include "smsbase.H" |
|
25 #include "smsutil.h" // for CATSmsUtils |
|
26 |
|
27 #include <exterror.h> // for KErrGsmSMS... error codes |
|
28 |
|
29 // Constants |
|
30 |
|
31 // |
|
32 // Macros |
|
33 // |
|
34 // This macro is used to help keep un-intereting details outside of the main code |
|
35 // in this file. The macro uses logging functions and always prefixes writes to the |
|
36 // log with the name of the class which is implemented in this file. This macro must |
|
37 // only be used by code in this file. |
|
38 #ifdef __LOGDEB__ |
|
39 _LIT8(KLogEntry,"CATSmsCommands::%S\t%S"); |
|
40 #define LOCAL_LOGTEXT(function,text) {_LIT8(F,function);_LIT8(T,text);LOGTEXT3(KLogEntry,&F,&T);} |
|
41 #else |
|
42 #define LOCAL_LOGTEXT(function,text) |
|
43 #endif |
|
44 |
|
45 // |
|
46 // CATSmsCommands definitions |
|
47 // |
|
48 |
|
49 CATSmsCommands::CATSmsCommands(CATIO* aIo, CTelObject* aTelObject, CATInit* aInit,CPhoneGlobals* aGlobals) |
|
50 :CATCommands(aIo,aTelObject,aInit,aGlobals) |
|
51 /** |
|
52 * C++ constructor |
|
53 */ |
|
54 { |
|
55 } |
|
56 |
|
57 CATSmsCommands::~CATSmsCommands() |
|
58 /** |
|
59 * C++ destructor |
|
60 */ |
|
61 {} |
|
62 |
|
63 CATSmsCommands::TRequest CATSmsCommands::RequestATCompleted() |
|
64 /** |
|
65 * This method is a query function which returns the TRequest value for a request which |
|
66 * has completed, otherwise ENone is returned to denote that no request has completed. |
|
67 * |
|
68 * If this method returns that a request has completed then this method will also |
|
69 * reset the iRequestCompleted flag so that this method that the completion of a |
|
70 * request is reported only once. |
|
71 * |
|
72 * @return The TRequest value of the request that completed, otherwise ENone |
|
73 */ |
|
74 { |
|
75 LOCAL_LOGTEXT("RequestATCompleted","enter function"); |
|
76 if(iRequestCompleted) |
|
77 { |
|
78 const TRequest tmp(iRequest); |
|
79 iRequest=ENone; |
|
80 iRequestCompleted=EFalse; |
|
81 return tmp; |
|
82 } |
|
83 |
|
84 return ENone; |
|
85 } |
|
86 |
|
87 TBool CATSmsCommands::RequestATActive() const |
|
88 { |
|
89 LOCAL_LOGTEXT("RequestATActive","enter function"); |
|
90 return iRequest!=ENone; |
|
91 } |
|
92 |
|
93 |
|
94 void CATSmsCommands::RequestATCommandCancel() |
|
95 /** |
|
96 */ |
|
97 { |
|
98 LOCAL_LOGTEXT("RequestATCommandCancel","enter function"); |
|
99 if(!RequestATActive()) |
|
100 return; // There's nothing to do if we're not active |
|
101 |
|
102 // Cancel operations |
|
103 LOCAL_LOGTEXT("RequestATCommandCancel","Cancelling..."); |
|
104 iRequestCancel=ETrue; |
|
105 } |
|
106 |
|
107 void CATSmsCommands::InitializeRequestData(TRequest aReq) |
|
108 { |
|
109 LOCAL_LOGTEXT("InitializeRequestData","enter function"); |
|
110 |
|
111 iRequest=aReq; |
|
112 iRequestStage=0; |
|
113 iRequestCompleted=EFalse; |
|
114 iRequestError=KErrNone; |
|
115 iRequestCancel=EFalse; |
|
116 } |
|
117 |
|
118 TInt CATSmsCommands::RequestATCommand(TRequest aReq) |
|
119 { |
|
120 LOCAL_LOGTEXT("RequestATCommand","enter function"); |
|
121 |
|
122 // Ensure we are not allready handling a request |
|
123 if(RequestATActive()) |
|
124 { |
|
125 LOCAL_LOGTEXT("RequestATCommand","A request is already in progress, returning KErrInUse"); |
|
126 return KErrInUse; |
|
127 } |
|
128 |
|
129 //Initialize request data |
|
130 InitializeRequestData(aReq); |
|
131 |
|
132 // Handle request |
|
133 TInt ret(KErrNone); |
|
134 const TEventSource nullSource(TEventSource(-1)); // This fiddle is so we can pass a 'null' event source |
|
135 |
|
136 switch(aReq) |
|
137 { |
|
138 case EGetSCAFromPhone: |
|
139 ret=GetSCAFromPhone(nullSource); |
|
140 break; |
|
141 |
|
142 case ESetSCAInPhone: |
|
143 ret=SetSCAInPhone(nullSource); |
|
144 break; |
|
145 |
|
146 case ESetPhoneToCMTMode: |
|
147 ret=SetPhoneToCMTMode(nullSource); |
|
148 break; |
|
149 |
|
150 case ESetPhoneToCMTIMode: |
|
151 ret=SetPhoneToCMTIMode(nullSource); |
|
152 break; |
|
153 |
|
154 case ENone: // Must not be caught by default case |
|
155 LOCAL_LOGTEXT("RequestATCommand","Request is ENone, so will not do anything"); |
|
156 break; |
|
157 |
|
158 default: |
|
159 LOCAL_LOGTEXT("RequestATCommand","Unknown request"); |
|
160 __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequest)); |
|
161 ret=KErrNotSupported; |
|
162 } |
|
163 |
|
164 LOCAL_LOGTEXT("RequestATCommand","exit function"); |
|
165 return ret; |
|
166 } |
|
167 |
|
168 |
|
169 TInt CATSmsCommands::SetSCAInPhone(const TEventSource& aEventSource) |
|
170 /** |
|
171 * Sets phone's default SCA to be that which is stored in iRequestSCA. |
|
172 * IMPORTANT: If this method returns an error then EventSignal will complete our request. |
|
173 * @return Standard KErr... codes |
|
174 */ |
|
175 { |
|
176 LOCAL_LOGTEXT("SetSCAInPhone","enter function"); |
|
177 __ASSERT_DEBUG(iRequest==ESetSCAInPhone,Panic(EATSmsCommandsWrongRequest)); |
|
178 |
|
179 TInt ret(KErrNone); |
|
180 switch(iRequestStage) |
|
181 { |
|
182 case EStage0: |
|
183 if(iRequestCancel) // Handle request cancellation, if needed |
|
184 { |
|
185 LOCAL_LOGTEXT("SetSCAInPhone","Request has been cancelled"); |
|
186 ret=KErrCancel; |
|
187 } |
|
188 else |
|
189 { |
|
190 // Set the SCA to use as the default in the phone's memory |
|
191 iTxBuffer.Copy(KSmsSetSCCommand); |
|
192 iTxBuffer.Append(KDblQuoteChar); |
|
193 const TInt count(iRequestSCA.iTelNumber.Length()); |
|
194 for(TInt i=0;i<count;++i) |
|
195 { |
|
196 if(CATSmsUtils::IsAddressChar(TChar(iRequestSCA.iTelNumber[i]))) |
|
197 iTxBuffer.Append(TChar(iRequestSCA.iTelNumber[i])); |
|
198 } |
|
199 iTxBuffer.Append(KDblQuoteChar); |
|
200 iTxBuffer.Append(KCommaChar); |
|
201 |
|
202 TUint val; |
|
203 CATSmsUtils::GetTypeOfAddressInDecimal(iRequestSCA,val); |
|
204 iTxBuffer.AppendNum(val,EDecimal); |
|
205 |
|
206 iTxBuffer.Append(KCarriageReturn); |
|
207 iIo->Write(this,iTxBuffer); |
|
208 iIo->SetTimeOut(this,KATWriteTimeout); |
|
209 } |
|
210 break; |
|
211 |
|
212 case EStage1: |
|
213 HandleWriteCompletion(aEventSource); |
|
214 break; |
|
215 |
|
216 case EStage2: |
|
217 // If we did not get an error |
|
218 if(HandleResponseCompletion(aEventSource)==KErrNone) |
|
219 CompleteRequest(); |
|
220 else |
|
221 { |
|
222 if(iRequestCancel) // Handle request cancellation, if needed |
|
223 { |
|
224 LOCAL_LOGTEXT("SetSCAInPhone","Request has been cancelled"); |
|
225 ret=KErrCancel; |
|
226 } |
|
227 else |
|
228 { |
|
229 // An error occurred |
|
230 // Try to set SCA again, but this time don't use <tosca> |
|
231 // The Motorola Timeport needs this behaviour |
|
232 iTxBuffer.Copy(KSmsSetSCCommand); |
|
233 iTxBuffer.Append(KDblQuoteChar); |
|
234 |
|
235 // Prefix phone number with a '+' if it's international |
|
236 if(iRequestSCA.iTypeOfNumber==RMobilePhone::EInternationalNumber) |
|
237 iTxBuffer.Append(KPlusChar); |
|
238 |
|
239 const TInt count(iRequestSCA.iTelNumber.Length()); |
|
240 for(TInt i=0;i<count;++i) |
|
241 { |
|
242 if(CATSmsUtils::IsAddressChar(TChar(iRequestSCA.iTelNumber[i]))) |
|
243 iTxBuffer.Append(TChar(iRequestSCA.iTelNumber[i])); |
|
244 } |
|
245 iTxBuffer.Append(KDblQuoteChar); |
|
246 iTxBuffer.Append(KCarriageReturn); |
|
247 iIo->Write(this,iTxBuffer); |
|
248 iIo->SetTimeOut(this,KATWriteTimeout); |
|
249 } |
|
250 } |
|
251 break; |
|
252 |
|
253 case EStage3: |
|
254 HandleWriteCompletion(aEventSource); |
|
255 break; |
|
256 |
|
257 case EStage4: |
|
258 if((ret=HandleResponseCompletion(aEventSource))==KErrNone) |
|
259 { |
|
260 // We've finished the request |
|
261 CompleteRequest(); |
|
262 } |
|
263 break; |
|
264 |
|
265 default: |
|
266 LOCAL_LOGTEXT("SetSCAInPhone","Unknown request stage"); |
|
267 __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequestStage)); |
|
268 ret=KErrGeneral; |
|
269 } |
|
270 |
|
271 ++iRequestStage; // Increment request stage for next iteration |
|
272 |
|
273 return ret; |
|
274 } |
|
275 |
|
276 |
|
277 TInt CATSmsCommands::GetSCAFromPhone(const TEventSource& aEventSource) |
|
278 /** |
|
279 * Gets phone's default SCA from phone and saves it in iRequestSCA. |
|
280 * IMPORTANT: If this method returns an error then EventSignal will complete our request. |
|
281 * @return Standard KErr... codes |
|
282 */ |
|
283 { |
|
284 LOCAL_LOGTEXT("GetSCAFromPhone","enter function"); |
|
285 __ASSERT_DEBUG(iRequest==EGetSCAFromPhone,Panic(EATSmsCommandsWrongRequest)); |
|
286 |
|
287 TInt ret(KErrNone); |
|
288 switch(iRequestStage) |
|
289 { |
|
290 case EStage0: |
|
291 if(iRequestCancel) // Handle request cancellation, if needed |
|
292 { |
|
293 LOCAL_LOGTEXT("GetSCAFromPhone","Request has been cancelled"); |
|
294 ret=KErrCancel; |
|
295 } |
|
296 else |
|
297 { |
|
298 // Initialize data |
|
299 iRequestSCA.iTypeOfNumber=RMobilePhone::EUnknownNumber; |
|
300 iRequestSCA.iNumberPlan=RMobilePhone::EUnknownNumberingPlan; |
|
301 iRequestSCA.iTelNumber.Zero(); |
|
302 |
|
303 // Send SCA request to phone |
|
304 iTxBuffer.Format(KServiceCentreQueryCommand); |
|
305 iIo->Write(this,iTxBuffer); |
|
306 iIo->SetTimeOut(this,KATWriteTimeout); |
|
307 } |
|
308 break; |
|
309 |
|
310 case EStage1: |
|
311 HandleWriteCompletion(aEventSource); |
|
312 break; |
|
313 |
|
314 case EStage2: |
|
315 ret=HandleResponseCompletion(aEventSource); |
|
316 if(ret!=KErrNone) |
|
317 break; |
|
318 |
|
319 // Did the phone have an SCA in default memory |
|
320 ret=ParseRxResultsForCSCAResponse(iRequestSCA); |
|
321 if(ret==KErrNone && iRequestSCA.iTelNumber.Length()>0) |
|
322 { |
|
323 // We've finished the request |
|
324 CompleteRequest(); |
|
325 ret=KErrNone; |
|
326 } |
|
327 else |
|
328 { |
|
329 if(iRequestCancel) // Handle request cancellation, if needed |
|
330 { |
|
331 LOCAL_LOGTEXT("GetSCAFromPhone","Request has been cancelled"); |
|
332 ret=KErrCancel; |
|
333 } |
|
334 else |
|
335 { |
|
336 // Check if the phone has a SCA after doing a memory refresh |
|
337 iTxBuffer.Format(KServiceCentreQueryCommandWithCRES); |
|
338 iIo->Write(this,iTxBuffer); |
|
339 iIo->SetTimeOut(this,KATWriteTimeout); |
|
340 } |
|
341 } |
|
342 break; |
|
343 |
|
344 case EStage3: |
|
345 HandleWriteCompletion(aEventSource); |
|
346 break; |
|
347 |
|
348 case EStage4: |
|
349 ret=HandleResponseCompletion(aEventSource); |
|
350 if(ret!=KErrNone) |
|
351 break; |
|
352 |
|
353 // Did the phone have an SCA in default memory, if so initialise iRequestSCA |
|
354 ret=ParseRxResultsForCSCAResponse(iRequestSCA); |
|
355 if(ret==KErrNone) |
|
356 { |
|
357 // We've finished the request |
|
358 CompleteRequest(); |
|
359 ret=KErrNone; |
|
360 } |
|
361 else |
|
362 { |
|
363 // We do not have an SCA and have exhausted all possibilities ;-( |
|
364 LOCAL_LOGTEXT("GetSCAFromPhone","Have not been able to find an SCA to use"); |
|
365 |
|
366 // |
|
367 // We have to complete with KErrNone so that the second part of the GetSMSP |
|
368 // retrieval IPC is called. If we do not do this the MSMSMESS file will get |
|
369 // it's iGetSMSPList array out of sync. |
|
370 CompleteRequest(); |
|
371 ret=KErrNone; |
|
372 } |
|
373 break; |
|
374 |
|
375 default: |
|
376 LOCAL_LOGTEXT("GetSCAFromPhone","Unknown request stage"); |
|
377 __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequestStage)); |
|
378 ret=KErrGeneral; |
|
379 } |
|
380 |
|
381 ++iRequestStage; // Increment request stage for next iteration |
|
382 |
|
383 return ret; |
|
384 } |
|
385 |
|
386 |
|
387 TInt CATSmsCommands::SetPhoneToCMTMode(const TEventSource& aEventSource) |
|
388 /** |
|
389 * Sets the phone into CMT mode by using 'AT+CNMI=x,2' |
|
390 * IMPORTANT: If this method returns an error then EventSignal will complete our request. |
|
391 * @return Standard KErr... codes |
|
392 */ |
|
393 { |
|
394 LOCAL_LOGTEXT("SetPhoneToCMTMode","enter function"); |
|
395 __ASSERT_DEBUG(iRequest==ESetPhoneToCMTMode,Panic(EATSmsCommandsWrongRequest)); |
|
396 |
|
397 TInt ret(KErrNone); |
|
398 switch(iRequestStage) |
|
399 { |
|
400 case EStage0: |
|
401 if(iRequestCancel) // Handle request cancellation, if needed |
|
402 { |
|
403 LOCAL_LOGTEXT("SetPhoneToCMTMode","Request has been cancelled"); |
|
404 ret=KErrCancel; |
|
405 } |
|
406 else |
|
407 { |
|
408 // Send 'AT+CNMI=?' to find out phones capabilities |
|
409 iTxBuffer.Format(KGetCNMIConfigCommand); |
|
410 iIo->Write(this,iTxBuffer); |
|
411 iIo->SetTimeOut(this,KATWriteTimeout); |
|
412 } |
|
413 break; |
|
414 |
|
415 case EStage1: |
|
416 HandleWriteCompletion(aEventSource); |
|
417 break; |
|
418 |
|
419 case EStage2: |
|
420 { // Curly brackets used to scope use of cnmiFirstValue |
|
421 // |
|
422 // If the phone returns ERROR then ignore the error and assume the |
|
423 // CNMI first parameter should be 2 |
|
424 TInt cnmiFirstValue(ECnmiMode2); |
|
425 if(HandleResponseCompletion(aEventSource)==KErrNone) |
|
426 { |
|
427 // Parse the response from the phone |
|
428 TRAP(ret,ParseCNMIFirstCapabilityL(cnmiFirstValue)); |
|
429 ret=KErrNone; // Ignore errors from ParseCNMIFirstCapabilityL call |
|
430 } |
|
431 |
|
432 // Send 'AT+CNMI=x,2' to phone to set it to CMT mode |
|
433 iTxBuffer.Format(KSmsSetCMTMode,cnmiFirstValue); |
|
434 iIo->Write(this,iTxBuffer); |
|
435 iIo->SetTimeOut(this,KATWriteTimeout); |
|
436 } |
|
437 break; |
|
438 |
|
439 case EStage3: |
|
440 HandleWriteCompletion(aEventSource); |
|
441 break; |
|
442 |
|
443 case EStage4: |
|
444 ret=HandleResponseCompletion(aEventSource); |
|
445 if(ret==KErrNone) |
|
446 { |
|
447 // We have completed our request |
|
448 CompleteRequest(); |
|
449 } |
|
450 break; |
|
451 |
|
452 default: |
|
453 LOCAL_LOGTEXT("SetPhoneToCMTMode","Unknown request stage"); |
|
454 __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequestStage)); |
|
455 ret=KErrGeneral; |
|
456 } |
|
457 |
|
458 ++iRequestStage; // Increment request stage for next iteration |
|
459 |
|
460 return ret; |
|
461 } |
|
462 |
|
463 |
|
464 TInt CATSmsCommands::SetPhoneToCMTIMode(const TEventSource& aEventSource) |
|
465 /** |
|
466 * Sets the phone into CMTI mode by using 'AT+CNMI=x,1' |
|
467 * IMPORTANT: If this method returns an error then EventSignal will complete our request. |
|
468 * @return Standard KErr... codes |
|
469 */ |
|
470 { |
|
471 LOCAL_LOGTEXT("SetPhoneToCMTIMode","enter function"); |
|
472 __ASSERT_DEBUG(iRequest==ESetPhoneToCMTIMode,Panic(EATSmsCommandsWrongRequest)); |
|
473 |
|
474 TInt ret(KErrNone); |
|
475 switch(iRequestStage) |
|
476 { |
|
477 case EStage0: |
|
478 if(iRequestCancel) // Handle request cancellation, if needed |
|
479 { |
|
480 LOCAL_LOGTEXT("SetPhoneToCMTIMode","Request has been cancelled"); |
|
481 ret=KErrCancel; |
|
482 } |
|
483 else |
|
484 { |
|
485 // Send 'AT+CNMI=?' to find out phones capabilities |
|
486 iTxBuffer.Format(KGetCNMIConfigCommand); |
|
487 iIo->Write(this,iTxBuffer); |
|
488 iIo->SetTimeOut(this,KATWriteTimeout); |
|
489 } |
|
490 break; |
|
491 |
|
492 case EStage1: |
|
493 HandleWriteCompletion(aEventSource); |
|
494 break; |
|
495 |
|
496 case EStage2: |
|
497 { // Curly brackets used to scope use of cnmiFirstValue |
|
498 // |
|
499 // If the phone returned ERROR then ignore the error and assume the |
|
500 // CNMI first parameter should be 2 |
|
501 TInt cnmiFirstValue(2); |
|
502 if(HandleResponseCompletion(aEventSource)==KErrNone) |
|
503 { |
|
504 // Parse the response from the phone |
|
505 TRAP(ret,ParseCNMIFirstCapabilityL(cnmiFirstValue)); |
|
506 ret=KErrNone; // Ignore errors from ParseCNMIFirstCapabilityL call |
|
507 } |
|
508 |
|
509 // Send 'AT+CNMI=x,1' to phone to set it to CMTI mode |
|
510 iTxBuffer.Format(KSmsSetCMTIMode,cnmiFirstValue); |
|
511 iIo->Write(this,iTxBuffer); |
|
512 iIo->SetTimeOut(this,KATWriteTimeout); |
|
513 } |
|
514 break; |
|
515 |
|
516 case EStage3: |
|
517 HandleWriteCompletion(aEventSource); |
|
518 break; |
|
519 |
|
520 case EStage4: |
|
521 ret=HandleResponseCompletion(aEventSource); |
|
522 if(ret==KErrNone) |
|
523 { |
|
524 // We have completed our request |
|
525 CompleteRequest(); |
|
526 } |
|
527 break; |
|
528 |
|
529 default: |
|
530 LOCAL_LOGTEXT("SetPhoneToCMTIMode","Unknown request stage"); |
|
531 __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequestStage)); |
|
532 ret=KErrGeneral; |
|
533 } |
|
534 |
|
535 ++iRequestStage; // Increment request stage for next iteration |
|
536 |
|
537 return ret; |
|
538 } |
|
539 |
|
540 |
|
541 |
|
542 void CATSmsCommands::CompleteRequest(TInt aError) |
|
543 /** |
|
544 * Common code for local AT request functions to complete a request from a derived class. |
|
545 * In the header file smsbase.h the default value for aError ir KErrNone. |
|
546 */ |
|
547 { |
|
548 LOCAL_LOGTEXT("CompleteRequest","enter function"); |
|
549 iRequestStage=0; |
|
550 iRequestCompleted=ETrue; |
|
551 iRequestError=aError; |
|
552 } |
|
553 |
|
554 void CATSmsCommands::HandleWriteCompletion(TEventSource aSource) |
|
555 /** |
|
556 * Common code for handling a write event from the CATIO class when communicating |
|
557 * with the modem. |
|
558 */ |
|
559 { |
|
560 LOCAL_LOGTEXT("HandleWriteCompletion","enter function"); |
|
561 __ASSERT_DEBUG(aSource==EWriteCompletion,Panic(EATCommand_IllegalCompletionWriteExpected)); |
|
562 iIo->WriteAndTimerCancel(this); |
|
563 AddCmsErrorExpectString(); |
|
564 StandardWriteCompletionHandler(aSource,KATResponseTimeout); |
|
565 } |
|
566 |
|
567 |
|
568 TInt CATSmsCommands::HandleResponseCompletion(TEventSource aSource,TBool aValidateExpectString) |
|
569 /** |
|
570 * Common code for handling a read event from the CATIO class when communicating |
|
571 * with the modem. Does some parsing of response to see if 'OK' or 'ERROR' was responded. |
|
572 */ |
|
573 { |
|
574 LOCAL_LOGTEXT("HandleResponseCompletion","enter function"); |
|
575 |
|
576 // |
|
577 // The below is an ASSERT ALWAYS just so that we do not get a WINSCW UREL warning. |
|
578 // The below only needs to be a ASSERT_DEBUG |
|
579 __ASSERT_ALWAYS(aSource==EReadCompletion,Panic(EATCommand_IllegalCompletionReadExpected)); |
|
580 iIo->WriteAndTimerCancel(this); |
|
581 |
|
582 TInt ret(KErrNone); |
|
583 if(aValidateExpectString) |
|
584 ret=ValidateExpectString(); // This will only check for 'OK' or 'ERROR' |
|
585 |
|
586 if(ret!=KErrNone) |
|
587 { |
|
588 // |
|
589 // If we received some kind of error, see if the CMS ERROR stuff can provide |
|
590 // a more meanigful error code |
|
591 ret=ConvertCMSErrorToKErr(CMSErrorValue()); |
|
592 } |
|
593 |
|
594 RemoveCmsErrorExpectString(); |
|
595 RemoveStdExpectStrings(); |
|
596 return ret; |
|
597 } |
|
598 |
|
599 void CATSmsCommands::EventSignal(TEventSource aEventSource) |
|
600 /** |
|
601 * Handles events for local AT commands |
|
602 * Will complete request if a handler returns anything other than KErrNone |
|
603 */ |
|
604 { |
|
605 LOCAL_LOGTEXT("EventSignal","enter function"); |
|
606 TInt error(KErrNone); |
|
607 // Check if a timeout occurred |
|
608 if(aEventSource==ETimeOutCompletion) |
|
609 { |
|
610 LOCAL_LOGTEXT("EventSignal","Timeout event has occurred"); |
|
611 iIo->RemoveExpectStrings(this); |
|
612 iIo->WriteAndTimerCancel(this); |
|
613 error=KErrTimedOut; |
|
614 } |
|
615 else |
|
616 { |
|
617 // Dispatch event to appropriate request handler |
|
618 switch(iRequest) |
|
619 { |
|
620 case EGetSCAFromPhone: |
|
621 error=GetSCAFromPhone(aEventSource); |
|
622 break; |
|
623 |
|
624 case ESetSCAInPhone: |
|
625 error=SetSCAInPhone(aEventSource); |
|
626 break; |
|
627 |
|
628 case ESetPhoneToCMTMode: |
|
629 error=SetPhoneToCMTMode(aEventSource); |
|
630 break; |
|
631 |
|
632 case ESetPhoneToCMTIMode: |
|
633 error=SetPhoneToCMTIMode(aEventSource); |
|
634 break; |
|
635 |
|
636 case ENone: // Must not be caught by default case |
|
637 break; |
|
638 default: |
|
639 LOCAL_LOGTEXT("EventSignal","Unknown request"); |
|
640 __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequest)); |
|
641 } |
|
642 } |
|
643 |
|
644 if(error!=KErrNone) |
|
645 CompleteRequest(error); |
|
646 } |
|
647 |
|
648 |
|
649 TBool CATSmsCommands::ComparePrefMem(const TStorageType& aName) const |
|
650 { |
|
651 LOCAL_LOGTEXT("ComparePrefMem","enter function"); |
|
652 return iPhoneGlobals->iPhonePrefMem==aName; |
|
653 } |
|
654 |
|
655 void CATSmsCommands::SetCurrentPrefMem(const TStorageType& aStorageName) |
|
656 { |
|
657 LOCAL_LOGTEXT("SetCurrentPrefMem","enter function"); |
|
658 iTxBuffer.Format(KSetPrefMemCommandWithString,&aStorageName,&aStorageName); // Setting both the read and write memory to one and the same store(ME or SM). |
|
659 iIo->Write(this,iTxBuffer); |
|
660 iIo->SetTimeOut(this,KATWriteTimeout); |
|
661 } |
|
662 |
|
663 |
|
664 |
|
665 TInt CATSmsCommands::ParseRxResultsForCSCAResponse(RMobilePhone::TMobileAddress& aTelNumber) |
|
666 /** |
|
667 * Analyse rx results for a CSCA response and attempt to parse into provided tel. |
|
668 * The actual work is done in DoParseRxResultsForCSCAResponseL. Since this method |
|
669 * can't leave and ParseBufferLC() has to be called and ParseBufferLC() puts something |
|
670 * on the cleanup stack, the "Do" method had to be added. |
|
671 * @return Standard KErr... values |
|
672 */ |
|
673 { |
|
674 LOCAL_LOGTEXT("ParseRxResultsForCSCAResponse","enter function"); |
|
675 TInt ret(KErrNone); |
|
676 TRAPD(leaveCode,ret = DoParseRxResultsForCSCAResponseL(aTelNumber)); |
|
677 if(leaveCode) |
|
678 return leaveCode; |
|
679 else |
|
680 return ret; |
|
681 } |
|
682 |
|
683 |
|
684 TInt CATSmsCommands::DoParseRxResultsForCSCAResponseL(RMobilePhone::TMobileAddress& aTelNumber) |
|
685 /** |
|
686 * Analyse rx results for a CSCA response and attempt to parse into provided tel |
|
687 * number object |
|
688 * @return Standard KErr... values |
|
689 */ |
|
690 { |
|
691 LOCAL_LOGTEXT("DoParseRxResultsForCSCAResponseL","enter function"); |
|
692 TInt ret(KErrNotFound); |
|
693 |
|
694 // Parse buffer |
|
695 ParseBufferLC(); |
|
696 TDblQueIter<CATParamListEntry> iter(iRxResults); |
|
697 |
|
698 // Extract tokens from parser |
|
699 CATParamListEntry* cscaEntry=iter++; |
|
700 |
|
701 if((cscaEntry)&&(cscaEntry->iResultPtr == KCSCAResponseString)) |
|
702 { |
|
703 CATParamListEntry* telNumberEntry=iter++; |
|
704 if (telNumberEntry) |
|
705 { |
|
706 // |
|
707 // Parse tokens into a TMobileAddress |
|
708 // |
|
709 // Type of number field <tosca> of +CSCA is optional so we have to accomodate for that. |
|
710 // If <tosca> was missing then we subsitute it with a dummy '000' <tosca>. |
|
711 _LIT8(KDummyNumberTypeEntry,"000"); |
|
712 CATParamListEntry* numberTypeEntry=iter++; |
|
713 if (!numberTypeEntry) |
|
714 ret=CATSmsUtils::CopyAddressStringToAddressStruct(telNumberEntry->iResultPtr,KDummyNumberTypeEntry,aTelNumber); |
|
715 else |
|
716 ret=CATSmsUtils::CopyAddressStringToAddressStruct(telNumberEntry->iResultPtr,numberTypeEntry->iResultPtr,aTelNumber); |
|
717 } |
|
718 } |
|
719 |
|
720 CleanupStack::PopAndDestroy(); // ParseBufferLC |
|
721 return ret; |
|
722 } |
|
723 |
|
724 |
|
725 TInt CATSmsCommands::CMSErrorValue() |
|
726 /* |
|
727 * Returns the error code decoded from the response string .eg '+CMS ERROR: xxx'. |
|
728 * This functions considers '+CMS ERROR: 500' and 'ERROR' as the error 500. |
|
729 * @return if there was an error the ETSI or KErr error value |
|
730 * @return if there was not an error then KErrNone |
|
731 */ |
|
732 { |
|
733 LOCAL_LOGTEXT("CMSErrorValue","enter function"); |
|
734 // Locate error string |
|
735 iBuffer.Set(iIo->Buffer()); |
|
736 TInt pos=iBuffer.FindF(KERRORResponseString); |
|
737 if (pos==KErrNotFound) |
|
738 return KErrNone; // If we can't find the 'ERROR' string then that means there was not an error ;-) |
|
739 |
|
740 // Locate error value |
|
741 // (ie. read in all digits form the first found to the end of the string) |
|
742 const TInt length=iBuffer.Length(); |
|
743 pos+=KCMGSResponseStringLength; |
|
744 while(pos<length && !(TChar(iBuffer[pos]).IsDigit())) |
|
745 pos++; |
|
746 |
|
747 TInt ret=500; // 500 is the error value for 'undefined' |
|
748 if(pos<length) // Only decode error value if we found some digits |
|
749 { |
|
750 TLex8 lex(iBuffer.Mid(pos)); |
|
751 TUint16 val; |
|
752 if(lex.Val(val,EDecimal)==KErrNone) |
|
753 ret=val; |
|
754 } |
|
755 |
|
756 LOGTEXT2(_L8("CATSmsCommands::CmsErrorValue\terror = %d"),ret); |
|
757 return ret; |
|
758 } |
|
759 |
|
760 |
|
761 TInt CATSmsCommands::ConvertCMSErrorToKErr(const TInt& aCmsError) const |
|
762 { |
|
763 LOCAL_LOGTEXT("ConvertCMSErrorToKErr","enter function"); |
|
764 if(aCmsError==0) |
|
765 return KErrNone; |
|
766 |
|
767 return KErrGsmSmsBase-aCmsError; |
|
768 } |
|
769 |
|
770 |
|
771 void CATSmsCommands::ProcessCapsElementL(TDblQueIter<CATParamListEntry>& aIter,TInt32& aCapsMask) |
|
772 // |
|
773 // Process a single element, i.e. a range or a bracketed list |
|
774 // |
|
775 { |
|
776 TInt r=KErrNone; |
|
777 _LIT8(KOpenBracket, "("); |
|
778 _LIT8(KCloseBracket, ")"); |
|
779 _LIT8(KDashChar, "-"); |
|
780 |
|
781 CATParamListEntry* entry=aIter; |
|
782 if(!entry) |
|
783 return; |
|
784 |
|
785 aIter++; |
|
786 |
|
787 TBool listPresent=EFalse; // Is there a list here? |
|
788 if(entry->iResultPtr==KOpenBracket) |
|
789 { |
|
790 listPresent=ETrue; |
|
791 entry=aIter++; |
|
792 if(!entry) |
|
793 return; |
|
794 } |
|
795 |
|
796 // Process the element |
|
797 do |
|
798 { |
|
799 // It might be a range, signified by a '-' |
|
800 TInt pos=entry->iResultPtr.Find(KDashChar); |
|
801 if(pos!=KErrNotFound) |
|
802 { |
|
803 TInt32 rangeStart; |
|
804 TLex8 rangeStartString(entry->iResultPtr.Left(pos)); |
|
805 if((r=rangeStartString.Val(rangeStart))!=KErrNone) |
|
806 User::Leave(r); |
|
807 |
|
808 TInt32 rangeEnd; |
|
809 TInt l; |
|
810 if((l=entry->iResultPtr.Length()-pos-1)<=0) |
|
811 User::Leave(KErrGeneral); |
|
812 TLex8 rangeEndString(entry->iResultPtr.Right(l)); |
|
813 if((r=rangeEndString.Val(rangeEnd))!=KErrNone) |
|
814 User::Leave(r); |
|
815 |
|
816 if((rangeStart<0)||(rangeStart>31)||(rangeEnd<0)||(rangeEnd>31)) |
|
817 User::Leave(KErrGeneral); |
|
818 |
|
819 for(TInt i=rangeStart;i<(rangeEnd+1);i++) |
|
820 aCapsMask|=(1<<i); |
|
821 } |
|
822 // Or it might be the close bracket ')' |
|
823 else if(entry->iResultPtr==KCloseBracket) |
|
824 listPresent=EFalse; |
|
825 // Or it might be a single value |
|
826 else |
|
827 { |
|
828 TInt32 value; |
|
829 TLex8 string(entry->iResultPtr); |
|
830 if((r=string.Val(value))!=KErrNone) |
|
831 User::Leave(r); |
|
832 |
|
833 if((value<0)||(value>31)) |
|
834 User::Leave(KErrGeneral); |
|
835 |
|
836 aCapsMask|=(1<<value); |
|
837 } |
|
838 entry=aIter++; |
|
839 } |
|
840 while((listPresent)&&(entry!=NULL)); |
|
841 aIter--; |
|
842 } |
|
843 |
|
844 |
|
845 void CATSmsCommands::ParseCNMIFirstCapabilityL(TInt& aHighestValue) |
|
846 { |
|
847 ParseBufferLC(ETrue); |
|
848 TDblQueIter<CATParamListEntry> iter(iRxResults); |
|
849 CATParamListEntry* entry=iter++; |
|
850 |
|
851 if((entry==NULL)||(entry->iResultPtr!=KCNMIResponseString)) |
|
852 { |
|
853 LOGTEXT(_L8("Error - Cannot find CNMI: string")); |
|
854 User::Leave(KErrNotFound); |
|
855 } |
|
856 |
|
857 TInt32 bitmap(0); |
|
858 ProcessCapsElementL(iter,bitmap); |
|
859 |
|
860 aHighestValue=ECnmiMode0; // bitmap&0x01 denotes highest value of 0 |
|
861 |
|
862 if(bitmap&KCapsCnmiMode2) |
|
863 aHighestValue=ECnmiMode2; |
|
864 else if(bitmap&KCapsCnmiMode1) // Mode 1 only set if mode 2 not supported |
|
865 aHighestValue=ECnmiMode1; |
|
866 else if(bitmap&KCapsCnmiMode3) // Only set to mode 3 if this is the only mode supported |
|
867 aHighestValue=ECnmiMode3; |
|
868 |
|
869 CleanupStack::PopAndDestroy(); // ParseBufferLC object |
|
870 } |