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