1 /* (c) 2002-2008 by Marcin Wiacek and Michal Cihar */
2
3 /**
4 * @file atgen.c
5 * @author Michal Čihař
6 * @author Marcin Wiacek
7 */
8 /**
9 * @ingroup Phone
10 * @{
11 */
12 /**
13 * @addtogroup ATPhone
14 * @{
15 */
16
17 #define _GNU_SOURCE
18 #include <gammu-config.h>
19
20 #ifdef GSM_ENABLE_ATGEN
21
22 #include <string.h>
23 #include <time.h>
24 #include <ctype.h>
25 #include <stdarg.h>
26
27 #include "../../gsmcomon.h"
28 #include "../../gsmphones.h"
29 #include "../../misc/coding/coding.h"
30 #include "../../service/gsmmisc.h"
31 #include "../../service/gsmpbk.h"
32 #include "../pfunc.h"
33
34 #include "atgen.h"
35 #include "atfunc.h"
36
37 #include "samsung.h"
38 #include "siemens.h"
39 #include "motorola.h"
40 #include "sonyericsson.h"
41
42 #include "../../../libgammu/misc/string.h"
43
44 #ifdef GSM_ENABLE_ALCATEL
45 GSM_Error ALCATEL_ProtocolVersionReply (GSM_Protocol_Message *, GSM_StateMachine *);
46 #endif
47
48 #ifdef GSM_ENABLE_ATOBEX
49 #include "../atobex/atobexfunc.h"
50 #endif
51
52
53 typedef struct {
54 const GSM_AT_Charset charset;
55 const char *text;
56 const gboolean unicode;
57 const gboolean ira;
58 const gboolean GSM;
59 } GSM_AT_Charset_Info;
60
61 /**
62 * List of charsets and text identifying them in phone responses, order
63 * defines their preferences, so if first is found it is used.
64 */
65 static GSM_AT_Charset_Info AT_Charsets[] = {
66 {AT_CHARSET_HEX, "HEX", FALSE, FALSE, FALSE},
67 {AT_CHARSET_GSM, "GSM", FALSE, FALSE, TRUE},
68 {AT_CHARSET_PCCP437, "PCCP437", FALSE, FALSE, FALSE},
69 {AT_CHARSET_UTF_8, "UTF-8", TRUE, FALSE, FALSE},
70 {AT_CHARSET_UTF8, "UTF8", TRUE, FALSE, FALSE},
71 {AT_CHARSET_UCS_2, "UCS-2", TRUE, FALSE, FALSE},
72 {AT_CHARSET_UCS2, "UCS2", TRUE, FALSE, FALSE},
73 {AT_CHARSET_IRA, "IRA", FALSE, TRUE, TRUE},
74 {AT_CHARSET_ASCII, "ASCII", FALSE, TRUE, TRUE},
75 #ifdef ICONV_FOUND
76 {AT_CHARSET_ISO88591, "8859-1", FALSE, FALSE, FALSE},
77 {AT_CHARSET_ISO88592, "8859-2", FALSE, FALSE, FALSE},
78 {AT_CHARSET_ISO88593, "8859-3", FALSE, FALSE, FALSE},
79 {AT_CHARSET_ISO88594, "8859-4", FALSE, FALSE, FALSE},
80 {AT_CHARSET_ISO88595, "8859-5", FALSE, FALSE, FALSE},
81 {AT_CHARSET_ISO88596, "8859-6", FALSE, FALSE, FALSE},
82 #endif
83 {0, NULL, FALSE, FALSE, FALSE}
84 };
85
86 typedef struct {
87 int Number;
88 char Text[60];
89 } ATErrorCode;
90
91 static ATErrorCode CMSErrorCodes[] = {
92 /*
93 * Error codes not specified here were either undefined or reserved in my
94 * copy of specifications, if you have newer one, please fill in the gaps.
95 */
96 /* 0...127 from GSM 04.11 Annex E-2 */
97 {1, "Unassigned (unallocated) number"},
98 {8, "Operator determined barring"},
99 {10, "Call barred"},
100 {21, "Short message transfer rejected"},
101 {27, "Destination out of service"},
102 {28, "Unidentified subscriber"},
103 {29, "Facility rejected"},
104 {30, "Unknown subscriber"},
105 {38, "Network out of order"},
106 {41, "Temporary failure"},
107 {42, "Congestion"},
108 {47, "Resources unavailable, unspecified"},
109 {50, "Requested facility not subscribed"},
110 {69, "Requested facility not implemented"},
111 {81, "Invalid short message transfer reference value"},
112 {95, "Invalid message, unspecified"},
113 {96, "Invalid mandatory information"},
114 {97, "Message type non-existent or not implemented"},
115 {98, "Message not compatible with short message protocol state"},
116 {99, "Information element non-existent or not implemented"},
117 {111, "Protocol error, unspecified"},
118 {127, "Interworking, unspecified"},
119 /* 128...255 from GSM 03.40 subclause 9.2.3.22 */
120 {0x80, "Telematic interworking not supported"},
121 {0x81, "Short message Type 0 not supported"},
122 {0x82, "Cannot replace short message"},
123 {0x8F, "Unspecified TP-PID error"},
124 {0x90, "Data coding scheme (alphabet) not supported"},
125 {0x91, "Message class not supported"},
126 {0x9F, "Unspecified TP-DCS error"},
127 {0xA0, "Command cannot be actioned"},
128 {0xA1, "Command unsupported"},
129 {0xAF, "Unspecified TP-Command error"},
130 {0xB0, "TPDU not supported"},
131 {0xC0, "SC busy"},
132 {0xC1, "No SC subscription"},
133 {0xC2, "SC system failure"},
134 {0xC3, "Invalid SME address"},
135 {0xC4, "Destination SME barred"},
136 {0xC5, "SM Rejected-Duplicate SM"},
137 {0xC6, "TP-VPF not supported"},
138 {0xC7, "TP-VP not supported"},
139 {0xD0, "SIM SMS storage full"},
140 {0xD1, "No SMS storage capability in SIM"},
141 {0xD2, "Error in MS"},
142 {0xD3, "Memory Capacity Exceede"},
143 {0xD4, "SIM Application Toolkit Busy"},
144 {0xFF, "Unspecified error cause"},
145 /* From Siemens documentation, does not have to be valid for all vendors */
146 {256, "Operation temporary not allowed"},
147 {257, "call barred"},
148 {258, "phone busy"},
149 {259, "user abort"},
150 {260, "invalid dial string"},
151 {261, "ss not executed"},
152 {262, "SIM blocked"},
153 {263, "Invalid Block"},
154 /* 300...511 from GSM 07.05 subclause 3.2.5 */
155 {300, "ME failure"},
156 {301, "SMS service of ME reserved"},
157 {302, "operation not allowed"},
158 {303, "operation not supported"},
159 {304, "invalid PDU mode parameter"},
160 {305, "invalid text mode parameter"},
161 {310, "SIM not inserted"},
162 {311, "SIM PIN required"},
163 {312, "PH-SIM PIN required"},
164 {313, "SIM failure"},
165 {314, "SIM busy"},
166 {315, "SIM wrong"},
167 {316, "SIM PUK required"},
168 {317, "SIM PIN2 required"},
169 {318, "SIM PUK2 required"},
170 {320, "memory failure"},
171 {321, "invalid memory index"},
172 {322, "memory full"},
173 {330, "SMSC address unknown"},
174 {331, "no network service"},
175 {332, "network timeout"},
176 {340, "no CNMA acknowledgement expected"},
177 {500, "unknown error"},
178 /* > 512 are manufacturer specific according to GSM 07.05 subclause 3.2.5 */
179 {516, "Motorola - too high location?"},
180 /* Siemens */
181 {512, "User abort"},
182 {513, "unable to store"},
183 {514, "invalid status"},
184 {515, "invalid character in address string"},
185 {516, "invalid length"},
186 {517, "invalid character in pdu"},
187 {519, "invalid length or character"},
188 {520, "invalid character in text"},
189 {521, "timer expired"},
190 {522, "Operation temporary not allowed"},
191 {532, "SIM not ready"},
192 {534, "Cell Broadcast error unknown"},
193 {535, "PS busy"},
194 {538, "invalid parameter"},
195 {549, "incorrect PDU length"},
196 {550, "invalid message type indication (MTI)"},
197 {551, "invalid (non-hex) chars in address"},
198 {553, "incorrect PDU length (UDL)"},
199 {554, "incorrect SCA length"},
200 {578, "GPRS - unspecified activation rejection"},
201 {588, "GPRS - feature not supported"},
202 {594, "GPRS - invalid address length"},
203 {595, "GPRS - invalid character in address string"},
204 {596, "GPRS - invalid cid value"},
205 {607, "GPRS - missing or unknown APN"},
206 {615, "network failure"},
207 {616, "network is down"},
208 {625, "GPRS - pdp type not supported"},
209 {630, "GPRS - profile (cid) not defined"},
210 {632, "GPRS - QOS not accepted"},
211 {633, "GPRS - QOS validation fail"},
212 {639, "service type not yet available"},
213 {640, "operation of service temporary not allowed"},
214 {643, "GPRS - unknown PDP address or type"},
215 {644, "GPRS - unknown PDP context"},
216 {646, "GPRS - QOS invalid parameter"},
217 {764, "missing input value"},
218 {765, "invalid input value"},
219 {767, "operation failed"},
220 {769, "unable to get control of required module"},
221 {770, "SIM invalid - network reject"},
222 {771, "call setup in progress"},
223 {772, "SIM powered down"},
224 {-1, ""}
225 };
226
227 static ATErrorCode CMEErrorCodes[] = {
228 /* CME Error codes from GSM 07.07 section 9.2 */
229 {0, "phone failure"},
230 {1, "no connection to phone"},
231 {2, "phone-adaptor link reserved"},
232 {3, "operation not allowed"},
233 {4, "operation not supported"},
234 {5, "PH-SIM PIN required"},
235 {10, "SIM not inserted"},
236 {11, "SIM PIN required"},
237 {12, "SIM PUK required"},
238 {13, "SIM failure"},
239 {14, "SIM busy"},
240 {15, "SIM wrong"},
241 {16, "incorrect password"},
242 {17, "SIM PIN2 required"},
243 {18, "SIM PUK2 required"},
244 {20, "memory full"},
245 {21, "invalid index"},
246 {22, "not found"},
247 {23, "memory failure"},
248 {24, "text string too long"},
249 {25, "invalid characters in text string"},
250 {26, "dial string too long"},
251 {27, "invalid characters in dial string"},
252 {30, "no network service"},
253 {31, "network timeout"},
254 /* 3GPP TS 27.007 /2/ */
255 {32, "Network not allowed - emergency calls only."},
256 {40, "Network personalization PIN required."},
257 {41, "Network personalization PUK required."},
258 {42, "Network subset personalization PIN required."},
259 {43, "Network subset personalization PUK required."},
260 {44, "Service provider personalization PIN required."},
261 {45, "Service provider personalization PUK required."},
262 {46, "Corporate personalization PIN required."},
263 {47, "Corporate personalization PUK required."},
264 {100, "unknown"},
265 /* GPRS-related errors - (#X = GSM 04.08 cause codes) */
266 {103, "Illegal MS (#3)."},
267 {106, "Illegal ME (#6)."},
268 {107, "GPRS services not allowed (#7)."},
269 {111, "Public Land Mobile Network (PLMN) not allowed (#11)."},
270 {112, "Location area not allowed (#12)."},
271 {113, "Roaming not allowed in this location area (#13)."},
272 /* Errors related to a failure in Activating a Context and
273 Other GPRS errors */
274 {132, "Service option not supported (#32)."},
275 {133, "Requested service option not subscribed (#33)."},
276 {134, "Service option temporarily out of order (#34)."},
277 {148, "Unspecified GPRS error."},
278 {149, "PDP authentication failure."},
279 {150, "Invalid mobile class."},
280 {-1, ""}
281 };
282
283 static char samsung_location_error[] = "[Samsung] Empty location";
284
ATGEN_BeforeDeferredEventHook(GSM_StateMachine * s)285 GSM_Error ATGEN_BeforeDeferredEventHook(GSM_StateMachine *s)
286 {
287 /* we can do this because deferred events must only be run when no other
288 * request is executing */
289 s->Protocol.Data.AT.Msg.Length = 0;
290
291 return ERR_NONE;
292 }
293
ATGEN_IsMemoryAvailable(const GSM_Phone_ATGENData * data,GSM_MemoryType type)294 gboolean ATGEN_IsMemoryAvailable(const GSM_Phone_ATGENData *data, GSM_MemoryType type)
295 {
296 return
297 (type == MEM_ME && data->PhoneSMSMemory == AT_AVAILABLE) ||
298 (type == MEM_SM && data->SIMSMSMemory == AT_AVAILABLE) ||
299 (type == MEM_MT && (data->PhoneSMSMemory == AT_AVAILABLE || data->SIMSMSMemory == AT_AVAILABLE)) ||
300 (type == MEM_SR && data->SRSMSMemory == AT_AVAILABLE);
301 }
302
ATGEN_IsMemoryWriteable(const GSM_Phone_ATGENData * data,GSM_MemoryType type)303 gboolean ATGEN_IsMemoryWriteable(const GSM_Phone_ATGENData *data, GSM_MemoryType type)
304 {
305 // we assume that if memory is writeable, then it's also enabled
306 return
307 (type == MEM_ME && data->PhoneSaveSMS == AT_AVAILABLE) ||
308 (type == MEM_SM && data->SIMSaveSMS == AT_AVAILABLE) ||
309 (type == MEM_MT && (data->PhoneSaveSMS == AT_AVAILABLE || data->SIMSaveSMS == AT_AVAILABLE)) ||
310 (type == MEM_SR && data->SRSaveSMS == AT_AVAILABLE);
311 }
312
ATGEN_HandleCMEError(GSM_StateMachine * s)313 GSM_Error ATGEN_HandleCMEError(GSM_StateMachine *s)
314 {
315 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
316
317 if (Priv->ErrorCode == 0) {
318 smprintf(s, "CME Error occured, but it's type not detected\n");
319 } else if (Priv->ErrorText == NULL) {
320 smprintf(s, "CME Error %i, no description available\n", Priv->ErrorCode);
321 } else {
322 smprintf(s, "CME Error %i: \"%s\"\n", Priv->ErrorCode, Priv->ErrorText);
323 }
324 /* For error codes descriptions see table a bit above */
325 switch (Priv->ErrorCode) {
326 case -1:
327 return ERR_EMPTY;
328 case 4:
329 case 601: /* This seems to be returned by SE P1i when writing to pbk */
330 return ERR_NOTSUPPORTED;
331 case 3:
332 case 5:
333 case 11:
334 case 12:
335 case 16:
336 case 17:
337 case 18:
338 case 40:
339 case 41:
340 case 42:
341 case 43:
342 case 44:
343 case 45:
344 case 46:
345 case 47:
346 return ERR_SECURITYERROR;
347 case 10:
348 case 13:
349 case 14:
350 case 15:
351 return ERR_NOSIM;
352 case 20:
353 return ERR_FULL;
354 case 21:
355 return ERR_INVALIDLOCATION;
356 case 22:
357 return ERR_EMPTY;
358 case 23:
359 return ERR_MEMORY;
360 case 24:
361 case 25:
362 case 26:
363 case 27:
364 return ERR_INVALIDDATA;
365 case 30:
366 case 31:
367 case 32:
368 return ERR_NETWORK_ERROR;
369 case 515:
370 return ERR_BUSY;
371 default:
372 return ERR_UNKNOWN;
373 }
374 }
375
ATGEN_HandleCMSError(GSM_StateMachine * s)376 GSM_Error ATGEN_HandleCMSError(GSM_StateMachine *s)
377 {
378 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
379
380 if (Priv->ErrorCode == 0) {
381 smprintf(s, "CMS Error occured, but it's type not detected\n");
382 } else if (Priv->ErrorText == NULL) {
383 smprintf(s, "CMS Error %i, no description available\n", Priv->ErrorCode);
384 } else {
385 smprintf(s, "CMS Error %i: \"%s\"\n", Priv->ErrorCode, Priv->ErrorText);
386 }
387 /* For error codes descriptions see table a bit above */
388 switch (Priv->ErrorCode) {
389 case 0xD3:
390 return ERR_FULL;
391 case 0:
392 case 300:
393 case 320:
394 return ERR_PHONE_INTERNAL;
395 case 38:
396 case 41:
397 case 42:
398 case 47:
399 case 111:
400 case 331:
401 case 332:
402 case 615:
403 case 616:
404 return ERR_NETWORK_ERROR;
405 case 304:
406 return ERR_NOTSUPPORTED;
407 case 305:
408 case 514:
409 case 515:
410 case 517:
411 case 519:
412 case 520:
413 case 538:
414 case 549:
415 case 550:
416 case 551:
417 case 553:
418 case 554:
419 return ERR_BUG;
420 case 302:
421 case 311:
422 case 312:
423 case 316:
424 case 317:
425 case 318:
426 return ERR_SECURITYERROR;
427 case 313:
428 case 314:
429 case 315:
430 return ERR_NOSIM;
431 case 322:
432 return ERR_FULL;
433 case 321:
434 case 516:
435 return ERR_INVALIDLOCATION;
436 case 535:
437 return ERR_BUSY;
438 default:
439 return ERR_UNKNOWN;
440 }
441 }
442
443 /**
444 * Wrapper around \ref GSM_WaitFor, which automatically sets
445 * correct Motorola mode. It accepts same parameters as
446 * \ref GSM_WaitFor.
447 */
ATGEN_WaitFor(GSM_StateMachine * s,const char * cmd,size_t len,int type,int timeout,GSM_Phone_RequestID request)448 GSM_Error ATGEN_WaitFor(GSM_StateMachine *s, const char * cmd, size_t len,
449 int type, int timeout, GSM_Phone_RequestID request)
450 {
451 GSM_Error error;
452 error = MOTOROLA_SetMode(s, cmd);
453 if (error != ERR_NONE) {
454 return error;
455 }
456 error = GSM_WaitFor(s, cmd, len, type, timeout, request);
457 return error;
458 }
459
460 /**
461 * Checks whether string contains some non hex chars.
462 *
463 * \param text String to check.
464 *
465 * \return True when text does not contain non hex chars.
466 */
ATGEN_HasOnlyHexChars(const char * text,const size_t length)467 gboolean ATGEN_HasOnlyHexChars(const char *text, const size_t length)
468 {
469 size_t i = 0;
470
471 for (i = 0; i < length; i++) {
472 if (!isxdigit((int)(unsigned char)text[i])) {
473 return FALSE;
474 }
475 }
476 return TRUE;
477 }
478
479 /**
480 * Checks whether string contains only digits.
481 *
482 * \param text String to check.
483 *
484 * \return True when text does not contain non digits chars.
485 */
ATGEN_HasOnlyDigits(const char * text,const size_t length)486 gboolean ATGEN_HasOnlyDigits(const char *text, const size_t length)
487 {
488 size_t i = 0;
489
490 for (i = 0; i < length; i++) {
491 if (!isdigit((int)(unsigned char)text[i])) {
492 return FALSE;
493 }
494 }
495 return TRUE;
496 }
497
498 /**
499 * Detects whether given text can be UCS2.
500 *
501 * \param s State machine structure.
502 * \param len Length of string.
503 * \param text Text.
504 * \return True when text can be UCS2.
505 */
ATGEN_IsUCS2(const char * text,const size_t length)506 gboolean ATGEN_IsUCS2(const char *text, const size_t length)
507 {
508 return (length > 3) &&
509 (length % 4 == 0) &&
510 ATGEN_HasOnlyHexChars(text, length);
511 }
512
513 /**
514 * Detects whether given text can be HEX.
515 *
516 * \param s State machine structure.
517 * \param len Length of string.
518 * \param text Text.
519 * \return True when text can be HEX.
520 */
ATGEN_IsHex(const char * text,const size_t length)521 gboolean ATGEN_IsHex(const char *text, const size_t length)
522 {
523 return (length > 4) &&
524 (length % 2 == 0) &&
525 ATGEN_HasOnlyHexChars(text, length);
526 }
527
528 /**
529 * Detects whether given text can be phone number.
530 *
531 * \param s State machine structure.
532 * \param len Length of string.
533 * \param text Text.
534 * \return True when text can be HEX.
535 */
ATGEN_IsNumber(const char * text,const size_t length)536 gboolean ATGEN_IsNumber(const char *text, const size_t length)
537 {
538 return ATGEN_HasOnlyDigits(text, length);
539 }
540
541 /**
542 * Encodes text to current phone charset.
543 *
544 * \param s State machine structure.
545 * \param input Input string.
546 * \param inlength Length of string to convert.
547 * \param output Storage for converted text.
548 * \param outlength Size of output storage.
549 *
550 * \return Error code.
551 */
ATGEN_EncodeText(GSM_StateMachine * s,const unsigned char * input,const size_t inlength,unsigned char * output,const size_t outlength,size_t * resultlength)552 GSM_Error ATGEN_EncodeText(GSM_StateMachine *s,
553 const unsigned char *input,
554 const size_t inlength,
555 unsigned char *output,
556 const size_t outlength,
557 size_t *resultlength
558 )
559 {
560 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
561 unsigned char *uname = NULL;
562 size_t len = inlength;
563
564 /* As input is unicode, we should not need that much memory, but it is safe */
565 uname = (unsigned char *)malloc(2 * (inlength + 1));
566
567 if (uname == NULL) {
568 return ERR_MOREMEMORY;
569 }
570 switch (Priv->Charset) {
571 case AT_CHARSET_HEX:
572 EncodeDefault(uname, input, &len, TRUE, NULL);
573 EncodeHexBin(output, uname, len);
574 len = strlen(output);
575 break;
576 case AT_CHARSET_GSM:
577 smprintf(s, "str: %s\n", DecodeUnicodeString(input));
578 EncodeDefault(output, input, &len, TRUE, NULL);
579 break;
580 case AT_CHARSET_UCS2:
581 case AT_CHARSET_UCS_2:
582 EncodeHexUnicode(output, input, UnicodeLength(input));
583 len = strlen(output);
584 break;
585 case AT_CHARSET_IRA:
586 case AT_CHARSET_ASCII:
587 free(uname);
588 uname = NULL;
589 return ERR_NOTSUPPORTED;
590 case AT_CHARSET_UTF8:
591 case AT_CHARSET_UTF_8:
592 EncodeUTF8(output, input);
593 len = strlen(output);
594 break;
595 #ifdef ICONV_FOUND
596 case AT_CHARSET_PCCP437:
597 IconvEncode("CP437", input, 2 * len, output, outlength);
598 len = strlen(output);
599 break;
600 case AT_CHARSET_ISO88591:
601 IconvEncode("ISO-8859-1", input, 2 * len, output, outlength);
602 len = strlen(output);
603 break;
604 case AT_CHARSET_ISO88592:
605 IconvEncode("ISO-8859-2", input, 2 * len, output, outlength);
606 len = strlen(output);
607 break;
608 case AT_CHARSET_ISO88593:
609 IconvEncode("ISO-8859-3", input, 2 * len, output, outlength);
610 len = strlen(output);
611 break;
612 case AT_CHARSET_ISO88594:
613 IconvEncode("ISO-8859-4", input, 2 * len, output, outlength);
614 len = strlen(output);
615 break;
616 case AT_CHARSET_ISO88595:
617 IconvEncode("ISO-8859-5", input, 2 * len, output, outlength);
618 len = strlen(output);
619 break;
620 case AT_CHARSET_ISO88596:
621 IconvEncode("ISO-8859-6", input, 2 * len, output, outlength);
622 len = strlen(output);
623 break;
624 #else
625 case AT_CHARSET_PCCP437:
626 /* FIXME: correctly encode to PCCP437 */
627 smprintf(s, "str: %s\n", DecodeUnicodeString(input));
628 EncodeDefault(output, input, &len, TRUE, NULL);
629 break;
630 #endif
631 default:
632 smprintf(s, "Unsupported charset! (%d)\n", Priv->Charset);
633 free(uname);
634 uname = NULL;
635 return ERR_SOURCENOTAVAILABLE;
636 }
637 *resultlength = len;
638 free(uname);
639 uname = NULL;
640 return ERR_NONE;
641 }
642
643
644 /**
645 * Decodes text from phone encoding to internal representation.
646 *
647 * \param s State machine structure.
648 * \param input Input string.
649 * \param length Length of string to convert.
650 * \param output Storage for converted text.
651 * \param outlength Size of output storage.
652 * \param guess Allow guessing whether input is really encoded.
653 * \param phone Whether input is phone number, used only when guessing.
654 *
655 * \return Error code.
656 */
ATGEN_DecodeText(GSM_StateMachine * s,const unsigned char * input,const size_t length,unsigned char * output,const size_t outlength,const gboolean guess,const gboolean phone)657 GSM_Error ATGEN_DecodeText(GSM_StateMachine *s,
658 const unsigned char *input,
659 const size_t length,
660 unsigned char *output,
661 const size_t outlength,
662 const gboolean guess,
663 const gboolean phone)
664 {
665 unsigned char *buffer;
666 GSM_AT_Charset charset;
667 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
668 gboolean is_hex, is_ucs, is_number;
669
670 /* Default to charset from state machine */
671 charset = s->Phone.Data.Priv.ATGEN.Charset;
672
673 /* Canonical names */
674 if (charset == AT_CHARSET_UCS_2) {
675 charset = AT_CHARSET_UCS2;
676 } else if (charset == AT_CHARSET_UTF_8) {
677 charset = AT_CHARSET_UTF8;
678 }
679
680 /* Basic type checks */
681 is_hex = ATGEN_IsHex(input, length);
682 is_ucs = ATGEN_IsUCS2(input, length);
683
684 /* Can we do guesses? */
685 if (guess) {
686 is_number = ATGEN_IsNumber(input, length);
687 /* Are there HEX only chars? */
688 if (charset == AT_CHARSET_HEX
689 && ! is_hex) {
690 charset = AT_CHARSET_GSM;
691 }
692 /* Should be HEX encoded, but is a phone number */
693 if (charset == AT_CHARSET_HEX && is_number) {
694 /* Check whether it would not be number hex decoded as well */
695 buffer = (unsigned char *)malloc(length);
696
697 if (buffer == NULL) {
698 return ERR_MOREMEMORY;
699 }
700 DecodeHexBin(buffer, input, length);
701 if (!ATGEN_IsNumber(buffer, strlen(buffer))) {
702 charset = AT_CHARSET_GSM;
703 }
704 free(buffer);
705 }
706 /*
707 * Motorola sometimes replies in UCS2 while there is HEX chosen.
708 * If string starts with two zeroes, it is definitely not HEX.
709 */
710 if (charset == AT_CHARSET_HEX
711 && is_ucs
712 && input[0] == '0'
713 && input[1] == '0'
714 && input[4] == '0'
715 && input[5] == '0'
716 ) {
717 charset = AT_CHARSET_UCS2;
718 }
719 /*
720 * For phone numbers, we can assume all unicode chars
721 * will be < 256, so they will fit one byte.
722 */
723 if (charset == AT_CHARSET_UCS2
724 && (! is_ucs ||
725 (phone &&
726 (input[0] != '0' ||
727 input[1] != '0' ||
728 input[4] != '0' ||
729 input[5] != '0'
730 )))) {
731 charset = AT_CHARSET_GSM;
732 }
733 /*
734 * Phone number can also contain email, catch it by @.
735 */
736 if (charset == AT_CHARSET_GSM
737 && phone
738 && (! is_ucs)
739 && strchr(input, '@') != NULL) {
740 charset = AT_CHARSET_UTF8;
741 }
742 /*
743 * Phone number are unusally not that long
744 */
745 if (charset == AT_CHARSET_GSM
746 && phone
747 && length >= 16
748 && is_ucs) {
749 charset = AT_CHARSET_UCS2;
750 }
751 /*
752 * Motorola sometimes criples HEX reply while UCS-2 is chosen.
753 * It seems to be identified by trailing zero.
754 */
755 if (charset == AT_CHARSET_UCS2
756 && is_hex
757 && Priv->Manufacturer == AT_Motorola
758 && input[length - 1] == '0'
759 && input[length - 2] == '0'
760 ) {
761 charset = AT_CHARSET_HEX;
762 }
763 } else {
764 /* No guessing, but still do some sanity checks */
765 if (charset == AT_CHARSET_UCS2 && !is_ucs) {
766 charset = AT_CHARSET_GSM;
767 }
768 if (charset == AT_CHARSET_HEX && !is_hex) {
769 charset = AT_CHARSET_GSM;
770 }
771 }
772
773 /* Check for broken phones */
774 if (charset == AT_CHARSET_GSM &&
775 GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_FORCE_UTF8)) {
776 charset = AT_CHARSET_UTF8;
777 }
778
779 /* Finally do conversion */
780 switch (charset) {
781 case AT_CHARSET_HEX:
782 /* Length must be enough, because we have two chars for byte */
783 buffer = (unsigned char *)malloc(length);
784
785 if (buffer == NULL) {
786 return ERR_MOREMEMORY;
787 }
788 DecodeHexBin(buffer, input, length);
789 if (2 * strlen(buffer) >= outlength) {
790 free(buffer);
791 return ERR_MOREMEMORY;
792 }
793 DecodeDefault(output, buffer, strlen(buffer), TRUE, NULL);
794 free(buffer);
795 buffer = NULL;
796 break;
797 case AT_CHARSET_GSM:
798 if (2 * length >= outlength) return ERR_MOREMEMORY;
799 DecodeDefault(output, input, length, TRUE, NULL);
800 break;
801 case AT_CHARSET_UCS2:
802 case AT_CHARSET_UCS_2:
803 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SAMSUNG_UTF8)) {
804 unsigned char *buf;
805 unsigned i;
806 int state = 0;
807
808 if (length >= outlength) {
809 return ERR_MOREMEMORY;
810 }
811 buf = malloc (length / 2 + 5);
812 if (!buf) {
813 return ERR_MOREMEMORY;
814 }
815 DecodeHexUnicode(buf, input, length);
816 for (i = 0; 2 * i + 1 < length / 2; i++) {
817 buf[i] = (buf[2 * i] == 0x20 && buf[2 * i + 1] == 0xac) ? 0xe5 : buf[2 * i + 1];
818 if (!(buf[i] & 0x80)) {
819 if (state && buf[i] == 0x40) {
820 buf[i] = 0x80;
821 state--;
822 } else if (state && buf[i] == 0x5b) {
823 buf[i] = 0xbc;
824 state--;
825 } else if (state && buf[i] == 0x5c) {
826 buf[i] = 0xaf;
827 state--;
828 } else if (state && buf[i] == 0x5d) {
829 buf[i] = 0xbe;
830 state--;
831 } else if (state && buf[i] == 0x5e) {
832 buf[i] = 0x94;
833 state--;
834 } else if (state && buf[i] == 0x7b) {
835 buf[i] = 0xa8;
836 state--;
837 } else if (state && buf[i] == 0x7d) {
838 buf[i] = 0xa9;
839 state--;
840 } else if (state && buf[i] == 0x7e) {
841 buf[i] = 0xbd;
842 state--;
843 } else {
844 state = 0;
845 }
846 } else if ((buf[i] & 0xc0) == 0x80) {
847 if (state) {
848 state--;
849 }
850 } else if ((buf[i] & 0xe0) == 0xc0) {
851 state = 1;
852 } else if ((buf[i] & 0xf0) == 0xe0) {
853 state = 2;
854 } else {
855 state = 3;
856 }
857
858 }
859 buf[i] = 0;
860
861 DecodeUTF8(output, buf, length / 2);
862 free (buf);
863 } else {
864 if (length / 2 >= outlength) {
865 return ERR_MOREMEMORY;
866 }
867 DecodeHexUnicode(output, input, length);
868 }
869 break;
870 case AT_CHARSET_IRA: /* IRA is ASCII only, so it's safe to treat is as UTF-8 */
871 case AT_CHARSET_ASCII:
872 case AT_CHARSET_UTF8:
873 case AT_CHARSET_UTF_8:
874 if (2 * length >= outlength) return ERR_MOREMEMORY;
875 DecodeUTF8(output, input, length);
876 break;
877 #ifdef ICONV_FOUND
878 case AT_CHARSET_PCCP437:
879 IconvDecode("CP437", input, length, output, outlength);
880 break;
881 case AT_CHARSET_ISO88591:
882 IconvDecode("ISO-8859-1", input, length, output, outlength);
883 break;
884 case AT_CHARSET_ISO88592:
885 IconvDecode("ISO-8859-2", input, length, output, outlength);
886 break;
887 case AT_CHARSET_ISO88593:
888 IconvDecode("ISO-8859-3", input, length, output, outlength);
889 break;
890 case AT_CHARSET_ISO88594:
891 IconvDecode("ISO-8859-4", input, length, output, outlength);
892 break;
893 case AT_CHARSET_ISO88595:
894 IconvDecode("ISO-8859-5", input, length, output, outlength);
895 break;
896 case AT_CHARSET_ISO88596:
897 IconvDecode("ISO-8859-6", input, length, output, outlength);
898 break;
899 #else
900 case AT_CHARSET_PCCP437:
901 /* FIXME: correctly decode PCCP437 */
902 if (2 * length >= outlength) return ERR_MOREMEMORY;
903 DecodeDefault(output, input, length, FALSE, NULL);
904 break;
905 #endif
906 default:
907 smprintf(s, "Unsupported charset! (%d)\n", charset);
908 return ERR_SOURCENOTAVAILABLE;
909 }
910
911 return ERR_NONE;
912 }
913
ATGEN_ExtractOneParameter(unsigned char * input,unsigned char * output)914 int ATGEN_ExtractOneParameter(unsigned char *input, unsigned char *output)
915 {
916 int position = 0;
917 gboolean inside_quotes = FALSE;
918
919 while ((*input!=',' || inside_quotes) && *input != 0x0d && *input != 0x00) {
920 if (*input == '"') inside_quotes = ! inside_quotes;
921 *output = *input;
922 input ++;
923 output ++;
924 position++;
925 }
926 *output = 0;
927 position++;
928 return position;
929 }
930
931 /**
932 * Grabs single string parameter from AT command reply. Removing possible quotes.
933 *
934 * \param s State machine structure.
935 * \param input Input string to parse.
936 * \param output Pointer to pointer to char, buffer will be allocated.
937 *
938 * \return Length of parsed string.
939 */
ATGEN_GrabString(GSM_StateMachine * s,const unsigned char * input,unsigned char ** output)940 size_t ATGEN_GrabString(GSM_StateMachine *s, const unsigned char *input, unsigned char **output)
941 {
942 size_t size = 4, position = 0;
943 gboolean inside_quotes = FALSE;
944
945 /* Allocate initial buffer in case string is empty */
946 *output = (unsigned char *)malloc(size);
947
948 if (*output == NULL) {
949 smprintf(s, "Ran out of memory!\n");
950 return 0;
951 }
952 while (inside_quotes ||
953 ( *input != ','
954 && *input != ')'
955 && *input != 0x0d
956 && *input != 0x0a
957 && *input != 0x00)) {
958 /* Check for quotes */
959 if (*input == '"') {
960 inside_quotes = ! inside_quotes;
961 }
962
963 /* We also allocate space for traling zero */
964 if (position + 2 > size) {
965 size += 10;
966 *output = (unsigned char *)realloc(*output, size);
967 if (*output == NULL) {
968 smprintf(s, "Ran out of memory!\n");
969 return 0;
970 }
971 }
972
973 /* Copy to output */
974 (*output)[position] = *input;
975 position++;
976 input ++;
977 }
978
979 (*output)[position] = 0;
980
981 /* Strip quotes */
982 if ((*output)[0] == '"' && (*output)[position - 1]) {
983 memmove(*output, (*output) + 1, position - 2);
984 (*output)[position - 2] = 0;
985 }
986
987 smprintf(s, "Grabbed string from reply: \"%s\" (parsed %ld bytes)\n", *output, (long)position);
988 return position;
989 }
990
991 /**
992 * This function parses datetime strings in the format:
993 * [YY[YY]/MM/DD,]hh:mm[:ss[+TZ]] , [] enclosed parts are optional
994 * (or the same hex/unicode encoded).
995 *
996 * It also handles when date and time are swapped.
997 *
998 * And tries to detect if the date is not in format MM-DD-YYYY.
999 *
1000 * @todo Too many static buffers are used here.
1001 */
ATGEN_DecodeDateTime(GSM_StateMachine * s,GSM_DateTime * dt,unsigned char * _input)1002 GSM_Error ATGEN_DecodeDateTime(GSM_StateMachine *s, GSM_DateTime *dt, unsigned char *_input)
1003 {
1004 unsigned char buffer[100]={'\0'};
1005 unsigned char *pos = NULL;
1006 unsigned char buffer_unicode[200]={'\0'};
1007 unsigned char input[100]={'\0'};
1008 char separator = '\0', *separator_pos, *comma_pos, *date_start, *time_start;
1009 int year;
1010 GSM_Error error;
1011 size_t len;
1012
1013 strncpy(input, _input, 100);
1014 input[99] = '\0';
1015 pos = input;
1016
1017 /* Strip possible leading comma */
1018 if (*pos == ',') pos++;
1019 if (input[0] == 0) return ERR_EMPTY;
1020 if (input[strlen(pos) - 1] == ',') input[strlen(pos) - 1] = 0;
1021 if (input[0] == 0) return ERR_EMPTY;
1022
1023 /* Strip possible quotes */
1024 if (*pos == '"') pos++;
1025 if (input[0] == 0) return ERR_EMPTY;
1026 if (input[strlen(pos) - 1] == '"') input[strlen(pos) - 1] = 0;
1027 if (input[0] == 0) return ERR_EMPTY;
1028
1029 /* Convert to normal charset */
1030 error = ATGEN_DecodeText(s,
1031 pos, strlen(pos),
1032 buffer_unicode, sizeof(buffer_unicode),
1033 TRUE, FALSE);
1034 if (error != ERR_NONE) return error;
1035 DecodeUnicode(buffer_unicode, buffer);
1036
1037 pos = buffer;
1038
1039 /* Strip possible quotes again */
1040 if (*pos == '"') {
1041 pos++;
1042 }
1043 len = strlen(pos);
1044 if (len == 0) {
1045 return ERR_EMPTY;
1046 }
1047 if (buffer[len - 1] == '"') {
1048 buffer[len - 1] = 0;
1049 }
1050
1051 /* Check whether date is separated by / or - */
1052 if ((separator_pos = strchr(pos, '/')) != NULL) {
1053 separator = '/';
1054 } else if ((separator_pos = strchr(pos, '-')) != NULL) {
1055 separator = '-';
1056 }
1057
1058 /* Find out where we have comma */
1059 comma_pos = strchr(pos, ',');
1060
1061 /* Skip comma and possible whitespace */
1062 if (comma_pos != NULL) {
1063 while (isspace(*(comma_pos + 1)) && *(comma_pos + 1) != '\0') {
1064 comma_pos++;
1065 }
1066 }
1067
1068 /* Find out locations of date parts */
1069 if (comma_pos != NULL && separator_pos > comma_pos) {
1070 date_start = comma_pos + 1;
1071 time_start = pos;
1072 } else if (separator_pos != NULL) {
1073 date_start = pos;
1074 time_start = comma_pos + 1;
1075 } else {
1076 date_start = NULL;
1077 time_start = pos;
1078 }
1079
1080 /* Do we have date? */
1081 if (date_start != NULL) {
1082 dt->Year = atoi(date_start);
1083 pos = strchr(date_start, separator);
1084 if (pos == NULL) return ERR_UNKNOWN;
1085 pos++;
1086 dt->Month = atoi(pos);
1087 pos = strchr(pos, separator);
1088 if (pos == NULL) return ERR_UNKNOWN;
1089 pos++;
1090 dt->Day = atoi(pos);
1091
1092 /* Are day, month and year swapped? */
1093 if (dt->Day > 31) {
1094 year = dt->Day;
1095 dt->Day = dt->Month;
1096 dt->Month = dt->Year;
1097 dt->Year = year;
1098 }
1099
1100 /* Do we need to handle Y2K (Samsung usually does this)? */
1101 if (dt->Year > 80 && dt->Year < 1000) {
1102 dt->Year += 1900;
1103 } else if (dt->Year < 100) {
1104 dt->Year += 2000;
1105 }
1106
1107 } else {
1108 /* if date was not found, it is still necessary to initialize
1109 the variables, maybe Today() would be better in some replies */
1110 dt->Year = 0;
1111 dt->Month = 0;
1112 dt->Day = 0;
1113 }
1114
1115 /* Parse time */
1116 dt->Hour = atoi(time_start);
1117 pos = strchr(time_start, ':');
1118 if (pos == NULL) return ERR_UNKNOWN;
1119 pos++;
1120 dt->Minute = atoi(pos);
1121 pos = strchr(pos, ':');
1122 if (pos != NULL) {
1123 /* seconds present */
1124 pos++;
1125 dt->Second = atoi(pos);
1126 } else {
1127 dt->Second = 0;
1128 }
1129
1130 pos = strchr(time_start, '+');
1131 if (pos == NULL)
1132 pos = strchr(time_start, '-');
1133
1134 if (pos != NULL) {
1135 /* timezone present */
1136 dt->Timezone = (*pos == '+' ? 1 : -1) * atoi(pos+1) * 3600 / 4;
1137 } else {
1138 dt->Timezone = 0;
1139 }
1140 smprintf(s, "Parsed date: %d-%d-%d %d:%d:%d, TZ %d\n",
1141 dt->Year,
1142 dt->Month,
1143 dt->Day,
1144 dt->Hour,
1145 dt->Minute,
1146 dt->Second,
1147 dt->Timezone);
1148 return ERR_NONE;
1149 }
1150
ATGEN_ParseReply(GSM_StateMachine * s,const unsigned char * input,const char * format,...)1151 GSM_Error ATGEN_ParseReply(GSM_StateMachine *s, const unsigned char *input, const char *format, ...)
1152 {
1153 const char *fmt = format;
1154 const char *input_pos = input;
1155 char *endptr = NULL, *out_s = NULL, *search_pos = NULL;
1156 GSM_DateTime *out_dt;
1157 unsigned char *out_us = NULL,*buffer = NULL,*buffer2=NULL;
1158 size_t length = 0,storage_size = 0;
1159 int *out_i = NULL;
1160 long int *out_l = NULL;
1161 va_list ap;
1162 GSM_Error error = ERR_NONE;
1163
1164 smprintf(s, "Parsing %s with %s\n", input, format);
1165
1166 va_start(ap, format);
1167 while (*fmt) {
1168 switch(*fmt++) {
1169 case '@':
1170 if (*fmt == 0) {
1171 smprintf(s, "Invalid format string: %s\n", format);
1172 error = ERR_BUG;
1173 goto end;
1174 }
1175 switch(*fmt++) {
1176 case 'i':
1177 out_i = va_arg(ap, int *);
1178 *out_i = strtol(input_pos, &endptr, 10);
1179 if (endptr == input_pos) {
1180 error = ERR_UNKNOWNRESPONSE;
1181 goto end;
1182 }
1183 smprintf(s, "Parsed int %d\n", *out_i);
1184 input_pos = endptr;
1185 break;
1186 case 'n':
1187 out_i = va_arg(ap, int *);
1188 length = ATGEN_GrabString(s, input_pos, &buffer);
1189 *out_i = strtol(buffer, &endptr, 10);
1190 if (endptr == (char *)buffer) {
1191 free(buffer);
1192 error = ERR_UNKNOWNRESPONSE;
1193 goto end;
1194 }
1195 free(buffer);
1196 smprintf(s, "Parsed int %d\n", *out_i);
1197 input_pos += length;
1198 break;
1199 case 'I':
1200 out_i = va_arg(ap, int *);
1201 *out_i = strtol(input_pos, &endptr, 10);
1202 if (endptr == input_pos) {
1203 smprintf(s, "Number empty\n");
1204 *out_i = 0;
1205 } else {
1206 smprintf(s, "Parsed int %d\n", *out_i);
1207 input_pos = endptr;
1208 }
1209 break;
1210 case 'l':
1211 out_l = va_arg(ap, long int *);
1212 *out_l = strtol(input_pos, &endptr, 10);
1213 if (endptr == input_pos) {
1214 error = ERR_UNKNOWNRESPONSE;
1215 goto end;
1216 }
1217 smprintf(s, "Parsed long int %ld\n", *out_l);
1218 input_pos = endptr;
1219 break;
1220 case 'p':
1221 out_s = va_arg(ap, char *);
1222 storage_size = va_arg(ap, size_t);
1223 length = ATGEN_GrabString(s, input_pos, &buffer);
1224 smprintf(s, "Parsed phone string \"%s\"\n", buffer);
1225 error = ATGEN_DecodeText(s,
1226 buffer, strlen(buffer),
1227 out_s, storage_size,
1228 TRUE, TRUE);
1229 if (error == ERR_NONE) {
1230 smprintf(s, "Phone string decoded as \"%s\"\n", DecodeUnicodeString(out_s));
1231 }
1232 free(buffer);
1233 buffer = NULL;
1234
1235 if (error != ERR_NONE) {
1236 goto end;
1237 }
1238 input_pos += length;
1239 break;
1240 case 's':
1241 out_s = va_arg(ap, char *);
1242 storage_size = va_arg(ap, size_t);
1243 length = ATGEN_GrabString(s, input_pos, &buffer);
1244 smprintf(s, "Parsed generic string \"%s\"\n", buffer);
1245 error = ATGEN_DecodeText(s,
1246 buffer, strlen(buffer),
1247 out_s, storage_size,
1248 TRUE, FALSE);
1249 if (error == ERR_NONE) {
1250 smprintf(s, "Generic string decoded as \"%s\"\n", DecodeUnicodeString(out_s));
1251 }
1252 free(buffer);
1253 buffer = NULL;
1254
1255 if (error != ERR_NONE) {
1256 goto end;
1257 }
1258 input_pos += length;
1259 break;
1260 case 't':
1261 out_s = va_arg(ap, char *);
1262 storage_size = va_arg(ap, size_t);
1263 length = ATGEN_GrabString(s, input_pos, &buffer);
1264 smprintf(s, "Parsed string with length \"%s\"\n", buffer);
1265 if (!isdigit((int)buffer[0])) {
1266 free(buffer);
1267 buffer = NULL;
1268 error = ERR_UNKNOWNRESPONSE;
1269 goto end;
1270 }
1271 search_pos = strchr(buffer, ',');
1272 if (search_pos == NULL) {
1273 free(buffer);
1274 buffer = NULL;
1275 error = ERR_UNKNOWNRESPONSE;
1276 goto end;
1277 }
1278 search_pos++;
1279 error = ATGEN_DecodeText(s,
1280 search_pos, strlen(search_pos),
1281 out_s, storage_size,
1282 TRUE, FALSE);
1283 if (error == ERR_NONE) {
1284 smprintf(s, "String with length decoded as \"%s\"\n", DecodeUnicodeString(out_s));
1285 }
1286 free(buffer);
1287 buffer = NULL;
1288
1289 if (error != ERR_NONE) {
1290 goto end;
1291 }
1292 input_pos += length;
1293 break;
1294 case 'u':
1295 out_s = va_arg(ap, char *);
1296 storage_size = va_arg(ap, size_t);
1297 length = ATGEN_GrabString(s, input_pos, &buffer);
1298 smprintf(s, "Parsed utf-8 string \"%s\"\n", buffer);
1299 DecodeUTF8(out_s, buffer, strlen(buffer));
1300 smprintf(s, "utf-8 string with length decoded as \"%s\"\n", DecodeUnicodeString(out_s));
1301 free(buffer);
1302 buffer = NULL;
1303 input_pos += length;
1304 break;
1305 case 'T':
1306 out_s = va_arg(ap, char *);
1307 storage_size = va_arg(ap, size_t);
1308 length = ATGEN_GrabString(s, input_pos, &buffer);
1309 smprintf(s, "Parsed utf-8 string with length \"%s\"\n", buffer);
1310 if (!isdigit((int)buffer[0])) {
1311 free(buffer);
1312 buffer = NULL;
1313 error = ERR_UNKNOWNRESPONSE;
1314 goto end;
1315 }
1316 search_pos = strchr(buffer, ',');
1317 if (search_pos == NULL) {
1318 free(buffer);
1319 buffer = NULL;
1320 error = ERR_UNKNOWNRESPONSE;
1321 goto end;
1322 }
1323 search_pos++;
1324 DecodeUTF8(out_s, search_pos, strlen(search_pos));
1325 smprintf(s, "utf-8 string with length decoded as \"%s\"\n", DecodeUnicodeString(out_s));
1326 free(buffer);
1327 buffer = NULL;
1328 input_pos += length;
1329 break;
1330 case 'e':
1331 out_s = va_arg(ap, char *);
1332 storage_size = va_arg(ap, size_t);
1333 length = ATGEN_GrabString(s, input_pos, &buffer);
1334 smprintf(s, "Parsed generic string \"%s\"\n", buffer);
1335 error = ATGEN_DecodeText(s,
1336 buffer, strlen(buffer),
1337 out_s, storage_size,
1338 FALSE, FALSE);
1339 if (error == ERR_NONE) {
1340 smprintf(s, "Generic string decoded as \"%s\"\n", DecodeUnicodeString(out_s));
1341 }
1342 free(buffer);
1343 buffer = NULL;
1344
1345 if (error != ERR_NONE) {
1346 goto end;
1347 }
1348 input_pos += length;
1349 break;
1350 case 'S':
1351 out_s = va_arg(ap, char *);
1352 storage_size = va_arg(ap, size_t);
1353 length = ATGEN_GrabString(s, input_pos, &buffer);
1354 if (buffer[0] == 0x02 && buffer[strlen(buffer) - 1] == 0x03) {
1355 memmove(buffer, buffer + 1, strlen(buffer) - 2);
1356 buffer[strlen(buffer) - 2] = 0;
1357 }
1358 smprintf(s, "Parsed Samsung string \"%s\"\n", buffer);
1359 DecodeUTF8(out_s, buffer, strlen(buffer));
1360 smprintf(s, "Samsung string decoded as \"%s\"\n", DecodeUnicodeString(out_s));
1361 free(buffer);
1362 buffer = NULL;
1363 input_pos += length;
1364 break;
1365 case 'r':
1366 out_us = va_arg(ap, unsigned char *);
1367 storage_size = va_arg(ap, size_t);
1368 length = ATGEN_GrabString(s, input_pos, &buffer);
1369 smprintf(s, "Parsed raw string \"%s\"\n", buffer);
1370 if (strlen(buffer) > storage_size) {
1371 free(buffer);
1372 buffer = NULL;
1373 error = ERR_MOREMEMORY;
1374 goto end;
1375 }
1376 strcpy(out_us, buffer);
1377 free(buffer);
1378 buffer = NULL;
1379 input_pos += length;
1380 break;
1381 case 'd':
1382 out_dt = va_arg(ap, GSM_DateTime *);
1383 length = ATGEN_GrabString(s, input_pos, &buffer);
1384 /* Fix up reply from broken phones which split
1385 * date to two strings */
1386 if (length > 0 && *(input_pos + length) == ',' &&
1387 strchr(buffer, ',') == NULL
1388 ) {
1389 length++;
1390 length += ATGEN_GrabString(s, input_pos + length, &buffer2);
1391 buffer = (unsigned char *)realloc(buffer, length + 2);
1392 strcat(buffer, ",");
1393 strcat(buffer, buffer2);
1394 free(buffer2);
1395 buffer2=NULL;
1396 }
1397 /* Ignore missing date */
1398 if (strlen(buffer) != 0) {
1399 smprintf(s, "Parsed string for date \"%s\"\n", buffer);
1400 error = ATGEN_DecodeDateTime(s, out_dt, buffer);
1401 free(buffer);
1402 buffer = NULL;
1403
1404 if (error != ERR_NONE) {
1405 goto end;
1406 }
1407 input_pos += length;
1408 } else {
1409 free(buffer);
1410 buffer = NULL;
1411 }
1412 break;
1413 case '@':
1414 if (*input_pos++ != '@') {
1415 error = ERR_UNKNOWNRESPONSE;
1416 goto end;
1417 }
1418 break;
1419 case '0':
1420 /* Just skip the rest */
1421 goto end;
1422 default:
1423 smprintf(s, "Invalid format string (@%c): %s\n", *(fmt - 1), format);
1424 error = ERR_BUG;
1425 goto end;
1426 }
1427 break;
1428 case ' ':
1429 while (isspace((int)*input_pos)) input_pos++;
1430 break;
1431 default:
1432 if (*input_pos++ != *(fmt - 1)) {
1433 error = ERR_UNKNOWNRESPONSE;
1434 goto end;
1435 }
1436 break;
1437 }
1438 }
1439
1440 /* Ignore trailing spaces */
1441 while (isspace((int)*input_pos)) input_pos++;
1442
1443 if (*input_pos != 0) {
1444 smprintf(s, "String do not end same!\n");
1445 error = ERR_UNKNOWNRESPONSE;
1446 goto end;
1447 }
1448 end:
1449 va_end(ap);
1450 return error;
1451 }
1452
ATGEN_PrintReplyLines(GSM_StateMachine * s)1453 int ATGEN_PrintReplyLines(GSM_StateMachine *s)
1454 {
1455 int i = 0;
1456 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1457 GSM_Protocol_Message *msg = s->Phone.Data.RequestMsg;
1458
1459 /* Find number of lines */
1460 while (Priv->Lines.numbers[i*2+1] != 0) {
1461 /* FIXME: handle special chars correctly */
1462 smprintf(s, "%i \"%s\"\n",i+1,GetLineString(msg->Buffer,&Priv->Lines,i+1));
1463 i++;
1464 }
1465 return i;
1466 }
1467
ATGEN_DispatchMessage(GSM_StateMachine * s)1468 GSM_Error ATGEN_DispatchMessage(GSM_StateMachine *s)
1469 {
1470 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1471 GSM_Protocol_Message *msg = s->Phone.Data.RequestMsg;
1472 int i = 0,j = 0,k = 0;
1473 const char *err, *line;
1474 ATErrorCode *ErrorCodes = NULL;
1475 char *line1, *line2;
1476
1477 SplitLines(msg->Buffer, msg->Length, &Priv->Lines, "\x0D\x0A", 2, "\"", 1, TRUE);
1478
1479 /* Find number of lines */
1480 i = ATGEN_PrintReplyLines(s);
1481
1482 /* Check for duplicated command in response (bug#1069) */
1483 if (i >= 2) {
1484 /* Get first two lines */
1485 line1 = strdup(GetLineString(msg->Buffer, &Priv->Lines, 1));
1486 line2 = strdup(GetLineString(msg->Buffer, &Priv->Lines, 2));
1487 if (line1 == NULL || line2 == NULL) {
1488 free(line1);
1489 free(line2);
1490 return ERR_MOREMEMORY;
1491 }
1492 /* Is it AT command? */
1493 if (strncmp(line1, "AT", 2) == 0) {
1494 /* Are two lines same */
1495 if (strcmp(line1, line2) == 0) {
1496 smprintf(s, "Removing first reply, because it is duplicated\n");
1497 /* Remove first line */
1498 memmove(Priv->Lines.numbers, Priv->Lines.numbers + 2, (Priv->Lines.allocated - 2) * sizeof(int));
1499 i--;
1500 ATGEN_PrintReplyLines(s);
1501 }
1502 }
1503 /* Free allocated memory */
1504 free(line1);
1505 free(line2);
1506 }
1507
1508 Priv->ReplyState = AT_Reply_Unknown;
1509 Priv->ErrorText = NULL;
1510 Priv->ErrorCode = 0;
1511
1512 line = GetLineString(msg->Buffer,&Priv->Lines,i);
1513
1514 smprintf(s, "Checking line: %s\n", line);
1515
1516 if (!strcmp(line,"OK")) {
1517 Priv->ReplyState = AT_Reply_OK;
1518 }
1519 if (!strncmp(line,"+CPIN:", 6) && s->Protocol.Data.AT.CPINNoOK) {
1520 Priv->ReplyState = AT_Reply_OK;
1521 }
1522 if (!strcmp(line,"> ")) {
1523 Priv->ReplyState = AT_Reply_SMSEdit;
1524 }
1525 if (!strcmp(line,"CONNECT")) {
1526 Priv->ReplyState = AT_Reply_Connect;
1527 }
1528 if (!strcmp(line,"ERROR")) {
1529 Priv->ReplyState = AT_Reply_Error;
1530 }
1531 if (!strcmp(line,"NO CARRIER")) {
1532 Priv->ReplyState = AT_Reply_Error;
1533 }
1534
1535 if (!strncmp(line,"+CME ERROR:",11)) {
1536 Priv->ReplyState = AT_Reply_CMEError;
1537 ErrorCodes = CMEErrorCodes;
1538 }
1539 if (!strncmp(line,"+CMS ERROR:",11)) {
1540 Priv->ReplyState = AT_Reply_CMSError;
1541 ErrorCodes = CMSErrorCodes;
1542 }
1543
1544 /* Huawei E220 returns COMMAND NOT SUPPORT on AT+MODE=2 */
1545 if (!strncmp(line, "COMMAND NOT SUPPORT", 19)) {
1546 Priv->ReplyState = AT_Reply_Error;
1547 }
1548
1549 /* Motorola A1200 */
1550 if (!strncmp(line, "MODEM ERROR:", 12)) {
1551 Priv->ReplyState = AT_Reply_Error;
1552 }
1553
1554 /* FIXME: Samsung phones can answer +CME ERROR:-1 meaning empty location */
1555 if (Priv->ReplyState == AT_Reply_CMEError && Priv->Manufacturer == AT_Samsung) {
1556 err = line + 11;
1557 Priv->ErrorCode = atoi(err);
1558
1559 if (Priv->ErrorCode == -1) {
1560 Priv->ErrorText = samsung_location_error;
1561 return GSM_DispatchMessage(s);
1562 }
1563 }
1564
1565 if (Priv->ReplyState == AT_Reply_CMEError || Priv->ReplyState == AT_Reply_CMSError) {
1566 if (ErrorCodes == NULL) {
1567 return ERR_BUG;
1568 }
1569 j = 0;
1570 /* One char behind +CM[SE] ERROR */
1571 err = line + 11;
1572 while (err[j] && !isalnum((int)err[j])) j++;
1573
1574 if (isdigit((int)err[j])) {
1575 Priv->ErrorCode = atoi(&(err[j]));
1576 for (k = 0; ErrorCodes[k].Number != -1; k++) {
1577 if (ErrorCodes[k].Number == Priv->ErrorCode) {
1578 Priv->ErrorText = ErrorCodes[k].Text;
1579 break;
1580 }
1581 }
1582 } else if (isalpha((int)err[j])) {
1583 for (k = 0; ErrorCodes[k].Number != -1; k++) {
1584 if (!strncmp(err + j, ErrorCodes[k].Text, strlen(ErrorCodes[k].Text))) {
1585 Priv->ErrorCode = ErrorCodes[k].Number;
1586 Priv->ErrorText = ErrorCodes[k].Text;
1587 break;
1588 }
1589 }
1590 }
1591 }
1592 smprintf(s, "AT reply state: %d\n", Priv->ReplyState);
1593 return GSM_DispatchMessage(s);
1594 }
1595
ATGEN_GenericReplyIgnore(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s UNUSED)1596 GSM_Error ATGEN_GenericReplyIgnore(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s UNUSED)
1597 {
1598 return ERR_NONE;
1599 }
1600
ATGEN_GenericReply(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)1601 GSM_Error ATGEN_GenericReply(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
1602 {
1603 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
1604 case AT_Reply_OK:
1605 case AT_Reply_Connect:
1606 return ERR_NONE;
1607 case AT_Reply_Error:
1608 return ERR_UNKNOWN;
1609 case AT_Reply_CMSError:
1610 return ATGEN_HandleCMSError(s);
1611 case AT_Reply_CMEError:
1612 return ATGEN_HandleCMEError(s);
1613 default:
1614 break;
1615 }
1616 return ERR_UNKNOWNRESPONSE;
1617 }
1618
ATGEN_SQWEReply(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)1619 GSM_Error ATGEN_SQWEReply(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
1620 {
1621 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1622
1623 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
1624 case AT_Reply_OK:
1625 /* Parse reply code */
1626 return ATGEN_ParseReply(s,
1627 GetLineString(msg->Buffer, &Priv->Lines, 2),
1628 "^SQWE: @i",
1629 &Priv->SQWEMode);
1630 case AT_Reply_Connect:
1631 return ERR_NONE;
1632 case AT_Reply_Error:
1633 return ERR_NOTSUPPORTED;
1634 case AT_Reply_CMSError:
1635 return ATGEN_HandleCMSError(s);
1636 case AT_Reply_CMEError:
1637 return ATGEN_HandleCMEError(s);
1638 default:
1639 break;
1640 }
1641 return ERR_UNKNOWNRESPONSE;
1642 }
1643
ATGEN_ReplyGetUSSD(GSM_Protocol_Message * msg,GSM_StateMachine * s)1644 GSM_Error ATGEN_ReplyGetUSSD(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1645 {
1646 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1647 GSM_USSDMessage ussd;
1648 GSM_Error error = ERR_NONE;
1649 unsigned char *pos = NULL;
1650 int code = 0;
1651 int dcs = 0;
1652 GSM_Coding_Type coding;
1653 char hex_encoded[2 * (GSM_MAX_USSD_LENGTH + 1)] = {0};
1654 char packed[GSM_MAX_USSD_LENGTH + 1] = {0};
1655 char decoded[GSM_MAX_USSD_LENGTH + 1] = {0};
1656
1657 /*
1658 * Reply format:
1659 * +CUSD: 2,"...",15
1660 */
1661 smprintf(s, "Incoming USSD received\n");
1662
1663 if (s->Phone.Data.EnableIncomingUSSD) {
1664 /* Find start of reply */
1665 pos = strstr(msg->Buffer, "+CUSD:");
1666 if (pos == NULL) {
1667 if (s->Phone.Data.RequestID == ID_GetUSSD) {
1668 /*
1669 * We usually get reply right after AT+CUSD=, but
1670 * if this is not the case, we should wait.
1671 */
1672 return ERR_NONE;
1673 }
1674 return ERR_UNKNOWNRESPONSE;
1675 }
1676
1677 /* Parse reply code */
1678 error = ATGEN_ParseReply(s, pos,
1679 "+CUSD: @i @0",
1680 &code);
1681
1682 if (error != ERR_NONE) return error;
1683
1684 /* Try to parse text here, we ignore error code intentionally */
1685 ussd.Text[0] = 0;
1686 ussd.Text[1] = 0;
1687
1688 /* Decode status */
1689 smprintf(s, "Status: %d\n", code);
1690 switch(code) {
1691 case 0:
1692 ussd.Status = USSD_NoActionNeeded;
1693 break;
1694 case 1:
1695 ussd.Status = USSD_ActionNeeded;
1696 break;
1697 case 2:
1698 ussd.Status = USSD_Terminated;
1699 break;
1700 case 3:
1701 ussd.Status = USSD_AnotherClient;
1702 break;
1703 case 4:
1704 ussd.Status = USSD_NotSupported;
1705 error = ERR_NETWORK_ERROR;
1706 goto done;
1707 case 5:
1708 ussd.Status = USSD_Timeout;
1709 error = ERR_TIMEOUT;
1710 goto done;
1711 default:
1712 ussd.Status = USSD_Unknown;
1713 }
1714
1715 // if it looks like we only received a USSD code we're done.
1716 if(strchr(msg->Buffer + 8, ',') == NULL)
1717 goto done;
1718
1719 error = ATGEN_ParseReply(s, pos,
1720 "+CUSD: @i, @r, @i @0",
1721 &code,
1722 hex_encoded, sizeof(hex_encoded),
1723 &dcs);
1724
1725 if (error == ERR_NONE || GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_ENCODED_USSD)) {
1726 if (error != ERR_NONE) {
1727 dcs = 0;
1728 error = ATGEN_ParseReply(s, pos,
1729 "+CUSD: @i, @r @0",
1730 &code,
1731 hex_encoded, sizeof(hex_encoded));
1732 }
1733 if (error != ERR_NONE) {
1734 goto done;
1735 }
1736
1737 if ((dcs & 0xc0) == 0) {
1738 if ((dcs & 0x30) != 0x10) {
1739 /* GSM-7 */
1740 coding = SMS_Coding_Default_No_Compression;
1741 } else {
1742 if ((dcs & 0xf) == 0) {
1743 /* GSM-7 */
1744 coding = SMS_Coding_Default_No_Compression;
1745 } else if ((dcs & 0xf) == 1) {
1746 coding = SMS_Coding_Unicode_No_Compression;
1747 } else {
1748 smprintf(s, "WARNING: unknown DCS: 0x%02x\n", dcs);
1749 coding = SMS_Coding_Default_No_Compression;
1750 }
1751 }
1752 } else {
1753 /* Fallback to SMS coding */
1754 coding = GSM_GetMessageCoding(&(s->di), dcs);
1755 }
1756
1757 smprintf(s, "USSD coding DCS = %d -> Coding = %d\n", dcs, coding);
1758
1759 if (coding == SMS_Coding_Default_No_Compression) {
1760 if (Priv->Charset == AT_CHARSET_HEX || GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_ENCODED_USSD)) {
1761 DecodeHexBin(packed, hex_encoded, strlen(hex_encoded));
1762 GSM_UnpackEightBitsToSeven(0, strlen(hex_encoded), sizeof(decoded), packed, decoded);
1763 DecodeDefault(ussd.Text, decoded, strlen(decoded), TRUE, NULL);
1764 } else {
1765 error = ATGEN_DecodeText(s, hex_encoded, strlen(hex_encoded), ussd.Text, sizeof(ussd.Text) - 1, FALSE, FALSE);
1766 if (error != ERR_NONE) {
1767 return error;
1768 }
1769 }
1770 } else if (coding == SMS_Coding_Unicode_No_Compression) {
1771 DecodeHexUnicode(ussd.Text, hex_encoded, strlen(hex_encoded));
1772 } else if (coding == SMS_Coding_8bit) {
1773 DecodeHexBin(decoded, hex_encoded, strlen(hex_encoded));
1774 GSM_UnpackEightBitsToSeven(0, strlen(hex_encoded), sizeof(decoded), packed, decoded);
1775 DecodeDefault(ussd.Text, decoded, strlen(decoded), TRUE, NULL);
1776 smprintf(s, "WARNING: 8-bit encoding!\n");
1777 } else {
1778 smprintf(s, "WARNING: unknown encoding!\n");
1779 }
1780 } else {
1781 error = ATGEN_ParseReply(s, pos,
1782 "+CUSD: @i, @s @0",
1783 &code,
1784 ussd.Text, sizeof(ussd.Text));
1785 if (error != ERR_NONE) {
1786 goto done;
1787 }
1788 }
1789
1790 done:
1791 /* Notify application */
1792 if (s->User.IncomingUSSD != NULL) {
1793 s->User.IncomingUSSD(s, &ussd, s->User.IncomingUSSDUserData);
1794 }
1795 }
1796
1797 return error;
1798 }
1799
ATGEN_SetIncomingUSSD(GSM_StateMachine * s,gboolean enable)1800 GSM_Error ATGEN_SetIncomingUSSD(GSM_StateMachine *s, gboolean enable)
1801 {
1802 GSM_Error error;
1803
1804 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_NORMAL);
1805
1806 if (error != ERR_NONE) {
1807 return error;
1808 }
1809 if (enable) {
1810 smprintf(s, "Enabling incoming USSD\n");
1811 error = ATGEN_WaitForAutoLen(s, "AT+CUSD=1\r", 0x00, 10, ID_SetUSSD);
1812 } else {
1813 if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NO_STOP_CUSD)) {
1814 smprintf(s, "Terminating possible incoming USSD\n");
1815 error = ATGEN_WaitForAutoLen(s, "AT+CUSD=2\r", 0x00, 10, ID_SetUSSD);
1816 }
1817 smprintf(s, "Disabling incoming USSD\n");
1818 error = ATGEN_WaitForAutoLen(s, "AT+CUSD=0\r", 0x00, 10, ID_SetUSSD);
1819 }
1820 if (error == ERR_NONE) {
1821 s->Phone.Data.EnableIncomingUSSD = enable;
1822 }
1823 if (error == ERR_UNKNOWN) {
1824 return ERR_NOTSUPPORTED;
1825 }
1826 return error;
1827 }
1828
ATGEN_ReplyGetModel(GSM_Protocol_Message * msg,GSM_StateMachine * s)1829 GSM_Error ATGEN_ReplyGetModel(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1830 {
1831 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1832 GSM_Phone_Data *Data = &s->Phone.Data;
1833 const char *pos, *pos2 = NULL;
1834 const char *line;
1835
1836 if (s->Phone.Data.Priv.ATGEN.ReplyState != AT_Reply_OK) {
1837 return ERR_NOTSUPPORTED;
1838 }
1839 line = GetLineString(msg->Buffer, &Priv->Lines, 2);
1840 pos = line;
1841
1842 /* Samsungs gives all information at once */
1843 if (strstr(line, "Manufacturer") != NULL) {
1844 line = GetLineString(msg->Buffer, &Priv->Lines, 3);
1845 if (strstr(line, "Model") == NULL) {
1846 line = GetLineString(msg->Buffer, &Priv->Lines, 2);
1847 }
1848 pos = line;
1849 }
1850
1851 /*
1852 * Motorola returns something like:
1853 * "+CGMM: "GSM900","GSM1800","GSM1900","GSM850","MODEL=V3""
1854 */
1855 if ((pos2 = strstr(line, "\"MODEL=")) != NULL) {
1856 pos = pos2 + 7; /* Skip above string */
1857 pos2 = strchr(pos, '"'); /* Find end quote */
1858 /* Sometimes phone adds this before manufacturer (Motorola) */
1859 } else if (strncmp("+CGMM: \"", line, 8) == 0) {
1860 pos += 8; /* Skip above string */
1861 pos2 = strchr(pos, '"'); /* Find end quote */
1862 /* Sometimes phone adds this before manufacturer (Sagem) */
1863 } else if (strncmp("+CGMM: ", line, 7) == 0) {
1864 pos += 7; /* Skip above string */
1865 }
1866 /* Samsung */
1867 if (strncmp("Model: ", pos, 7) == 0) {
1868 pos += 7; /* Skip above string */
1869 }
1870 /* Samsung */
1871 if (strncmp("I: ", pos, 3) == 0) {
1872 pos += 3; /* Skip above string */
1873 }
1874
1875 /* Skip white spaces */
1876 while (isspace(*pos)) {
1877 pos++;
1878 }
1879 if (pos2 == NULL) {
1880 pos2 = pos + strlen(pos);
1881 }
1882 /* Go before last char */
1883 pos2--;
1884 while(isspace(*pos2) && pos2 > pos) {
1885 pos2--;
1886 }
1887
1888 /* Now store string if it fits */
1889 if (1 + pos2 - pos > GSM_MAX_MODEL_LENGTH) {
1890 smprintf(s, "WARNING: Model name too long, increase GSM_MAX_MODEL_LENGTH to at least %ld (currently %d)\n",
1891 (long int)(1 + pos2 - pos),
1892 GSM_MAX_MODEL_LENGTH);
1893 }
1894
1895 strncpy(Data->Model, pos, MIN(1 + pos2 - pos, GSM_MAX_MODEL_LENGTH));
1896 Data->Model[1 + pos2 - pos] = 0;
1897
1898 Data->ModelInfo = GetModelData(s, NULL, Data->Model, NULL);
1899
1900 if (Data->ModelInfo->number[0] == 0)
1901 Data->ModelInfo = GetModelData(s, NULL, NULL, Data->Model);
1902
1903 if (Data->ModelInfo->number[0] == 0)
1904 Data->ModelInfo = GetModelData(s, Data->Model, NULL, NULL);
1905
1906 if (Data->ModelInfo->number[0] == 0) {
1907 smprintf(s, "Unknown model, but it should still work\n");
1908 }
1909 smprintf(s, "[Model name: `%s']\n", Data->Model);
1910 smprintf(s, "[Model data: `%s']\n", Data->ModelInfo->number);
1911 smprintf(s, "[Model data: `%s']\n", Data->ModelInfo->model);
1912
1913 s->Protocol.Data.AT.FastWrite = !GSM_IsPhoneFeatureAvailable(Data->ModelInfo, F_SLOWWRITE);
1914 s->Protocol.Data.AT.CPINNoOK = GSM_IsPhoneFeatureAvailable(Data->ModelInfo, F_CPIN_NO_OK);
1915
1916 return ERR_NONE;
1917 }
1918
ATGEN_GetModel(GSM_StateMachine * s)1919 GSM_Error ATGEN_GetModel(GSM_StateMachine *s)
1920 {
1921 GSM_Error error;
1922
1923 if (s->Phone.Data.Model[0] != 0) return ERR_NONE;
1924
1925 smprintf(s, "Getting model\n");
1926 error = ATGEN_WaitForAutoLen(s, "AT+CGMM\r", 0x00, 10, ID_GetModel);
1927
1928 if (error != ERR_NONE) {
1929 error = ATGEN_WaitForAutoLen(s, "ATI4\r", 0x00, 10, ID_GetModel);
1930 }
1931 if (error == ERR_NONE) {
1932 smprintf_level(s, D_TEXT, "[Connected model - \"%s\"]\n",
1933 s->Phone.Data.Model);
1934 }
1935 return error;
1936 }
1937
ATGEN_ReplyGetManufacturer(GSM_Protocol_Message * msg,GSM_StateMachine * s)1938 GSM_Error ATGEN_ReplyGetManufacturer(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1939 {
1940 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1941
1942 typedef struct {
1943 char name[20];
1944 GSM_AT_Manufacturer id;
1945 } vendors_t;
1946 vendors_t vendors[] = {
1947 {"Falcom", AT_Falcom},
1948 {"Nokia", AT_Nokia},
1949 {"Siemens", AT_Siemens},
1950 {"Sharp", AT_Sharp},
1951 {"Huawei", AT_Huawei},
1952 {"Sony Ericsson", AT_Ericsson},
1953 {"Ericsson", AT_Ericsson},
1954 {"iPAQ", AT_HP},
1955 {"Alcatel", AT_Alcatel},
1956 {"Samsung", AT_Samsung},
1957 {"Philips", AT_Philips},
1958 {"Mitsubishi", AT_Mitsubishi},
1959 {"Motorola", AT_Motorola},
1960 {"Option", AT_Option},
1961 {"Wavecom", AT_Wavecom},
1962 {"Qualcomm", AT_Qualcomm},
1963 {"Telit", AT_Telit},
1964 {"ZTE", AT_ZTE},
1965 {"\0", 0}
1966 };
1967 vendors_t *vendor;
1968
1969
1970
1971 switch (Priv->ReplyState) {
1972 case AT_Reply_OK:
1973 smprintf(s, "Manufacturer info received\n");
1974 Priv->Manufacturer = AT_Unknown;
1975
1976 if (GetLineLength(msg->Buffer, &Priv->Lines, 2) <= GSM_MAX_MANUFACTURER_LENGTH) {
1977 CopyLineString(s->Phone.Data.Manufacturer, msg->Buffer, &Priv->Lines, 2);
1978 } else {
1979 smprintf(s, "WARNING: Manufacturer name too long, increase GSM_MAX_MANUFACTURER_LENGTH to at least %d\n", GetLineLength(msg->Buffer, &Priv->Lines, 2));
1980 s->Phone.Data.Manufacturer[0] = 0;
1981 }
1982 /* Sometimes phone adds this before manufacturer (Sagem) */
1983 if (strncmp("+CGMI: ", s->Phone.Data.Manufacturer, 7) == 0) {
1984 memmove(s->Phone.Data.Manufacturer, s->Phone.Data.Manufacturer + 7, strlen(s->Phone.Data.Manufacturer + 7) + 1);
1985 }
1986 /* Samsung */
1987 if (strncmp("Manufacturer: ", s->Phone.Data.Manufacturer, 14) == 0) {
1988 memmove(s->Phone.Data.Manufacturer, s->Phone.Data.Manufacturer + 14, strlen(s->Phone.Data.Manufacturer + 14) + 1);
1989 }
1990 if (strncmp("I: ", s->Phone.Data.Manufacturer, 3) == 0) {
1991 memmove(s->Phone.Data.Manufacturer, s->Phone.Data.Manufacturer + 3, strlen(s->Phone.Data.Manufacturer + 3) + 1);
1992 }
1993
1994 /* Lookup in vendor table */
1995 for (vendor = vendors; vendor->id != 0; vendor++) {
1996 if (strcasestr(msg->Buffer, vendor->name)) {
1997 strcpy(s->Phone.Data.Manufacturer, vendor->name);
1998 Priv->Manufacturer = vendor->id;
1999 }
2000 }
2001
2002 /* Vendor specific hacks*/
2003 if (Priv->Manufacturer == AT_Falcom && strstr(msg->Buffer,"A2D")) {
2004 strcpy(s->Phone.Data.Model,"A2D");
2005 s->Phone.Data.ModelInfo = GetModelData(s, NULL, s->Phone.Data.Model, NULL);
2006 smprintf(s, "Model A2D\n");
2007 }
2008 if (Priv->Manufacturer == AT_Nokia) {
2009 smprintf(s, "HINT: Consider using Nokia specific protocol instead of generic AT.\n");
2010 }
2011
2012 /*
2013 * IAXmodem can not currently reasonably work with Gammu,
2014 * but we can try to fixup at least something.
2015 */
2016 if (strstr(msg->Buffer, "www.soft-switch.org")) {
2017 /* It replies OK to anything, but this just clutters output */
2018 Priv->Mode = FALSE;
2019 }
2020 smprintf(s, "[Manufacturer: %s]\n", s->Phone.Data.Manufacturer);
2021 return ERR_NONE;
2022 case AT_Reply_CMSError:
2023 return ATGEN_HandleCMSError(s);
2024 case AT_Reply_CMEError:
2025 return ATGEN_HandleCMEError(s);
2026 case AT_Reply_Error:
2027 return ERR_NOTSUPPORTED;
2028 default:
2029 break;
2030 }
2031 return ERR_UNKNOWNRESPONSE;
2032 }
2033
ATGEN_GetManufacturer(GSM_StateMachine * s)2034 GSM_Error ATGEN_GetManufacturer(GSM_StateMachine *s)
2035 {
2036 GSM_Error error;
2037 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2038
2039 if (Priv->Manufacturer != 0 && s->Phone.Data.Manufacturer[0] != 0) return ERR_NONE;
2040
2041 strcpy(s->Phone.Data.Manufacturer, "Unknown");
2042
2043 error = ATGEN_WaitForAutoLen(s, "AT+CGMI\r", 0x00, 40, ID_GetManufacturer);
2044
2045 if (error != ERR_NONE) {
2046 error = ATGEN_WaitForAutoLen(s, "ATI3\r", 0x00, 40, ID_GetManufacturer);
2047 }
2048 return ERR_NONE;
2049 }
2050
ATGEN_ReplyGetFirmware(GSM_Protocol_Message * msg,GSM_StateMachine * s)2051 GSM_Error ATGEN_ReplyGetFirmware(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2052 {
2053
2054 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2055 int line = 0;
2056
2057 strcpy(s->Phone.Data.Version, "Unknown");
2058
2059 if (s->Phone.Data.Priv.ATGEN.ReplyState != AT_Reply_OK) {
2060 return ERR_NOTSUPPORTED;
2061 }
2062
2063 s->Phone.Data.VerNum = 0;
2064 if (Priv->ReplyState == AT_Reply_OK) {
2065 line = 2;
2066
2067 if (strstr(GetLineString(msg->Buffer, &Priv->Lines, line), "Manufacturer:") != NULL) {
2068 line ++;
2069 }
2070 if (strstr(GetLineString(msg->Buffer, &Priv->Lines, line), "Model:") != NULL) {
2071 line ++;
2072 }
2073 if (GetLineLength(msg->Buffer, &Priv->Lines, line) > GSM_MAX_VERSION_LENGTH - 1) {
2074 smprintf(s, "Please increase GSM_MAX_VERSION_LENGTH!\n");
2075 return ERR_MOREMEMORY;
2076 }
2077 CopyLineString(s->Phone.Data.Version, msg->Buffer, &Priv->Lines, line);
2078 /* Sometimes phone adds this before version (Sagem) */
2079 if (strncmp("+CGMR: ", s->Phone.Data.Version, 7) == 0) {
2080 /* Need to use memmove as strcpy does not correctly handle overlapping regions */
2081 memmove(s->Phone.Data.Version, s->Phone.Data.Version + 7, strlen(s->Phone.Data.Version + 7) + 1);
2082 }
2083 /* Sometimes phone adds this before version (Shrap) */
2084 if (strncmp("Revision: ", s->Phone.Data.Version, 10) == 0) {
2085 /* Need to use memmove as strcpy does not correctly handle overlapping regions */
2086 memmove(s->Phone.Data.Version, s->Phone.Data.Version + 10, strlen(s->Phone.Data.Version + 10) + 1);
2087 }
2088 /* Samsung */
2089 if (strncmp("I: ", s->Phone.Data.Version, 3) == 0) {
2090 /* Need to use memmove as strcpy does not correctly handle overlapping regions */
2091 memmove(s->Phone.Data.Version, s->Phone.Data.Version + 3, strlen(s->Phone.Data.Version + 3) + 1);
2092 }
2093 /* Add second line if it also contains version information */
2094 if (strcmp(GetLineString(msg->Buffer, &Priv->Lines, 3), "OK") != 0) {
2095 if (GetLineLength(msg->Buffer, &Priv->Lines, 3) + 1 + strlen(s->Phone.Data.Version) < GSM_MAX_VERSION_LENGTH - 1) {
2096 strcat(s->Phone.Data.Version, ",");
2097 CopyLineString(s->Phone.Data.Version + strlen(s->Phone.Data.Version), msg->Buffer, &Priv->Lines, 3);
2098 }
2099 }
2100 }
2101 smprintf(s, "Received firmware version: \"%s\"\n",s->Phone.Data.Version);
2102 GSM_CreateFirmwareNumber(s);
2103 return ERR_NONE;
2104 }
2105
ATGEN_GetFirmware(GSM_StateMachine * s)2106 GSM_Error ATGEN_GetFirmware(GSM_StateMachine *s)
2107 {
2108 GSM_Error error;
2109
2110 if (s->Phone.Data.Version[0] != 0) return ERR_NONE;
2111
2112 smprintf(s, "Getting firmware versions\n");
2113 error = ATGEN_WaitForAutoLen(s, "AT+CGMR\r", 0x00, 16, ID_GetFirmware);
2114
2115 if (error != ERR_NONE) {
2116 error = ATGEN_WaitForAutoLen(s, "ATI5\r", 0x00, 10, ID_GetFirmware);
2117 }
2118
2119 if (error == ERR_NONE) {
2120 smprintf_level(s, D_TEXT, "[Firmware version - \"%s\"]\n",
2121 s->Phone.Data.Version);
2122 }
2123 return error;
2124 }
2125
ATGEN_PostConnect(GSM_StateMachine * s)2126 GSM_Error ATGEN_PostConnect(GSM_StateMachine *s)
2127 {
2128 GSM_Error error;
2129
2130 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_HUAWEI_INIT)) {
2131 /* Disable Huawei specific unsolicited codes */
2132 error = ATGEN_WaitForAutoLen(s, "AT^CURC=0\r", 0x00, 10, ID_SetIncomingCall);
2133 if (error != ERR_NONE) {
2134 return error;
2135 }
2136
2137 /* Power on the modem */
2138 error = GSM_WaitForAutoLen(s, "AT+CFUN=1\r", 0, 40, ID_SetPower);
2139 if (error != ERR_NONE) {
2140 return error;
2141 }
2142
2143 /* Tell device that this is modem port */
2144 error = ATGEN_WaitForAutoLen(s, "AT^PORTSEL=1\r", 0x00, 10, ID_SetIncomingCall);
2145 if (error != ERR_NONE) {
2146 return error;
2147 }
2148 }
2149
2150 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_ZTE_INIT)) {
2151 /* Disable CDROM mode */
2152 error = ATGEN_WaitForAutoLen(s, "AT+ZCDRUN=8\r", 0x00, 10, ID_Initialise);
2153 if (error != ERR_NONE) {
2154 return error;
2155 }
2156
2157 /* Stay online */
2158 error = ATGEN_WaitForAutoLen(s, "AT+ZOPRT=5\r", 0x00, 10, ID_Initialise);
2159 if (error != ERR_NONE) {
2160 return error;
2161 }
2162 }
2163
2164 return ERR_NONE;
2165 }
2166
ATGEN_Initialise(GSM_StateMachine * s)2167 GSM_Error ATGEN_Initialise(GSM_StateMachine *s)
2168 {
2169 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2170 GSM_Error error;
2171 char buff[2]={0};
2172
2173 InitLines(&Priv->Lines);
2174
2175 Priv->SMSMode = 0;
2176 Priv->SQWEMode = -1;
2177 Priv->SMSTextDetails = FALSE;
2178 Priv->Manufacturer = 0;
2179 Priv->MotorolaSMS = FALSE;
2180 Priv->PhoneSMSMemory = 0;
2181 Priv->PhoneSaveSMS = 0;
2182 Priv->SIMSaveSMS = 0;
2183 Priv->SIMSMSMemory = 0;
2184 Priv->SMSMemory = 0;
2185 Priv->SMSMemoryWrite = FALSE;
2186 Priv->PBKMemory = 0;
2187 Priv->PBKSBNR = 0;
2188 Priv->PBK_SPBR = 0;
2189 Priv->PBK_MPBR = 0;
2190 Priv->SamsungCalendar = 0;
2191 Priv->Charset = 0;
2192 Priv->EncodedCommands = FALSE;
2193 Priv->NormalCharset = 0;
2194 Priv->IRACharset = 0;
2195 Priv->GSMCharset = 0;
2196 Priv->UnicodeCharset = 0;
2197 Priv->PBKMemories[0] = 0;
2198 Priv->FirstCalendarPos = 0;
2199 Priv->FirstFreeCalendarPos = 0;
2200 Priv->NextMemoryEntry = 0;
2201 Priv->FirstMemoryEntry = -1;
2202 Priv->MotorolaFirstMemoryEntry = -1;
2203 Priv->file.Used = 0;
2204 Priv->file.Buffer = NULL;
2205 Priv->Mode = FALSE;
2206 Priv->MemorySize = 0;
2207 Priv->MotorolaMemorySize = 0;
2208 Priv->MemoryUsed = 0;
2209 Priv->TextLength = 0;
2210 Priv->NumberLength = 0;
2211
2212 Priv->CNMIMode = -1;
2213 Priv->CNMIProcedure = -1;
2214 Priv->CNMIDeliverProcedure = -1;
2215 #ifdef GSM_ENABLE_CELLBROADCAST
2216 Priv->CNMIBroadcastProcedure = -1;
2217 #endif
2218 Priv->CNMIClearUnsolicitedResultCodes = -1;
2219
2220 Priv->ErrorText = NULL;
2221
2222 Priv->SMSCount = 0;
2223 Priv->SMSCache = NULL;
2224 Priv->ReplyState = 0;
2225
2226 if (s->ConnectionType != GCT_IRDAAT && s->ConnectionType != GCT_BLUEAT) {
2227 /* We try to escape AT+CMGS mode, at least Siemens M20
2228 * then needs to get some rest
2229 */
2230 smprintf(s, "Escaping SMS mode\n");
2231 error = s->Protocol.Functions->WriteMessage(s, "\x1B\r", 2, 0x00);
2232 if (error != ERR_NONE) {
2233 return error;
2234 }
2235
2236 /* Grab any possible garbage */
2237 while (s->Device.Functions->ReadDevice(s, buff, sizeof(buff)) > 0) {
2238 usleep(10000);
2239 }
2240 }
2241
2242 /* When some phones (Alcatel BE5) is first time connected, it needs extra
2243 * time to react, sending just AT wakes up the phone and it then can react
2244 * to ATE1. We don't need to check whether this fails as it is just to
2245 * wake up the phone and does nothing.
2246 */
2247 smprintf(s, "Sending simple AT command to wake up some devices\n");
2248 error = GSM_WaitForAutoLen(s, "AT\r", 0x00, 20, ID_Initialise);
2249
2250 /* We want to see our commands to allow easy detection of reply functions */
2251 smprintf(s, "Enabling echo\n");
2252 error = GSM_WaitForAutoLen(s, "ATE1\r", 0x00, 10, ID_EnableEcho);
2253
2254 /* Some modems (Sony Ericsson GC 79, GC 85) need to enable functionality
2255 * (with reset), otherwise they return ERROR on anything!
2256 */
2257 if (error == ERR_UNKNOWN) {
2258 error = GSM_WaitForAutoLen(s, "AT+CFUN=1,1\r", 0x00, 10, ID_Reset);
2259
2260 if (error != ERR_NONE) {
2261 return error;
2262 }
2263 error = GSM_WaitForAutoLen(s, "ATE1\r", 0x00, 10, ID_EnableEcho);
2264 }
2265 if (error != ERR_NONE) {
2266 smprintf(s, "Phone does not support enabled echo, it can not work with Gammu!\n");
2267 smprintf(s, "It might be caused by other program using the modem.\n");
2268 smprintf(s, "See <https://wammu.eu/docs/manual/faq/general.html#echo> for help.\n");
2269 return error;
2270 }
2271
2272 /* Try whether phone supports mode switching as Motorola phones. */
2273 smprintf(s, "Trying Motorola mode switch\n");
2274 error = GSM_WaitForAutoLen(s, "AT+MODE=2\r", 0x00, 10, ID_ModeSwitch);
2275
2276 if (error != ERR_NONE) {
2277 smprintf(s, "Seems not to be supported\n");
2278 Priv->Mode = FALSE;
2279 } else {
2280 smprintf(s, "Works, will use it\n");
2281 Priv->Mode = TRUE;
2282 Priv->CurrentMode = 2;
2283 }
2284 smprintf(s, "Enabling CME errors\n");
2285
2286 /* Try numeric errors */
2287 error = ATGEN_WaitForAutoLen(s, "AT+CMEE=1\r", 0x00, 10, ID_EnableErrorInfo);
2288
2289 if (error != ERR_NONE) {
2290 /* Try textual errors */
2291 error = ATGEN_WaitForAutoLen(s, "AT+CMEE=2\r", 0x00, 10, ID_EnableErrorInfo);
2292
2293 if (error != ERR_NONE) {
2294 smprintf(s, "CME errors could not be enabled, some error types won't be detected.\n");
2295 }
2296 }
2297
2298 /* Switch to GSM charset */
2299 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_NORMAL);
2300 if (error != ERR_NONE && error != ERR_SECURITYERROR) return error;
2301
2302 /* Get model, it is useful to know it now */
2303 error = ATGEN_GetModel(s);
2304 if (error != ERR_NONE && error != ERR_SECURITYERROR) return error;
2305
2306 /* Get manufacturer, needed for some detection */
2307 error = ATGEN_GetManufacturer(s);
2308 if (error != ERR_NONE && error != ERR_SECURITYERROR) return error;
2309 /* Clear error flag */
2310 error = ERR_NONE;
2311
2312 /* Mode switching cabaple phones can switch using AT+MODE */
2313 if (!Priv->Mode) {
2314 smprintf(s, "Checking for OBEX support\n");
2315 /* We don't care about error here */
2316 error = ATGEN_WaitForAutoLen(s, "AT+CPROT=?\r", 0x00, 20, ID_SetOBEX);
2317 error = ERR_NONE;
2318 /* Disabled by default as it usually fails to work */
2319 } else {
2320 /*
2321 * Enable OBEX for Motorolas, they usually support this and
2322 * AT+OBEX can fallback to pure AT.
2323 *
2324 * This usually does not work on Bluetooth and IrDA, as there
2325 * you can access OBEX another way.
2326 */
2327 #ifdef GSM_ENABLE_ATOBEX_AUTO_MODE
2328 if (s->ConnectionType != GCT_IRDAAT &&
2329 s->ConnectionType != GCT_BLUEAT &&
2330 !GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NO_ATOBEX) &&
2331 !GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_OBEX)
2332 ) {
2333 smprintf(s, "Automatically enabling F_OBEX, please report bug if it causes problems\n");
2334 GSM_AddPhoneFeature(s->Phone.Data.ModelInfo, F_OBEX);
2335 GSM_AddPhoneFeature(s->Phone.Data.ModelInfo, F_MODE22);
2336 GSM_AddPhoneFeature(s->Phone.Data.ModelInfo, F_IRMC_LEVEL_2);
2337 }
2338 #else
2339 smprintf(s, "There is a chance that phone supports F_OBEX,F_MODE22, please report bug if it works\n");
2340 #endif
2341 }
2342
2343 if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_MOBEX) && !GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_TSSPCSW) && !GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NO_ATSYNCML)) {
2344 smprintf(s, "Checking for SYNCML/OBEX support\n");
2345 /* We don't care about error here */
2346 error = ATGEN_WaitForAutoLen(s, "AT+SYNCML=?\r", 0x00, 20, ID_SetOBEX);
2347 error = ERR_NONE;
2348 /* We don't care about error here */
2349 error = ATGEN_WaitForAutoLen(s, "AT$TSSPCSW=?\r", 0x00, 20, ID_SetOBEX);
2350 error = ERR_NONE;
2351 }
2352
2353 #ifdef GSM_ENABLE_ATOBEX
2354 if (Priv->Manufacturer == AT_Siemens) {
2355 error = ATGEN_WaitForAutoLen(s, "AT^SQWE?\r", 0x00, 10, ID_GetProtocol);
2356
2357 if (error == ERR_NONE) {
2358 #ifdef GSM_ENABLE_ATOBEX_AUTO_MODE
2359 if (s->ConnectionType != GCT_IRDAAT &&
2360 s->ConnectionType != GCT_BLUEAT &&
2361 !GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NO_ATOBEX) &&
2362 !GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_OBEX)
2363 ) {
2364 smprintf(s, "Phone seems to support Siemens like mode switching, adding OBEX feature.\n");
2365 GSM_AddPhoneFeature(s->Phone.Data.ModelInfo, F_OBEX);
2366 GSM_AddPhoneFeature(s->Phone.Data.ModelInfo, F_SQWE);
2367 }
2368 #else
2369 smprintf(s, "There is a chance that phone supports F_OBEX,F_SQWE, please report bug if it works\n");
2370 #endif
2371
2372 /* Switch to mode 0 if we're in different mode */
2373 if (Priv->SQWEMode != 0) {
2374 error = ATGEN_WaitForAutoLen(s, "AT^SQWE=0\r", 0x00, 10, ID_SetOBEX);
2375
2376 if (error != ERR_NONE) {
2377 return error;
2378 }
2379 Priv->SQWEMode = 0;
2380 }
2381 }
2382 /* Clear error flag */
2383 error = ERR_NONE;
2384 }
2385 #endif
2386
2387 /* can we use CHUP to hangup calls (otherwise use ATH) */
2388 ATGEN_WaitForAutoLen(s, "AT+CHUP=?\r", 0x00, 40, ID_CheckCHUP);
2389
2390 s->Protocol.Data.AT.FastWrite = !GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SLOWWRITE);
2391 s->Protocol.Data.AT.CPINNoOK = GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CPIN_NO_OK);
2392
2393 return error;
2394 }
2395
ATGEN_ReplyGetCharset(GSM_Protocol_Message * msg,GSM_StateMachine * s)2396 GSM_Error ATGEN_ReplyGetCharset(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2397 {
2398 /*
2399 * Reply we get here:
2400 * AT+CSCS?
2401 * +CSCS: "GSM"
2402 * OK
2403 *
2404 * Or
2405 *
2406 * AT+CSCS?
2407 * +CSCS:0
2408 * OK
2409 */
2410 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2411 const char *line;
2412 int i = 0;
2413
2414 switch (Priv->ReplyState) {
2415 case AT_Reply_OK:
2416 /* Can not use ATGEN_ParseReply safely here as we do not know charset yet */
2417 line = GetLineString(msg->Buffer, &Priv->Lines, 2);
2418 if (strcmp(line, "+CSCS:0") == 0) {
2419 smprintf(s, "WARNING: Charsets support broken! Assuming GSM as default!\n");
2420 Priv->Charset = AT_CHARSET_GSM;
2421 }
2422 /* First current charset: */
2423 while (AT_Charsets[i].charset != 0) {
2424 if (strstr(line, AT_Charsets[i].text) != NULL) {
2425 Priv->Charset = AT_Charsets[i].charset;
2426 break;
2427 }
2428 /* We detect encoded UCS2 reply here so that we can handle encoding of values later. */
2429 if (strstr(line, "0055004300530032") != NULL) {
2430 Priv->Charset = AT_CHARSET_UCS2;
2431 Priv->EncodedCommands = TRUE;
2432 break;
2433 }
2434 i++;
2435 }
2436 if (Priv->Charset == 0) {
2437 smprintf(s, "Could not determine charset returned by phone, probably not supported!\n");
2438 return ERR_NOTSUPPORTED;
2439 }
2440 return ERR_NONE;
2441 case AT_Reply_Error:
2442 return ERR_NOTSUPPORTED;
2443 case AT_Reply_CMSError:
2444 return ATGEN_HandleCMSError(s);
2445 case AT_Reply_CMEError:
2446 return ATGEN_HandleCMEError(s);
2447 default:
2448 return ERR_UNKNOWNRESPONSE;
2449 }
2450 }
2451
ATGEN_ReplyGetCharsets(GSM_Protocol_Message * msg,GSM_StateMachine * s)2452 GSM_Error ATGEN_ReplyGetCharsets(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2453 {
2454 /* Reply we get here:
2455 AT+CSCS=?
2456 +CSCS: ("GSM","UCS2")
2457
2458 OK
2459 */
2460 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2461 const char *line;
2462 int i = 0;
2463 gboolean IgnoredUTF8 = FALSE, IRAset = FALSE, GSMset = FALSE;
2464
2465 switch (Priv->ReplyState) {
2466 case AT_Reply_OK:
2467 line = GetLineString(msg->Buffer, &Priv->Lines, 2);
2468
2469 if (strcmp(line, "+CSCS:") == 0) {
2470 smprintf(s, "WARNING: Charsets support broken! Assuming that only GSM is supported!\n");
2471 Priv->NormalCharset = AT_CHARSET_GSM;
2472 Priv->IRACharset = AT_CHARSET_GSM;
2473 Priv->GSMCharset = AT_CHARSET_GSM;
2474 Priv->UnicodeCharset = AT_CHARSET_GSM;
2475 return ERR_NONE;
2476 }
2477 /* First find good charset for non-unicode: */
2478 while (AT_Charsets[i].charset != 0) {
2479 if (strstr(line, AT_Charsets[i].text) != NULL) {
2480 Priv->NormalCharset = AT_Charsets[i].charset;
2481 Priv->IRACharset = AT_Charsets[i].charset;
2482 Priv->GSMCharset = AT_Charsets[i].charset;
2483 smprintf(s, "Chosen %s as normal charset\n", AT_Charsets[i].text);
2484 break;
2485 }
2486 i++;
2487 }
2488 /* Check if we have proper normal charset */
2489 if (Priv->NormalCharset == 0) {
2490 smprintf(s, "Could not find supported charset in list returned by phone!\n");
2491 return ERR_UNKNOWNRESPONSE;
2492 }
2493 /* Then find good charset for unicode and IRA */
2494 Priv->UnicodeCharset = 0;
2495 while (AT_Charsets[i].charset != 0) {
2496 if ((Priv->UnicodeCharset == 0) && AT_Charsets[i].unicode && (strstr(line, AT_Charsets[i].text) != NULL)) {
2497 if ((AT_Charsets[i].charset == AT_CHARSET_UTF8 ||
2498 AT_Charsets[i].charset == AT_CHARSET_UTF_8) &&
2499 Priv->Manufacturer == AT_Motorola) {
2500 IgnoredUTF8 = TRUE;
2501 smprintf(s, "Skipped %s because it is usually wrongly implemented on Motorola phones\n", AT_Charsets[i].text);
2502 } else if ((AT_Charsets[i].charset == AT_CHARSET_UTF8 ||
2503 AT_Charsets[i].charset == AT_CHARSET_UTF_8) &&
2504 GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NO_UTF8)) {
2505 IgnoredUTF8 = TRUE;
2506 smprintf(s, "Skipped %s because it is reported to be broken on this phone\n", AT_Charsets[i].text);
2507 } else if ((AT_Charsets[i].charset != AT_CHARSET_UCS2 &&
2508 AT_Charsets[i].charset != AT_CHARSET_UCS_2) ||
2509 !GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NO_UCS2)) {
2510 Priv->UnicodeCharset = AT_Charsets[i].charset;
2511 smprintf(s, "Chosen %s as unicode charset\n", AT_Charsets[i].text);
2512 }
2513 }
2514 if (!IRAset && AT_Charsets[i].ira && (strstr(line, AT_Charsets[i].text) != NULL)) {
2515 Priv->IRACharset = AT_Charsets[i].charset;
2516 IRAset = TRUE;
2517 }
2518 if (!GSMset && AT_Charsets[i].GSM && (strstr(line, AT_Charsets[i].text) != NULL)) {
2519 Priv->GSMCharset = AT_Charsets[i].charset;
2520 GSMset = TRUE;
2521 }
2522 i++;
2523 }
2524 /* Fallback for unicode charset */
2525 if (Priv->UnicodeCharset == 0) {
2526 if (IgnoredUTF8) {
2527 Priv->UnicodeCharset = AT_CHARSET_UTF8;
2528 smprintf(s, "Switched back to UTF8 charset, expect problems\n");
2529 } else {
2530 Priv->UnicodeCharset = Priv->NormalCharset;
2531 }
2532 }
2533 /* If we have unicode charset, it's better than GSM for IRA */
2534 if (Priv->IRACharset == AT_CHARSET_GSM) {
2535 Priv->IRACharset = Priv->UnicodeCharset;
2536 }
2537 return ERR_NONE;
2538 case AT_Reply_Error:
2539 /* Phone does not support charsets, everything should
2540 * be in GSM. */
2541 smprintf(s, "INFO: assuming GSM charset\n");
2542 Priv->IRACharset = AT_CHARSET_GSM;
2543 Priv->GSMCharset = AT_CHARSET_GSM;
2544 Priv->UnicodeCharset = AT_CHARSET_GSM;
2545 Priv->NormalCharset = AT_CHARSET_GSM;
2546 Priv->Charset = AT_CHARSET_GSM;
2547 return ERR_NONE;
2548 case AT_Reply_CMSError:
2549 return ATGEN_HandleCMSError(s);
2550 case AT_Reply_CMEError:
2551 return ATGEN_HandleCMEError(s);
2552 default:
2553 return ERR_UNKNOWNRESPONSE;
2554 }
2555 }
2556
2557
ATGEN_SetCharset(GSM_StateMachine * s,GSM_AT_Charset_Preference Prefer)2558 GSM_Error ATGEN_SetCharset(GSM_StateMachine *s, GSM_AT_Charset_Preference Prefer)
2559 {
2560 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2561 GSM_Error error;
2562 char buffer[100];
2563 char buffer2[100];
2564 char buffer3[100];
2565 int i = 0;
2566 GSM_AT_Charset cset;
2567 size_t len;
2568
2569 /* Do we know current charset? */
2570 if (Priv->Charset == 0) {
2571 /* Get current charset */
2572 error = ATGEN_WaitForAutoLen(s, "AT+CSCS?\r", 0x00, 10, ID_GetMemoryCharset);
2573
2574 /* ERR_NOTSUPPORTED means that we do not know charset phone returned */
2575 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) {
2576 return error;
2577 }
2578 }
2579
2580 /* Do we know available charsets? */
2581 if (Priv->NormalCharset == 0) {
2582 /* Switch to GSM to be safe (UCS2 can give us encoded result) */
2583 if (Priv->Charset == AT_CHARSET_UCS2 && Priv->EncodedCommands) {
2584 error = ATGEN_WaitForAutoLen(s, "AT+CSCS=\"00470053004D\"\r", 0x00, 10, ID_SetMemoryCharset);
2585
2586 if (error == ERR_NONE) {
2587 Priv->Charset = AT_CHARSET_GSM;
2588 }
2589 }
2590 /* Get available charsets */
2591 error = ATGEN_WaitForAutoLen(s, "AT+CSCS=?\r", 0x00, 10, ID_GetMemoryCharset);
2592
2593 if (error != ERR_NONE) return error;
2594 }
2595
2596 /* Find charset we want */
2597 if (Prefer == AT_PREF_CHARSET_UNICODE) {
2598 cset = Priv->UnicodeCharset;
2599 } else if (Prefer == AT_PREF_CHARSET_NORMAL) {
2600 cset = Priv->NormalCharset;
2601 } else if (Prefer == AT_PREF_CHARSET_GSM) {
2602 cset = Priv->GSMCharset;
2603 } else if (Prefer == AT_PREF_CHARSET_IRA) {
2604 if (Priv->IRACharset == Priv->UnicodeCharset &&
2605 GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CKPD_NO_UNICODE)) {
2606 cset = Priv->NormalCharset;
2607 } else {
2608 cset = Priv->IRACharset;
2609 }
2610 } else if (Prefer == AT_PREF_CHARSET_RESET) {
2611 cset = Priv->Charset;
2612 Priv->Charset = 0;
2613 } else {
2614 return ERR_BUG;
2615 }
2616
2617 /* If we already have set our prefered charset there is nothing to do*/
2618 if (Priv->Charset == cset) return ERR_NONE;
2619
2620 /* Find text representation */
2621 while (AT_Charsets[i].charset != 0) {
2622 if (AT_Charsets[i].charset == cset) {
2623 break;
2624 }
2625 i++;
2626 }
2627
2628 /* Should not happen! */
2629 if (AT_Charsets[i].charset == 0) {
2630 smprintf(s, "Could not find string representation for charset (%d)!\n",
2631 cset);
2632 return ERR_BUG;
2633 }
2634
2635 /* And finally set the charset */
2636 if (Priv->EncodedCommands && Priv->Charset == AT_CHARSET_UCS2) {
2637 EncodeUnicode(buffer2, AT_Charsets[i].text, strlen(AT_Charsets[i].text));
2638 EncodeHexUnicode(buffer3, buffer2, strlen(AT_Charsets[i].text));
2639 len = sprintf(buffer, "AT+CSCS=\"%s\"\r", buffer3);
2640 } else {
2641 len = sprintf(buffer, "AT+CSCS=\"%s\"\r", AT_Charsets[i].text);
2642 }
2643 error = ATGEN_WaitFor(s, buffer, len, 0x00, 20, ID_SetMemoryCharset);
2644
2645 if (error == ERR_NONE) {
2646 Priv->Charset = cset;
2647 }
2648 else {
2649 return error;
2650 }
2651
2652 /* Verify we have charset we wanted (this is especially needed to detect whether phone encodes also control information and not only data) */
2653 error = ATGEN_WaitForAutoLen(s, "AT+CSCS?\r", 0x00, 10, ID_GetMemoryCharset);
2654
2655 return error;
2656 }
2657
ATGEN_ReplyGetIMEI(GSM_Protocol_Message * msg,GSM_StateMachine * s)2658 GSM_Error ATGEN_ReplyGetIMEI(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2659 {
2660 if (s->Phone.Data.Priv.ATGEN.ReplyState != AT_Reply_OK) return ERR_NOTSUPPORTED;
2661
2662 if (GetLineLength(msg->Buffer, &s->Phone.Data.Priv.ATGEN.Lines, 2) > GSM_MAX_IMEI_LENGTH) {
2663 smprintf(s, "IMEI too long!\n");
2664 return ERR_MOREMEMORY;
2665 }
2666
2667 CopyLineString(s->Phone.Data.IMEI, msg->Buffer, &s->Phone.Data.Priv.ATGEN.Lines, 2);
2668 /* Remove various prefies some phones add */
2669 if (strncmp(s->Phone.Data.IMEI, "+CGSN: IMEI", 11) == 0) { /* Motorola */
2670 memmove(s->Phone.Data.IMEI, s->Phone.Data.IMEI + 11, strlen(s->Phone.Data.IMEI + 11) + 1);
2671 } else if (strncmp(s->Phone.Data.IMEI, "+CGSN: ", 7) == 0) {
2672 memmove(s->Phone.Data.IMEI, s->Phone.Data.IMEI + 7, strlen(s->Phone.Data.IMEI + 7) + 1);
2673 }
2674 smprintf(s, "Received IMEI %s\n",s->Phone.Data.IMEI);
2675 return ERR_NONE;
2676 }
2677
ATGEN_GetIMEI(GSM_StateMachine * s)2678 GSM_Error ATGEN_GetIMEI (GSM_StateMachine *s)
2679 {
2680 GSM_Error error;
2681
2682 if (s->Phone.Data.IMEI[0] != 0) return ERR_NONE;
2683 smprintf(s, "Getting IMEI\n");
2684 error = ATGEN_WaitForAutoLen(s, "AT+CGSN\r", 0x00, 20, ID_GetIMEI);
2685
2686 return error;
2687 }
2688
ATGEN_ReplyGetDateTime(GSM_Protocol_Message * msg,GSM_StateMachine * s)2689 GSM_Error ATGEN_ReplyGetDateTime(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2690 {
2691 GSM_Phone_Data *Data = &s->Phone.Data;
2692 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2693
2694 switch (Priv->ReplyState) {
2695 case AT_Reply_OK:
2696 return ATGEN_ParseReply(s,
2697 GetLineString(msg->Buffer, &Priv->Lines, 2),
2698 "+CCLK: @d",
2699 Data->DateTime);
2700 case AT_Reply_Error:
2701 return ERR_NOTSUPPORTED;
2702 case AT_Reply_CMSError:
2703 return ATGEN_HandleCMSError(s);
2704 case AT_Reply_CMEError:
2705 return ATGEN_HandleCMEError(s);
2706 default:
2707 break;
2708 }
2709 return ERR_UNKNOWNRESPONSE;
2710 }
2711
2712
ATGEN_ReplyGetAlarm(GSM_Protocol_Message * msg,GSM_StateMachine * s)2713 GSM_Error ATGEN_ReplyGetAlarm(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2714 {
2715 GSM_Phone_Data *Data = &s->Phone.Data;
2716 unsigned char buffer[100];
2717 GSM_Error error;
2718 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2719 int i;
2720 int location;
2721 const char *str;
2722
2723 switch (Priv->ReplyState) {
2724 case AT_Reply_OK:
2725 /* Try simple date string as alarm */
2726 error = ATGEN_ParseReply(s,
2727 GetLineString(msg->Buffer, &Priv->Lines, 2),
2728 "+CALA: @d",
2729 &(Data->Alarm->DateTime));
2730 if (error == ERR_NONE) {
2731 if (Data->Alarm->Location != 1) return ERR_INVALIDLOCATION;
2732 return ERR_NONE;
2733 }
2734
2735 /* Ok we have something more complex, try to handle it */
2736 i = 2;
2737 /* Need to scan over all reply lines */
2738 while (strcmp("OK", str = GetLineString(msg->Buffer, &Priv->Lines, i)) != 0) {
2739 i++;
2740 /**
2741 * +CALA: [<time1>,<n1>,<type1>,[<text1>],[<recurr1>],<silent1>]
2742 */
2743 error = ATGEN_ParseReply(s, str,
2744 "+CALA: @d, @i, @s, @s, @s",
2745 &(Data->Alarm->DateTime),
2746 &location,
2747 buffer, sizeof(buffer),
2748 Data->Alarm->Text, sizeof(Data->Alarm->Text),
2749 buffer, sizeof(buffer));
2750 if (error == ERR_NONE && location == Data->Alarm->Location) {
2751 /**
2752 * \todo This is not exact, repeating
2753 * can be set for only limited
2754 * set of days (eg. "4,5,6").
2755 */
2756 if (!strcmp(buffer, "\"1,2,3,4,5,6,7\"")) {
2757 Data->Alarm->Repeating = TRUE;
2758 } else {
2759 Data->Alarm->Repeating = FALSE;
2760 }
2761 return ERR_NONE;
2762 }
2763 }
2764
2765 return ERR_EMPTY;
2766 case AT_Reply_Error:
2767 return ERR_NOTSUPPORTED;
2768 case AT_Reply_CMSError:
2769 return ATGEN_HandleCMSError(s);
2770 case AT_Reply_CMEError:
2771 return ATGEN_HandleCMEError(s);
2772 default:
2773 break;
2774 }
2775 return ERR_UNKNOWNRESPONSE;
2776 }
2777
ATGEN_GetDateTime(GSM_StateMachine * s,GSM_DateTime * date_time)2778 GSM_Error ATGEN_GetDateTime(GSM_StateMachine *s, GSM_DateTime *date_time)
2779 {
2780 GSM_Error error;
2781 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2782
2783 /* If phone encodes also values in command, we need normal charset */
2784 if (Priv->EncodedCommands) {
2785 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_NORMAL);
2786 if (error != ERR_NONE) return error;
2787 }
2788
2789 s->Phone.Data.DateTime = date_time;
2790 smprintf(s, "Getting date & time\n");
2791 error = ATGEN_WaitForAutoLen(s, "AT+CCLK?\r", 0x00, 40, ID_GetDateTime);
2792
2793 return error;
2794 }
2795
ATGEN_PrivSetDateTime(GSM_StateMachine * s,GSM_DateTime * date_time,gboolean set_timezone)2796 GSM_Error ATGEN_PrivSetDateTime(GSM_StateMachine *s, GSM_DateTime *date_time, gboolean set_timezone)
2797 {
2798 char tz[8] = "";
2799 char req[128];
2800 GSM_Error error;
2801 size_t len;
2802
2803 if (set_timezone) {
2804 sprintf(tz, "%+03i", date_time->Timezone / 3600);
2805 }
2806
2807 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_FOUR_DIGIT_YEAR)) {
2808 len = sprintf(req, "AT+CCLK=\"%04i/%02i/%02i,%02i:%02i:%02i%s\"\r",
2809 date_time->Year,
2810 date_time->Month ,
2811 date_time->Day,
2812 date_time->Hour,
2813 date_time->Minute,
2814 date_time->Second,
2815 tz);
2816 } else {
2817 len = sprintf(req, "AT+CCLK=\"%02i/%02i/%02i,%02i:%02i:%02i%s\"\r",
2818 (date_time->Year > 2000 ? date_time->Year-2000 : date_time->Year-1900),
2819 date_time->Month ,
2820 date_time->Day,
2821 date_time->Hour,
2822 date_time->Minute,
2823 date_time->Second,
2824 tz);
2825 }
2826 smprintf(s, "Setting date & time\n");
2827
2828 error = ATGEN_WaitFor(s, req, len, 0x00, 40, ID_SetDateTime);
2829 if (error == ERR_UNKNOWN) error = ERR_NOTSUPPORTED;
2830
2831 if (set_timezone && (
2832 s->Phone.Data.Priv.ATGEN.ReplyState == AT_Reply_CMEError
2833 && ((error == ERR_INVALIDDATA
2834 && s->Phone.Data.Priv.ATGEN.ErrorCode == 24) ||
2835 (error == ERR_INVALIDLOCATION
2836 && s->Phone.Data.Priv.ATGEN.ErrorCode == 21))
2837 )) {
2838 /*
2839 * Some firmwares of Ericsson R320s don't like the timezone part,
2840 * even though it is in its command reference. Similar issue
2841 * exists for MC75
2842 */
2843 smprintf(s, "Retrying without timezone suffix\n");
2844 error = ATGEN_PrivSetDateTime(s, date_time, FALSE);
2845 }
2846 return error;
2847 }
2848
ATGEN_SetDateTime(GSM_StateMachine * s,GSM_DateTime * date_time)2849 GSM_Error ATGEN_SetDateTime(GSM_StateMachine *s, GSM_DateTime *date_time)
2850 {
2851 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2852 GSM_Error error;
2853
2854 /* If phone encodes also values in command, we need normal charset */
2855 if (Priv->EncodedCommands) {
2856 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_NORMAL);
2857 if (error != ERR_NONE) return error;
2858 }
2859 return ATGEN_PrivSetDateTime(s, date_time, TRUE);
2860 }
2861
ATGEN_GetAlarm(GSM_StateMachine * s,GSM_Alarm * Alarm)2862 GSM_Error ATGEN_GetAlarm(GSM_StateMachine *s, GSM_Alarm *Alarm)
2863 {
2864 GSM_Error error;
2865 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2866
2867 /* If phone encodes also values in command, we need normal charset */
2868 if (Priv->EncodedCommands) {
2869 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_NORMAL);
2870 if (error != ERR_NONE) return error;
2871 }
2872
2873 s->Phone.Data.Alarm = Alarm;
2874 smprintf(s, "Getting alarm\n");
2875 error = ATGEN_WaitForAutoLen(s, "AT+CALA?\r", 0x00, 40, ID_GetAlarm);
2876
2877 return error;
2878 }
2879
2880 /* R320 only takes HH:MM. Do other phones understand full date? */
ATGEN_SetAlarm(GSM_StateMachine * s,GSM_Alarm * Alarm)2881 GSM_Error ATGEN_SetAlarm(GSM_StateMachine *s, GSM_Alarm *Alarm)
2882 {
2883 char req[20]={0};
2884 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2885 GSM_Error error;
2886 int length = 0;
2887
2888 if (Alarm->Location != 1) {
2889 return ERR_INVALIDLOCATION;
2890 }
2891
2892 /* If phone encodes also values in command, we need normal charset */
2893 if (Priv->EncodedCommands) {
2894 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_NORMAL);
2895 if (error != ERR_NONE) return error;
2896 }
2897 smprintf(s, "Setting Alarm\n");
2898 length = sprintf(req, "AT+CALA=\"%02i:%02i\"\r",Alarm->DateTime.Hour,Alarm->DateTime.Minute);
2899 error = ATGEN_WaitFor(s, req, length, 0x00, 10, ID_SetAlarm);
2900 return error;
2901 }
2902
ATGEN_ReplyGetPacketNetworkLAC_CID(GSM_Protocol_Message * msg,GSM_StateMachine * s)2903 GSM_Error ATGEN_ReplyGetPacketNetworkLAC_CID(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2904 {
2905 GSM_NetworkInfo *NetworkInfo = s->Phone.Data.NetworkInfo;
2906 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2907 int i, state;
2908 int act;
2909 char rac[8];
2910 GSM_Error error;
2911
2912 if (s->Phone.Data.RequestID != ID_GetNetworkInfo) {
2913 smprintf(s, "Incoming LAC & CID info, ignoring\n");
2914 return ERR_NONE;
2915 }
2916
2917 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
2918 case AT_Reply_OK:
2919 break;
2920 case AT_Reply_CMSError:
2921 return ATGEN_HandleCMSError(s);
2922 case AT_Reply_CMEError:
2923 return ATGEN_HandleCMEError(s);
2924 default:
2925 return ERR_UNKNOWNRESPONSE;
2926 }
2927
2928 if (strcmp("OK", GetLineString(msg->Buffer, &Priv->Lines, 2)) == 0) {
2929 NetworkInfo->PacketState = GSM_NoNetwork;
2930 NetworkInfo->PacketLAC[0] = 0;
2931 NetworkInfo->PacketCID[0] = 0;
2932 return ERR_NONE;
2933 }
2934
2935 smprintf(s, "Network LAC & CID & state received\n");
2936
2937 NetworkInfo->PacketLAC[0] = 0;
2938 NetworkInfo->PacketCID[0] = 0;
2939
2940 /* Full reply */
2941 error = ATGEN_ParseReply(s,
2942 GetLineString(msg->Buffer, &Priv->Lines, 2),
2943 "+CGREG: @i, @i, @r, @r, @i, @r",
2944 &i, /* Mode, ignored for now */
2945 &state,
2946 NetworkInfo->PacketLAC, sizeof(NetworkInfo->PacketLAC),
2947 NetworkInfo->PacketCID, sizeof(NetworkInfo->PacketCID),
2948 &act, /* Access Technology, ignored for now */
2949 &rac, sizeof(rac) /* Routing Area Code, ignored for now */
2950 );
2951
2952 /* Reply without RAC */
2953 if (error == ERR_UNKNOWNRESPONSE) {
2954 error = ATGEN_ParseReply(s,
2955 GetLineString(msg->Buffer, &Priv->Lines, 2),
2956 "+CGREG: @i, @i, @r, @r, @i",
2957 &i, /* Mode, ignored for now */
2958 &state,
2959 NetworkInfo->PacketLAC, sizeof(NetworkInfo->PacketLAC),
2960 NetworkInfo->PacketCID, sizeof(NetworkInfo->PacketCID),
2961 &act /* Access Technology, ignored for now */
2962 );
2963 }
2964
2965 /* Reply without ACT/RAC */
2966 if (error == ERR_UNKNOWNRESPONSE) {
2967 error = ATGEN_ParseReply(s,
2968 GetLineString(msg->Buffer, &Priv->Lines, 2),
2969 "+CGREG: @i, @i, @r, @r",
2970 &i, /* Mode, ignored for now */
2971 &state,
2972 NetworkInfo->PacketLAC, sizeof(NetworkInfo->PacketLAC),
2973 NetworkInfo->PacketCID, sizeof(NetworkInfo->PacketCID));
2974 }
2975
2976 /* Reply without LAC/CID */
2977 if (error == ERR_UNKNOWNRESPONSE) {
2978 error = ATGEN_ParseReply(s,
2979 GetLineString(msg->Buffer, &Priv->Lines, 2),
2980 "+CGREG: @i, @i",
2981 &i, /* Mode, ignored for now */
2982 &state);
2983 }
2984
2985 if (error != ERR_NONE) {
2986 return error;
2987 }
2988
2989 /* Decode network state */
2990 switch (state) {
2991 case 0:
2992 smprintf(s, "Not registered into any network. Not searching for network\n");
2993 NetworkInfo->PacketState = GSM_NoNetwork;
2994 break;
2995 case 1:
2996 smprintf(s, "Home network\n");
2997 NetworkInfo->PacketState = GSM_HomeNetwork;
2998 break;
2999 case 2:
3000 smprintf(s, "Not registered into any network. Searching for network\n");
3001 NetworkInfo->PacketState = GSM_RequestingNetwork;
3002 break;
3003 case 3:
3004 smprintf(s, "Registration denied\n");
3005 NetworkInfo->PacketState = GSM_RegistrationDenied;
3006 break;
3007 case 4:
3008 smprintf(s, "Unknown\n");
3009 NetworkInfo->PacketState = GSM_NetworkStatusUnknown;
3010 break;
3011 case 5:
3012 smprintf(s, "Registered in roaming network\n");
3013 NetworkInfo->PacketState = GSM_RoamingNetwork;
3014 break;
3015 default:
3016 smprintf(s, "Unknown: %d\n", state);
3017 NetworkInfo->PacketState = GSM_NetworkStatusUnknown;
3018 break;
3019 }
3020
3021 return ERR_NONE;
3022 }
3023
ATGEN_ReplyGetNetworkLAC_CID(GSM_Protocol_Message * msg,GSM_StateMachine * s)3024 GSM_Error ATGEN_ReplyGetNetworkLAC_CID(GSM_Protocol_Message *msg, GSM_StateMachine *s)
3025 {
3026 GSM_NetworkInfo *NetworkInfo = s->Phone.Data.NetworkInfo;
3027 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3028 int i, state;
3029 int act;
3030 GSM_Error error;
3031
3032 if (s->Phone.Data.RequestID != ID_GetNetworkInfo) {
3033 smprintf(s, "Incoming LAC & CID info, ignoring\n");
3034 return ERR_NONE;
3035 }
3036
3037 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
3038 case AT_Reply_OK:
3039 break;
3040 case AT_Reply_CMSError:
3041 return ATGEN_HandleCMSError(s);
3042 case AT_Reply_CMEError:
3043 return ATGEN_HandleCMEError(s);
3044 default:
3045 return ERR_UNKNOWNRESPONSE;
3046 }
3047
3048 if (strcmp("OK", GetLineString(msg->Buffer, &Priv->Lines, 2)) == 0) {
3049 NetworkInfo->State = GSM_NoNetwork;
3050 NetworkInfo->LAC[0] = 0;
3051 NetworkInfo->CID[0] = 0;
3052 return ERR_NONE;
3053 }
3054
3055 smprintf(s, "Network LAC & CID & state received\n");
3056
3057 NetworkInfo->LAC[0] = 0;
3058 NetworkInfo->CID[0] = 0;
3059
3060 /* Full reply */
3061 error = ATGEN_ParseReply(s,
3062 GetLineString(msg->Buffer, &Priv->Lines, 2),
3063 "+CREG: @i, @i, @r, @r, @i",
3064 &i, /* Mode, ignored for now */
3065 &state,
3066 NetworkInfo->LAC, sizeof(NetworkInfo->LAC),
3067 NetworkInfo->CID, sizeof(NetworkInfo->CID),
3068 &act /* Access Technology, ignored for now */
3069 );
3070
3071 /* Reply without ACT */
3072 if (error == ERR_UNKNOWNRESPONSE) {
3073 error = ATGEN_ParseReply(s,
3074 GetLineString(msg->Buffer, &Priv->Lines, 2),
3075 "+CREG: @i, @i, @r, @r",
3076 &i, /* Mode, ignored for now */
3077 &state,
3078 NetworkInfo->LAC, sizeof(NetworkInfo->LAC),
3079 NetworkInfo->CID, sizeof(NetworkInfo->CID));
3080 }
3081
3082 /* Reply without mode */
3083 if (error == ERR_UNKNOWNRESPONSE) {
3084 error = ATGEN_ParseReply(s,
3085 GetLineString(msg->Buffer, &Priv->Lines, 2),
3086 "+CREG: @i, @r, @r",
3087 &state,
3088 NetworkInfo->LAC, sizeof(NetworkInfo->LAC),
3089 NetworkInfo->CID, sizeof(NetworkInfo->CID));
3090 }
3091
3092 /* Reply without LAC/CID */
3093 if (error == ERR_UNKNOWNRESPONSE) {
3094 error = ATGEN_ParseReply(s,
3095 GetLineString(msg->Buffer, &Priv->Lines, 2),
3096 "+CREG: @i, @i",
3097 &i, /* Mode, ignored for now */
3098 &state);
3099 }
3100
3101 if (error != ERR_NONE) {
3102 return error;
3103 }
3104
3105 /* Decode network state */
3106 switch (state) {
3107 case 0:
3108 smprintf(s, "Not registered into any network. Not searching for network\n");
3109 NetworkInfo->State = GSM_NoNetwork;
3110 break;
3111 case 1:
3112 smprintf(s, "Home network\n");
3113 NetworkInfo->State = GSM_HomeNetwork;
3114 break;
3115 case 2:
3116 smprintf(s, "Not registered into any network. Searching for network\n");
3117 NetworkInfo->State = GSM_RequestingNetwork;
3118 break;
3119 case 3:
3120 smprintf(s, "Registration denied\n");
3121 NetworkInfo->State = GSM_RegistrationDenied;
3122 break;
3123 case 4:
3124 smprintf(s, "Unknown\n");
3125 NetworkInfo->State = GSM_NetworkStatusUnknown;
3126 break;
3127 case 5:
3128 smprintf(s, "Registered in roaming network\n");
3129 NetworkInfo->State = GSM_RoamingNetwork;
3130 break;
3131 default:
3132 smprintf(s, "Unknown: %d\n", state);
3133 NetworkInfo->State = GSM_NetworkStatusUnknown;
3134 break;
3135 }
3136
3137 return ERR_NONE;
3138 }
3139
ATGEN_ReplyGetNetworkCode(GSM_Protocol_Message * msg,GSM_StateMachine * s)3140 GSM_Error ATGEN_ReplyGetNetworkCode(GSM_Protocol_Message *msg, GSM_StateMachine *s)
3141 {
3142 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3143 GSM_NetworkInfo *NetworkInfo = s->Phone.Data.NetworkInfo;
3144 int i;
3145 GSM_Error error;
3146
3147 switch (Priv->ReplyState) {
3148 case AT_Reply_OK:
3149 smprintf(s, "Network code received\n");
3150 error = ATGEN_ParseReply(s,
3151 GetLineString(msg->Buffer, &Priv->Lines, 2),
3152 "+COPS: @i, @i, @r",
3153 &i, /* Mode, ignored for now */
3154 &i, /* Format of reply, we set this */
3155 NetworkInfo->NetworkCode, sizeof(NetworkInfo->NetworkCode));
3156
3157 /* Some Sony-Ericsson phones use this */
3158 if (error == ERR_UNKNOWNRESPONSE) {
3159 error = ATGEN_ParseReply(s,
3160 GetLineString(msg->Buffer, &Priv->Lines, 2),
3161 "+COPS: @i, @i, @r, @i",
3162 &i, /* Mode, ignored for now */
3163 &i, /* Format of reply, we set this */
3164 NetworkInfo->NetworkCode, sizeof(NetworkInfo->NetworkCode),
3165 &i);
3166 }
3167
3168 if (error != ERR_NONE) {
3169 /* Cleanup if something went wrong */
3170 NetworkInfo->NetworkCode[0] = 0;
3171 NetworkInfo->NetworkCode[1] = 0;
3172
3173 return error;
3174 }
3175
3176 /* Split network code for country and operator */
3177 if (strlen(NetworkInfo->NetworkCode) == 5) {
3178 NetworkInfo->NetworkCode[6] = 0;
3179 NetworkInfo->NetworkCode[5] = NetworkInfo->NetworkCode[4];
3180 NetworkInfo->NetworkCode[4] = NetworkInfo->NetworkCode[3];
3181 NetworkInfo->NetworkCode[3] = ' ';
3182 }
3183
3184 smprintf(s, " Network code : %s\n",
3185 NetworkInfo->NetworkCode);
3186 smprintf(s, " Network name for Gammu : %s ",
3187 DecodeUnicodeString(GSM_GetNetworkName(NetworkInfo->NetworkCode)));
3188 smprintf(s, "(%s)\n",
3189 DecodeUnicodeString(GSM_GetCountryName(NetworkInfo->NetworkCode)));
3190 return ERR_NONE;
3191 case AT_Reply_CMSError:
3192 return ATGEN_HandleCMSError(s);
3193 case AT_Reply_CMEError:
3194 return ATGEN_HandleCMEError(s);
3195 default:
3196 break;
3197 }
3198 return ERR_UNKNOWNRESPONSE;
3199 }
3200
ATGEN_ReplyGetNetworkName(GSM_Protocol_Message * msg,GSM_StateMachine * s)3201 GSM_Error ATGEN_ReplyGetNetworkName(GSM_Protocol_Message *msg, GSM_StateMachine *s)
3202 {
3203 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3204 GSM_NetworkInfo *NetworkInfo = s->Phone.Data.NetworkInfo;
3205 int i;
3206 GSM_Error error;
3207
3208 switch (Priv->ReplyState) {
3209 case AT_Reply_OK:
3210 smprintf(s, "Network name received\n");
3211 error = ATGEN_ParseReply(s,
3212 GetLineString(msg->Buffer, &Priv->Lines, 2),
3213 "+COPS: @i, @i, @s",
3214 &i, /* Mode, ignored for now */
3215 &i, /* Format of reply, we set this */
3216 NetworkInfo->NetworkName, sizeof(NetworkInfo->NetworkName));
3217
3218 /* Some Sony-Ericsson phones use this */
3219 if (error == ERR_UNKNOWNRESPONSE) {
3220 error = ATGEN_ParseReply(s,
3221 GetLineString(msg->Buffer, &Priv->Lines, 2),
3222 "+COPS: @i, @i, @s, @i",
3223 &i, /* Mode, ignored for now */
3224 &i, /* Format of reply, we set this */
3225 NetworkInfo->NetworkName, sizeof(NetworkInfo->NetworkName),
3226 &i);
3227 }
3228
3229 /* Cleanup if something went wrong */
3230 if (error != ERR_NONE) {
3231 smprintf(s, "WARNING: Failed to store network name - ERROR(%s)", GSM_ErrorName(error));
3232 NetworkInfo->NetworkName[0] = 0;
3233 NetworkInfo->NetworkName[1] = 0;
3234 }
3235
3236 return error;
3237 case AT_Reply_CMSError:
3238 return ATGEN_HandleCMSError(s);
3239 case AT_Reply_CMEError:
3240 return ATGEN_HandleCMEError(s);
3241 default:
3242 break;
3243 }
3244 return ERR_UNKNOWNRESPONSE;
3245 }
3246
ATGEN_ReplyGetGPRSState(GSM_Protocol_Message * msg,GSM_StateMachine * s)3247 GSM_Error ATGEN_ReplyGetGPRSState(GSM_Protocol_Message *msg, GSM_StateMachine *s)
3248 {
3249 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3250 GSM_NetworkInfo *NetworkInfo = s->Phone.Data.NetworkInfo;
3251 int i;
3252 GSM_Error error;
3253
3254 switch (Priv->ReplyState) {
3255 case AT_Reply_OK:
3256 smprintf(s, "GPRS state received\n");
3257 error = ATGEN_ParseReply(s,
3258 GetLineString(msg->Buffer, &Priv->Lines, 2),
3259 "+CGATT: @i",
3260 &i);
3261
3262 if (error == ERR_NONE) {
3263 if (i == 1) {
3264 NetworkInfo->GPRS = GSM_GPRS_Attached;
3265 } else if (i == 0) {
3266 NetworkInfo->GPRS = GSM_GPRS_Detached;
3267 } else {
3268 smprintf(s, "WARNING: Unknown GPRS state %d\n", i);
3269 error = ERR_UNKNOWN;
3270 }
3271 }
3272 return error;
3273 case AT_Reply_CMSError:
3274 return ATGEN_HandleCMSError(s);
3275 case AT_Reply_CMEError:
3276 return ATGEN_HandleCMEError(s);
3277 default:
3278 break;
3279 }
3280 return ERR_UNKNOWNRESPONSE;
3281 }
3282
ATGEN_GetNetworkInfo(GSM_StateMachine * s,GSM_NetworkInfo * netinfo)3283 GSM_Error ATGEN_GetNetworkInfo(GSM_StateMachine *s, GSM_NetworkInfo *netinfo)
3284 {
3285 GSM_Error error;
3286
3287 s->Phone.Data.NetworkInfo = netinfo;
3288
3289 netinfo->NetworkName[0] = 0;
3290 netinfo->NetworkName[1] = 0;
3291 netinfo->NetworkCode[0] = 0;
3292 netinfo->GPRS = 0;
3293
3294 smprintf(s, "Enable full network info\n");
3295 error = ATGEN_WaitForAutoLen(s, "AT+CREG=2\r", 0x00, 40, ID_ConfigureNetworkInfo);
3296
3297 if (error == ERR_UNKNOWN) {
3298 /* Try basic info at least */
3299 error = ATGEN_WaitForAutoLen(s, "AT+CREG=1\r", 0x00, 40, ID_ConfigureNetworkInfo);
3300 }
3301
3302 if (error != ERR_NONE) {
3303 return error;
3304 }
3305
3306 smprintf(s, "Enable full packet network info\n");
3307 error = ATGEN_WaitForAutoLen(s, "AT+CGREG=2\r", 0x00, 40, ID_ConfigureNetworkInfo);
3308 if (error == ERR_UNKNOWN) {
3309 /* Try basic info at least */
3310 error = ATGEN_WaitForAutoLen(s, "AT+CGREG=1\r", 0x00, 40, ID_ConfigureNetworkInfo);
3311 }
3312 if (error != ERR_NONE) {
3313 return error;
3314 }
3315
3316 smprintf(s, "Getting GPRS state\n");
3317 error = ATGEN_WaitForAutoLen(s, "AT+CGATT?\r", 0x00, 40, ID_GetGPRSState);
3318
3319 if (error != ERR_NONE) {
3320 return error;
3321 }
3322 smprintf(s, "Getting network LAC and CID and state\n");
3323 error = ATGEN_WaitForAutoLen(s, "AT+CREG?\r", 0x00, 40, ID_GetNetworkInfo);
3324
3325 if (error != ERR_NONE) {
3326 return error;
3327 }
3328 smprintf(s, "Getting packet network LAC and CID and state\n");
3329 error = ATGEN_WaitForAutoLen(s, "AT+CGREG?\r", 0x00, 40, ID_GetNetworkInfo);
3330
3331 if (error != ERR_NONE) {
3332 return error;
3333 }
3334 if (netinfo->State == GSM_HomeNetwork ||
3335 netinfo->State == GSM_RoamingNetwork ||
3336 netinfo->PacketState == GSM_HomeNetwork ||
3337 netinfo->PacketState == GSM_RoamingNetwork
3338 ) {
3339 /* Set numeric format for AT+COPS? */
3340 smprintf(s, "Setting short network name format\n");
3341 error = ATGEN_WaitForAutoLen(s, "AT+COPS=3,2\r", 0x00, 40, ID_ConfigureNetworkInfo);
3342
3343 /* Get operator code */
3344 smprintf(s, "Getting network code\n");
3345 error = ATGEN_WaitForAutoLen(s, "AT+COPS?\r", 0x00, 40, ID_GetNetworkCode);
3346
3347 /* Set string format for AT+COPS? */
3348 smprintf(s, "Setting long string network name format\n");
3349 error = ATGEN_WaitForAutoLen(s, "AT+COPS=3,0\r", 0x00, 40, ID_ConfigureNetworkInfo);
3350
3351 /* Get operator code */
3352 smprintf(s, "Getting network code\n");
3353 error = ATGEN_WaitForAutoLen(s, "AT+COPS?\r", 0x00, 40, ID_GetNetworkName);
3354
3355 /* All information here is optional */
3356 error = ERR_NONE;
3357 }
3358 return error;
3359 }
3360
3361 /**
3362 * Stores available phonebook memories in PBKMemories.
3363 *
3364 * @todo Should parse reply, not copy it as is.
3365 */
ATGEN_ReplyGetPBKMemories(GSM_Protocol_Message * msg,GSM_StateMachine * s)3366 GSM_Error ATGEN_ReplyGetPBKMemories(GSM_Protocol_Message *msg, GSM_StateMachine *s)
3367 {
3368 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3369
3370 switch (Priv->ReplyState) {
3371 case AT_Reply_OK:
3372 break;
3373 case AT_Reply_Error:
3374 return ERR_NOTSUPPORTED;
3375 case AT_Reply_CMSError:
3376 return ATGEN_HandleCMSError(s);
3377 case AT_Reply_CMEError:
3378 return ATGEN_HandleCMEError(s);
3379 default:
3380 return ERR_UNKNOWNRESPONSE;
3381 }
3382
3383 if (GetLineLength(msg->Buffer, &Priv->Lines, 2) >= AT_PBK_MAX_MEMORIES) {
3384 smprintf(s, "ERROR: Too long phonebook memories information received! (Recevided %d, AT_PBK_MAX_MEMORIES is %d\n",
3385 GetLineLength(msg->Buffer, &Priv->Lines, 2), AT_PBK_MAX_MEMORIES);
3386 return ERR_MOREMEMORY;
3387 }
3388 CopyLineString(Priv->PBKMemories, msg->Buffer, &Priv->Lines, 2);
3389 smprintf(s, "PBK memories received: %s\n", s->Phone.Data.Priv.ATGEN.PBKMemories);
3390 return ERR_NONE;
3391 }
3392
ATGEN_ReplySetPBKMemory(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)3393 GSM_Error ATGEN_ReplySetPBKMemory(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
3394 {
3395 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
3396 case AT_Reply_OK:
3397 case AT_Reply_Connect:
3398 return ERR_NONE;
3399 case AT_Reply_Error:
3400 return ERR_NOTSUPPORTED;
3401 case AT_Reply_CMSError:
3402 return ATGEN_HandleCMSError(s);
3403 case AT_Reply_CMEError:
3404 return ATGEN_HandleCMEError(s);
3405 default:
3406 break;
3407 }
3408 return ERR_UNKNOWNRESPONSE;
3409 }
3410
ATGEN_CheckSBNR(GSM_StateMachine * s)3411 GSM_Error ATGEN_CheckSBNR(GSM_StateMachine *s)
3412 {
3413 GSM_Error error;
3414 char req[] = "AT^SBNR=?\r";
3415 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3416
3417 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SIEMENS_PBK)) {
3418 smprintf(s, "Forcing AT^SBNR support\n");
3419 Priv->PBKSBNR = AT_AVAILABLE;
3420 return ERR_NONE;
3421 }
3422
3423 smprintf(s, "Checking availability of SBNR\n");
3424 error = ATGEN_WaitForAutoLen(s, req, 0x00, 40, ID_GetMemory);
3425 return error;
3426 }
3427
ATGEN_CheckSPBR(GSM_StateMachine * s)3428 GSM_Error ATGEN_CheckSPBR(GSM_StateMachine *s)
3429 {
3430 GSM_Error error;
3431 char req[] = "AT+SPBR=?\r";
3432
3433 smprintf(s, "Checking availability of SPBR\n");
3434 error = ATGEN_WaitForAutoLen(s, req, 0x00, 40, ID_GetMemory);
3435 return error;
3436 }
3437
ATGEN_CheckMPBR(GSM_StateMachine * s)3438 GSM_Error ATGEN_CheckMPBR(GSM_StateMachine *s)
3439 {
3440 GSM_Error error;
3441 char req[] = "AT+MPBR=?\r";
3442
3443 smprintf(s, "Checking availability of MPBR\n");
3444 error = ATGEN_WaitForAutoLen(s, req, 0x00, 40, ID_GetMemory);
3445 return error;
3446 }
3447
3448
ATGEN_SetPBKMemory(GSM_StateMachine * s,GSM_MemoryType MemType)3449 GSM_Error ATGEN_SetPBKMemory(GSM_StateMachine *s, GSM_MemoryType MemType)
3450 {
3451 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3452 char req[] = "AT+CPBS=\"XX\"\r";
3453 GSM_Error error;
3454
3455 if (Priv->PBKMemory == MemType) return ERR_NONE;
3456
3457 /* Zero values that are for actual memory */
3458 Priv->MemorySize = 0;
3459 Priv->MemoryUsed = 0;
3460 Priv->FirstMemoryEntry = -1;
3461 Priv->NextMemoryEntry = 0;
3462 Priv->TextLength = 0;
3463 Priv->NumberLength = 0;
3464
3465 /* If phone encodes also values in command, we need normal charset */
3466 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_NORMAL);
3467 if (error != ERR_NONE) return error;
3468
3469 if (Priv->PBKMemories[0] == 0) {
3470 error = ATGEN_WaitForAutoLen(s, "AT+CPBS=?\r", 0x00, 10, ID_SetMemoryType);
3471
3472 if (error != ERR_NONE) {
3473 /*
3474 * We weren't able to read available memories, let's
3475 * guess that phone supports all. This is TRUE at least
3476 * for Samsung.
3477 */
3478 strcpy(s->Phone.Data.Priv.ATGEN.PBKMemories, "\"ME\",\"SM\",\"DC\",\"ON\",\"LD\",\"FD\",\"MC\",\"RC\"");
3479 smprintf(s, "Falling back to default memories list: %s\n", s->Phone.Data.Priv.ATGEN.PBKMemories);
3480 }
3481 }
3482
3483 switch (MemType) {
3484 case MEM_SM:
3485 req[9] = 'S'; req[10] = 'M';
3486 break;
3487 case MEM_ME:
3488 if (strstr(Priv->PBKMemories,"ME") != NULL) {
3489 req[9] = 'M'; req[10] = 'E';
3490 break;
3491 }
3492 if (strstr(Priv->PBKMemories,"MT") != NULL) {
3493 req[9] = 'M'; req[10] = 'T';
3494 break;
3495 }
3496 return ERR_NOTSUPPORTED;
3497 case MEM_RC:
3498 if (strstr(Priv->PBKMemories,"RC")==NULL) return ERR_NOTSUPPORTED;
3499 req[9] = 'R'; req[10] = 'C';
3500 break;
3501 case MEM_MC:
3502 if (strstr(Priv->PBKMemories,"MC")==NULL) return ERR_NOTSUPPORTED;
3503 req[9] = 'M'; req[10] = 'C';
3504 break;
3505 case MEM_ON:
3506 if (strstr(Priv->PBKMemories,"ON")==NULL) return ERR_NOTSUPPORTED;
3507 req[9] = 'O'; req[10] = 'N';
3508 break;
3509 case MEM_FD:
3510 if (strstr(Priv->PBKMemories,"FD")==NULL) return ERR_NOTSUPPORTED;
3511 req[9] = 'F'; req[10] = 'D';
3512 break;
3513 case MEM_QD:
3514 if (strstr(Priv->PBKMemories,"QD")==NULL) return ERR_NOTSUPPORTED;
3515 req[9] = 'Q'; req[10] = 'D';
3516 break;
3517 case MEM_DC:
3518 if (strstr(Priv->PBKMemories,"DC")!=NULL) {
3519 req[9] = 'D'; req[10] = 'C';
3520 break;
3521 }
3522 if (strstr(Priv->PBKMemories,"LD")!=NULL) {
3523 req[9] = 'L'; req[10] = 'D';
3524 break;
3525 }
3526 return ERR_NOTSUPPORTED;
3527 default:
3528 return ERR_NOTSUPPORTED;
3529 }
3530
3531 smprintf(s, "Setting memory type\n");
3532 error = ATGEN_WaitForAutoLen(s, req, 0x00, 10, ID_SetMemoryType);
3533
3534 if (error == ERR_NONE) {
3535 Priv->PBKMemory = MemType;
3536 }
3537 if (MemType == MEM_ME) {
3538 if (Priv->PBKSBNR == 0) {
3539 ATGEN_CheckSBNR(s);
3540 }
3541 if (Priv->PBK_SPBR == 0) {
3542 ATGEN_CheckSPBR(s);
3543 }
3544 if (Priv->PBK_MPBR == 0) {
3545 ATGEN_CheckMPBR(s);
3546 }
3547 }
3548 return error;
3549 }
3550
ATGEN_ReplyGetCPBSMemoryStatus(GSM_Protocol_Message * msg,GSM_StateMachine * s)3551 GSM_Error ATGEN_ReplyGetCPBSMemoryStatus(GSM_Protocol_Message *msg, GSM_StateMachine *s)
3552 {
3553 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3554 unsigned char tmp[200]={0};
3555 GSM_Error error;
3556 const char *str;
3557
3558 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
3559 case AT_Reply_OK:
3560 smprintf(s, "Memory status received\n");
3561 str = GetLineString(msg->Buffer, &Priv->Lines, 2);
3562
3563 error = ATGEN_ParseReply(s, str,
3564 "+CPBS: @s, @i, @i",
3565 tmp, sizeof(tmp) / 2,
3566 &Priv->MemoryUsed,
3567 &Priv->MemorySize);
3568 if (error == ERR_UNKNOWNRESPONSE) {
3569 return ERR_NOTSUPPORTED;
3570 }
3571 return error;
3572 case AT_Reply_CMSError:
3573 return ATGEN_HandleCMSError(s);
3574 case AT_Reply_CMEError:
3575 return ATGEN_HandleCMEError(s);
3576 default:
3577 break;
3578 }
3579 return ERR_UNKNOWNRESPONSE;
3580 }
3581
3582 /**
3583 * Parses reply from phone about available entries.
3584 *
3585 * Standard format:
3586 * \verbatim
3587 * +CPBR: (first-last),max_number_len,max_name_len
3588 * \endverbatim
3589 * \verbatim
3590 * +CPBR: (location),max_number_len,max_name_len
3591 * \endverbatim
3592 *
3593 * Some phones (eg. Motorola C350) reply is different:
3594 * \verbatim
3595 * +CPBR: first-last,max_number_len,max_name_len
3596 * \endverbatim
3597 *
3598 * Some phones do not list positions (Sharp):
3599 * \verbatim
3600 * +CPBR: (),max_number_len,max_name_len
3601 * \endverbatim
3602 *
3603 * Some phones (eg. Nokia 6600 slide) append some additional values to
3604 * standard format.
3605 *
3606 * Samsung phones sometimes have additional number after standard format.
3607 * I currently have no idea what does this number mean.
3608 *
3609 * \todo
3610 * We currently guess memory size for Sharp to 1000.
3611 */
ATGEN_ReplyGetCPBRMemoryInfo(GSM_Protocol_Message * msg,GSM_StateMachine * s)3612 GSM_Error ATGEN_ReplyGetCPBRMemoryInfo(GSM_Protocol_Message *msg, GSM_StateMachine *s)
3613 {
3614 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3615 const char *str;
3616 GSM_Error error;
3617 int ignore;
3618
3619 switch (Priv->ReplyState) {
3620 case AT_Reply_OK:
3621 smprintf(s, "Memory info received\n");
3622
3623 str = GetLineString(msg->Buffer, &Priv->Lines, 2);
3624
3625 /* Check for empty reply */
3626 if (strcmp("OK", str) == 0) {
3627 return ERR_UNKNOWN;
3628 }
3629
3630 /* Try standard format first */
3631 error = ATGEN_ParseReply(s, str,
3632 "+CPBR: (@i-@i), @i, @i",
3633 &Priv->FirstMemoryEntry,
3634 &Priv->MemorySize,
3635 &Priv->NumberLength,
3636 &Priv->TextLength);
3637 if (error == ERR_NONE) {
3638 /* Calculate memory size from last position we got from phone */
3639 Priv->MemorySize = Priv->MemorySize + 1 - Priv->FirstMemoryEntry;
3640 return ERR_NONE;
3641 }
3642
3643 /* Try Motorola format then */
3644 error = ATGEN_ParseReply(s, str,
3645 "+CPBR: @i-@i, @i, @i",
3646 &Priv->FirstMemoryEntry,
3647 &Priv->MemorySize,
3648 &Priv->NumberLength,
3649 &Priv->TextLength);
3650 if (error == ERR_NONE) {
3651 /* Calculate memory size from last position we got from phone */
3652 Priv->MemorySize = Priv->MemorySize + 1 - Priv->FirstMemoryEntry;
3653 return ERR_NONE;
3654 }
3655
3656 /* Try Sharp format */
3657 error = ATGEN_ParseReply(s, str,
3658 "+CPBR: (), @i, @i",
3659 &Priv->NumberLength,
3660 &Priv->TextLength);
3661 if (error == ERR_NONE) {
3662 /* Hardcode size, we have no other choice here */
3663 Priv->FirstMemoryEntry = 1;
3664 Priv->MemorySize = 1000;
3665 return ERR_NONE;
3666 }
3667
3668 /* Try single entry format */
3669 error = ATGEN_ParseReply(s, str,
3670 "+CPBR: (@i), @i, @i",
3671 &Priv->FirstMemoryEntry,
3672 &Priv->NumberLength,
3673 &Priv->TextLength);
3674 if (error == ERR_NONE) {
3675 /* Hardcode size, we have no other choice here */
3676 Priv->MemorySize = 1;
3677 return ERR_NONE;
3678 }
3679
3680 /* Try Samsung format at the end */
3681 error = ATGEN_ParseReply(s, str,
3682 "+CPBR: (@i-@i), @i, @i, @i",
3683 &Priv->FirstMemoryEntry,
3684 &Priv->MemorySize,
3685 &Priv->NumberLength,
3686 &Priv->TextLength,
3687 &ignore);
3688 if (error == ERR_NONE) {
3689 /* Calculate memory size from last position we got from phone */
3690 Priv->MemorySize = Priv->MemorySize + 1 - Priv->FirstMemoryEntry;
3691 return ERR_NONE;
3692 }
3693
3694
3695 /* Try standard format + unknown field */
3696 error = ATGEN_ParseReply(s, str,
3697 "+CPBR: (@i-@i), @i, @i, @0",
3698 &Priv->FirstMemoryEntry,
3699 &Priv->MemorySize,
3700 &Priv->NumberLength,
3701 &Priv->TextLength);
3702 if (error == ERR_NONE) {
3703 /* Calculate memory size from last position we got from phone */
3704 Priv->MemorySize = Priv->MemorySize + 1 - Priv->FirstMemoryEntry;
3705 return ERR_NONE;
3706 }
3707
3708 /* Try cripled standard format */
3709 error = ATGEN_ParseReply(s, str,
3710 "+CPBR: (@i-@i)",
3711 &Priv->FirstMemoryEntry,
3712 &Priv->MemorySize);
3713 if (error == ERR_NONE) {
3714 /* Calculate memory size from last position we got from phone */
3715 Priv->MemorySize = Priv->MemorySize + 1 - Priv->FirstMemoryEntry;
3716 return ERR_NONE;
3717 }
3718
3719 /* We don't get reply on first attempt on some Samsung phones */
3720 if (Priv->Manufacturer == AT_Samsung) {
3721 return ERR_NONE;
3722 }
3723 return ERR_UNKNOWNRESPONSE;
3724 case AT_Reply_Error:
3725 return ERR_UNKNOWN;
3726 case AT_Reply_CMSError:
3727 return ATGEN_HandleCMSError(s);
3728 case AT_Reply_CMEError:
3729 return ATGEN_HandleCMEError(s);
3730 default:
3731 return ERR_UNKNOWNRESPONSE;
3732 }
3733 }
3734
ATGEN_ReplyGetCPBRMemoryStatus(GSM_Protocol_Message * msg,GSM_StateMachine * s)3735 GSM_Error ATGEN_ReplyGetCPBRMemoryStatus(GSM_Protocol_Message *msg, GSM_StateMachine *s)
3736 {
3737 GSM_Error error;
3738 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3739 int line = 1;
3740 const char *str;
3741 int cur, last = -1;
3742
3743 switch (Priv->ReplyState) {
3744 case AT_Reply_OK:
3745 smprintf(s, "Memory entries for status received\n");
3746 /* Walk through lines with +CPBR: */
3747 while (strcmp("OK", str = GetLineString(msg->Buffer, &Priv->Lines, line + 1)) != 0) {
3748
3749 /* Parse reply */
3750 error = ATGEN_ParseReply(s, str, "+CPBR: @i, @0", &cur);
3751 if (error != ERR_NONE) {
3752 return error;
3753 }
3754
3755 /* Some phones wrongly return several lines with same location,
3756 * we need to catch it here to get correct count. */
3757 if (cur != last) {
3758 Priv->MemoryUsed++;
3759 }
3760 last = cur;
3761 cur -= Priv->FirstMemoryEntry - 1;
3762 if (cur == Priv->NextMemoryEntry || Priv->NextMemoryEntry == 0)
3763 Priv->NextMemoryEntry = cur + 1;
3764
3765 /* Go to next line */
3766 line++;
3767 }
3768 smprintf(s, "Memory status: Used: %d, Next: %d\n",
3769 Priv->MemoryUsed,
3770 Priv->NextMemoryEntry);
3771 return ERR_NONE;
3772 case AT_Reply_Error:
3773 return ERR_UNKNOWN;
3774 case AT_Reply_CMSError:
3775 return ATGEN_HandleCMSError(s);
3776 case AT_Reply_CMEError:
3777 return ATGEN_HandleCMEError(s);
3778 default:
3779 return ERR_UNKNOWNRESPONSE;
3780 }
3781 }
3782
ATGEN_GetMemoryInfo(GSM_StateMachine * s,GSM_MemoryStatus * Status,GSM_AT_NeededMemoryInfo NeededInfo)3783 GSM_Error ATGEN_GetMemoryInfo(GSM_StateMachine *s, GSM_MemoryStatus *Status, GSM_AT_NeededMemoryInfo NeededInfo)
3784 {
3785 GSM_Error error;
3786 char req[20]={'\0'};
3787 int start = 0,end = 0,memory_end = 0;
3788 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3789 gboolean free_read = FALSE;
3790 size_t len;
3791 int step = 20;
3792
3793 /* This can be NULL at this point */
3794 if (Status != NULL) {
3795 Status->MemoryUsed = 0;
3796 Status->MemoryFree = 0;
3797 }
3798
3799 /* For reading we prefer unicode */
3800 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_UNICODE);
3801 if (error != ERR_NONE) return error;
3802
3803 Priv->MemorySize = 0;
3804 Priv->MemoryUsed = 0;
3805 /* Safe default values */
3806 Priv->TextLength = 20;
3807 Priv->NumberLength = 20;
3808 Priv->FirstMemoryEntry = 1;
3809
3810 /*
3811 * First we try AT+CPBS?. It should return size of memory and
3812 * number of used entries, but some vendors do not support this
3813 * (SE).
3814 */
3815 /*
3816 * Some workaround for buggy mobile, that hangs after "AT+CPBS?" for other
3817 * memory than SM.
3818 */
3819 if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_BROKENCPBS) || (Priv->PBKMemory == MEM_SM)) {
3820 smprintf(s, "Getting memory status\n");
3821 error = ATGEN_WaitForAutoLen(s, "AT+CPBS?\r", 0x00, 40, ID_GetMemoryStatus);
3822
3823 if (error == ERR_NONE) {
3824 free_read = TRUE;
3825 }
3826 }
3827
3828 /**
3829 * Try to get memory size, first entry and length of entries
3830 * this way.
3831 */
3832 smprintf(s, "Getting memory information\n");
3833 if (Status != NULL && Status->MemoryType == MEM_ME && Priv->PBK_MPBR == AT_AVAILABLE) {
3834 error = ATGEN_WaitForAutoLen(s, "AT+MPBR=?\r", 0x00, 40, ID_GetMemoryStatus);
3835 } else {
3836 error = ATGEN_WaitForAutoLen(s, "AT+CPBR=?\r", 0x00, 40, ID_GetMemoryStatus);
3837 }
3838
3839 /* Did we fail to get size in either way? */
3840 if (error != ERR_NONE && Priv->MemorySize == 0) return error;
3841 /* Fill in Status structure if we were asked for it */
3842 if (Priv->MemorySize != 0 && Status != NULL) {
3843 Status->MemoryUsed = Priv->MemoryUsed;
3844 Status->MemoryFree = Priv->MemorySize - Priv->MemoryUsed;
3845 }
3846 if (((NeededInfo != AT_NextEmpty) &&
3847 (NeededInfo != AT_Status || free_read)) || Status == NULL) {
3848 return ERR_NONE;
3849 }
3850
3851 smprintf(s, "Getting memory status by reading values\n");
3852
3853 Status->MemoryUsed = 0;
3854 Status->MemoryFree = 0;
3855 start = Priv->FirstMemoryEntry;
3856 Priv->NextMemoryEntry = Priv->FirstMemoryEntry;
3857 memory_end = Priv->MemorySize + Priv->FirstMemoryEntry - 1;
3858
3859 while (1) {
3860 /* Calculate end of next request */
3861 end = start + step;
3862 if (end > memory_end)
3863 end = memory_end;
3864
3865 /* Read next interval */
3866 if (start == end) {
3867 len = sprintf(req, "AT+CPBR=%i\r", start);
3868 } else {
3869 len = sprintf(req, "AT+CPBR=%i,%i\r", start, end);
3870 }
3871 error = ATGEN_WaitFor(s, req, len, 0x00, 50, ID_GetMemoryStatus);
3872
3873 if (error == ERR_SECURITYERROR) {
3874 /* Some Samsung phones fail to read more entries at once */
3875 step = 0;
3876 continue;
3877 } else if (error == ERR_EMPTY) {
3878 Priv->NextMemoryEntry = start;
3879 if (NeededInfo == AT_NextEmpty) {
3880 return ERR_NONE;
3881 }
3882 } else if (error != ERR_NONE) {
3883 return error;
3884 }
3885
3886 /* Do we already have first empty record? */
3887 if (NeededInfo == AT_NextEmpty &&
3888 Priv->NextMemoryEntry != end + 1)
3889 return ERR_NONE;
3890
3891 /* Did we hit memory end? */
3892 if (end == memory_end) {
3893 Status->MemoryUsed = Priv->MemoryUsed;
3894 Status->MemoryFree = Priv->MemorySize - Priv->MemoryUsed;
3895 return ERR_NONE;
3896 }
3897
3898 /* Continue on next location */
3899 start = end + 1;
3900 }
3901 }
3902
ATGEN_GetMemoryStatus(GSM_StateMachine * s,GSM_MemoryStatus * Status)3903 GSM_Error ATGEN_GetMemoryStatus(GSM_StateMachine *s, GSM_MemoryStatus *Status)
3904 {
3905 GSM_Error error;
3906 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3907
3908 error = ATGEN_SetPBKMemory(s, Status->MemoryType);
3909 if (error != ERR_NONE) return error;
3910
3911 /* Catch errorneous 0 returned by some Siemens phones for ME. There is
3912 * probably no way to get status there. */
3913 if (Priv->PBKSBNR == AT_AVAILABLE && Status->MemoryType == MEM_ME && Status->MemoryFree == 0)
3914 return ERR_NOTSUPPORTED;
3915
3916 return ATGEN_GetMemoryInfo(s, Status, AT_Status);
3917 }
3918
3919 /**
3920 * Parses reply on AT+CPBR=n.
3921 *
3922 * \todo Handle special replies from some phones:
3923 * LG C1200:
3924 * +CPBR: 23,"Primary Number",145,"Name",3,"0123456789",145,2,"0123456789",145,1,"E-Mail-Address without domain","Fax-Number",255
3925 * 3 = Home Number
3926 * 2 = Office Number
3927 * 1 = Mobile Number
3928 *
3929 * Samsung SGH-P900 reply:
3930 * +CPBR: 81,"#121#",129,"My Tempo",0
3931 */
ATGEN_ReplyGetMemory(GSM_Protocol_Message * msg,GSM_StateMachine * s)3932 GSM_Error ATGEN_ReplyGetMemory(GSM_Protocol_Message *msg, GSM_StateMachine *s)
3933 {
3934 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3935 GSM_MemoryEntry *Memory = s->Phone.Data.Memory;
3936 GSM_Error error;
3937 unsigned char buffer[500];
3938 int offset, i;
3939 int number_type, types[10];
3940
3941 switch (Priv->ReplyState) {
3942 case AT_Reply_OK:
3943 smprintf(s, "Phonebook entry received\n");
3944 /* Check for empty entries */
3945 if (strcmp("OK", GetLineString(msg->Buffer, &Priv->Lines, 2)) == 0) {
3946 Memory->EntriesNum = 0;
3947 return ERR_EMPTY;
3948 }
3949
3950 /* Set number type */
3951 Memory->Entries[0].EntryType = PBK_Number_General;
3952 Memory->Entries[0].Location = PBK_Location_Unknown;
3953 Memory->Entries[0].VoiceTag = 0;
3954 Memory->Entries[0].SMSList[0] = 0;
3955
3956 /* Set name type */
3957 Memory->Entries[1].EntryType = PBK_Text_Name;
3958 Memory->Entries[1].Location = PBK_Location_Unknown;
3959
3960 /* Try standard reply */
3961 if (Priv->Manufacturer == AT_Motorola) {
3962 /* Enable encoding guessing for Motorola */
3963 error = ATGEN_ParseReply(s,
3964 GetLineString(msg->Buffer, &Priv->Lines, 2),
3965 "+CPBR: @i, @p, @I, @s",
3966 &Memory->Location,
3967 Memory->Entries[0].Text, sizeof(Memory->Entries[0].Text),
3968 &number_type,
3969 Memory->Entries[1].Text, sizeof(Memory->Entries[1].Text));
3970 } else {
3971 error = ATGEN_ParseReply(s,
3972 GetLineString(msg->Buffer, &Priv->Lines, 2),
3973 "+CPBR: @i, @p, @I, @e",
3974 &Memory->Location,
3975 Memory->Entries[0].Text, sizeof(Memory->Entries[0].Text),
3976 &number_type,
3977 Memory->Entries[1].Text, sizeof(Memory->Entries[1].Text));
3978 }
3979 if (error == ERR_NONE) {
3980 smprintf(s, "Generic AT reply detected\n");
3981 /* Adjust location */
3982 Memory->Location = Memory->Location + 1 - Priv->FirstMemoryEntry;
3983 /* Adjust number */
3984 GSM_TweakInternationalNumber(Memory->Entries[0].Text, number_type);
3985 /* Set number of entries */
3986 Memory->EntriesNum = 2;
3987 return ERR_NONE;
3988 }
3989
3990 /* Try reply with extra unknown number (maybe group?), seen on Samsung SGH-P900 */
3991 error = ATGEN_ParseReply(s,
3992 GetLineString(msg->Buffer, &Priv->Lines, 2),
3993 "+CPBR: @i, @p, @I, @e, @i",
3994 &Memory->Location,
3995 Memory->Entries[0].Text, sizeof(Memory->Entries[0].Text),
3996 &number_type,
3997 Memory->Entries[1].Text, sizeof(Memory->Entries[1].Text),
3998 &i /* Don't know what this means */
3999 );
4000 if (error == ERR_NONE) {
4001 smprintf(s, "AT reply with extra number detected\n");
4002 /* Adjust location */
4003 Memory->Location = Memory->Location + 1 - Priv->FirstMemoryEntry;
4004 /* Adjust number */
4005 GSM_TweakInternationalNumber(Memory->Entries[0].Text, number_type);
4006 /* Set number of entries */
4007 Memory->EntriesNum = 2;
4008 return ERR_NONE;
4009 }
4010
4011 /* Try reply with call date */
4012 error = ATGEN_ParseReply(s,
4013 GetLineString(msg->Buffer, &Priv->Lines, 2),
4014 "+CPBR: @i, @p, @I, @s, @d",
4015 &Memory->Location,
4016 Memory->Entries[0].Text, sizeof(Memory->Entries[0].Text),
4017 &number_type,
4018 Memory->Entries[1].Text, sizeof(Memory->Entries[1].Text),
4019 &Memory->Entries[2].Date);
4020 if (error == ERR_NONE) {
4021 smprintf(s, "Reply with date detected\n");
4022 /* Adjust location */
4023 Memory->Location = Memory->Location + 1 - Priv->FirstMemoryEntry;
4024 /* Adjust number */
4025 GSM_TweakInternationalNumber(Memory->Entries[0].Text, number_type);
4026 /* Set date type */
4027 Memory->Entries[2].EntryType = PBK_Date;
4028 Memory->Entries[2].Location = PBK_Location_Unknown;
4029 /* Set number of entries */
4030 Memory->EntriesNum = 3;
4031 /* Check whether date is correct */
4032 if (!CheckTime(&Memory->Entries[2].Date) || !CheckDate(&Memory->Entries[2].Date)) {
4033 smprintf(s, "Date looks invalid, ignoring!\n");
4034 Memory->EntriesNum = 2;
4035 }
4036 return ERR_NONE;
4037 }
4038
4039 /*
4040 * Try reply with call date and some additional string.
4041 * I have no idea what should be stored there.
4042 * We store it in Entry 3, but do not use it for now.
4043 * Seen on T630.
4044 */
4045 error = ATGEN_ParseReply(s,
4046 GetLineString(msg->Buffer, &Priv->Lines, 2),
4047 "+CPBR: @i, @s, @p, @I, @s, @d",
4048 &Memory->Location,
4049 Memory->Entries[3].Text, sizeof(Memory->Entries[3].Text),
4050 Memory->Entries[0].Text, sizeof(Memory->Entries[0].Text),
4051 &number_type,
4052 Memory->Entries[1].Text, sizeof(Memory->Entries[1].Text),
4053 &Memory->Entries[2].Date);
4054 if (error == ERR_NONE) {
4055 smprintf(s, "Reply with date detected\n");
4056 /* Adjust location */
4057 Memory->Location = Memory->Location + 1 - Priv->FirstMemoryEntry;
4058 /* Adjust number */
4059 GSM_TweakInternationalNumber(Memory->Entries[0].Text, number_type);
4060 /* Set date type */
4061 Memory->Entries[2].EntryType = PBK_Date;
4062 /* Set number of entries */
4063 Memory->EntriesNum = 3;
4064 return ERR_NONE;
4065 }
4066
4067 /**
4068 * Samsung format:
4069 * location,"number",type,"0x02surname0x03","0x02firstname0x03","number",
4070 * type,"number",type,"number",type,"number",type,"email","NA",
4071 * "0x02note0x03",category?,x,x,x,ringtone?,"NA","photo"
4072 *
4073 * NA fields were empty
4074 * x fields are some numbers, default is 1,65535,255,255,65535
4075 *
4076 * Samsung number types:
4077 * 2 - fax
4078 * 4 - cell
4079 * 5 - other
4080 * 6 - home
4081 * 7 - office
4082 */
4083 if (Priv->Manufacturer == AT_Samsung) {
4084 /* Parse reply */
4085 error = ATGEN_ParseReply(s,
4086 GetLineString(msg->Buffer, &Priv->Lines, 2),
4087 "+CPBR: @i,@p,@i,@S,@S,@p,@i,@p,@i,@p,@i,@p,@i,@s,@s,@S,@i,@i,@i,@i,@i,@s,@s",
4088 &Memory->Location,
4089 Memory->Entries[0].Text, sizeof(Memory->Entries[0].Text),
4090 &types[0],
4091 Memory->Entries[1].Text, sizeof(Memory->Entries[1].Text), /* surname */
4092 Memory->Entries[2].Text, sizeof(Memory->Entries[2].Text), /* first name */
4093 Memory->Entries[3].Text, sizeof(Memory->Entries[3].Text),
4094 &types[3],
4095 Memory->Entries[4].Text, sizeof(Memory->Entries[4].Text),
4096 &types[4],
4097 Memory->Entries[5].Text, sizeof(Memory->Entries[5].Text),
4098 &types[5],
4099 Memory->Entries[6].Text, sizeof(Memory->Entries[6].Text),
4100 &types[6],
4101 Memory->Entries[7].Text, sizeof(Memory->Entries[7].Text), /* email */
4102 buffer, sizeof(buffer), /* We don't know this */
4103 Memory->Entries[8].Text, sizeof(Memory->Entries[8].Text), /* note */
4104 &Memory->Entries[9].Number, /* category */
4105 &number_type, /* We don't know this */
4106 &number_type, /* We don't know this */
4107 &number_type, /* We don't know this */
4108 &Memory->Entries[10].Number, /* ringtone ID */
4109 buffer, sizeof(buffer), /* We don't know this */
4110 Memory->Entries[11].Text, sizeof(Memory->Entries[11].Text) /* photo ID */
4111 );
4112
4113 if (error == ERR_NONE) {
4114 smprintf(s, "Samsung reply detected\n");
4115 /* Set types */
4116 Memory->Entries[1].EntryType = PBK_Text_LastName;
4117 Memory->Entries[1].Location = PBK_Location_Unknown;
4118 Memory->Entries[2].EntryType = PBK_Text_FirstName;
4119 Memory->Entries[2].Location = PBK_Location_Unknown;
4120 Memory->Entries[7].EntryType = PBK_Text_Email;
4121 Memory->Entries[7].Location = PBK_Location_Unknown;
4122 Memory->Entries[8].EntryType = PBK_Text_Note;
4123 Memory->Entries[8].Location = PBK_Location_Unknown;
4124 Memory->Entries[9].EntryType = PBK_Category;
4125 Memory->Entries[9].Location = PBK_Location_Unknown;
4126 Memory->Entries[10].EntryType = PBK_RingtoneID;
4127 Memory->Entries[10].Location = PBK_Location_Unknown;
4128 Memory->Entries[11].EntryType = PBK_Text_PictureName;
4129 Memory->Entries[11].Location = PBK_Location_Unknown;
4130
4131 /* Adjust location */
4132 Memory->Location = Memory->Location + 1 - Priv->FirstMemoryEntry;
4133
4134 /* Shift entries when needed */
4135 offset = 0;
4136
4137 #define SHIFT_ENTRIES(index) \
4138 for (i = index - offset + 1; i < GSM_PHONEBOOK_ENTRIES; i++) { \
4139 Memory->Entries[i - 1] = Memory->Entries[i]; \
4140 } \
4141 offset++;
4142
4143 #define CHECK_TEXT(index) \
4144 if (UnicodeLength(Memory->Entries[index - offset].Text) == 0) { \
4145 smprintf(s, "Entry %d is empty\n", index); \
4146 SHIFT_ENTRIES(index); \
4147 }
4148 #define CHECK_NUMBER(index) \
4149 if (UnicodeLength(Memory->Entries[index - offset].Text) == 0) { \
4150 smprintf(s, "Entry %d is empty\n", index); \
4151 SHIFT_ENTRIES(index); \
4152 } else { \
4153 Memory->Entries[index - offset].VoiceTag = 0; \
4154 Memory->Entries[index - offset].SMSList[0] = 0; \
4155 switch (types[index]) { \
4156 case 2: \
4157 Memory->Entries[index - offset].EntryType = PBK_Number_Fax; \
4158 Memory->Entries[index - offset].Location = PBK_Location_Unknown; \
4159 break; \
4160 case 4: \
4161 Memory->Entries[index - offset].EntryType = PBK_Number_Mobile; \
4162 Memory->Entries[index - offset].Location = PBK_Location_Unknown; \
4163 break; \
4164 case 5: \
4165 Memory->Entries[index - offset].EntryType = PBK_Number_Other; \
4166 Memory->Entries[index - offset].Location = PBK_Location_Unknown; \
4167 break; \
4168 case 6: \
4169 Memory->Entries[index - offset].EntryType = PBK_Number_General; \
4170 Memory->Entries[index - offset].Location = PBK_Location_Home; \
4171 break; \
4172 case 7: \
4173 Memory->Entries[index - offset].EntryType = PBK_Number_General; \
4174 Memory->Entries[index - offset].Location = PBK_Location_Work; \
4175 break; \
4176 default: \
4177 Memory->Entries[index - offset].EntryType = PBK_Number_Other; \
4178 Memory->Entries[index - offset].Location = PBK_Location_Unknown; \
4179 smprintf(s, "WARNING: Unknown memory entry type %d\n", types[index]); \
4180 break; \
4181 } \
4182 }
4183 CHECK_NUMBER(0);
4184 CHECK_TEXT(1);
4185 CHECK_TEXT(2);
4186 CHECK_NUMBER(3);
4187 CHECK_NUMBER(4);
4188 CHECK_NUMBER(5);
4189 CHECK_NUMBER(6);
4190 CHECK_TEXT(7);
4191 CHECK_TEXT(8);
4192 if (Memory->Entries[10 - offset].Number == 65535) {
4193 SHIFT_ENTRIES(10);
4194 }
4195 CHECK_TEXT(11);
4196
4197 #undef CHECK_NUMBER
4198 #undef CHECK_TEXT
4199 #undef SHIFT_ENTRIES
4200 /* Set number of entries */
4201 Memory->EntriesNum = 12 - offset;
4202 return ERR_NONE;
4203 }
4204
4205 }
4206
4207 /*
4208 * Nokia 2730 adds some extra fields to the end, we ignore
4209 * them for now
4210 */
4211 error = ATGEN_ParseReply(s,
4212 GetLineString(msg->Buffer, &Priv->Lines, 2),
4213 "+CPBR: @i, @p, @I, @e, @0",
4214 &Memory->Location,
4215 Memory->Entries[0].Text, sizeof(Memory->Entries[0].Text),
4216 &number_type,
4217 Memory->Entries[1].Text, sizeof(Memory->Entries[1].Text));
4218 if (error == ERR_NONE) {
4219 smprintf(s, "Extended AT reply detected\n");
4220 /* Adjust location */
4221 Memory->Location = Memory->Location + 1 - Priv->FirstMemoryEntry;
4222 /* Adjust number */
4223 GSM_TweakInternationalNumber(Memory->Entries[0].Text, number_type);
4224 /* Set number of entries */
4225 Memory->EntriesNum = 2;
4226 return ERR_NONE;
4227 }
4228
4229 return ERR_UNKNOWNRESPONSE;
4230 case AT_Reply_CMEError:
4231 if (Priv->ErrorCode == 100)
4232 return ERR_EMPTY;
4233 if (Priv->ErrorCode == 3)
4234 return ERR_INVALIDLOCATION;
4235 error = ATGEN_HandleCMEError(s);
4236 if (error == ERR_MEMORY) {
4237 smprintf(s, "Assuming that memory error means empty entry\n");
4238 return ERR_EMPTY;
4239 }
4240 return error;
4241 case AT_Reply_Error:
4242 smprintf(s, "Error - too high location ?\n");
4243 return ERR_INVALIDLOCATION;
4244 case AT_Reply_CMSError:
4245 return ATGEN_HandleCMSError(s);
4246 default:
4247 break;
4248 }
4249 return ERR_UNKNOWNRESPONSE;
4250 }
4251
ATGEN_PrivGetMemory(GSM_StateMachine * s,GSM_MemoryEntry * entry,int endlocation)4252 GSM_Error ATGEN_PrivGetMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry, int endlocation)
4253 {
4254 GSM_Error error;
4255 char req[20];
4256 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
4257 size_t len;
4258
4259 if (entry->Location == 0x00) return ERR_INVALIDLOCATION;
4260
4261 /* For reading we prefer unicode */
4262 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_UNICODE);
4263 if (error != ERR_NONE) return error;
4264
4265 if (entry->MemoryType == MEM_ME) {
4266 if (Priv->PBKSBNR == 0) {
4267 ATGEN_CheckSBNR(s);
4268 }
4269 if (Priv->PBK_SPBR == 0) {
4270 ATGEN_CheckSPBR(s);
4271 }
4272 if (Priv->PBK_MPBR == 0) {
4273 ATGEN_CheckMPBR(s);
4274 }
4275 if (Priv->PBKSBNR == AT_AVAILABLE) {
4276 /* FirstMemoryEntry is not applied here, it is always 0 */
4277 len = sprintf(req, "AT^SBNR=\"vcf\",%i\r",entry->Location - 1);
4278 goto read_memory;
4279 }
4280 if (Priv->PBK_SPBR == AT_AVAILABLE) {
4281 error = ATGEN_SetPBKMemory(s, entry->MemoryType);
4282 if (error != ERR_NONE) return error;
4283
4284 /* FirstMemoryEntry is not applied here, it is always 1 */
4285 len = sprintf(req, "AT+SPBR=%i\r", entry->Location);
4286 goto read_memory;
4287 }
4288 if (Priv->PBK_MPBR == AT_AVAILABLE) {
4289 error = ATGEN_SetPBKMemory(s, entry->MemoryType);
4290 if (error != ERR_NONE) return error;
4291
4292 if (Priv->MotorolaFirstMemoryEntry == -1) {
4293 ATGEN_CheckMPBR(s);
4294 }
4295 if (entry->Location > Priv->MotorolaMemorySize) {
4296 /* Reached end of memory, phone silently returns OK */
4297 return ERR_EMPTY;
4298 }
4299 len = sprintf(req, "AT+MPBR=%i\r", entry->Location + Priv->MotorolaFirstMemoryEntry - 1);
4300 goto read_memory;
4301 }
4302 }
4303
4304 error = ATGEN_SetPBKMemory(s, entry->MemoryType);
4305 if (error != ERR_NONE) return error;
4306
4307 if (Priv->FirstMemoryEntry == -1) {
4308 error = ATGEN_GetMemoryInfo(s, NULL, AT_First);
4309 if (error != ERR_NONE) return error;
4310 }
4311
4312 if (endlocation == 0) {
4313 len = sprintf(req, "AT+CPBR=%i\r", entry->Location + Priv->FirstMemoryEntry - 1);
4314 } else {
4315 len = sprintf(req, "AT+CPBR=%i,%i\r", entry->Location + Priv->FirstMemoryEntry - 1, endlocation + Priv->FirstMemoryEntry - 1);
4316 }
4317
4318 read_memory:
4319 s->Phone.Data.Memory=entry;
4320 smprintf(s, "Getting phonebook entry\n");
4321 error = ATGEN_WaitFor(s, req, len, 0x00, 30, ID_GetMemory);
4322 return error;
4323 }
4324
ATGEN_GetMemory(GSM_StateMachine * s,GSM_MemoryEntry * entry)4325 GSM_Error ATGEN_GetMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry)
4326 {
4327 return ATGEN_PrivGetMemory(s, entry, 0);
4328 }
4329
ATGEN_GetNextMemory(GSM_StateMachine * s,GSM_MemoryEntry * entry,gboolean start)4330 GSM_Error ATGEN_GetNextMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry, gboolean start)
4331 {
4332 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
4333 GSM_Error error;
4334 int step = 0;
4335
4336 if (entry->MemoryType == MEM_ME) {
4337 if (Priv->PBKSBNR == 0) {
4338 ATGEN_CheckSBNR(s);
4339 }
4340 if (Priv->PBK_SPBR == 0) {
4341 ATGEN_CheckSPBR(s);
4342 }
4343 if (Priv->PBK_MPBR == 0) {
4344 ATGEN_CheckMPBR(s);
4345 }
4346 }
4347 /* There are no status functions for SBNR */
4348 if (entry->MemoryType != MEM_ME || Priv->PBKSBNR != AT_AVAILABLE) {
4349 error = ATGEN_SetPBKMemory(s, entry->MemoryType);
4350 if (error != ERR_NONE) return error;
4351
4352 if (Priv->MemorySize == 0) {
4353 error = ATGEN_GetMemoryInfo(s, NULL, AT_Total);
4354 if (error != ERR_NONE) return error;
4355 }
4356 }
4357
4358 if (start) {
4359 entry->Location = 1;
4360 } else {
4361 entry->Location++;
4362 }
4363 while ((error = ATGEN_PrivGetMemory(s, entry, step == 0 ? 0 : MIN(Priv->MemorySize, entry->Location + step))) == ERR_EMPTY) {
4364 entry->Location += step + 1;
4365 if (Priv->PBK_MPBR == AT_AVAILABLE && entry->MemoryType == MEM_ME) {
4366 if (entry->Location > Priv->MotorolaMemorySize) break;
4367 } else {
4368 if (entry->Location > Priv->MemorySize) break;
4369 }
4370 /* SBNR works only for one location */
4371 if ((entry->MemoryType != MEM_ME || Priv->PBKSBNR != AT_AVAILABLE) &&
4372 Priv->PBK_MPBR != AT_AVAILABLE &&
4373 Priv->PBK_SPBR != AT_AVAILABLE) {
4374 step = MIN(step + 2, 20);
4375 }
4376 }
4377 if (error == ERR_INVALIDLOCATION) return ERR_EMPTY;
4378 return error;
4379 }
4380
ATGEN_DeleteAllMemory(GSM_StateMachine * s,GSM_MemoryType type)4381 GSM_Error ATGEN_DeleteAllMemory(GSM_StateMachine *s, GSM_MemoryType type)
4382 {
4383 GSM_Error error;
4384 unsigned char req[100];
4385 int i;
4386 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
4387 size_t len;
4388
4389 error = ATGEN_SetPBKMemory(s, type);
4390 if (error != ERR_NONE) return error;
4391
4392 if (Priv->MemorySize == 0) {
4393 error = ATGEN_GetMemoryInfo(s, NULL, AT_Total);
4394 if (error != ERR_NONE) return error;
4395 }
4396
4397 if (Priv->FirstMemoryEntry == -1) {
4398 error = ATGEN_GetMemoryInfo(s, NULL, AT_First);
4399 if (error != ERR_NONE) return error;
4400 }
4401
4402
4403 smprintf(s, "Deleting all phonebook entries\n");
4404 for (i = Priv->FirstMemoryEntry; i < Priv->FirstMemoryEntry + Priv->MemorySize; i++) {
4405 len = sprintf(req, "AT+CPBW=%d\r",i);
4406 error = ATGEN_WaitFor(s, req, len, 0x00, 40, ID_SetMemory);
4407
4408 if (error != ERR_NONE) {
4409 return error;
4410 }
4411 }
4412 return ERR_NONE;
4413 }
4414
ATGEN_ReplyDialVoice(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)4415 GSM_Error ATGEN_ReplyDialVoice(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
4416 {
4417 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
4418 case AT_Reply_OK:
4419 smprintf(s, "Dial voice OK\n");
4420 return ERR_NONE;
4421 case AT_Reply_Error:
4422 smprintf(s, "Dial voice error\n");
4423 return ERR_UNKNOWN;
4424 case AT_Reply_CMSError:
4425 return ATGEN_HandleCMSError(s);
4426 case AT_Reply_CMEError:
4427 return ATGEN_HandleCMEError(s);
4428 default:
4429 break;
4430 }
4431 return ERR_UNKNOWNRESPONSE;
4432 }
4433
ATGEN_DialService(GSM_StateMachine * s,char * number)4434 GSM_Error ATGEN_DialService(GSM_StateMachine *s, char *number)
4435 {
4436 GSM_Error error;
4437 char *req = NULL,*encoded = NULL;
4438 unsigned char *tmp = NULL;
4439 const char format[] = "AT+CUSD=%d,\"%s\",15\r";
4440 size_t len = 0, allocsize, sevenlen = 0;
4441
4442 len = strlen(number);
4443 /*
4444 * We need to allocate four times more memory for number here, because it
4445 * might be encoded later to UCS2.
4446 */
4447 allocsize = 4 * (len + 1);
4448 req = (char *)malloc(strlen(format) + allocsize + 1);
4449
4450 if (req == NULL) {
4451 return ERR_MOREMEMORY;
4452 }
4453 /* Prefer unicode to be able to deal with unicode response */
4454 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_USSD_GSM_CHARSET)) {
4455 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_GSM);
4456 } else {
4457 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_UNICODE);
4458 }
4459
4460 if (error != ERR_NONE) {
4461 free(req);
4462 req = NULL;
4463 return error;
4464 }
4465 encoded = (char *)malloc(allocsize);
4466 tmp = (unsigned char *)malloc(allocsize);
4467 if (tmp == NULL || encoded == NULL) {
4468 free(req);
4469 free(tmp);
4470 free(encoded);
4471 return ERR_MOREMEMORY;
4472 }
4473 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_ENCODED_USSD)) {
4474 /* This is against GSM specs, but Huawei seems to use this */
4475 sevenlen = GSM_PackSevenBitsToEight(0, number, tmp, len);
4476 EncodeHexBin(encoded, tmp, sevenlen);
4477 } else {
4478 EncodeUnicode(tmp, number, strlen(number));
4479 error = ATGEN_EncodeText(s, tmp, len, encoded, allocsize, &len);
4480 }
4481 free(tmp);
4482 if (error != ERR_NONE) {
4483 free(req);
4484 free(encoded);
4485 return error;
4486 }
4487
4488 len = sprintf(req, format, s->Phone.Data.EnableIncomingUSSD ? 1 : 0, encoded);
4489
4490 free(encoded);
4491
4492 error = ATGEN_WaitFor(s, req, len, 0x00, 30, ID_GetUSSD);
4493 free(req);
4494 req = NULL;
4495 return error;
4496 }
4497
ATGEN_DialVoice(GSM_StateMachine * s,char * number,GSM_CallShowNumber ShowNumber)4498 GSM_Error ATGEN_DialVoice(GSM_StateMachine *s, char *number, GSM_CallShowNumber ShowNumber)
4499 {
4500 GSM_Error error;
4501 char buffer[GSM_MAX_NUMBER_LENGTH + 6] = {'\0'};
4502 size_t length = 0;
4503 int oldretry;
4504 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
4505
4506 if (ShowNumber != GSM_CALL_DefaultNumberPresence) {
4507 return ERR_NOTSUPPORTED;
4508 }
4509 if (strlen(number) > GSM_MAX_NUMBER_LENGTH) {
4510 return ERR_MOREMEMORY;
4511 }
4512
4513 oldretry = s->ReplyNum;
4514 s->ReplyNum = 1;
4515 smprintf(s, "Making voice call\n");
4516 length = sprintf(buffer, "ATDT%s;\r", number);
4517 error = ATGEN_WaitFor(s, buffer, length, 0x00, 100, ID_DialVoice);
4518
4519 if (error == ERR_INVALIDLOCATION || error == ERR_UNKNOWN) {
4520 smprintf(s, "Making voice call without forcing to tone dial\n");
4521 length = sprintf(buffer, "ATD%s;\r", number);
4522 error = ATGEN_WaitFor(s, buffer, length, 0x00, 100, ID_DialVoice);
4523 }
4524 if (error == ERR_TIMEOUT && Priv->Manufacturer == AT_Samsung) {
4525 smprintf(s, "Assuming voice call succeeded even without reply from phone\n");
4526 return ERR_NONE;
4527 }
4528 s->ReplyNum = oldretry;
4529 return error;
4530 }
4531
ATGEN_ReplyEnterSecurityCode(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)4532 GSM_Error ATGEN_ReplyEnterSecurityCode(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
4533 {
4534 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
4535 case AT_Reply_OK:
4536 smprintf(s, "Security code was OK\n");
4537 return ERR_NONE;
4538 case AT_Reply_Error:
4539 smprintf(s, "Incorrect security code\n");
4540 return ERR_SECURITYERROR;
4541 case AT_Reply_CMSError:
4542 return ATGEN_HandleCMSError(s);
4543 case AT_Reply_CMEError:
4544 return ATGEN_HandleCMEError(s);
4545 default:
4546 break;
4547 }
4548 return ERR_UNKNOWNRESPONSE;
4549 }
4550
ATGEN_EnterSecurityCode(GSM_StateMachine * s,GSM_SecurityCode * Code)4551 GSM_Error ATGEN_EnterSecurityCode(GSM_StateMachine *s, GSM_SecurityCode *Code)
4552 {
4553 GSM_Error error;
4554 GSM_SecurityCodeType Status;
4555 unsigned char req[GSM_SECURITY_CODE_LEN + 30] = {'\0'};
4556 size_t len;
4557
4558 if (Code->Type == SEC_Pin2 &&
4559 s->Phone.Data.Priv.ATGEN.Manufacturer == AT_Siemens) {
4560 len = sprintf(req, "AT+CPIN2=\"%s\"\r", Code->Code);
4561 } else {
4562 error = ATGEN_GetSecurityStatus(s, &Status);
4563 if (error != ERR_NONE) {
4564 return error;
4565 }
4566 if (Status != Code->Type) {
4567 smprintf(s, "Phone is expecting different security code!\n");
4568 return ERR_SECURITYERROR;
4569 }
4570 if (Code->Type == SEC_Puk) {
4571 if (Code->NewPIN[0] == 0) {
4572 smprintf(s, "Need new PIN code to enter PUK!\n");
4573 return ERR_SECURITYERROR;
4574 }
4575 len = sprintf(req, "AT+CPIN=\"%s\",\"%s\"\r" , Code->Code, Code->NewPIN);
4576 } else {
4577 len = sprintf(req, "AT+CPIN=\"%s\"\r" , Code->Code);
4578 }
4579
4580 }
4581 smprintf(s, "Entering security code\n");
4582 error = ATGEN_WaitFor(s, req, len, 0x00, 20, ID_EnterSecurityCode);
4583 return error;
4584 }
4585
ATGEN_ReplyGetSecurityStatus(GSM_Protocol_Message * msg,GSM_StateMachine * s)4586 GSM_Error ATGEN_ReplyGetSecurityStatus(GSM_Protocol_Message *msg, GSM_StateMachine *s)
4587 {
4588 GSM_Error error;
4589 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
4590 GSM_SecurityCodeType *Status = s->Phone.Data.SecurityStatus;
4591 char status[100] = {'\0'};
4592
4593 if (Priv->ReplyState != AT_Reply_OK) {
4594 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
4595 case AT_Reply_Error:
4596 return ERR_NOTSUPPORTED;
4597 case AT_Reply_CMSError:
4598 return ATGEN_HandleCMSError(s);
4599 case AT_Reply_CMEError:
4600 return ATGEN_HandleCMEError(s);
4601 default:
4602 return ERR_UNKNOWNRESPONSE;
4603 }
4604 }
4605
4606 error = ATGEN_ParseReply(s,
4607 GetLineString(msg->Buffer, &Priv->Lines, 2),
4608 "+CPIN: @r",
4609 status,
4610 sizeof(status));
4611 if (error != ERR_NONE) {
4612 /* Alcatel mangled reply */
4613 if (strcmp(GetLineString(msg->Buffer, &Priv->Lines, 2), "+CPIN: ") == 0) {
4614 *Status = SEC_None;
4615 smprintf(s, "nothing to enter\n");
4616 return ERR_NONE;
4617 }
4618 return error;
4619 }
4620
4621 smprintf(s, "Security status received - ");
4622 if (strstr(status, "READY")) {
4623 *Status = SEC_None;
4624 smprintf(s, "nothing to enter\n");
4625 return ERR_NONE;
4626 }
4627 if (strstr(status, "PH-SIM PIN")) {
4628 *Status = SEC_Phone;
4629 smprintf(s, "Phone code needed\n");
4630 return ERR_NONE;
4631 }
4632 if (strstr(status, "PH-NET PIN")) {
4633 *Status = SEC_Network;
4634 smprintf(s, "Network code needed\n");
4635 return ERR_NONE;
4636 }
4637 if (strstr(status, "PH_SIM PIN")) {
4638 smprintf(s, "no SIM inside or other error\n");
4639 return ERR_UNKNOWN;
4640 }
4641 if (strstr(status, "SIM PIN2")) {
4642 *Status = SEC_Pin2;
4643 smprintf(s, "waiting for PIN2\n");
4644 return ERR_NONE;
4645 }
4646 if (strstr(status, "SIM PUK2")) {
4647 *Status = SEC_Puk2;
4648 smprintf(s, "waiting for PUK2\n");
4649 return ERR_NONE;
4650 }
4651 if (strstr(status, "SIM PIN")) {
4652 *Status = SEC_Pin;
4653 smprintf(s, "waiting for PIN\n");
4654 return ERR_NONE;
4655 }
4656 if (strstr(status, "SIM PUK")) {
4657 *Status = SEC_Puk;
4658 smprintf(s, "waiting for PUK\n");
4659 return ERR_NONE;
4660 }
4661 smprintf(s, "unknown\n");
4662 return ERR_UNKNOWNRESPONSE;
4663 }
4664
ATGEN_GetSecurityStatus(GSM_StateMachine * s,GSM_SecurityCodeType * Status)4665 GSM_Error ATGEN_GetSecurityStatus(GSM_StateMachine *s, GSM_SecurityCodeType *Status)
4666 {
4667 GSM_Error error;
4668
4669 s->Phone.Data.SecurityStatus = Status;
4670
4671 smprintf(s, "Getting security code status\n");
4672 /* Please note, that A2D doesn't return OK on the end.
4673 * Because of it we try to read another reply after reading
4674 * status.
4675 */
4676 error = ATGEN_WaitForAutoLen(s, "AT+CPIN?\r", 0x00, 40, ID_GetSecurityStatus);
4677
4678 /* Read the possible left over OK */
4679 GSM_WaitForOnce(s, NULL, 0x00, 0x00, 4);
4680 return error;
4681 }
4682
ATGEN_ReplyAnswerCall(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)4683 GSM_Error ATGEN_ReplyAnswerCall(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
4684 {
4685 GSM_Call call;
4686
4687 switch(s->Phone.Data.Priv.ATGEN.ReplyState) {
4688 case AT_Reply_OK:
4689 smprintf(s, "Calls answered\n");
4690 call.CallIDAvailable = FALSE;
4691 call.Status = GSM_CALL_CallEstablished;
4692
4693 if (s->User.IncomingCall) {
4694 s->User.IncomingCall(s, &call, s->User.IncomingCallUserData);
4695 }
4696 return ERR_NONE;
4697 case AT_Reply_CMSError:
4698 return ATGEN_HandleCMSError(s);
4699 case AT_Reply_CMEError:
4700 return ATGEN_HandleCMEError(s);
4701 default:
4702 return ERR_UNKNOWN;
4703 }
4704 }
4705
ATGEN_AnswerCall(GSM_StateMachine * s,int ID UNUSED,gboolean all)4706 GSM_Error ATGEN_AnswerCall(GSM_StateMachine *s, int ID UNUSED, gboolean all)
4707 {
4708 GSM_Error error;
4709
4710 if (all) {
4711 smprintf(s, "Answering all calls\n");
4712 error = ATGEN_WaitForAutoLen(s, "ATA\r", 0x00, 40, ID_AnswerCall);
4713 return error;
4714 }
4715 return ERR_NOTSUPPORTED;
4716 }
4717
ATGEN_ReplyCancelCall(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)4718 GSM_Error ATGEN_ReplyCancelCall(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
4719 {
4720 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
4721 GSM_Call call;
4722
4723 switch(Priv->ReplyState) {
4724 case AT_Reply_OK:
4725 smprintf(s, "Calls canceled\n");
4726 Priv->CancellingCall = FALSE;
4727 call.CallIDAvailable = FALSE;
4728 call.Status = GSM_CALL_CallLocalEnd;
4729
4730 if (s->User.IncomingCall) {
4731 GSM_DeferIncomingCallEvent(s, &call, ATGEN_BeforeDeferredEventHook);
4732 }
4733 return ERR_NONE;
4734 case AT_Reply_CMSError:
4735 return ATGEN_HandleCMSError(s);
4736 case AT_Reply_CMEError:
4737 return ATGEN_HandleCMEError(s);
4738 default:
4739 return ERR_UNKNOWN;
4740 }
4741 }
4742
ATGEN_CancelCall(GSM_StateMachine * s,int ID UNUSED,gboolean all)4743 GSM_Error ATGEN_CancelCall(GSM_StateMachine *s, int ID UNUSED, gboolean all)
4744 {
4745 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
4746 GSM_Error error;
4747
4748 if(!all)
4749 return ERR_NOTSUPPORTED;
4750
4751 if(Priv->CancellingCall)
4752 return ERR_NONE;
4753
4754 smprintf(s, "Dropping all calls\n");
4755 Priv->CancellingCall = TRUE;
4756
4757 if(Priv->HasCHUP) {
4758 error = ATGEN_WaitForAutoLen(s, "AT+CHUP\r", 0x00, 40, ID_CancelCall);
4759 } else {
4760 error = ATGEN_WaitForAutoLen(s, "ATH\r", 0x00, 40, ID_CancelCall);
4761 }
4762
4763 return error;
4764 }
4765
ATGEN_ReplyReset(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)4766 GSM_Error ATGEN_ReplyReset(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
4767 {
4768 smprintf(s, "Reset done\n");
4769 return ERR_NONE;
4770 }
4771
ATGEN_Reset(GSM_StateMachine * s,gboolean hard)4772 GSM_Error ATGEN_Reset(GSM_StateMachine *s, gboolean hard)
4773 {
4774 GSM_Error error;
4775
4776 if (hard) {
4777 return ERR_NOTSUPPORTED;
4778 }
4779 smprintf(s, "Resetting device\n");
4780
4781 /* Siemens 35 */
4782 error = ATGEN_WaitForAutoLen(s, "AT+CFUN=1,1\r", 0x00, 20, ID_Reset);
4783
4784 if (error != ERR_NONE) {
4785 /* Siemens M20 */
4786 error = ATGEN_WaitForAutoLen(s, "AT^SRESET\r", 0x00, 20, ID_Reset);
4787 }
4788 return error;
4789 }
4790
ATGEN_ReplyResetPhoneSettings(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)4791 GSM_Error ATGEN_ReplyResetPhoneSettings(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
4792 {
4793 smprintf(s, "Reset done\n");
4794 return ERR_NONE;
4795 }
4796
ATGEN_ResetPhoneSettings(GSM_StateMachine * s,GSM_ResetSettingsType Type UNUSED)4797 GSM_Error ATGEN_ResetPhoneSettings(GSM_StateMachine *s, GSM_ResetSettingsType Type UNUSED)
4798 {
4799 GSM_Error error;
4800
4801 smprintf(s, "Resetting settings to default\n");
4802 error = ATGEN_WaitForAutoLen(s, "AT&F\r", 0x00, 40, ID_ResetPhoneSettings);
4803
4804 return error;
4805 }
4806
ATGEN_SetAutoNetworkLogin(GSM_StateMachine * s)4807 GSM_Error ATGEN_SetAutoNetworkLogin(GSM_StateMachine *s)
4808 {
4809 GSM_Error error;
4810
4811 smprintf(s, "Enabling automatic network login\n");
4812 error = ATGEN_WaitForAutoLen(s, "AT+COPS=0\r", 0x00, 40, ID_SetAutoNetworkLogin);
4813
4814 return error;
4815 }
4816
ATGEN_ReplyGetDivert(GSM_Protocol_Message * msg,GSM_StateMachine * s)4817 GSM_Error ATGEN_ReplyGetDivert(GSM_Protocol_Message *msg, GSM_StateMachine *s)
4818 {
4819 GSM_Error error;
4820 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
4821 const char *str;
4822 int line, number_type;
4823 int status, class, ignore;
4824 char ignore_buf[100];
4825 GSM_MultiCallDivert *response = s->Phone.Data.Divert;
4826
4827 response->EntriesNum = 0;
4828
4829 if (Priv->ReplyState != AT_Reply_OK) {
4830 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
4831 case AT_Reply_Error:
4832 return ERR_NOTSUPPORTED;
4833 case AT_Reply_CMSError:
4834 return ATGEN_HandleCMSError(s);
4835 case AT_Reply_CMEError:
4836 return ATGEN_HandleCMEError(s);
4837 default:
4838 return ERR_UNKNOWNRESPONSE;
4839 }
4840 }
4841
4842 for (line = 2; strcmp("OK", str = GetLineString(msg->Buffer, &Priv->Lines, line)) != 0; line++) {
4843
4844 error = ATGEN_ParseReply(s, str,
4845 "+CCFC: @i, @i",
4846 &status,
4847 &class);
4848 if (error != ERR_NONE) {
4849 error = ATGEN_ParseReply(s, str,
4850 "+CCFC: @i, @i, @p, @I",
4851 &status,
4852 &class,
4853 response->Entries[response->EntriesNum].Number,
4854 sizeof(response->Entries[response->EntriesNum].Number),
4855 &number_type
4856 );
4857 }
4858 if (error != ERR_NONE) {
4859 error = ATGEN_ParseReply(s, str,
4860 "+CCFC: @i, @i, @p, @I, @s, @i",
4861 &status,
4862 &class,
4863 response->Entries[response->EntriesNum].Number,
4864 sizeof(response->Entries[response->EntriesNum].Number),
4865 &number_type,
4866 ignore_buf, sizeof(ignore_buf),
4867 &ignore
4868 );
4869 }
4870
4871 if (error != ERR_NONE) {
4872 error = ATGEN_ParseReply(s, str,
4873 "+CCFC: @i, @i, @p, @I, @s, @I, @I",
4874 &status,
4875 &class,
4876 response->Entries[response->EntriesNum].Number,
4877 sizeof(response->Entries[response->EntriesNum].Number),
4878 &number_type,
4879 ignore_buf, sizeof(ignore_buf),
4880 &ignore,
4881 &(response->Entries[response->EntriesNum].Timeout)
4882 );
4883 }
4884
4885 if (error != ERR_NONE) {
4886 return error;
4887 }
4888
4889 /* We handle only active entries */
4890 if (status == 1) {
4891 switch (class) {
4892 case 1:
4893 response->Entries[response->EntriesNum].CallType = GSM_DIVERT_VoiceCalls;
4894 break;
4895 case 2:
4896 response->Entries[response->EntriesNum].CallType = GSM_DIVERT_DataCalls;
4897 break;
4898 case 4:
4899 response->Entries[response->EntriesNum].CallType = GSM_DIVERT_FaxCalls;
4900 break;
4901 case 7:
4902 response->Entries[response->EntriesNum].CallType = GSM_DIVERT_AllCalls;
4903 break;
4904 default:
4905 smprintf(s, "WARNING: Unknown divert class %d, assuming all numbers\n", class);
4906 response->Entries[response->EntriesNum].CallType = GSM_DIVERT_AllCalls;
4907 break;
4908 }
4909
4910 response->EntriesNum++;
4911 }
4912 }
4913 return ERR_NONE;
4914 }
4915
ATGEN_CancelAllDiverts(GSM_StateMachine * s)4916 GSM_Error ATGEN_CancelAllDiverts(GSM_StateMachine *s)
4917 {
4918 GSM_Error error;
4919
4920 error = ATGEN_WaitForAutoLen(s, "AT+CCFC=4,4\r", 0x00, 40, ID_SetDivert);
4921
4922 return error;
4923 }
4924
ATGEN_GetCallDivert(GSM_StateMachine * s,GSM_CallDivert * request,GSM_MultiCallDivert * response)4925 GSM_Error ATGEN_GetCallDivert(GSM_StateMachine *s, GSM_CallDivert *request, GSM_MultiCallDivert *response)
4926 {
4927 GSM_Error error;
4928 int reason = 0;
4929 char buffer[50];
4930 int i;
4931
4932 switch (request->DivertType) {
4933 case GSM_DIVERT_Busy:
4934 reason = 1;
4935 break;
4936 case GSM_DIVERT_NoAnswer:
4937 reason = 2;
4938 break;
4939 case GSM_DIVERT_OutOfReach:
4940 reason = 3;
4941 break;
4942 case GSM_DIVERT_AllTypes:
4943 reason = 0;
4944 break;
4945 default:
4946 smprintf(s, "Invalid divert type: %d\n", request->DivertType);
4947 return ERR_BUG;
4948 }
4949
4950 /* Set reason (can not get it from phone) */
4951 for (i = 0; i < GSM_MAX_CALL_DIVERTS; i++) {
4952 response->Entries[i].DivertType = request->DivertType;
4953 response->Entries[i].Timeout = 0;
4954 }
4955
4956 s->Phone.Data.Divert = response;
4957
4958 smprintf(s, "Getting diversions\n");
4959 sprintf(buffer, "AT+CCFC=%d,2\r", reason);
4960 error = ATGEN_WaitForAutoLen(s, buffer, 0x00, 40, ID_Divert);
4961
4962 return error;
4963 }
4964
ATGEN_SetCallDivert(GSM_StateMachine * s,GSM_CallDivert * divert)4965 GSM_Error ATGEN_SetCallDivert(GSM_StateMachine *s, GSM_CallDivert *divert)
4966 {
4967 GSM_Error error;
4968 int reason = 0;
4969 int class = 0;
4970 char buffer[50 + 2 * GSM_MAX_NUMBER_LENGTH], number[2 * GSM_MAX_NUMBER_LENGTH + 1];
4971 size_t len;
4972
4973 switch (divert->DivertType) {
4974 case GSM_DIVERT_Busy:
4975 reason = 1;
4976 break;
4977 case GSM_DIVERT_NoAnswer:
4978 reason = 2;
4979 break;
4980 case GSM_DIVERT_OutOfReach:
4981 reason = 3;
4982 break;
4983 case GSM_DIVERT_AllTypes:
4984 reason = 0;
4985 break;
4986 default:
4987 smprintf(s, "Invalid divert type: %d\n", divert->DivertType);
4988 return ERR_BUG;
4989 }
4990 switch (divert->CallType) {
4991 case GSM_DIVERT_VoiceCalls:
4992 class = 1;
4993 break;
4994 case GSM_DIVERT_FaxCalls:
4995 class = 4;
4996 break;
4997 case GSM_DIVERT_DataCalls:
4998 class = 2;
4999 break;
5000 case GSM_DIVERT_AllCalls:
5001 class = 7;
5002 break;
5003 default:
5004 smprintf(s, "Invalid divert call type: %d\n", divert->CallType);
5005 return ERR_BUG;
5006 }
5007
5008 len = UnicodeLength(divert->Number);
5009 EncodeDefault(number, divert->Number, &len, TRUE, NULL);
5010
5011 smprintf(s, "Setting diversion\n");
5012 sprintf(buffer, "AT+CCFC=%d,3,\"%s\",129,\"\",128,%d\r",
5013 reason,
5014 number,
5015 class);
5016
5017 error = ATGEN_WaitForAutoLen(s, buffer, 0x00, 40, ID_SetDivert);
5018 if (error != ERR_NONE) {
5019 smprintf(s, "Setting diversion, trying shorter command\n");
5020 sprintf(buffer, "AT+CCFC=%d,3,\"%s\"\r",
5021 reason,
5022 number);
5023
5024 error = ATGEN_WaitForAutoLen(s, buffer, 0x00, 40, ID_SetDivert);
5025 }
5026
5027 if (error != ERR_NONE) {
5028 return error;
5029 }
5030
5031 smprintf(s, "Enabling diversion\n");
5032 sprintf(buffer, "AT+CCFC=%d,1\r", reason);
5033 error = ATGEN_WaitForAutoLen(s, buffer, 0x00, 40, ID_SetDivert);
5034
5035 return error;
5036 }
5037
ATGEN_SendDTMF(GSM_StateMachine * s,char * sequence)5038 GSM_Error ATGEN_SendDTMF(GSM_StateMachine *s, char *sequence)
5039 {
5040 GSM_Error error;
5041 char req[50] = "AT+VTS=";
5042 int n = 0, len = 0, pos = 0;
5043
5044 len = strlen(sequence);
5045
5046 if (len > 32) {
5047 return ERR_INVALIDDATA;
5048 }
5049 pos = strlen(req);
5050
5051 for (n = 0; n < len; n++) {
5052 if (n != 0) {
5053 req[pos++] = ',';
5054 }
5055 req[pos++] = sequence[n];
5056 }
5057 req[pos++] = '\r';
5058 req[pos++] = '\0';
5059 smprintf(s, "Sending DTMF\n");
5060 error = ATGEN_WaitForAutoLen(s, req, 0x00, 40, ID_SendDTMF);
5061 return error;
5062 }
5063
ATGEN_ReplySetMemory(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)5064 GSM_Error ATGEN_ReplySetMemory(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
5065 {
5066 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
5067 case AT_Reply_OK:
5068 smprintf(s, "Phonebook entry written OK\n");
5069 return ERR_NONE;
5070 case AT_Reply_CMSError:
5071 return ATGEN_HandleCMSError(s);
5072 case AT_Reply_CMEError:
5073 if (s->Phone.Data.Priv.ATGEN.ErrorCode == 255 && s->Phone.Data.Priv.ATGEN.Manufacturer == AT_Ericsson) {
5074 smprintf(s, "CME Error %i, probably means empty entry\n", s->Phone.Data.Priv.ATGEN.ErrorCode);
5075 return ERR_EMPTY;
5076 }
5077 if (s->Phone.Data.Priv.ATGEN.ErrorCode == 100) {
5078 return ERR_NOTSUPPORTED;
5079 }
5080 return ATGEN_HandleCMEError(s);
5081 case AT_Reply_Error:
5082 return ERR_INVALIDDATA;
5083 default:
5084 return ERR_UNKNOWNRESPONSE;
5085 }
5086 }
5087
ATGEN_DeleteMemory(GSM_StateMachine * s,GSM_MemoryEntry * entry)5088 GSM_Error ATGEN_DeleteMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
5089 {
5090 GSM_Error error;
5091 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5092 unsigned char req[100] = {'\0'};
5093 size_t len;
5094
5095 if (entry->Location < 1) {
5096 return ERR_INVALIDLOCATION;
5097 }
5098 error = ATGEN_SetPBKMemory(s, entry->MemoryType);
5099
5100 if (error != ERR_NONE) {
5101 return error;
5102 }
5103 if (Priv->FirstMemoryEntry == -1) {
5104 error = ATGEN_GetMemoryInfo(s, NULL, AT_First);
5105
5106 if (error != ERR_NONE) {
5107 return error;
5108 }
5109 }
5110 len = sprintf(req, "AT+CPBW=%d\r",entry->Location + Priv->FirstMemoryEntry - 1);
5111 smprintf(s, "Deleting phonebook entry\n");
5112 error = ATGEN_WaitFor(s, req, len, 0x00, 40, ID_SetMemory);
5113
5114 if (error == ERR_EMPTY) {
5115 return ERR_NONE;
5116 }
5117 return error;
5118 }
5119
ATGEN_PrivSetMemory(GSM_StateMachine * s,GSM_MemoryEntry * entry)5120 GSM_Error ATGEN_PrivSetMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
5121 {
5122 /* REQUEST_SIZE should be big enough to handle all possibl cases
5123 * correctly, especially with unicode entries */
5124 #define REQUEST_SIZE ((4 * GSM_PHONEBOOK_TEXT_LENGTH) + 30)
5125 GSM_Error error;
5126 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5127 GSM_AT_Charset_Preference Prefer = AT_PREF_CHARSET_NORMAL;
5128 /* 129 seems to be safer option for empty number */
5129 int NumberType = 129;
5130 size_t len = 0;
5131 unsigned char req[REQUEST_SIZE + 1] = {'\0'};
5132 unsigned char name[2*(GSM_PHONEBOOK_TEXT_LENGTH + 1)] = {'\0'};
5133 unsigned char uname[2*(GSM_PHONEBOOK_TEXT_LENGTH + 1)] = {'\0'};
5134 unsigned char number[GSM_PHONEBOOK_TEXT_LENGTH + 1] = {'\0'};
5135 unsigned char unumber[2*(GSM_PHONEBOOK_TEXT_LENGTH + 1)] = {'\0'};
5136 int Group = 0, Name = 0, Number = 0, reqlen = 0, i = 0;
5137
5138 if (entry->Location == 0) {
5139 return ERR_INVALIDLOCATION;
5140 }
5141 if (entry->MemoryType == MEM_ME) {
5142 if (Priv->PBK_SPBR == 0) {
5143 ATGEN_CheckSPBR(s);
5144 }
5145 if (Priv->PBK_MPBR == 0) {
5146 ATGEN_CheckMPBR(s);
5147 }
5148 if (Priv->PBKSBNR == 0) {
5149 ATGEN_CheckSBNR(s);
5150 }
5151 if (Priv->PBK_SPBR == AT_AVAILABLE) {
5152 return SAMSUNG_SetMemory(s, entry);
5153 }
5154 if (Priv->PBK_MPBR == AT_AVAILABLE) {
5155 smprintf(s, "WARNING: setting memory for Motorola not implemented yet!\n");
5156 }
5157 if (Priv->PBKSBNR == AT_AVAILABLE) {
5158 return SIEMENS_SetMemory(s, entry);
5159 }
5160 }
5161 error = ATGEN_SetPBKMemory(s, entry->MemoryType);
5162
5163 if (error != ERR_NONE) {
5164 return error;
5165 }
5166 for (i = 0;i < entry->EntriesNum;i++) {
5167 entry->Entries[i].AddError = ERR_NOTSUPPORTED;
5168 }
5169 GSM_PhonebookFindDefaultNameNumberGroup(entry, &Name, &Number, &Group);
5170 name[0] = 0;
5171
5172 if (Name != -1) {
5173 len = UnicodeLength(entry->Entries[Name].Text);
5174
5175 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBK_UNICODE)) {
5176 Prefer = AT_PREF_CHARSET_UNICODE;
5177 } else {
5178 /* Compare if we would loose some information when not using
5179 * unicode */
5180 EncodeDefault(name, entry->Entries[Name].Text, &len, TRUE, NULL);
5181 DecodeDefault(uname, name, len, TRUE, NULL);
5182
5183 if (!mywstrncmp(uname, entry->Entries[Name].Text, len)) {
5184 /* Get maximum text length */
5185 if (Priv->TextLength == 0) {
5186 ATGEN_GetMemoryInfo(s, NULL, AT_Sizes);
5187 }
5188
5189 /* I char stored in GSM alphabet takes 7 bits, one
5190 * unicode 16, if storing in unicode would truncate
5191 * text, do not use it, otherwise we will use it */
5192 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_LENGTH_BYTES) &&
5193 (Priv->TextLength != 0) &&
5194 ((Priv->TextLength * 7 / 16) <= len)
5195 ) {
5196 Prefer = AT_PREF_CHARSET_NORMAL;
5197 } else {
5198 Prefer = AT_PREF_CHARSET_UNICODE;
5199 }
5200 }
5201 }
5202 error = ATGEN_SetCharset(s, Prefer);
5203
5204 if (error != ERR_NONE) {
5205 return error;
5206 }
5207 len = UnicodeLength(entry->Entries[Name].Text);
5208 error = ATGEN_EncodeText(s, entry->Entries[Name].Text, len, name, sizeof(name), &len);
5209
5210 if (error != ERR_NONE) {
5211 return error;
5212 }
5213 entry->Entries[Name].AddError = ERR_NONE;
5214 } else {
5215 smprintf(s, "WARNING: No usable name found!\n");
5216 len = 0;
5217 }
5218 if (Number != -1) {
5219 GSM_PackSemiOctetNumber(entry->Entries[Number].Text, number, FALSE);
5220 NumberType = number[0];
5221 /* We need to encode number, however
5222 * - it is not encoded in UCS2
5223 * - no encoding is needed for most charsets
5224 */
5225 if (Priv->Charset == AT_CHARSET_HEX &&
5226 GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBK_ENCODENUMBER)) {
5227 len = UnicodeLength(entry->Entries[Number].Text);
5228 EncodeDefault(unumber, entry->Entries[Number].Text, &len, TRUE, NULL);
5229 EncodeHexBin(number, unumber, len);
5230 } else {
5231 sprintf(number, "%s", DecodeUnicodeString(entry->Entries[Number].Text));
5232 }
5233 entry->Entries[Number].AddError = ERR_NONE;
5234 } else {
5235 smprintf(s, "WARNING: No usable number found!\n");
5236 number[0] = 0;
5237 }
5238
5239 if (Priv->FirstMemoryEntry == -1) {
5240 error = ATGEN_GetMemoryInfo(s, NULL, AT_First);
5241
5242 if (error != ERR_NONE) {
5243 return error;
5244 }
5245 }
5246
5247 /* We can't use here:
5248 * sprintf(req, "AT+CPBW=%d, \"%s\", %i, \"%s\"\r",
5249 * entry->Location, number, NumberType, name);
5250 * because name can contain 0 when using GSM alphabet.
5251 */
5252 reqlen = sprintf(req, "AT+CPBW=%d,\"%s\",%i,\"", entry->Location + Priv->FirstMemoryEntry - 1, number, NumberType);
5253
5254 if (reqlen + len > REQUEST_SIZE - 4) {
5255 smprintf(s, "WARNING: Text truncated to fit in buffer!\n");
5256 len = REQUEST_SIZE - 4 - reqlen;
5257 }
5258 /* Add name */
5259 memcpy(req + reqlen, name, len);
5260 reqlen += len;
5261
5262 /* Terminate quotes */
5263 memcpy(req + reqlen, "\"", 1);
5264 reqlen += 1;
5265
5266 /* Some phones need ,0 at the end, whatever this number means */
5267 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_EXTRA_PBK_FIELD)) {
5268 memcpy(req + reqlen, ",0", 2);
5269 reqlen += 2;
5270 }
5271 /* Terminate request */
5272 memcpy(req + reqlen, "\r", 1);
5273 reqlen += 1;
5274 smprintf(s, "Writing phonebook entry\n");
5275 error = ATGEN_WaitFor(s, req, reqlen, 0x00, 40, ID_SetMemory);
5276 return error;
5277 #undef REQUEST_SIZE
5278 }
5279
ATGEN_SetMemory(GSM_StateMachine * s,GSM_MemoryEntry * entry)5280 GSM_Error ATGEN_SetMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
5281 {
5282 if (entry->Location == 0) {
5283 return ERR_INVALIDLOCATION;
5284 }
5285 return ATGEN_PrivSetMemory(s, entry);
5286 }
5287
ATGEN_AddMemory(GSM_StateMachine * s,GSM_MemoryEntry * entry)5288 GSM_Error ATGEN_AddMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
5289 {
5290 GSM_Error error;
5291 GSM_MemoryStatus Status;
5292 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5293
5294 /* Switch to desired memory type */
5295 error = ATGEN_SetPBKMemory(s, entry->MemoryType);
5296
5297 if (error != ERR_NONE) {
5298 return error;
5299 }
5300 /* Find out empty location */
5301 error = ATGEN_GetMemoryInfo(s, &Status, AT_NextEmpty);
5302
5303 if (error != ERR_NONE) {
5304 return error;
5305 }
5306 if (Priv->NextMemoryEntry == 0) {
5307 return ERR_FULL;
5308 }
5309 entry->Location = Priv->NextMemoryEntry;
5310 return ATGEN_PrivSetMemory(s, entry);
5311 }
5312
ATGEN_SetIncomingCall(GSM_StateMachine * s,gboolean enable)5313 GSM_Error ATGEN_SetIncomingCall(GSM_StateMachine *s, gboolean enable)
5314 {
5315 GSM_Error error;
5316
5317 if (enable) {
5318 smprintf(s, "Enabling incoming call notification\n");
5319
5320 if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NO_CLIP)) {
5321 /* Some (especially SE) phones are messed up when we want to
5322 * see CLIP information */
5323 error = ATGEN_WaitForAutoLen(s, "AT+CLIP=1\r", 0x00, 10, ID_SetIncomingCall);
5324
5325 if (error != ERR_NONE) {
5326 return error;
5327 }
5328 error = ATGEN_WaitForAutoLen(s, "AT+CRC=1\r", 0x00, 10, ID_SetIncomingCall);
5329
5330 if (error != ERR_NONE) {
5331 return error;
5332 }
5333 } else {
5334 error = ATGEN_WaitForAutoLen(s, "AT+CRC=0\r", 0x00, 10, ID_SetIncomingCall);
5335
5336 if (error != ERR_NONE) {
5337 return error;
5338 }
5339 }
5340 error = ATGEN_WaitForAutoLen(s, "AT+CCWA=1\r", 0x00, 10, ID_SetIncomingCall);
5341
5342 /* We don't care if phone does not support this */
5343 } else {
5344 error = ATGEN_WaitForAutoLen(s, "AT+CCWA=0\r", 0x00, 10, ID_SetIncomingCall);
5345
5346 /* We don't care if phone does not support this */
5347 smprintf(s, "Disabling incoming call notification\n");
5348 }
5349 s->Phone.Data.EnableIncomingCall = enable;
5350 return ERR_NONE;
5351 }
5352
5353 /**
5354 * Extract number of incoming call from +CLIP: response.
5355 */
ATGEN_Extract_CLIP_number(GSM_StateMachine * s,unsigned char * dest,size_t destsize,const char * buf)5356 GSM_Error ATGEN_Extract_CLIP_number(GSM_StateMachine *s, unsigned char *dest, size_t destsize, const char *buf)
5357 {
5358 return ATGEN_ParseReply(s, buf, "+CLIP: @p,@0", dest, destsize);
5359 }
5360
5361 /**
5362 * Extract number of incoming call from +CLIP: response.
5363 */
ATGEN_Extract_CCWA_number(GSM_StateMachine * s,unsigned char * dest,size_t destsize,const char * buf)5364 GSM_Error ATGEN_Extract_CCWA_number(GSM_StateMachine *s, unsigned char *dest, size_t destsize, const char *buf)
5365 {
5366 return ATGEN_ParseReply(s, buf, "+CCWA: @p,@0", dest, destsize);
5367 }
5368
ATGEN_ReplyIncomingCallInfo(GSM_Protocol_Message * msg,GSM_StateMachine * s)5369 GSM_Error ATGEN_ReplyIncomingCallInfo(GSM_Protocol_Message *msg, GSM_StateMachine *s)
5370 {
5371 GSM_Call call;
5372 GSM_Error error;
5373
5374 memset(&call, 0, sizeof(call));
5375
5376 smprintf(s, "Incoming call info\n");
5377
5378 if (s->Phone.Data.EnableIncomingCall && s->User.IncomingCall != NULL) {
5379 call.Status = 0;
5380 call.StatusCode = 0;
5381 call.CallIDAvailable = FALSE;
5382
5383 if (strstr(msg->Buffer, "RING")) {
5384 smprintf(s, "Ring detected - ");
5385
5386 if(s->Phone.Data.Priv.ATGEN.CancellingCall) {
5387 smprintf(s, "call is being dropped.\n");
5388 return ERR_NONE;
5389 }
5390
5391 /* We ignore RING for most phones, see ATGEN_SetIncomingCall */
5392 if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NO_CLIP)) {
5393 smprintf(s, "waiting for caller ID.\n");
5394 return ERR_NONE;
5395 }
5396 smprintf(s, "generating event\n");
5397 call.Status = GSM_CALL_IncomingCall;
5398 call.CallIDAvailable = TRUE;
5399 error = ATGEN_Extract_CLIP_number(s, call.PhoneNumber, sizeof(call.PhoneNumber), msg->Buffer);
5400 if (error != ERR_NONE) {
5401 return error;
5402 }
5403 } else if (strstr(msg->Buffer, "CLIP:")) {
5404 smprintf(s, "CLIP detected (caller ID)\n");
5405 call.Status = GSM_CALL_IncomingCall;
5406 call.CallIDAvailable = TRUE;
5407 error = ATGEN_Extract_CLIP_number(s, call.PhoneNumber, sizeof(call.PhoneNumber), msg->Buffer);
5408 if (error != ERR_NONE) {
5409 return error;
5410 }
5411 } else if (strstr(msg->Buffer, "CCWA:")) {
5412 smprintf(s, "CCWA detected (caller ID)\n");
5413 call.Status = GSM_CALL_IncomingCall;
5414 error = ATGEN_Extract_CCWA_number(s, call.PhoneNumber, sizeof(call.PhoneNumber), msg->Buffer);
5415 if (error != ERR_NONE) {
5416 return error;
5417 }
5418 call.CallIDAvailable = TRUE;
5419 } else if (strstr(msg->Buffer, "NO CARRIER")) {
5420 smprintf(s, "Call end detected\n");
5421 GSM_CancelEventsOfType(s, GSM_EV_CALL);
5422 s->Phone.Data.Priv.ATGEN.CancellingCall = FALSE;
5423 call.Status = GSM_CALL_CallRemoteEnd;
5424 call.CallIDAvailable = TRUE;
5425 } else if (strstr(msg->Buffer, "COLP:")) {
5426 smprintf(s, "CLIP detected (caller ID)\n");
5427 call.Status = GSM_CALL_CallStart;
5428 call.CallIDAvailable = TRUE;
5429 error = ATGEN_Extract_CLIP_number(s, call.PhoneNumber, sizeof(call.PhoneNumber), msg->Buffer);
5430 if (error != ERR_NONE) {
5431 return error;
5432 }
5433 } else {
5434 smprintf(s, "Incoming call error\n");
5435 return ERR_NONE;
5436 }
5437
5438 GSM_DeferIncomingCallEvent(s, &call, ATGEN_BeforeDeferredEventHook);
5439 }
5440
5441 return ERR_NONE;
5442 }
5443
ATGEN_IncomingGPRS(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)5444 GSM_Error ATGEN_IncomingGPRS(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
5445 {
5446 /* "+CGREG: 1,1" */
5447 smprintf(s, "GPRS change\n");
5448 return ERR_NONE;
5449 }
5450
ATGEN_IncomingBattery(GSM_Protocol_Message * msg,GSM_StateMachine * s)5451 GSM_Error ATGEN_IncomingBattery(GSM_Protocol_Message *msg, GSM_StateMachine *s)
5452 {
5453 char *p = NULL;
5454 int level = 0;
5455
5456 /* "_OBS: 92,1" */
5457 p = strstr(msg->Buffer, "_OBS:");
5458
5459 if (p) {
5460 level = atoi(p + 5);
5461 }
5462 smprintf(s, "Battery level changed to %d\n", level);
5463 return ERR_NONE;
5464 }
5465
ATGEN_IncomingNetworkLevel(GSM_Protocol_Message * msg,GSM_StateMachine * s)5466 GSM_Error ATGEN_IncomingNetworkLevel(GSM_Protocol_Message *msg, GSM_StateMachine *s)
5467 {
5468 char *p = NULL;
5469 int level = 0;
5470
5471 /* "_OSIGQ: 12,0" */
5472 p = strstr(msg->Buffer, "_OSIGQ: ");
5473
5474 if (p) {
5475 level = atoi(p + 7);
5476 }
5477 smprintf(s, "Network level changed to %d\n", level);
5478 return ERR_NONE;
5479 }
5480
ATGEN_ReplyGetSIMIMSI(GSM_Protocol_Message * msg,GSM_StateMachine * s)5481 GSM_Error ATGEN_ReplyGetSIMIMSI(GSM_Protocol_Message *msg, GSM_StateMachine *s)
5482 {
5483 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5484 GSM_Phone_Data *Data = &s->Phone.Data;
5485
5486 switch (Priv->ReplyState) {
5487 case AT_Reply_OK:
5488 CopyLineString(Data->PhoneString, msg->Buffer, &Priv->Lines, 2);
5489
5490 /* Remove various prefies some phones add */
5491 if (strncmp(s->Phone.Data.IMEI, "<IMSI>: ", 7) == 0) { /* Alcatel */
5492 memmove(s->Phone.Data.IMEI, s->Phone.Data.IMEI + 7, strlen(s->Phone.Data.IMEI + 7) + 1);
5493 } else if (strncmp(s->Phone.Data.IMEI, "+CIMI: ", 7) == 0) { /* Motorola */
5494 memmove(s->Phone.Data.IMEI, s->Phone.Data.IMEI + 7, strlen(s->Phone.Data.IMEI + 7) + 1);
5495 }
5496
5497 smprintf(s, "Received IMSI %s\n",Data->PhoneString);
5498 return ERR_NONE;
5499 case AT_Reply_Error:
5500 smprintf(s, "No access to SIM card or not supported by device\n");
5501 return ERR_SECURITYERROR;
5502 case AT_Reply_CMSError:
5503 return ATGEN_HandleCMSError(s);
5504 case AT_Reply_CMEError:
5505 return ATGEN_HandleCMEError(s);
5506 default:
5507 break;
5508 }
5509 return ERR_UNKNOWNRESPONSE;
5510 }
5511
ATGEN_GetSIMIMSI(GSM_StateMachine * s,char * IMSI)5512 GSM_Error ATGEN_GetSIMIMSI(GSM_StateMachine *s, char *IMSI)
5513 {
5514 GSM_Error error;
5515
5516 s->Phone.Data.PhoneString = IMSI;
5517 smprintf(s, "Getting SIM IMSI\n");
5518 error = ATGEN_WaitForAutoLen(s, "AT+CIMI\r", 0x00, 40, ID_GetSIMIMSI);
5519 return error;
5520 }
5521
ATGEN_GetDisplayStatus(GSM_StateMachine * s UNUSED,GSM_DisplayFeatures * features UNUSED)5522 GSM_Error ATGEN_GetDisplayStatus(GSM_StateMachine *s UNUSED, GSM_DisplayFeatures *features UNUSED)
5523 {
5524 return ERR_NOTIMPLEMENTED;
5525 #if 0
5526 /**
5527 * \todo Parsing of response is not implemented.
5528 */
5529
5530 s->Phone.Data.DisplayFeatures = features;
5531 smprintf(s, "Getting display status\n");
5532 error = ATGEN_WaitForAutoLen(s, "AT+CIND?\r", 0x00, 40, ID_GetDisplayStatus);
5533 return error;
5534 #endif
5535 }
5536
ATGEN_ReplyGetBatteryCharge(GSM_Protocol_Message * msg,GSM_StateMachine * s)5537 GSM_Error ATGEN_ReplyGetBatteryCharge(GSM_Protocol_Message *msg, GSM_StateMachine *s)
5538 {
5539 GSM_Error error;
5540 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5541 GSM_BatteryCharge *BatteryCharge = s->Phone.Data.BatteryCharge;
5542 int bcs = 0, bcl = 0;
5543
5544 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
5545 case AT_Reply_OK:
5546 smprintf(s, "Battery level received\n");
5547 error = ATGEN_ParseReply(s,
5548 GetLineString(msg->Buffer, &Priv->Lines, 2),
5549 "+CBC: @i, @i",
5550 &bcs,
5551 &bcl);
5552
5553 /* Arduino GPRS shield adds extra value */
5554 if (error != ERR_NONE) {
5555 error = ATGEN_ParseReply(s,
5556 GetLineString(msg->Buffer, &Priv->Lines, 2),
5557 "+CBC: @i, @i, @0",
5558 &bcs,
5559 &bcl);
5560 }
5561
5562 /* LG phones reply just with value */
5563 if (error != ERR_NONE) {
5564 error = ATGEN_ParseReply(s,
5565 GetLineString(msg->Buffer, &Priv->Lines, 2),
5566 "@i, @i",
5567 &bcs,
5568 &bcl);
5569 }
5570
5571 if (error != ERR_NONE) {
5572 return error;
5573 }
5574 BatteryCharge->BatteryPercent = bcl;
5575
5576 switch (bcs) {
5577 case 0:
5578 BatteryCharge->ChargeState = GSM_BatteryPowered;
5579 break;
5580 case 1:
5581 BatteryCharge->ChargeState = GSM_BatteryConnected;
5582 break;
5583 case 2:
5584 BatteryCharge->ChargeState = GSM_BatteryCharging;
5585 break;
5586 default:
5587 BatteryCharge->ChargeState = 0;
5588 smprintf(s, "WARNING: Unknown battery state: %d\n", bcs);
5589 break;
5590 }
5591 return ERR_NONE;
5592 case AT_Reply_Error:
5593 smprintf(s, "Can't get battery level\n");
5594 return ERR_NOTSUPPORTED;
5595 case AT_Reply_CMSError:
5596 smprintf(s, "Can't get battery level\n");
5597 return ATGEN_HandleCMSError(s);
5598 case AT_Reply_CMEError:
5599 return ATGEN_HandleCMEError(s);
5600 default:
5601 return ERR_UNKNOWNRESPONSE;
5602 }
5603 }
5604
ATGEN_GetBatteryCharge(GSM_StateMachine * s,GSM_BatteryCharge * bat)5605 GSM_Error ATGEN_GetBatteryCharge(GSM_StateMachine *s, GSM_BatteryCharge *bat)
5606 {
5607 GSM_Error error;
5608
5609 GSM_ClearBatteryCharge(bat);
5610 s->Phone.Data.BatteryCharge = bat;
5611 smprintf(s, "Getting battery charge\n");
5612 error = ATGEN_WaitForAutoLen(s, "AT+CBC\r", 0x00, 40, ID_GetBatteryCharge);
5613 return error;
5614 }
5615
ATGEN_ReplyGetSignalQuality(GSM_Protocol_Message * msg,GSM_StateMachine * s)5616 GSM_Error ATGEN_ReplyGetSignalQuality(GSM_Protocol_Message *msg, GSM_StateMachine *s)
5617 {
5618 GSM_Error error;
5619 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5620 GSM_SignalQuality *Signal = s->Phone.Data.SignalQuality;
5621 int rssi = 0, ber = 0;
5622
5623 Signal->SignalStrength = -1;
5624 Signal->SignalPercent = -1;
5625 Signal->BitErrorRate = -1;
5626
5627 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
5628 case AT_Reply_OK:
5629 smprintf(s, "Signal quality info received\n");
5630 error = ATGEN_ParseReply(s,
5631 GetLineString(msg->Buffer, &Priv->Lines, 2),
5632 "+CSQ: @i, @i",
5633 &rssi,
5634 &ber);
5635
5636 if (error != ERR_NONE) {
5637 /* Some phones do not prepend CSQ */
5638 error = ATGEN_ParseReply(s,
5639 GetLineString(msg->Buffer, &Priv->Lines, 2),
5640 "@i, @i",
5641 &rssi,
5642 &ber);
5643 if (error != ERR_NONE) {
5644 return error;
5645 }
5646 }
5647
5648 /* 99 is Not known or not detectable. */
5649 if (rssi != 99) {
5650 /* from GSM 07.07 section 8.5 */
5651 Signal->SignalStrength = 2 * rssi - 113;
5652
5653 /* received signal strength indication is in range 0 - 31 */
5654 if (rssi == 31) {
5655 Signal->SignalPercent = 100;
5656 } else {
5657 Signal->SignalPercent = 3 * rssi;
5658 }
5659 if (Signal->SignalPercent > 100) {
5660 Signal->SignalPercent = 100;
5661 }
5662 }
5663
5664 /* from GSM 05.08 section 8.2.4 */
5665 switch (ber) {
5666 case 0: Signal->BitErrorRate = 0; break; /* 0.14 */
5667 case 1: Signal->BitErrorRate = 0; break; /* 0.28 */
5668 case 2: Signal->BitErrorRate = 1; break; /* 0.57 */
5669 case 3: Signal->BitErrorRate = 1; break; /* 1.13 */
5670 case 4: Signal->BitErrorRate = 2; break; /* 2.26 */
5671 case 5: Signal->BitErrorRate = 5; break; /* 4.53 */
5672 case 6: Signal->BitErrorRate = 9; break; /* 9.05 */
5673 case 7: Signal->BitErrorRate = 18; break; /* 18.10 */
5674 }
5675 return ERR_NONE;
5676 case AT_Reply_CMSError:
5677 return ATGEN_HandleCMSError(s);
5678 case AT_Reply_CMEError:
5679 return ATGEN_HandleCMEError(s);
5680 case AT_Reply_Error:
5681 return ERR_NOTSUPPORTED;
5682 default:
5683 break;
5684 }
5685 return ERR_UNKNOWNRESPONSE;
5686 }
5687
ATGEN_GetSignalQuality(GSM_StateMachine * s,GSM_SignalQuality * sig)5688 GSM_Error ATGEN_GetSignalQuality(GSM_StateMachine *s, GSM_SignalQuality *sig)
5689 {
5690 GSM_Error error;
5691
5692 s->Phone.Data.SignalQuality = sig;
5693 smprintf(s, "Getting signal quality info\n");
5694 error = ATGEN_WaitForAutoLen(s, "AT+CSQ\r", 0x00, 20, ID_GetSignalQuality);
5695 return error;
5696 }
5697
5698 /**
5699 * Just ignores reply we got.
5700 */
ATGEN_ReplyIgnore(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s UNUSED)5701 GSM_Error ATGEN_ReplyIgnore(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s UNUSED)
5702 {
5703 return ERR_NONE;
5704 }
5705
ATGEN_GetNextCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Note,gboolean start)5706 static GSM_Error ATGEN_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note, gboolean start)
5707 {
5708 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5709
5710 switch (Priv->Manufacturer) {
5711 case AT_Siemens:
5712 return SIEMENS_GetNextCalendar(s,Note,start);
5713 case AT_Samsung:
5714 return SAMSUNG_GetNextCalendar(s,Note,start);
5715 default:
5716 return ERR_NOTSUPPORTED;
5717 }
5718 }
5719
ATGEN_GetCalendarStatus(GSM_StateMachine * s,GSM_CalendarStatus * Status)5720 GSM_Error ATGEN_GetCalendarStatus(GSM_StateMachine *s, GSM_CalendarStatus *Status)
5721 {
5722 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5723
5724 switch (Priv->Manufacturer) {
5725 case AT_Motorola:
5726 return MOTOROLA_GetCalendarStatus(s, Status);
5727 case AT_Samsung:
5728 return SAMSUNG_GetCalendarStatus(s, Status);
5729 default:
5730 return ERR_NOTSUPPORTED;
5731 }
5732 }
5733
ATGEN_GetCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Note)5734 GSM_Error ATGEN_GetCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
5735 {
5736 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5737
5738 switch (Priv->Manufacturer) {
5739 case AT_Siemens:
5740 return SIEMENS_GetCalendar(s, Note);
5741 case AT_Motorola:
5742 return MOTOROLA_GetCalendar(s, Note);
5743 case AT_Samsung:
5744 return SAMSUNG_GetCalendar(s, Note);
5745 default:
5746 return ERR_NOTSUPPORTED;
5747 }
5748 }
5749
ATGEN_Terminate(GSM_StateMachine * s)5750 GSM_Error ATGEN_Terminate(GSM_StateMachine *s)
5751 {
5752 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5753
5754 FreeLines(&Priv->Lines);
5755 free(Priv->file.Buffer);
5756 Priv->file.Buffer = NULL;
5757 free(Priv->SMSCache);
5758 Priv->SMSCache = NULL;
5759 return ERR_NONE;
5760 }
5761
ATGEN_SetCalendarNote(GSM_StateMachine * s,GSM_CalendarEntry * Note)5762 GSM_Error ATGEN_SetCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note)
5763 {
5764 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5765
5766 switch (Priv->Manufacturer) {
5767 case AT_Siemens:
5768 return SIEMENS_SetCalendarNote(s, Note);
5769 case AT_Motorola:
5770 return MOTOROLA_SetCalendar(s, Note);
5771 case AT_Samsung:
5772 return SAMSUNG_SetCalendar(s, Note);
5773 default:
5774 return ERR_NOTSUPPORTED;
5775 }
5776 }
5777
ATGEN_AddCalendarNote(GSM_StateMachine * s,GSM_CalendarEntry * Note)5778 GSM_Error ATGEN_AddCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note)
5779 {
5780 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5781
5782 switch (Priv->Manufacturer) {
5783 case AT_Siemens:
5784 return SIEMENS_AddCalendarNote(s, Note);
5785 case AT_Samsung:
5786 return SAMSUNG_AddCalendar(s, Note);
5787 case AT_Motorola:
5788 return MOTOROLA_AddCalendar(s, Note);
5789 default:
5790 return ERR_NOTSUPPORTED;
5791 }
5792 }
5793
ATGEN_DelCalendarNote(GSM_StateMachine * s,GSM_CalendarEntry * Note)5794 GSM_Error ATGEN_DelCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note)
5795 {
5796 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5797
5798 switch (Priv->Manufacturer) {
5799 case AT_Siemens:
5800 return SIEMENS_DelCalendarNote(s, Note);
5801 case AT_Samsung:
5802 return SAMSUNG_DelCalendar(s, Note);
5803 case AT_Motorola:
5804 return MOTOROLA_DelCalendar(s, Note);
5805 default:
5806 return ERR_NOTSUPPORTED;
5807 }
5808 }
5809
5810
ATGEN_GetBitmap(GSM_StateMachine * s,GSM_Bitmap * Bitmap)5811 GSM_Error ATGEN_GetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap)
5812 {
5813 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5814
5815 switch (Priv->Manufacturer) {
5816 case AT_Siemens:
5817 return SIEMENS_GetBitmap(s, Bitmap);
5818 case AT_Samsung:
5819 return SAMSUNG_GetBitmap(s, Bitmap);
5820 default:
5821 return ERR_NOTSUPPORTED;
5822 }
5823 }
5824
ATGEN_SetBitmap(GSM_StateMachine * s,GSM_Bitmap * Bitmap)5825 GSM_Error ATGEN_SetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap)
5826 {
5827 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5828
5829 switch (Priv->Manufacturer) {
5830 case AT_Siemens:
5831 return SIEMENS_SetBitmap(s, Bitmap);
5832 case AT_Samsung:
5833 return SAMSUNG_SetBitmap(s, Bitmap);
5834 default:
5835 return ERR_NOTSUPPORTED;
5836 }
5837 }
5838
ATGEN_GetRingtone(GSM_StateMachine * s,GSM_Ringtone * Ringtone,gboolean PhoneRingtone)5839 GSM_Error ATGEN_GetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, gboolean PhoneRingtone)
5840 {
5841 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5842
5843 switch (Priv->Manufacturer) {
5844 case AT_Siemens:
5845 return SIEMENS_GetRingtone(s, Ringtone, PhoneRingtone);
5846 case AT_Samsung:
5847 return SAMSUNG_GetRingtone(s, Ringtone, PhoneRingtone);
5848 default:
5849 return ERR_NOTSUPPORTED;
5850 }
5851 }
5852
ATGEN_SetRingtone(GSM_StateMachine * s,GSM_Ringtone * Ringtone,int * maxlength)5853 GSM_Error ATGEN_SetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, int *maxlength)
5854 {
5855 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5856
5857 switch (Priv->Manufacturer) {
5858 case AT_Siemens:
5859 return SIEMENS_SetRingtone(s, Ringtone, maxlength);
5860 case AT_Samsung:
5861 return SAMSUNG_SetRingtone(s, Ringtone, maxlength);
5862 default:
5863 return ERR_NOTSUPPORTED;
5864 }
5865 }
5866
ATGEN_SetPower(GSM_StateMachine * s,gboolean on)5867 GSM_Error ATGEN_SetPower(GSM_StateMachine *s, gboolean on)
5868 {
5869 GSM_Error error;
5870
5871 smprintf(s, "Set AT phone power %s\n", on ? "on" : "off");
5872
5873 /* Set power */
5874 error = GSM_WaitForAutoLen(s, on ? "AT+CFUN=1\r" : "AT+CFUN=4\r", 0, 40, ID_SetPower);
5875
5876 return error;
5877 }
5878
ATGEN_PressKey(GSM_StateMachine * s,GSM_KeyCode Key,gboolean Press)5879 GSM_Error ATGEN_PressKey(GSM_StateMachine *s, GSM_KeyCode Key, gboolean Press)
5880 {
5881 GSM_Error error;
5882 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5883 unsigned char frame[40] = {'\0'}, unicode_key[20] = {'\0'};
5884 char key[20] = {'\0'};
5885 size_t len = 0;
5886
5887 /* We do nothing on release event */
5888 if (!Press) {
5889 return ERR_NONE;
5890 }
5891
5892 /* Prefer IRA charaset to avoid tricky conversions */
5893 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_IRA);
5894
5895 /* Check error */
5896 if (error != ERR_NONE) {
5897 return error;
5898 }
5899 frame[0] = 0;
5900 strcat(frame, "AT+CKPD=\"");
5901
5902 /* Get key code */
5903 switch (Key) {
5904 case GSM_KEY_1 : strcpy(key, "1"); break;
5905 case GSM_KEY_2 : strcpy(key, "2"); break;
5906 case GSM_KEY_3 : strcpy(key, "3"); break;
5907 case GSM_KEY_4 : strcpy(key, "4"); break;
5908 case GSM_KEY_5 : strcpy(key, "5"); break;
5909 case GSM_KEY_6 : strcpy(key, "6"); break;
5910 case GSM_KEY_7 : strcpy(key, "7"); break;
5911 case GSM_KEY_8 : strcpy(key, "8"); break;
5912 case GSM_KEY_9 : strcpy(key, "9"); break;
5913 case GSM_KEY_0 : strcpy(key, "0"); break;
5914 case GSM_KEY_HASH : strcpy(key, "#"); break;
5915 case GSM_KEY_ASTERISK : strcpy(key, "*"); break;
5916 case GSM_KEY_POWER : strcpy(key, "P"); break;
5917 case GSM_KEY_GREEN : strcpy(key, "S"); break;
5918 case GSM_KEY_RED : strcpy(key, "E"); break;
5919 case GSM_KEY_INCREASEVOLUME : strcpy(key, "U"); break;
5920 case GSM_KEY_DECREASEVOLUME : strcpy(key, "D"); break;
5921 case GSM_KEY_UP : strcpy(key, "^"); break;
5922 case GSM_KEY_DOWN : strcpy(key, "V"); break;
5923 case GSM_KEY_MENU : strcpy(key, "F"); break;
5924 case GSM_KEY_LEFT : strcpy(key, "<"); break;
5925 case GSM_KEY_RIGHT : strcpy(key, ">"); break;
5926 case GSM_KEY_SOFT1 : strcpy(key, "["); break;
5927 case GSM_KEY_SOFT2 : strcpy(key, "]"); break;
5928 case GSM_KEY_HEADSET : strcpy(key, "H"); break;
5929 case GSM_KEY_JOYSTICK : strcpy(key, ":J"); break;
5930 case GSM_KEY_CAMERA : strcpy(key, ":C"); break;
5931 case GSM_KEY_OPERATOR : strcpy(key, ":O"); break;
5932 case GSM_KEY_RETURN : strcpy(key, ":R"); break;
5933 case GSM_KEY_CLEAR : strcpy(key, "C"); break;
5934 case GSM_KEY_MEDIA : strcpy(key, ":S"); break;
5935 case GSM_KEY_DESKTOP : strcpy(key, ":D"); break;
5936 case GSM_KEY_NONE : return ERR_NONE; /* Nothing to do here */
5937 case GSM_KEY_NAMES : return ERR_NOTSUPPORTED;
5938 }
5939
5940 /* Convert charset if needed */
5941 EncodeUnicode(unicode_key, key, strlen(key));
5942 len = UnicodeLength(unicode_key);
5943
5944 switch (Priv->Charset) {
5945 case AT_CHARSET_GSM:
5946 /* No extensions here */
5947 EncodeDefault(key, unicode_key, &len, FALSE, NULL);
5948 if (strcmp(key, "?") == 0) {
5949 smprintf(s, "Could not encode key to GSM charset!\n");
5950 return ERR_NOTSUPPORTED;
5951 }
5952 break;
5953 case AT_CHARSET_IRA:
5954 case AT_CHARSET_ASCII:
5955 case AT_CHARSET_UTF8:
5956 case AT_CHARSET_UTF_8:
5957 case AT_CHARSET_ISO88591:
5958 /* Nothing to do here */
5959 break;
5960 case AT_CHARSET_UCS2:
5961 case AT_CHARSET_UCS_2:
5962 EncodeHexUnicode(key, unicode_key, len);
5963 break;
5964 default:
5965 smprintf(s, "Not supported charset for key presses (%d)!\n", Priv->Charset);
5966 return ERR_NOTIMPLEMENTED;
5967 }
5968 strcat(frame, key);
5969 strcat(frame, "\"\r");
5970 smprintf(s, "Pressing key\n");
5971 error = ATGEN_WaitForAutoLen(s, frame, 0x00, 40, ID_PressKey);
5972
5973 if (error != ERR_NONE) {
5974 return error;
5975 }
5976
5977 /* Strange. My T310 needs it */
5978 error = ATGEN_WaitForAutoLen(s, "ATE1\r", 0x00, 40, ID_EnableEcho);
5979 return error;
5980 }
5981
5982 /**
5983 * Check what kind of protocols switching is supported.
5984 */
ATGEN_ReplyCheckSyncML(GSM_Protocol_Message * msg,GSM_StateMachine * s)5985 GSM_Error ATGEN_ReplyCheckSyncML(GSM_Protocol_Message *msg, GSM_StateMachine *s)
5986 {
5987 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
5988
5989 switch (Priv->ReplyState) {
5990 case AT_Reply_OK:
5991 break;
5992 case AT_Reply_Error:
5993 return ERR_NOTSUPPORTED;
5994 case AT_Reply_CMSError:
5995 return ATGEN_HandleCMSError(s);
5996 case AT_Reply_CMEError:
5997 return ATGEN_HandleCMEError(s);
5998 default:
5999 return ERR_UNKNOWNRESPONSE;
6000 }
6001
6002 if (strstr("MOBEXSTART", GetLineString(msg->Buffer, &Priv->Lines, 2)) != NULL) {
6003 smprintf(s, "Automatically enabling F_MOBEX, please report bug if it causes problems\n");
6004 GSM_AddPhoneFeature(s->Phone.Data.ModelInfo, F_MOBEX);
6005 GSM_AddPhoneFeature(s->Phone.Data.ModelInfo, F_OBEX);
6006 }
6007
6008 return ERR_NONE;
6009 }
6010
6011 /**
6012 * Check what kind of protocols switching is supported.
6013 */
ATGEN_ReplyCheckTSSPCSW(GSM_Protocol_Message * msg,GSM_StateMachine * s)6014 GSM_Error ATGEN_ReplyCheckTSSPCSW(GSM_Protocol_Message *msg, GSM_StateMachine *s)
6015 {
6016 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
6017 char protocol_version[100] = {'\0'};
6018 int protocol_id = 0, protocol_level = 0;
6019 GSM_Error error;
6020
6021 switch (Priv->ReplyState) {
6022 case AT_Reply_OK:
6023 break;
6024 case AT_Reply_Error:
6025 return ERR_NOTSUPPORTED;
6026 case AT_Reply_CMSError:
6027 return ATGEN_HandleCMSError(s);
6028 case AT_Reply_CMEError:
6029 return ATGEN_HandleCMEError(s);
6030 default:
6031 return ERR_UNKNOWNRESPONSE;
6032 }
6033
6034 error = ATGEN_ParseReply(s, GetLineString(msg->Buffer, &Priv->Lines, 2),
6035 "+TSSPCSW: @i, @r, @i",
6036 &protocol_id,
6037 protocol_version, sizeof(protocol_version),
6038 &protocol_level);
6039 if (error != ERR_NONE) {
6040 return error;
6041 }
6042 if (protocol_id == 1) {
6043 smprintf(s, "Automatically enabling F_TSSPCSW, please report bug if it causes problems\n");
6044 GSM_AddPhoneFeature(s->Phone.Data.ModelInfo, F_TSSPCSW);
6045 GSM_AddPhoneFeature(s->Phone.Data.ModelInfo, F_OBEX);
6046 }
6047
6048 return ERR_NONE;
6049 }
6050
6051 /**
6052 * Detects what additional protocols are being supported
6053 */
ATGEN_ReplyCheckProt(GSM_Protocol_Message * msg,GSM_StateMachine * s)6054 GSM_Error ATGEN_ReplyCheckProt(GSM_Protocol_Message *msg, GSM_StateMachine *s)
6055 {
6056 GSM_Error error;
6057 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
6058 char protocol_version[100] = {'\0'};
6059 const char *string;
6060 int line = 1, protocol_id = 0, protocol_level = 0;
6061
6062 switch (Priv->ReplyState) {
6063 case AT_Reply_OK:
6064 smprintf(s, "Protocol entries received\n");
6065 /* Walk through lines with +CPROT: */
6066 while (strcmp("OK", string = GetLineString(msg->Buffer,&Priv->Lines,line+1)) != 0) {
6067
6068 /*
6069 * This is what Sony Ericsson phones usually
6070 * give.
6071 * +CPROT: (0),("1.2"),(8)
6072 */
6073 error = ATGEN_ParseReply(s, string,
6074 "+CPROT: (@i), (@r), (@i)",
6075 &protocol_id,
6076 protocol_version, sizeof(protocol_version),
6077 &protocol_level);
6078
6079 /*
6080 * This reply comes from Alcatel and Samsung.
6081 * +CPROT: 0,"1.0",8"
6082 */
6083 if (error != ERR_NONE) {
6084 error = ATGEN_ParseReply(s, string,
6085 "+CPROT: @i, @r, @i",
6086 &protocol_id,
6087 protocol_version, sizeof(protocol_version),
6088 &protocol_level);
6089 }
6090
6091 /*
6092 * As last resort try simple +CPROT: (0).
6093 */
6094 if (error != ERR_NONE) {
6095 protocol_level = 0;
6096 strcpy(protocol_version, "0");
6097 error = ATGEN_ParseReply(s, string,
6098 "+CPROT: (@i)",
6099 &protocol_id);
6100 }
6101
6102 /* Check for OBEX */
6103 if (error == ERR_NONE && protocol_id == 0) {
6104 smprintf(s, "OBEX seems to be supported, version %s, level %d!\n", protocol_version, protocol_level);
6105 /*
6106 * Level 1 is almost useless, require
6107 * higher levels.
6108 */
6109 if (protocol_level > 1 && (strcmp(protocol_version, "1.2") == 0 || strcmp(protocol_version, "1.3") == 0)) {
6110
6111 if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NO_ATOBEX) &&
6112 !GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_OBEX)
6113 ) {
6114 /* As AT+OBEX has automatic fallback we can try to enable OBEX here. */
6115 smprintf(s, "Automatically enabling F_OBEX, please report bug if it causes problems\n");
6116 GSM_AddPhoneFeature(s->Phone.Data.ModelInfo, F_OBEX);
6117 }
6118 GSM_AddPhoneFeature(s->Phone.Data.ModelInfo, F_CPROT);
6119 }
6120 }
6121 /* Check for Alcatel protocol */
6122 if (error == ERR_NONE && protocol_id == 16) {
6123 if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_ALCATEL)) {
6124 smprintf(s, "HINT: Please consider adding F_ALCATEL to your phone capabilities in common/gsmphones.c\n");
6125 }
6126 }
6127 line++;
6128 }
6129 return ERR_NONE;
6130 case AT_Reply_Error:
6131 return ERR_UNKNOWN;
6132 case AT_Reply_CMSError:
6133 return ATGEN_HandleCMSError(s);
6134 case AT_Reply_CMEError:
6135 return ATGEN_HandleCMEError(s);
6136 default:
6137 return ERR_UNKNOWNRESPONSE;
6138 }
6139 }
6140
ATGEN_ReplyCheckCHUP(GSM_Protocol_Message * msg,GSM_StateMachine * s)6141 GSM_Error ATGEN_ReplyCheckCHUP(GSM_Protocol_Message *msg, GSM_StateMachine *s)
6142 {
6143 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
6144 Priv->HasCHUP = FALSE;
6145
6146 if(Priv->ReplyState == AT_Reply_OK) {
6147 Priv->HasCHUP = TRUE;
6148 return ERR_NONE;
6149 }
6150
6151 return ATGEN_GenericReply(msg, s);
6152 }
6153
6154 GSM_Reply_Function ATGENReplyFunctions[] = {
6155 {ATGEN_GenericReply, "ATE1" ,0x00,0x00,ID_EnableEcho },
6156 {ATGEN_GenericReply, "ERROR" ,0x00,0x00,ID_EnableEcho },
6157 {ATGEN_GenericReply, "OK" ,0x00,0x00,ID_EnableEcho },
6158 {ATGEN_GenericReply, "AT+CMEE=" ,0x00,0x00,ID_EnableErrorInfo },
6159 {ATGEN_GenericReply, "AT+CKPD=" ,0x00,0x00,ID_PressKey },
6160 {ATGEN_ReplyGetSIMIMSI, "AT+CIMI" ,0x00,0x00,ID_GetSIMIMSI },
6161 {ATGEN_ReplyCheckProt, "AT+CPROT=?" ,0x00,0x00,ID_SetOBEX },
6162 {ATGEN_ReplyCheckSyncML, "AT+SYNCML=?" ,0x00,0x00,ID_SetOBEX },
6163 {ATGEN_ReplyCheckTSSPCSW, "AT$TSSPCSW=?" ,0x00,0x00,ID_SetOBEX },
6164 {ATGEN_GenericReply, "AT+XLNK=?" ,0x00,0x00,ID_SetOBEX },
6165
6166 {ATGEN_ReplyGetCNMIMode, "AT+CNMI=?" ,0x00,0x00,ID_GetCNMIMode },
6167 #ifdef GSM_ENABLE_CELLBROADCAST
6168 {ATGEN_ReplyIncomingCB, "+CBM:" ,0x00,0x00,ID_IncomingFrame },
6169 {ATGEN_GenericReply, "AT+CNMI" ,0x00,0x00,ID_SetIncomingCB },
6170 #endif
6171
6172 {ATGEN_IncomingBattery, "_OBS:" ,0x00,0x00,ID_IncomingFrame },
6173 {ATGEN_ReplyGetBatteryCharge, "AT+CBC" ,0x00,0x00,ID_GetBatteryCharge },
6174
6175 {ATGEN_ReplyGetModel, "AT+CGMM" ,0x00,0x00,ID_GetModel },
6176 {ATGEN_ReplyGetModel, "ATI4" ,0x00,0x00,ID_GetModel },
6177 {ATGEN_ReplyGetManufacturer, "AT+CGMI" ,0x00,0x00,ID_GetManufacturer },
6178 {ATGEN_ReplyGetManufacturer, "ATI3" ,0x00,0x00,ID_GetManufacturer },
6179 {ATGEN_ReplyGetFirmware, "AT+CGMR" ,0x00,0x00,ID_GetFirmware },
6180 {ATGEN_ReplyGetFirmware, "ATI5" ,0x00,0x00,ID_GetFirmware },
6181 {ATGEN_ReplyGetIMEI, "AT+CGSN" ,0x00,0x00,ID_GetIMEI },
6182
6183 {ATGEN_ReplySendSMS, "AT+CMGS" ,0x00,0x00,ID_IncomingFrame },
6184 {ATGEN_ReplySendSMS, "AT+CMSS" ,0x00,0x00,ID_IncomingFrame },
6185 {ATGEN_GenericReply, "AT+CNMI" ,0x00,0x00,ID_SetIncomingSMS },
6186 {ATGEN_GenericReply, "AT+CMGF" ,0x00,0x00,ID_GetSMSMode },
6187 {ATGEN_GenericReply, "AT+CSDH" ,0x00,0x00,ID_GetSMSMode },
6188 {ATGEN_ReplyGetSMSMessage, "AT+CMGR" ,0x00,0x00,ID_GetSMSMessage },
6189 {ATGEN_ReplyGetMessageList, "AT+CMGL" ,0x00,0x00,ID_GetSMSMessage },
6190 {ATGEN_GenericReply, "AT+CPMS" ,0x00,0x00,ID_SetMemoryType },
6191 {ATGEN_ReplyGetSMSStatus, "AT+CPMS" ,0x00,0x00,ID_GetSMSStatus },
6192 {ATGEN_ReplyGetSMSMemories, "AT+CPMS=?" ,0x00,0x00,ID_GetSMSMemories },
6193 {ATGEN_ReplyAddSMSMessage, "AT+CMGW" ,0x00,0x00,ID_SaveSMSMessage },
6194 {ATGEN_GenericReply, "AT+CSMP" ,0x00,0x00,ID_SetSMSParameters },
6195 {ATGEN_GenericReply, "AT+CSCA" ,0x00,0x00,ID_SetSMSC },
6196 {ATGEN_ReplyGetSMSC, "AT+CSCA?" ,0x00,0x00,ID_GetSMSC },
6197 {ATGEN_ReplyDeleteSMSMessage, "AT+CMGD" ,0x00,0x00,ID_DeleteSMSMessage },
6198 {ATGEN_GenericReply, "ATE1" ,0x00,0x00,ID_SetSMSParameters },
6199 {ATGEN_GenericReply, "\x1b\x0D" ,0x00,0x00,ID_SetSMSParameters },
6200 {ATGEN_GenericReply, "AT+CMMS" ,0x00,0x00,ID_SetFastSMSSending },
6201 {ATGEN_IncomingSMSInfo, "+CMTI:" ,0x00,0x00,ID_IncomingFrame },
6202 {ATGEN_IncomingSMSDeliver, "+CMT:" ,0x00,0x00,ID_IncomingFrame },
6203 {ATGEN_IncomingSMSReport, "+CDS:" ,0x00,0x00,ID_IncomingFrame },
6204 {ATGEN_IncomingSMSCInfo, "^SCN:" ,0x00,0x00,ID_IncomingFrame },
6205
6206 {ATGEN_ReplyGetDateTime, "AT+CCLK?" ,0x00,0x00,ID_GetDateTime },
6207 {ATGEN_GenericReply, "AT+CCLK=" ,0x00,0x00,ID_SetDateTime },
6208 {ATGEN_GenericReply, "AT+CALA=" ,0x00,0x00,ID_SetAlarm },
6209 {ATGEN_ReplyGetAlarm, "AT+CALA?" ,0x00,0x00,ID_GetAlarm },
6210
6211 {ATGEN_ReplyGetNetworkLAC_CID, "AT+CREG?" ,0x00,0x00,ID_GetNetworkInfo },
6212 {ATGEN_ReplyGetPacketNetworkLAC_CID, "AT+CGREG?" ,0x00,0x00,ID_GetNetworkInfo },
6213 {ATGEN_ReplyGetGPRSState, "AT+CGATT?" ,0x00,0x00,ID_GetGPRSState },
6214 {ATGEN_GenericReply, "AT+CREG=1" ,0x00,0x00,ID_ConfigureNetworkInfo },
6215 {ATGEN_GenericReply, "AT+CGREG=1" ,0x00,0x00,ID_ConfigureNetworkInfo },
6216 {ATGEN_GenericReply, "AT+CREG=2" ,0x00,0x00,ID_ConfigureNetworkInfo },
6217 {ATGEN_GenericReply, "AT+CGREG=2" ,0x00,0x00,ID_ConfigureNetworkInfo },
6218 {ATGEN_GenericReply, "AT+COPS=" ,0x00,0x00,ID_ConfigureNetworkInfo },
6219 {ATGEN_GenericReply, "AT+COPS=" ,0x00,0x00,ID_SetAutoNetworkLogin},
6220 {ATGEN_ReplyGetNetworkCode, "AT+COPS" ,0x00,0x00,ID_GetNetworkCode },
6221 {ATGEN_ReplyGetNetworkName, "AT+COPS" ,0x00,0x00,ID_GetNetworkName },
6222 {ATGEN_ReplyGetSignalQuality, "AT+CSQ" ,0x00,0x00,ID_GetSignalQuality },
6223 {ATGEN_IncomingNetworkLevel, "_OSIGQ:" ,0x00,0x00,ID_IncomingFrame },
6224 {ATGEN_IncomingGPRS, "+CGREG:" ,0x00,0x00,ID_IncomingFrame },
6225 {ATGEN_ReplyGetNetworkLAC_CID, "+CREG:" ,0x00,0x00,ID_IncomingFrame },
6226
6227 {ATGEN_ReplyGetPBKMemories, "AT+CPBS=?" ,0x00,0x00,ID_SetMemoryType },
6228 {ATGEN_ReplySetPBKMemory, "AT+CPBS=" ,0x00,0x00,ID_SetMemoryType },
6229 {ATGEN_ReplyGetCPBSMemoryStatus,"AT+CPBS?" ,0x00,0x00,ID_GetMemoryStatus },
6230 /* Samsung phones reply +CPBR: after OK --claudio */
6231 {ATGEN_ReplyGetCPBRMemoryInfo, "AT+CPBR=?" ,0x00,0x00,ID_GetMemoryStatus },
6232 {MOTOROLA_ReplyGetMPBRMemoryStatus, "AT+MPBR=?" ,0x00,0x00,ID_GetMemoryStatus },
6233 {ATGEN_ReplyGetCPBRMemoryInfo, "+CPBR:" ,0x00,0x00,ID_GetMemoryStatus },
6234 {ATGEN_ReplyGetCPBRMemoryStatus,"AT+CPBR=" ,0x00,0x00,ID_GetMemoryStatus },
6235 {ATGEN_ReplyGetCharsets, "AT+CSCS=?" ,0x00,0x00,ID_GetMemoryCharset },
6236 {ATGEN_ReplyGetCharset, "AT+CSCS?" ,0x00,0x00,ID_GetMemoryCharset },
6237 {ATGEN_GenericReply, "AT+CSCS=" ,0x00,0x00,ID_SetMemoryCharset },
6238 {ATGEN_ReplyGetMemory, "AT+CPBR=" ,0x00,0x00,ID_GetMemory },
6239 {SIEMENS_ReplyGetMemoryInfo, "AT^SBNR=?" ,0x00,0x00,ID_GetMemory },
6240 {SAMSUNG_ReplyGetMemoryInfo, "AT+SPBR=?" ,0x00,0x00,ID_GetMemory },
6241 {MOTOROLA_ReplyGetMemoryInfo, "AT+MPBR=?" ,0x00,0x00,ID_GetMemory },
6242 {SIEMENS_ReplyGetMemory, "AT^SBNR=\"vcf\"" ,0x00,0x00,ID_GetMemory },
6243 {SIEMENS_ReplySetMemory, "AT^SBNW=\"vcf\"" ,0x00,0x00,ID_SetMemory },
6244 {SAMSUNG_ReplyGetMemory, "AT+SPBR" ,0x00,0x00,ID_GetMemory },
6245 {MOTOROLA_ReplyGetMemory, "AT+MPBR" ,0x00,0x00,ID_GetMemory },
6246 {ATGEN_ReplySetMemory, "AT+CPBW" ,0x00,0x00,ID_SetMemory },
6247
6248 {SIEMENS_ReplyGetBitmap, "AT^SBNR=\"bmp\"" ,0x00,0x00,ID_GetBitmap },
6249 {SIEMENS_ReplySetBitmap, "AT^SBNW=\"bmp\"" ,0x00,0x00,ID_SetBitmap },
6250
6251 {SIEMENS_ReplyGetRingtone, "AT^SBNR=\"mid\"" ,0x00,0x00,ID_GetRingtone },
6252 {SIEMENS_ReplySetRingtone, "AT^SBNW=\"mid\"" ,0x00,0x00,ID_SetRingtone },
6253
6254 {SIEMENS_ReplyGetNextCalendar, "AT^SBNR=\"vcs\"" ,0x00,0x00,ID_GetCalendarNote },
6255 {SIEMENS_ReplyAddCalendarNote, "AT^SBNW=\"vcs\"" ,0x00,0x00,ID_SetCalendarNote },
6256 {SIEMENS_ReplyDelCalendarNote, "AT^SBNW=\"vcs\"" ,0x00,0x00,ID_DeleteCalendarNote },
6257
6258 {ATGEN_ReplyEnterSecurityCode, "AT+CPIN=" ,0x00,0x00,ID_EnterSecurityCode },
6259 {ATGEN_ReplyEnterSecurityCode, "AT+CPIN2=" ,0x00,0x00,ID_EnterSecurityCode },
6260 {ATGEN_ReplyGetSecurityStatus, "AT+CPIN?" ,0x00,0x00,ID_GetSecurityStatus },
6261
6262 /* No need to take care about this, we just need to ignore it */
6263 {MOTOROLA_Banner, "+MBAN:" ,0x00,0x00,ID_IncomingFrame },
6264
6265 {ATGEN_GenericReply, "AT+VTS" ,0x00,0x00,ID_SendDTMF },
6266 {ATGEN_ReplyCancelCall, "AT+CHUP" ,0x00,0x00,ID_CancelCall },
6267 {ATGEN_ReplyCheckCHUP, "AT+CHUP=?" ,0x00,0x00,ID_CheckCHUP },
6268 {ATGEN_ReplyDialVoice, "ATD" ,0x00,0x00,ID_DialVoice },
6269 {ATGEN_ReplyCancelCall, "ATH" ,0x00,0x00,ID_CancelCall },
6270 {ATGEN_ReplyAnswerCall, "ATA" ,0x00,0x00,ID_AnswerCall },
6271 {ATGEN_GenericReply, "AT+CRC" ,0x00,0x00,ID_SetIncomingCall },
6272 {ATGEN_GenericReply, "AT+CLIP" ,0x00,0x00,ID_SetIncomingCall },
6273 {ATGEN_GenericReply, "AT+CCWA" ,0x00,0x00,ID_SetIncomingCall },
6274 {ATGEN_GenericReply, "AT+CUSD" ,0x00,0x00,ID_SetUSSD },
6275 {ATGEN_GenericReply, "AT+CUSD" ,0x00,0x00,ID_GetUSSD },
6276 {ATGEN_ReplyGetUSSD, "+CUSD" ,0x00,0x00,ID_IncomingFrame },
6277 {ATGEN_GenericReply, "AT+CLIP=1" ,0x00,0x00,ID_IncomingFrame },
6278 {ATGEN_ReplyIncomingCallInfo, "+CLIP" ,0x00,0x00,ID_IncomingFrame },
6279 {ATGEN_ReplyIncomingCallInfo, "+CCWA" ,0x00,0x00,ID_IncomingFrame },
6280 {ATGEN_ReplyIncomingCallInfo, "+COLP" ,0x00,0x00,ID_IncomingFrame },
6281 {ATGEN_ReplyIncomingCallInfo, "RING" ,0x00,0x00,ID_IncomingFrame },
6282 {ATGEN_ReplyIncomingCallInfo, "+CRING" ,0x00,0x00,ID_IncomingFrame },
6283 {ATGEN_ReplyIncomingCallInfo, "NO CARRIER" ,0x00,0x00,ID_IncomingFrame },
6284
6285 {MOTOROLA_SetModeReply, "AT+MODE" ,0x00,0x00,ID_ModeSwitch },
6286
6287 {ATGEN_ReplyReset, "AT^SRESET" ,0x00,0x00,ID_Reset },
6288 {ATGEN_ReplyReset, "AT+CFUN=1,1" ,0x00,0x00,ID_Reset },
6289 {ATGEN_ReplyResetPhoneSettings, "AT&F" ,0x00,0x00,ID_ResetPhoneSettings },
6290
6291 {SAMSUNG_ReplyGetBitmap, "AT+IMGR=" ,0x00,0x00,ID_GetBitmap },
6292 {SAMSUNG_ReplySetBitmap, "SDNDCRC =" ,0x00,0x00,ID_SetBitmap },
6293
6294 {SAMSUNG_ReplyGetRingtone, "AT+MELR=" ,0x00,0x00,ID_GetRingtone },
6295 {SAMSUNG_ReplySetRingtone, "SDNDCRC =" ,0x00,0x00,ID_SetRingtone },
6296
6297 /* Call diverstion */
6298 {ATGEN_GenericReply, "AT+CCFC=" ,0x00,0x00,ID_SetDivert },
6299 {ATGEN_ReplyGetDivert, "AT+CCFC=" ,0x00,0x00,ID_Divert },
6300
6301 /* Protocol probing */
6302 {ATGEN_GenericReply, "AT+ORGI?" ,0x00,0x00,ID_GetProtocol },
6303 {ATGEN_GenericReply, "AT+SSHT?" ,0x00,0x00,ID_GetProtocol },
6304
6305 /* Samsung calendar ORG? */
6306 {SAMSUNG_ORG_ReplyGetCalendarStatus,"AT+ORGI?" ,0x00,0x00,ID_GetCalendarNotesInfo },
6307 {SAMSUNG_ORG_ReplyGetCalendar, "AT+ORGR=" ,0x00,0x00,ID_GetCalendarNote },
6308 {ATGEN_GenericReply, "AT+ORGD=" ,0x00,0x00,ID_DeleteCalendarNote },
6309 {SAMSUNG_ORG_ReplySetCalendar, "AT+ORGW=" ,0x00,0x00,ID_SetCalendarNote },
6310
6311 /* Samsung calendar SSH? */
6312 {SAMSUNG_SSH_ReplyGetCalendar, "AT+SSHR=" ,0x00,0x00,ID_GetCalendarNote },
6313 {ATGEN_GenericReply, "AT+SSHD=" ,0x00,0x00,ID_DeleteCalendarNote },
6314 {SAMSUNG_SSH_ReplyGetCalendarStatus,"AT+SSHI?" ,0x00,0x00,ID_GetCalendarNotesInfo },
6315
6316 {MOTOROLA_ReplyGetCalendarStatus,"AT+MDBR=?" ,0x00,0x00,ID_GetCalendarNotesInfo },
6317 {MOTOROLA_ReplyGetCalendar, "AT+MDBR=" ,0x00,0x00,ID_GetCalendarNote },
6318 {ATGEN_GenericReply, "AT+MDBWE=" ,0x00,0x00,ID_DeleteCalendarNote },
6319 {MOTOROLA_ReplySetCalendar, "AT+MDBW=" ,0x00,0x00,ID_SetCalendarNote },
6320 {ATGEN_GenericReply, "AT+MDBL=" ,0x00,0x00,ID_SetCalendarNote },
6321 {ATGEN_GenericReply, "AT+CIND?" ,0x00,0x00,ID_GetDisplayStatus },
6322
6323 {ATGEN_GenericReplyIgnore, "SAMSUNG PTS DG Test" ,0x00,0x00,ID_IncomingFrame },
6324 {ATGEN_GenericReplyIgnore, "NOT FOND ^,NOT CUSTOM AT",0x00,0x00,ID_IncomingFrame },
6325 {ATGEN_GenericReplyIgnore, "^RSSI:" ,0x00,0x00,ID_IncomingFrame },
6326 {ATGEN_GenericReplyIgnore, "^HCSQ:" ,0x00,0x00,ID_IncomingFrame },
6327 {ATGEN_GenericReplyIgnore, "^BOOT:" ,0x00,0x00,ID_IncomingFrame },
6328 {ATGEN_GenericReplyIgnore, "^MODE:" ,0x00,0x00,ID_IncomingFrame },
6329 {ATGEN_GenericReplyIgnore, "^DSFLOWRPT:" ,0x00,0x00,ID_IncomingFrame },
6330 {ATGEN_GenericReplyIgnore, "^CSNR:" ,0x00,0x00,ID_IncomingFrame },
6331 {ATGEN_GenericReplyIgnore, "^HCSQ:" ,0x00,0x00,ID_IncomingFrame },
6332 {ATGEN_GenericReplyIgnore, "^SRVST:" ,0x00,0x00,ID_IncomingFrame },
6333 {ATGEN_GenericReplyIgnore, "^SIMST:" ,0x00,0x00,ID_IncomingFrame },
6334 {ATGEN_GenericReplyIgnore, "^STIN:" ,0x00,0x00,ID_IncomingFrame },
6335 {ATGEN_GenericReplyIgnore, "+ZUSIMR:" ,0x00,0x00,ID_IncomingFrame },
6336 {ATGEN_GenericReplyIgnore, "+SPNWNAME:" ,0x00,0x00,ID_IncomingFrame },
6337 {ATGEN_GenericReplyIgnore, "+PSBEARER:" ,0x00,0x00,ID_IncomingFrame },
6338 {ATGEN_GenericReplyIgnore, "+ZEND" ,0x00,0x00,ID_IncomingFrame },
6339 {ATGEN_IncomingSMSInfo, "+CDSI:" ,0x00,0x00,ID_IncomingFrame },
6340 {ATGEN_GenericReplyIgnore, "+CLCC:" ,0x00,0x00,ID_IncomingFrame },
6341 {ATGEN_GenericReplyIgnore, "#STN:" ,0x00,0x00,ID_IncomingFrame },
6342
6343 /* Sony Ericsson screenshot */
6344 {SONYERICSSON_Reply_Screenshot, "AT*ZISI=?\r", 0x00,0x00,ID_Screenshot },
6345 {SONYERICSSON_Reply_ScreenshotData, "AT*ZISI\r", 0x00,0x00,ID_Screenshot },
6346
6347 #ifdef GSM_ENABLE_ATOBEX
6348 {ATGEN_GenericReply, "AT*EOBEX=?" ,0x00,0x00,ID_SetOBEX },
6349 {ATGEN_GenericReply, "AT*EOBEX" ,0x00,0x00,ID_SetOBEX },
6350 {ATGEN_GenericReply, "AT+CPROT=0" ,0x00,0x00,ID_SetOBEX },
6351 {ATGEN_GenericReply, "AT+MODE=22" ,0x00,0x00,ID_SetOBEX },
6352 {ATGEN_GenericReply, "AT+XLNK" ,0x00,0x00,ID_SetOBEX },
6353 {ATGEN_GenericReply, "AT^SQWE=3" ,0x00,0x00,ID_SetOBEX },
6354 {ATGEN_GenericReply, "AT+SYNCML=MOBEXSTART" ,0x00,0x00,ID_SetOBEX },
6355 {ATGEN_GenericReply, "AT$TSSPCSW=1" ,0x00,0x00,ID_SetOBEX },
6356 {ATGEN_GenericReply, "AT^SQWE=0" ,0x00,0x00,ID_SetOBEX },
6357 {ATGEN_SQWEReply, "AT^SQWE?" ,0x00,0x00,ID_GetProtocol },
6358
6359 {ATGEN_GenericReply, "AT*ESDF=" ,0x00,0x00,ID_SetLocale },
6360 {ATGEN_GenericReply, "AT*ESTF=" ,0x00,0x00,ID_SetLocale },
6361
6362 {ATOBEX_ReplyGetDateLocale, "AT*ESDF?" ,0x00,0x00,ID_GetLocale },
6363 {ATOBEX_ReplyGetTimeLocale, "AT*ESTF?" ,0x00,0x00,ID_GetLocale },
6364 {ATOBEX_ReplyGetFileSystemStatus,"AT*EMEM" ,0x00,0x00,ID_FileSystemStatus },
6365 {ATGEN_GenericReply, "AT*EBCA" ,0x00,0x00,ID_GetBatteryCharge },
6366 {ATOBEX_ReplyGetBatteryCharge, "*EBCA:" ,0x00,0x00,ID_IncomingFrame },
6367 #endif
6368 #ifdef GSM_ENABLE_ALCATEL
6369 /* Why do I give Alcatel specific things here? It's simple, Alcatel needs
6370 * some AT commands to start it's binary mode, so this needs to be in AT
6371 * related stuff.
6372 *
6373 * XXX: AT+IFC could later move outside this ifdef, because it is not Alcatel
6374 * specific and it's part of ETSI specifications
6375 */
6376 {ATGEN_GenericReply, "AT+IFC" ,0x00,0x00,ID_SetFlowControl },
6377 {ALCATEL_ProtocolVersionReply, "AT+CPROT=?" ,0x00,0x00,ID_AlcatelProtocol },
6378 {ATGEN_GenericReply, "AT+CPROT=16" ,0x00,0x00,ID_AlcatelConnect },
6379 #endif
6380 {ATGEN_GenericReply, "AT+CFUN=" ,0x00,0x00,ID_SetPower },
6381 {ATGEN_GenericReply, "AT^CURC=" ,0x00,0x00,ID_SetIncomingCall },
6382 {ATGEN_GenericReply, "AT^PORTSEL=" ,0x00,0x00,ID_SetIncomingCall },
6383 {ATGEN_GenericReply, "AT+ZCDRUN=" ,0x00,0x00,ID_Initialise },
6384 {ATGEN_GenericReply, "AT+ZOPRT=" ,0x00,0x00,ID_Initialise },
6385 {ATGEN_GenericReply, "AT\r" ,0x00,0x00,ID_Initialise },
6386 {ATGEN_GenericReply, "AT\n" ,0x00,0x00,ID_Initialise },
6387 {ATGEN_GenericReply, "OK" ,0x00,0x00,ID_Initialise },
6388 {ATGEN_GenericReply, "AT\r" ,0x00,0x00,ID_IncomingFrame },
6389
6390 {NULL, "\x00" ,0x00,0x00,ID_None }
6391 };
6392
6393 GSM_Phone_Functions ATGENPhone = {
6394 "A2D|iPAQ|at|M20|S25|MC35|TC35|C35i|S65|S300|5110|5130|5190|5210|6110|6130|6150|6190|6210|6250|6310|6310i|6510|7110|8210|8250|8290|8310|8390|8850|8855|8890|8910|9110|9210",
6395 ATGENReplyFunctions,
6396 NOTSUPPORTED, /* Install */
6397 ATGEN_Initialise,
6398 ATGEN_Terminate,
6399 ATGEN_DispatchMessage,
6400 NOTSUPPORTED, /* ShowStartInfo */
6401 ATGEN_GetManufacturer,
6402 ATGEN_GetModel,
6403 ATGEN_GetFirmware,
6404 ATGEN_GetIMEI,
6405 NOTSUPPORTED, /* GetOriginalIMEI */
6406 NOTSUPPORTED, /* GetManufactureMonth */
6407 NOTSUPPORTED, /* GetProductCode */
6408 NOTSUPPORTED, /* GetHardware */
6409 NOTSUPPORTED, /* GetPPM */
6410 ATGEN_GetSIMIMSI,
6411 ATGEN_GetDateTime,
6412 ATGEN_SetDateTime,
6413 ATGEN_GetAlarm,
6414 ATGEN_SetAlarm,
6415 NOTSUPPORTED, /* GetLocale */
6416 NOTSUPPORTED, /* SetLocale */
6417 ATGEN_PressKey,
6418 ATGEN_Reset,
6419 ATGEN_ResetPhoneSettings,
6420 ATGEN_EnterSecurityCode,
6421 ATGEN_GetSecurityStatus,
6422 ATGEN_GetDisplayStatus,
6423 ATGEN_SetAutoNetworkLogin,
6424 ATGEN_GetBatteryCharge,
6425 ATGEN_GetSignalQuality,
6426 ATGEN_GetNetworkInfo,
6427 NOTSUPPORTED, /* GetCategory */
6428 NOTSUPPORTED, /* AddCategory */
6429 NOTSUPPORTED, /* GetCategoryStatus */
6430 ATGEN_GetMemoryStatus,
6431 ATGEN_GetMemory,
6432 ATGEN_GetNextMemory,
6433 ATGEN_SetMemory,
6434 ATGEN_AddMemory,
6435 ATGEN_DeleteMemory,
6436 ATGEN_DeleteAllMemory,
6437 NOTSUPPORTED, /* GetSpeedDial */
6438 NOTSUPPORTED, /* SetSpeedDial */
6439 ATGEN_GetSMSC,
6440 ATGEN_SetSMSC,
6441 ATGEN_GetSMSStatus,
6442 ATGEN_GetSMS,
6443 ATGEN_GetNextSMS,
6444 NOTSUPPORTED, /* SetSMS */
6445 ATGEN_AddSMS,
6446 ATGEN_DeleteSMS,
6447 ATGEN_SendSMS,
6448 ATGEN_SendSavedSMS,
6449 ATGEN_SetFastSMSSending,
6450 ATGEN_SetIncomingSMS,
6451 ATGEN_SetIncomingCB,
6452 ATGEN_GetSMSFolders,
6453 NOTSUPPORTED, /* AddSMSFolder */
6454 NOTSUPPORTED, /* DeleteSMSFolder */
6455 ATGEN_DialVoice,
6456 ATGEN_DialService,
6457 ATGEN_AnswerCall,
6458 ATGEN_CancelCall,
6459 NOTSUPPORTED, /* HoldCall */
6460 NOTSUPPORTED, /* UnholdCall */
6461 NOTSUPPORTED, /* ConferenceCall */
6462 NOTSUPPORTED, /* SplitCall */
6463 NOTSUPPORTED, /* TransferCall */
6464 NOTSUPPORTED, /* SwitchCall */
6465 ATGEN_GetCallDivert,
6466 ATGEN_SetCallDivert,
6467 ATGEN_CancelAllDiverts,
6468 ATGEN_SetIncomingCall,
6469 ATGEN_SetIncomingUSSD,
6470 ATGEN_SendDTMF,
6471 ATGEN_GetRingtone,
6472 ATGEN_SetRingtone,
6473 NOTSUPPORTED, /* GetRingtonesInfo */
6474 NOTSUPPORTED, /* DeleteUserRingtones */
6475 NOTSUPPORTED, /* PlayTone */
6476 NOTSUPPORTED, /* GetWAPBookmark */
6477 NOTSUPPORTED, /* SetWAPBookmark */
6478 NOTSUPPORTED, /* DeleteWAPBookmark */
6479 NOTSUPPORTED, /* GetWAPSettings */
6480 NOTSUPPORTED, /* SetWAPSettings */
6481 NOTSUPPORTED, /* GetSyncMLSettings */
6482 NOTSUPPORTED, /* SetSyncMLSettings */
6483 NOTSUPPORTED, /* GetChatSettings */
6484 NOTSUPPORTED, /* SetChatSettings */
6485 NOTSUPPORTED, /* GetMMSSettings */
6486 NOTSUPPORTED, /* SetMMSSettings */
6487 NOTSUPPORTED, /* GetMMSFolders */
6488 NOTSUPPORTED, /* GetNextMMSFileInfo */
6489 ATGEN_GetBitmap, /* GetBitmap */
6490 ATGEN_SetBitmap, /* SetBitmap */
6491 NOTSUPPORTED, /* GetToDoStatus */
6492 NOTSUPPORTED, /* GetToDo */
6493 NOTSUPPORTED, /* GetNextToDo */
6494 NOTSUPPORTED, /* SetToDo */
6495 NOTSUPPORTED, /* AddToDo */
6496 NOTSUPPORTED, /* DeleteToDo */
6497 NOTSUPPORTED, /* DeleteAllToDo */
6498 ATGEN_GetCalendarStatus,
6499 ATGEN_GetCalendar,
6500 ATGEN_GetNextCalendar,
6501 ATGEN_SetCalendarNote,
6502 ATGEN_AddCalendarNote,
6503 ATGEN_DelCalendarNote,
6504 NOTIMPLEMENTED, /* DeleteAllCalendar */
6505 NOTSUPPORTED, /* GetCalendarSettings */
6506 NOTSUPPORTED, /* SetCalendarSettings */
6507 NOTSUPPORTED, /* GetNoteStatus */
6508 NOTSUPPORTED, /* GetNote */
6509 NOTSUPPORTED, /* GetNextNote */
6510 NOTSUPPORTED, /* SetNote */
6511 NOTSUPPORTED, /* AddNote */
6512 NOTSUPPORTED, /* DeleteNote */
6513 NOTSUPPORTED, /* DeleteAllNotes */
6514 NOTSUPPORTED, /* GetProfile */
6515 NOTSUPPORTED, /* SetProfile */
6516 NOTSUPPORTED, /* GetFMStation */
6517 NOTSUPPORTED, /* SetFMStation */
6518 NOTSUPPORTED, /* ClearFMStations */
6519 NOTSUPPORTED, /* GetNextFileFolder */
6520 NOTSUPPORTED, /* GetFolderListing */
6521 NOTSUPPORTED, /* GetNextRootFolder */
6522 NOTSUPPORTED, /* SetFileAttributes */
6523 NOTSUPPORTED, /* GetFilePart */
6524 NOTSUPPORTED, /* AddFilePart */
6525 NOTSUPPORTED, /* SendFilePart */
6526 NOTSUPPORTED, /* GetFileSystemStatus */
6527 NOTSUPPORTED, /* DeleteFile */
6528 NOTSUPPORTED, /* AddFolder */
6529 NOTSUPPORTED, /* DeleteFolder */
6530 NOTSUPPORTED, /* GetGPRSAccessPoint */
6531 NOTSUPPORTED, /* SetGPRSAccessPoint */
6532 SONYERICSSON_GetScreenshot,
6533 ATGEN_SetPower,
6534 ATGEN_PostConnect,
6535 NONEFUNCTION /* PreAPICall */
6536 };
6537
6538 #endif
6539 /*@}*/
6540 /*@}*/
6541
6542 /* How should editor hadle tabs in this file? Add editor commands here.
6543 * vim: noexpandtab sw=8 ts=8 sts=8:
6544 */
6545