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