"Fossies" - the Fresh Open Source Software Archive 
Member "gammu-1.42.0/libgammu/phone/at/atgen.c" (3 Oct 2020, 192105 Bytes) of package /linux/privat/gammu-1.42.0.tar.bz2:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "atgen.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.41.0_vs_1.42.0.
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
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
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
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
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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 */
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 */
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
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
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
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
1596 GSM_Error ATGEN_GenericReplyIgnore(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s UNUSED)
1597 {
1598 return ERR_NONE;
1599 }
1600
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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? */
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
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
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
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
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
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
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 */
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
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
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
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
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
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
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 */
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
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
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
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 */
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
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
4325 GSM_Error ATGEN_GetMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry)
4326 {
4327 return ATGEN_PrivGetMemory(s, entry, 0);
4328 }
4329
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
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
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
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
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
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
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
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
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
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
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
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;