summaryrefslogtreecommitdiffabout
path: root/gammu/emb/common/phone/at
Unidiff
Diffstat (limited to 'gammu/emb/common/phone/at') (more/less context) (ignore whitespace changes)
-rw-r--r--gammu/emb/common/phone/at/atgen.c3669
-rw-r--r--gammu/emb/common/phone/at/atgen.h110
-rw-r--r--gammu/emb/common/phone/at/siemens.c320
-rw-r--r--gammu/emb/common/phone/at/sonyeric.c411
4 files changed, 4510 insertions, 0 deletions
diff --git a/gammu/emb/common/phone/at/atgen.c b/gammu/emb/common/phone/at/atgen.c
new file mode 100644
index 0000000..1834f15
--- a/dev/null
+++ b/gammu/emb/common/phone/at/atgen.c
@@ -0,0 +1,3669 @@
1/* (c) 2002-2004 by Marcin Wiacek and Michal Cihar */
2
3#include "../../gsmstate.h"
4
5#ifdef GSM_ENABLE_ATGEN
6
7#include <string.h>
8#include <time.h>
9#include <ctype.h>
10
11#include "../../gsmcomon.h"
12#include "../../misc/coding/coding.h"
13#include "../../service/sms/gsmsms.h"
14#include "../pfunc.h"
15#include "atgen.h"
16
17#ifdef GSM_ENABLE_ALCATEL
18 extern GSM_Error ALCATEL_ProtocolVersionReply(GSM_Protocol_Message msg, GSM_StateMachine *s);
19#endif
20
21 extern GSM_Error ATGEN_CMS35ReplyGetBitmap(GSM_Protocol_Message msg, GSM_StateMachine *s);
22 extern GSM_Error ATGEN_CMS35ReplySetBitmap(GSM_Protocol_Message msg, GSM_StateMachine *s);
23 extern GSM_Error ATGEN_CMS35ReplyGetRingtone(GSM_Protocol_Message msg, GSM_StateMachine *s);
24 extern GSM_Error ATGEN_CMS35ReplySetRingtone(GSM_Protocol_Message msg, GSM_StateMachine *s);
25 extern GSM_Error ATGEN_CMS35ReplyGetNextCal(GSM_Protocol_Message msg, GSM_StateMachine *s);
26 extern GSM_Error ATGEN_CMS35ReplySetCalendar(GSM_Protocol_Message msg, GSM_StateMachine *s);
27 extern GSM_Error ATGEN_CMS35ReplyDeleteCalendar(GSM_Protocol_Message msg, GSM_StateMachine *s);
28 extern GSM_Error ATGEN_SL45ReplyGetMemory(GSM_Protocol_Message msg, GSM_StateMachine *s);
29
30 extern GSM_Error ATGEN_GetRingtone (GSM_StateMachine *s, GSM_Ringtone *Ringtone, bool PhoneRingtone);
31 extern GSM_Error ATGEN_SetRingtone (GSM_StateMachine *s, GSM_Ringtone *Ringtone, int *maxlength);
32 extern GSM_Error ATGEN_GetBitmap (GSM_StateMachine *s, GSM_Bitmap *Bitmap);
33 extern GSM_Error ATGEN_SetBitmap (GSM_StateMachine *s, GSM_Bitmap *Bitmap);
34 extern GSM_Error SIEMENS_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start);
35 extern GSM_Error SIEMENS_AddCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note);
36 extern GSM_Error SIEMENS_DelCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note);
37
38 extern GSM_Error SONYERIC_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start);
39 extern GSM_Error SONYERIC_GetNextToDo (GSM_StateMachine *s, GSM_ToDoEntry *ToDo, bool start);
40 extern GSM_Error SONYERIC_GetToDoStatus (GSM_StateMachine *s, GSM_ToDoStatus *status);
41 extern GSM_Error SONYERIC_AddCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note);
42 extern GSM_Error SONYERIC_AddToDo (GSM_StateMachine *s, GSM_ToDoEntry *ToDo);
43 extern GSM_Error SONYERIC_DeleteAllToDo (GSM_StateMachine *s);
44 extern GSM_Error SONYERIC_DelCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note);
45 extern GSM_Error SONYERIC_GetCalendarStatus(GSM_StateMachine *s, GSM_CalendarStatus *Status);
46
47typedef struct {
48 int Number;
49 char Text[60];
50} ATErrorCode;
51
52static ATErrorCode CMSErrorCodes[] = {
53 /*
54 * Error codes not specified here were either undefined or reserved in my
55 * copy of specifications, if you have newer one, please fill in the gaps.
56 */
57 /* 0...127 from GSM 04.11 Annex E-2 */
58 {1, "Unassigned (unallocated) number"},
59 {8, "Operator determined barring"},
60 {10, "Call barred"},
61 {21, "Short message transfer rejected"},
62 {27, "Destination out of service"},
63 {28, "Unidentified subscriber"},
64 {29, "Facility rejected"},
65 {30, "Unknown subscriber"},
66 {38, "Network out of order"},
67 {41, "Temporary failure"},
68 {42, "Congestion"},
69 {47, "Resources unavailable, unspecified"},
70 {50, "Requested facility not subscribed"},
71 {69, "Requested facility not implemented"},
72 {81, "Invalid short message transfer reference value"},
73 {95, "Invalid message, unspecified"},
74 {96, "Invalid mandatory information"},
75 {97, "Message type non-existent or not implemented"},
76 {98, "Message not compatible with short message protocol state"},
77 {99, "Information element non-existent or not implemented"},
78 {111, "Protocol error, unspecified"},
79 {127, "Interworking, unspecified"},
80 /* 128...255 from GSM 03.40 subclause 9.2.3.22 */
81 {0x80, "Telematic interworking not supported"},
82 {0x81, "Short message Type 0 not supported"},
83 {0x82, "Cannot replace short message"},
84 {0x8F, "Unspecified TP-PID error"},
85 {0x90, "Data coding scheme (alphabet) not supported"},
86 {0x91, "Message class not supported"},
87 {0x9F, "Unspecified TP-DCS error"},
88 {0xA0, "Command cannot be actioned"},
89 {0xA1, "Command unsupported"},
90 {0xAF, "Unspecified TP-Command error"},
91 {0xB0, "TPDU not supported"},
92 {0xC0, "SC busy"},
93 {0xC1, "No SC subscription"},
94 {0xC2, "SC system failure"},
95 {0xC3, "Invalid SME address"},
96 {0xC4, "Destination SME barred"},
97 {0xC5, "SM Rejected-Duplicate SM"},
98 {0xC6, "TP-VPF not supported"},
99 {0xC7, "TP-VP not supported"},
100 {0xD0, "SIM SMS storage full"},
101 {0xD1, "No SMS storage capability in SIM"},
102 {0xD2, "Error in MS"},
103 {0xD3, "Memory Capacity Exceede"},
104 {0xD4, "SIM Application Toolkit Busy"},
105 {0xFF, "Unspecified error cause"},
106 /* 300...511 from GSM 07.05 subclause 3.2.5 */
107 {300, "ME failure"},
108 {301, "SMS service of ME reserved"},
109 {302, "operation not allowed"},
110 {303, "operation not supported"},
111 {304, "invalid PDU mode parameter"},
112 {305, "invalid text mode parameter"},
113 {310, "SIM not inserted"},
114 {311, "SIM PIN required"},
115 {312, "PH-SIM PIN required"},
116 {313, "SIM failure"},
117 {314, "SIM busy"},
118 {315, "SIM wrong"},
119 {316, "SIM PUK required"},
120 {317, "SIM PIN2 required"},
121 {318, "SIM PUK2 required"},
122 {320, "memory failure"},
123 {321, "invalid memory index"},
124 {322, "memory full"},
125 {330, "SMSC address unknown"},
126 {331, "no network service"},
127 {332, "network timeout"},
128 {340, "no CNMA acknowledgement expected"},
129 {500, "unknown error"},
130 /* > 512 are manufacturer specific according to GSM 07.05 subclause 3.2.5 */
131 {-1, ""}
132};
133
134static ATErrorCode CMEErrorCodes[] = {
135 /* CME Error codes from GSM 07.07 section 9.2 */
136 {0, "phone failure"},
137 {1, "no connection to phone"},
138 {2, "phone-adaptor link reserved"},
139 {3, "operation not allowed"},
140 {4, "operation not supported"},
141 {5, "PH-SIM PIN required"},
142 {10, "SIM not inserted"},
143 {11, "SIM PIN required"},
144 {12, "SIM PUK required"},
145 {13, "SIM failure"},
146 {14, "SIM busy"},
147 {15, "SIM wrong"},
148 {16, "incorrect password"},
149 {17, "SIM PIN2 required"},
150 {18, "SIM PUK2 required"},
151 {20, "memory full"},
152 {21, "invalid index"},
153 {22, "not found"},
154 {23, "memory failure"},
155 {24, "text string too long"},
156 {25, "invalid characters in text string"},
157 {26, "dial string too long"},
158 {27, "invalid characters in dial string"},
159 {30, "no network service"},
160 {31, "network timeout"},
161 {100, "unknown"},
162};
163
164
165GSM_Error ATGEN_HandleCMEError(GSM_StateMachine *s)
166{
167 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
168
169 if (Priv->ErrorCode == 0) {
170 smprintf(s, "CME Error occured, but it's type not detected\n");
171 } else if (Priv->ErrorText == NULL) {
172 smprintf(s, "CME Error %i, no description available\n", Priv->ErrorCode);
173 } else {
174 smprintf(s, "CME Error %i: \"%s\"\n", Priv->ErrorCode, Priv->ErrorText);
175 }
176 /* For error codes descriptions see table a bit above */
177 switch (Priv->ErrorCode) {
178 case 3:
179 return ERR_PERMISSION;
180 case 4:
181 return ERR_NOTSUPPORTED;
182 case 5:
183 case 11:
184 case 12:
185 case 16:
186 case 17:
187 case 18:
188 return ERR_SECURITYERROR;
189 case 20:
190 return ERR_FULL;
191 case 21:
192 return ERR_INVALIDLOCATION;
193 case 22:
194 return ERR_EMPTY;
195 case 23:
196 return ERR_MEMORY;
197 case 24:
198 case 25:
199 case 26:
200 case 27:
201 return ERR_INVALIDDATA;
202 default:
203 return ERR_UNKNOWN;
204 }
205}
206
207GSM_Error ATGEN_HandleCMSError(GSM_StateMachine *s)
208{
209 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
210
211 if (Priv->ErrorCode == 0) {
212 smprintf(s, "CMS Error occured, but it's type not detected\n");
213 } else if (Priv->ErrorText == NULL) {
214 smprintf(s, "CMS Error %i, no description available\n", Priv->ErrorCode);
215 } else {
216 smprintf(s, "CMS Error %i: \"%s\"\n", Priv->ErrorCode, Priv->ErrorText);
217 }
218 /* For error codes descriptions see table a bit above */
219 switch (Priv->ErrorCode) {
220 case 304:
221 return ERR_NOTSUPPORTED;
222 case 305:
223 return ERR_BUG;
224 case 311:
225 case 312:
226 case 316:
227 case 317:
228 case 318:
229 return ERR_SECURITYERROR;
230 case 322:
231 return ERR_FULL;
232 case 321:
233 return ERR_INVALIDLOCATION;
234 default:
235 return ERR_UNKNOWN;
236 }
237}
238
239/* FIXME: Function doesn't respect quoting of parameters and thus +FOO:
240 * "ab","cd,ef" will consider as three arguments: "ab" >> "cd >> ef"
241 */
242int ATGEN_ExtractOneParameter(unsigned char *input, unsigned char *output)
243{
244 int position=0;
245
246 while (*input!=',' && *input!=0x0d && *input!=0x00) {
247 *output=*input;
248 input++;
249 output++;
250 position++;
251 }
252 *output=0;
253 position++;
254 return position;
255}
256
257void ATGEN_DecodeDateTime(GSM_DateTime *dt, unsigned char *input)
258{
259 dt->Year=2000+(*input-'0')*10; input++;
260 dt->Year=dt->Year+(*input-'0'); input++;
261
262 input++;
263 dt->Month=(*input-'0')*10; input++;
264 dt->Month=dt->Month+(*input-'0'); input++;
265
266 input++;
267 dt->Day=(*input-'0')*10; input++;
268 dt->Day=dt->Day+(*input-'0'); input++;
269
270 input++;
271 dt->Hour=(*input-'0')*10; input++;
272 dt->Hour=dt->Hour+(*input-'0'); input++;
273
274 input++;
275 dt->Minute=(*input-'0')*10; input++;
276 dt->Minute=dt->Minute+(*input-'0');input++;
277
278 input++;
279 dt->Second=(*input-'0')*10; input++;
280 dt->Second=dt->Second+(*input-'0');input++;
281
282 if (input!=NULL) {
283 input++;
284 dt->Timezone=(*input-'0')*10; input++;
285 dt->Timezone=dt->Timezone+(*input-'0');input++;
286 input=input-2;
287 if (*input=='-') dt->Timezone=-dt->Timezone;
288 }
289}
290
291GSM_Error ATGEN_DispatchMessage(GSM_StateMachine *s)
292{
293 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
294 GSM_Protocol_Message *msg= s->Phone.Data.RequestMsg;
295 int i= 0, j, k;
296 char *err, *line;
297 ATErrorCode *ErrorCodes = NULL;
298
299 SplitLines(msg->Buffer, msg->Length, &Priv->Lines, "\x0D\x0A", 2, true);
300
301 /* Find number of lines */
302 while (Priv->Lines.numbers[i*2+1] != 0) {
303 /* FIXME: handle special chars correctly */
304 smprintf(s, "%i \"%s\"\n",i+1,GetLineString(msg->Buffer,Priv->Lines,i+1));
305 i++;
306 }
307
308 Priv->ReplyState = AT_Reply_Unknown;
309 Priv->ErrorText = NULL;
310 Priv->ErrorCode = 0;
311
312 line = GetLineString(msg->Buffer,Priv->Lines,i);
313 if (!strcmp(line,"OK")) Priv->ReplyState = AT_Reply_OK;
314 if (!strcmp(line,"> ")) Priv->ReplyState = AT_Reply_SMSEdit;
315 if (!strcmp(line,"CONNECT"))Priv->ReplyState = AT_Reply_Connect;
316 if (!strcmp(line,"ERROR" ))Priv->ReplyState = AT_Reply_Error;
317 if (!strncmp(line,"+CME ERROR:",11)) {
318 Priv->ReplyState = AT_Reply_CMEError;
319 ErrorCodes = CMEErrorCodes;
320 }
321 if (!strncmp(line,"+CMS ERROR:",11)) {
322 Priv->ReplyState = AT_Reply_CMSError;
323 ErrorCodes = CMSErrorCodes;
324 }
325 if (Priv->ReplyState == AT_Reply_CMEError || Priv->ReplyState == AT_Reply_CMSError) {
326 j = 0;
327 /* One char behind +CM[SE] ERROR */
328 err = line + 12;
329 while (err[j] && !isalnum(err[j])) j++;
330 if (isdigit(err[j])) {
331 Priv->ErrorCode = atoi(&(err[j]));
332 k = 0;
333 while (ErrorCodes[k].Number != -1) {
334 if (ErrorCodes[k].Number == Priv->ErrorCode) {
335 Priv->ErrorText = (char *)&(ErrorCodes[k].Text);
336 break;
337 }
338 k++;
339 }
340 } else if (isalpha(err[j])) {
341 k = 0;
342 while (ErrorCodes[k].Number != -1) {
343 if (!strncmp(err + j, ErrorCodes[k].Text, strlen(ErrorCodes[k].Text))) {
344 Priv->ErrorCode = ErrorCodes[k].Number;
345 Priv->ErrorText = (char *)&(ErrorCodes[k].Text);
346 break;
347 }
348 k++;
349 }
350 }
351 }
352 return GSM_DispatchMessage(s);
353}
354
355GSM_Error ATGEN_GenericReply(GSM_Protocol_Message msg, GSM_StateMachine *s)
356{
357 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
358 case AT_Reply_OK:
359 case AT_Reply_Connect:
360 return ERR_NONE;
361 case AT_Reply_Error:
362 return ERR_UNKNOWN;
363 case AT_Reply_CMSError:
364 return ATGEN_HandleCMSError(s);
365 case AT_Reply_CMEError:
366 return ATGEN_HandleCMEError(s);
367 default:
368 break;
369 }
370 return ERR_UNKNOWNRESPONSE;
371}
372
373GSM_Error ATGEN_ReplyGetModel(GSM_Protocol_Message msg, GSM_StateMachine *s)
374{
375 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
376 GSM_Phone_Data *Data = &s->Phone.Data;
377
378 if (s->Phone.Data.Priv.ATGEN.ReplyState != AT_Reply_OK) return ERR_NOTSUPPORTED;
379
380 if (strlen(GetLineString(msg.Buffer, Priv->Lines, 2)) <= MAX_MODEL_LENGTH) {
381 CopyLineString(Data->Model, msg.Buffer, Priv->Lines, 2);
382
383 /* Sometimes phone adds this before manufacturer (Sagem) */
384 if (strncmp("+CGMM: ", Data->Model, 7) == 0) {
385 memmove(Data->Model, Data->Model + 7, strlen(Data->Model + 7) + 1);
386 }
387
388 Data->ModelInfo = GetModelData(NULL,Data->Model,NULL);
389 if (Data->ModelInfo->number[0] == 0) Data->ModelInfo = GetModelData(NULL,NULL,Data->Model);
390 if (Data->ModelInfo->number[0] == 0) Data->ModelInfo = GetModelData(Data->Model,NULL,NULL);
391
392 if (Data->ModelInfo->number[0] != 0) strcpy(Data->Model,Data->ModelInfo->number);
393
394 if (strstr(msg.Buffer,"Nokia")) Priv->Manufacturer = AT_Nokia;
395 else if (strstr(msg.Buffer,"M20")) Priv->Manufacturer = AT_Siemens;
396 else if (strstr(msg.Buffer,"MC35")) Priv->Manufacturer = AT_Siemens;
397 else if (strstr(msg.Buffer, "iPAQ")) Priv->Manufacturer = AT_HP;
398
399 if (strstr(msg.Buffer,"M20")) strcpy(Data->Model,"M20");
400 else if (strstr(msg.Buffer,"MC35")) strcpy(Data->Model,"MC35");
401 else if (strstr(msg.Buffer, "iPAQ")) strcpy(Data->Model,"iPAQ");
402 } else {
403 smprintf(s, "WARNING: Model name too long, increase MAX_MODEL_LENGTH to at least %zd\n", strlen(GetLineString(msg.Buffer, Priv->Lines, 2)));
404 }
405
406 return ERR_NONE;
407}
408
409GSM_Error ATGEN_GetModel(GSM_StateMachine *s)
410{
411 GSM_Error error;
412
413 if (s->Phone.Data.Model[0] != 0) return ERR_NONE;
414
415 smprintf(s, "Getting model\n");
416 error=GSM_WaitFor (s, "AT+CGMM\r", 8, 0x00, 3, ID_GetModel);
417 if (error==ERR_NONE) {
418 if (s->di.dl==DL_TEXT || s->di.dl==DL_TEXTALL ||
419 s->di.dl==DL_TEXTDATE || s->di.dl==DL_TEXTALLDATE) {
420 smprintf(s, "[Connected model - \"%s\"]\n",s->Phone.Data.Model);
421 }
422 }
423 return error;
424}
425
426GSM_Error ATGEN_ReplyGetManufacturer(GSM_Protocol_Message msg, GSM_StateMachine *s)
427{
428 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
429
430 switch (Priv->ReplyState) {
431 case AT_Reply_OK:
432 smprintf(s, "Manufacturer info received\n");
433 Priv->Manufacturer = AT_Unknown;
434 if (strlen(GetLineString(msg.Buffer, Priv->Lines, 2)) <= MAX_MANUFACTURER_LENGTH) {
435 CopyLineString(s->Phone.Data.Manufacturer, msg.Buffer, Priv->Lines, 2);
436 } else {
437 smprintf(s, "WARNING: Manufacturer name too long, increase MAX_MANUFACTURER_LENGTH to at least %zd\n", strlen(GetLineString(msg.Buffer, Priv->Lines, 2)));
438 s->Phone.Data.Manufacturer[0] = 0;
439 }
440 /* Sometimes phone adds this before manufacturer (Sagem) */
441 if (strncmp("+CGMI: ", s->Phone.Data.Manufacturer, 7) == 0) {
442 memmove(s->Phone.Data.Manufacturer, s->Phone.Data.Manufacturer + 7, strlen(s->Phone.Data.Manufacturer + 7) + 1);
443 }
444 if (strstr(msg.Buffer,"Falcom")) {
445 smprintf(s, "Falcom\n");
446 strcpy(s->Phone.Data.Manufacturer,"Falcom");
447 Priv->Manufacturer = AT_Falcom;
448 if (strstr(msg.Buffer,"A2D")) {
449 strcpy(s->Phone.Data.Model,"A2D");
450 s->Phone.Data.ModelInfo = GetModelData(NULL,s->Phone.Data.Model,NULL);
451 smprintf(s, "Model A2D\n");
452 }
453 }
454 if (strstr(msg.Buffer,"Nokia")) {
455 smprintf(s, "Nokia\n");
456 strcpy(s->Phone.Data.Manufacturer,"Nokia");
457 Priv->Manufacturer = AT_Nokia;
458 }
459 if (strstr(msg.Buffer,"SIEMENS")) {
460 smprintf(s, "Siemens\n");
461 strcpy(s->Phone.Data.Manufacturer,"Siemens");
462 Priv->Manufacturer = AT_Siemens;
463 }
464 if (strstr(msg.Buffer,"ERICSSON")) {
465 smprintf(s, "Ericsson\n");
466 strcpy(s->Phone.Data.Manufacturer,"Ericsson");
467 Priv->Manufacturer = AT_Ericsson;
468 }
469 if (strstr(msg.Buffer,"iPAQ")) {
470 smprintf(s, "iPAQ\n");
471 strcpy(s->Phone.Data.Manufacturer,"HP");
472 Priv->Manufacturer = AT_HP;
473 }
474 if (strstr(msg.Buffer,"ALCATEL")) {
475 smprintf(s, "Alcatel\n");
476 strcpy(s->Phone.Data.Manufacturer,"Alcatel");
477 Priv->Manufacturer = AT_Alcatel;
478 }
479 if (strstr(msg.Buffer,"SAGEM")) {
480 smprintf(s, "Sagem\n");
481 strcpy(s->Phone.Data.Manufacturer,"Sagem");
482 Priv->Manufacturer = AT_Sagem;
483 }
484 return ERR_NONE;
485 case AT_Reply_CMSError:
486 return ATGEN_HandleCMSError(s);
487 default:
488 break;
489 }
490 return ERR_UNKNOWNRESPONSE;
491}
492
493GSM_Error ATGEN_GetManufacturer(GSM_StateMachine *s)
494{
495 if (s->Phone.Data.Manufacturer[0] != 0) return ERR_NONE;
496
497 return GSM_WaitFor (s, "AT+CGMI\r", 8, 0x00, 4, ID_GetManufacturer);
498}
499
500GSM_Error ATGEN_ReplyGetFirmwareCGMR(GSM_Protocol_Message msg, GSM_StateMachine *s)
501{
502 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
503 unsigned int i = 0;
504
505 strcpy(s->Phone.Data.Version,"unknown");
506 s->Phone.Data.VerNum = 0;
507 if (Priv->ReplyState == AT_Reply_OK) {
508 CopyLineString(s->Phone.Data.Version, msg.Buffer, Priv->Lines, 2);
509 /* Sometimes phone adds this before manufacturer (Sagem) */
510 if (strncmp("+CGMR: ", s->Phone.Data.Version, 7) == 0) {
511 memmove(s->Phone.Data.Version, s->Phone.Data.Version + 7, strlen(s->Phone.Data.Version + 7) + 1);
512 }
513 }
514 if (Priv->Manufacturer == AT_Ericsson) {
515 while (1) {
516 if (s->Phone.Data.Version[i] == 0x20) {
517 s->Phone.Data.Version[i] = 0x00;
518 break;
519 }
520 if (i == strlen(s->Phone.Data.Version)) break;
521 i++;
522 }
523 }
524 smprintf(s, "Received firmware version: \"%s\"\n",s->Phone.Data.Version);
525 GSM_CreateFirmwareNumber(s);
526 return ERR_NONE;
527}
528
529GSM_Error ATGEN_ReplyGetFirmwareATI(GSM_Protocol_Message msg, GSM_StateMachine *s)
530{
531 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
532
533 switch (Priv->ReplyState) {
534 case AT_Reply_OK:
535 // strcpy(Data->Version,"0.00");
536 // *Data->VersionNum=0;
537 // if (Data->Priv.ATGEN.ReplyState==AT_Reply_OK) {
538 // CopyLineString(Data->Version, msg.Buffer, Priv->Lines, 2);
539 // }
540 // smprintf(s, "Received firmware version: \"%s\"\n",Data->Version);
541 // GSM_CreateFirmwareNumber(Data);
542 // return ERR_NONE;
543 case AT_Reply_Error:
544 return ERR_NOTSUPPORTED;
545 case AT_Reply_CMSError:
546 return ATGEN_HandleCMSError(s);
547 default:
548 break;
549 }
550 return ERR_UNKNOWNRESPONSE;
551}
552
553GSM_Error ATGEN_GetFirmware(GSM_StateMachine *s)
554{
555 GSM_Error error;
556
557 if (s->Phone.Data.Version[0] != 0) return ERR_NONE;
558
559 error=ATGEN_GetManufacturer(s);
560 if (error != ERR_NONE) return error;
561
562 //smprintf(s, "Getting firmware - method 1\n");
563 //error=GSM_WaitFor (s, "ATI\r", 4, 0x00, 3, ID_GetFirmware);
564 //if (error != ERR_NONE) {
565 smprintf(s, "Getting firmware - method 2\n");
566 error=GSM_WaitFor (s, "AT+CGMR\r", 8, 0x00, 3, ID_GetFirmware);
567 //}
568 if (error==ERR_NONE) {
569 if (s->di.dl==DL_TEXT || s->di.dl==DL_TEXTALL ||
570 s->di.dl==DL_TEXTDATE || s->di.dl==DL_TEXTALLDATE) {
571 smprintf(s, "[Firmware version - \"%s\"]\n",s->Phone.Data.Version);
572 }
573 }
574 return error;
575}
576
577GSM_Error ATGEN_Initialise(GSM_StateMachine *s)
578{
579 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
580 GSM_Error error;
581 char buff[2];
582
583 Priv->SMSMode = 0;
584 Priv->Manufacturer = 0;
585 Priv->PhoneSMSMemory = 0;
586 Priv->CanSaveSMS = false;
587 Priv->SIMSMSMemory = 0;
588 Priv->SMSMemory = 0;
589 Priv->PBKMemory = 0;
590 Priv->PBKSBNR = 0;
591 Priv->PBKCharset = 0;
592 Priv->UCS2CharsetFailed = false;
593 Priv->NonUCS2CharsetFailed= false;
594 Priv->PBKMemories[0] = 0;
595 Priv->FirstCalendarPos = 0;
596 Priv->NextMemoryEntry = 0;
597 Priv->FirstMemoryEntry = 0;
598 Priv->file.Used = 0;
599 Priv->file.Buffer = NULL;
600 Priv->OBEX = false;
601 Priv->MemorySize = 0;
602 Priv->TextLength = 0;
603 Priv->NumberLength = 0;
604
605 Priv->ErrorText = NULL;
606
607 if (s->ConnectionType != GCT_IRDAAT && s->ConnectionType != GCT_BLUEAT) {
608 /* We try to escape AT+CMGS mode, at least Siemens M20
609 * then needs to get some rest
610 */
611 smprintf(s, "Escaping SMS mode\n");
612 error = s->Protocol.Functions->WriteMessage(s, "\x1B\r", 2, 0x00);
613 if (error!=ERR_NONE) return error;
614
615 /* Grab any possible garbage */
616 while (s->Device.Functions->ReadDevice(s, buff, 2) > 0) my_sleep(10);
617 }
618
619 /* When some phones (Alcatel BE5) is first time connected, it needs extra
620 * time to react, sending just AT wakes up the phone and it then can react
621 * to ATE1. We don't need to check whether this fails as it is just to
622 * wake up the phone and does nothing.
623 */
624 smprintf(s, "Sending simple AT command to wake up some devices\n");
625 GSM_WaitFor (s, "AT\r", 3, 0x00, 2, ID_IncomingFrame);
626
627 smprintf(s, "Enabling echo\n");
628 error = GSM_WaitFor (s, "ATE1\r", 5, 0x00, 3, ID_EnableEcho);
629 if (error != ERR_NONE) return error;
630
631 smprintf(s, "Enabling CME errors\n");
632 /* Try numeric errors */
633 if (GSM_WaitFor (s, "AT+CMEE=1\r", 10, 0x00, 3, ID_EnableErrorInfo) != ERR_NONE) {
634 /* Try textual errors */
635 if (GSM_WaitFor (s, "AT+CMEE=2\r", 10, 0x00, 3, ID_EnableErrorInfo) != ERR_NONE) {
636 smprintf(s, "CME errors could not be enabled, some error types won't be detected.\n");
637 }
638 }
639
640 error = ATGEN_GetModel(s);
641 if (error != ERR_NONE) return error;
642
643 if (!IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SLOWWRITE)) {
644 s->Protocol.Data.AT.FastWrite = true;
645 }
646
647 return error;
648}
649
650GSM_Error ATGEN_SetSMSC(GSM_StateMachine *s, GSM_SMSC *smsc)
651{
652 unsigned char req[50];
653
654 if (smsc->Location!=1) return ERR_NOTSUPPORTED;
655
656 sprintf(req, "AT+CSCA=\"%s\"\r",DecodeUnicodeString(smsc->Number));
657
658 smprintf(s, "Setting SMSC\n");
659 return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_SetSMSC);
660}
661
662GSM_Error ATGEN_ReplyGetSMSMemories(GSM_Protocol_Message msg, GSM_StateMachine *s)
663{
664 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
665 case AT_Reply_OK:
666 /* Reply here is:
667 * (memories for reading)[, (memories for writing)[, (memories for storing received messages)]]
668 * each memory is in quotes,
669 * Example: ("SM"), ("SM"), ("SM")
670 *
671 * We need to get from this supported memories. For this case
672 * we assume, that just appearence of memory makes it
673 * available for everything. Then we need to find out whether
674 * phone supports writing to memory. This is done by searching
675 * for "), (", which will appear between lists.
676 */
677 s->Phone.Data.Priv.ATGEN.CanSaveSMS = (strstr(msg.Buffer, "), (") != NULL);
678 if (strstr(msg.Buffer, "\"SM\"") != NULL) s->Phone.Data.Priv.ATGEN.SIMSMSMemory = AT_AVAILABLE;
679 else s->Phone.Data.Priv.ATGEN.SIMSMSMemory = AT_NOTAVAILABLE;
680 if (strstr(msg.Buffer, "\"ME\"") != NULL) s->Phone.Data.Priv.ATGEN.PhoneSMSMemory = AT_AVAILABLE;
681 else s->Phone.Data.Priv.ATGEN.PhoneSMSMemory = AT_NOTAVAILABLE;
682 smprintf(s, "Available SMS memories received, ME = %d, SM = %d\n", s->Phone.Data.Priv.ATGEN.PhoneSMSMemory, s->Phone.Data.Priv.ATGEN.SIMSMSMemory);
683 return ERR_NONE;
684 case AT_Reply_Error:
685 case AT_Reply_CMSError:
686 return ATGEN_HandleCMSError(s);
687 default:
688 return ERR_UNKNOWNRESPONSE;
689 }
690}
691
692GSM_Error ATGEN_GetSMSMemories(GSM_StateMachine *s)
693{
694 smprintf(s, "Getting available SMS memories\n");
695 return GSM_WaitFor (s, "AT+CPMS=?\r", 10, 0x00, 4, ID_GetSMSMemories);
696}
697
698GSM_Error ATGEN_SetSMSMemory(GSM_StateMachine *s, bool SIM)
699{
700 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
701 char req[] = "AT+CPMS=\"XX\",\"XX\"\r";
702 int reqlen = 18;
703 GSM_Error error;
704
705 if ((SIM && Priv->SIMSMSMemory == 0) || (!SIM && Priv->PhoneSMSMemory == 0)) {
706 /* We silently ignore error here, because when this fails, we can try to setmemory anyway */
707 ATGEN_GetSMSMemories(s);
708 }
709
710 /* If phone can not save SMS, don't try to set memory for saving */
711 if (!Priv->CanSaveSMS) {
712 req[12] = '\r';
713 reqlen = 13;
714 }
715
716 if (SIM) {
717 if (Priv->SMSMemory == MEM_SM) return ERR_NONE;
718 if (Priv->SIMSMSMemory == AT_NOTAVAILABLE) return ERR_NOTSUPPORTED;
719
720 req[9] = 'S'; req[10] = 'M';
721 req[14] = 'S'; req[15] = 'M';
722
723 smprintf(s, "Setting SMS memory type to SM\n");
724 error=GSM_WaitFor (s, req, reqlen, 0x00, 3, ID_SetMemoryType);
725 if (Priv->SIMSMSMemory == 0 && error == ERR_NONE) {
726 Priv->SIMSMSMemory = AT_AVAILABLE;
727 }
728 if (error == ERR_NOTSUPPORTED) {
729 smprintf(s, "Can't access SIM card?\n");
730 return ERR_SECURITYERROR;
731 }
732 if (error != ERR_NONE) return error;
733 Priv->SMSMemory = MEM_SM;
734 } else {
735 if (Priv->SMSMemory == MEM_ME) return ERR_NONE;
736 if (Priv->PhoneSMSMemory == AT_NOTAVAILABLE) return ERR_NOTSUPPORTED;
737
738 req[9] = 'M'; req[10] = 'E';
739 req[14] = 'M'; req[15] = 'E';
740
741 smprintf(s, "Setting SMS memory type to ME\n");
742 error=GSM_WaitFor (s, req, reqlen, 0x00, 3, ID_SetMemoryType);
743 if (Priv->PhoneSMSMemory == 0 && error == ERR_NONE) {
744 Priv->PhoneSMSMemory = AT_AVAILABLE;
745 }
746 if (error == ERR_NONE) Priv->SMSMemory = MEM_ME;
747 }
748 return error;
749}
750
751GSM_Error ATGEN_GetSMSMode(GSM_StateMachine *s)
752{
753 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
754 GSM_Error error;
755
756 if (Priv->SMSMode != 0) return ERR_NONE;
757
758 smprintf(s, "Trying SMS PDU mode\n");
759 error=GSM_WaitFor (s, "AT+CMGF=0\r", 10, 0x00, 3, ID_GetSMSMode);
760 if (error==ERR_NONE) {
761 Priv->SMSMode = SMS_AT_PDU;
762 return ERR_NONE;
763 }
764
765 smprintf(s, "Trying SMS text mode\n");
766 error=GSM_WaitFor (s, "AT+CMGF=1\r", 10, 0x00, 3, ID_GetSMSMode);
767 if (error==ERR_NONE) {
768 smprintf(s, "Enabling displaying all parameters in text mode\n");
769 error=GSM_WaitFor (s, "AT+CSDH=1\r", 10, 0x00, 3, ID_GetSMSMode);
770 if (error == ERR_NONE) Priv->SMSMode = SMS_AT_TXT;
771 }
772
773 return error;
774}
775
776GSM_Error ATGEN_GetSMSLocation(GSM_StateMachine *s, GSM_SMSMessage *sms, unsigned char *folderid, int *location)
777{
778 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
779 int ifolderid, maxfolder;
780 GSM_Error error;
781
782 if (Priv->PhoneSMSMemory == 0) {
783 error = ATGEN_SetSMSMemory(s, false);
784 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) return error;
785 }
786 if (Priv->SIMSMSMemory == 0) {
787 error = ATGEN_SetSMSMemory(s, true);
788 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) return error;
789 }
790
791 if (Priv->SIMSMSMemory != AT_AVAILABLE && Priv->PhoneSMSMemory != AT_AVAILABLE) {
792 /* No SMS memory at all */
793 return ERR_NOTSUPPORTED;
794 }
795 if (Priv->SIMSMSMemory == AT_AVAILABLE && Priv->PhoneSMSMemory == AT_AVAILABLE) {
796 /* Both available */
797 maxfolder = 2;
798 } else {
799 /* One available */
800 maxfolder = 1;
801 }
802
803 /* simulate flat SMS memory */
804 if (sms->Folder == 0x00) {
805 ifolderid = sms->Location / PHONE_MAXSMSINFOLDER;
806 if (ifolderid + 1 > maxfolder) return ERR_NOTSUPPORTED;
807 *folderid = ifolderid + 1;
808 *location = sms->Location - ifolderid * PHONE_MAXSMSINFOLDER;
809 } else {
810 if (sms->Folder > 2 * maxfolder) return ERR_NOTSUPPORTED;
811 *folderid = sms->Folder <= 2 ? 1 : 2;
812 *location = sms->Location;
813 }
814 smprintf(s, "SMS folder %i & location %i -> ATGEN folder %i & location %i\n",
815 sms->Folder,sms->Location,*folderid,*location);
816
817 if (Priv->SIMSMSMemory == AT_AVAILABLE && *folderid == 1) {
818 return ATGEN_SetSMSMemory(s, true);
819 } else {
820 return ATGEN_SetSMSMemory(s, false);
821 }
822}
823
824void ATGEN_SetSMSLocation(GSM_StateMachine *s, GSM_SMSMessage *sms, unsigned char folderid, int location)
825{
826 sms->Folder= 0;
827 sms->Location= (folderid - 1) * PHONE_MAXSMSINFOLDER + location;
828 smprintf(s, "ATGEN folder %i & location %i -> SMS folder %i & location %i\n",
829 folderid,location,sms->Folder,sms->Location);
830}
831
832GSM_Error ATGEN_ReplyGetSMSMessage(GSM_Protocol_Message msg, GSM_StateMachine *s)
833{
834 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
835 GSM_SMSMessage *sms= &s->Phone.Data.GetSMSMessage->SMS[0];
836 int current = 0, current2, i;
837 unsigned char buffer[300],smsframe[800];
838 unsigned char firstbyte, TPDCS, TPUDL, TPStatus;
839 GSM_Error error;
840
841 switch (Priv->ReplyState) {
842 case AT_Reply_OK:
843 if (Priv->Lines.numbers[4] == 0x00) return ERR_EMPTY;
844 s->Phone.Data.GetSMSMessage->Number = 1;
845 s->Phone.Data.GetSMSMessage->SMS[0].Name[0] = 0;
846 s->Phone.Data.GetSMSMessage->SMS[0].Name[1]= 0;
847 switch (Priv->SMSMode) {
848 case SMS_AT_PDU:
849 CopyLineString(buffer, msg.Buffer, Priv->Lines, 2);
850 switch (buffer[7]) {
851 case '0': sms->State = SMS_UnRead; break;
852 case '1': sms->State = SMS_Read;break;
853 case '2': sms->State = SMS_UnSent;break;
854 default : sms->State = SMS_Sent;break;//case '3'
855 }
856 DecodeHexBin (buffer, GetLineString(msg.Buffer,Priv->Lines,3), strlen(GetLineString(msg.Buffer,Priv->Lines,3)));
857 /* Siemens MC35 (only ?) */
858 if (strstr(msg.Buffer,"+CMGR: 0,,0")!=NULL) return ERR_EMPTY;
859 /* Siemens M20 */
860 if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_M20SMS)) {
861 if (buffer[1]!=NUMBER_UNKNOWN && buffer[1]!=NUMBER_INTERNATIONAL &&
862 buffer[1]!=NUMBER_ALPHANUMERIC) {
863 /* Seems to be Delivery Report */
864 smprintf(s, "SMS type - status report (M20 style)\n");
865 sms->PDU = SMS_Status_Report;
866 sms->Folder = 1;/*INBOX SIM*/
867 sms->InboxFolder = true;
868
869 smsframe[12]=buffer[current++];
870 smsframe[PHONE_SMSStatusReport.TPMR]=buffer[current++];
871 current2=((buffer[current])+1)/2+1;
872 for(i=0;i<current2+1;i++) smsframe[PHONE_SMSStatusReport.Number+i]=buffer[current++];
873 for(i=0;i<7;i++) smsframe[PHONE_SMSStatusReport.DateTime+i]=buffer[current++];
874 smsframe[0] = 0;
875 for(i=0;i<7;i++) smsframe[PHONE_SMSStatusReport.SMSCTime+i]=buffer[current++];
876 smsframe[PHONE_SMSStatusReport.TPStatus]=buffer[current];
877 GSM_DecodeSMSFrame(sms,smsframe,PHONE_SMSStatusReport);
878 return ERR_NONE;
879 }
880 }
881 /* We use locations from SMS layouts like in ../phone2.c(h) */
882 for(i=0;i<buffer[0]+1;i++) smsframe[i]=buffer[current++];
883 smsframe[12]=buffer[current++];
884 /* See GSM 03.40 section 9.2.3.1 */
885 switch (smsframe[12] & 0x03) {
886 case 0x00:
887 smprintf(s, "SMS type - deliver\n");
888 sms->PDU = SMS_Deliver;
889 if (Priv->SMSMemory == MEM_SM) {
890 sms->Folder = 1; /*INBOX SIM*/
891 } else {
892 sms->Folder = 3; /*INBOX ME*/
893 }
894 sms->InboxFolder = true;
895 current2=((buffer[current])+1)/2+1;
896 if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_M20SMS)) {
897 if (buffer[current+1]==NUMBER_ALPHANUMERIC) {
898 smprintf(s, "Trying to read alphanumeric number\n");
899 for(i=0;i<4;i++) smsframe[PHONE_SMSDeliver.Number+i]=buffer[current++];
900 current+=6;
901 for(i=0;i<current2-3;i++) smsframe[PHONE_SMSDeliver.Number+i+4]=buffer[current++];
902 } else {
903 for(i=0;i<current2+1;i++) smsframe[PHONE_SMSDeliver.Number+i]=buffer[current++];
904 }
905 } else {
906 for(i=0;i<current2+1;i++) smsframe[PHONE_SMSDeliver.Number+i]=buffer[current++];
907 }
908 smsframe[PHONE_SMSDeliver.TPPID] = buffer[current++];
909 smsframe[PHONE_SMSDeliver.TPDCS] = buffer[current++];
910 for(i=0;i<7;i++) smsframe[PHONE_SMSDeliver.DateTime+i]=buffer[current++];
911 smsframe[PHONE_SMSDeliver.TPUDL] = buffer[current++];
912 for(i=0;i<smsframe[PHONE_SMSDeliver.TPUDL];i++) smsframe[i+PHONE_SMSDeliver.Text]=buffer[current++];
913 GSM_DecodeSMSFrame(sms,smsframe,PHONE_SMSDeliver);
914 return ERR_NONE;
915 case 0x01:
916 smprintf(s, "SMS type - submit\n");
917 sms->PDU = SMS_Submit;
918 if (Priv->SMSMemory == MEM_SM) {
919 sms->Folder = 2; /*OUTBOX SIM*/
920 smprintf(s, "Outbox SIM\n");
921 } else {
922 sms->Folder = 4; /*OUTBOX ME*/
923 }
924 sms->InboxFolder = false;
925 smsframe[PHONE_SMSSubmit.TPMR] = buffer[current++];
926 current2=((buffer[current])+1)/2+1;
927 if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_M20SMS)) {
928 if (buffer[current+1]==NUMBER_ALPHANUMERIC) {
929 smprintf(s, "Trying to read alphanumeric number\n");
930 for(i=0;i<4;i++) smsframe[PHONE_SMSSubmit.Number+i]=buffer[current++];
931 current+=6;
932 for(i=0;i<current2-3;i++) smsframe[PHONE_SMSSubmit.Number+i+4]=buffer[current++];
933 } else {
934 for(i=0;i<current2+1;i++) smsframe[PHONE_SMSSubmit.Number+i]=buffer[current++];
935 }
936 } else {
937 for(i=0;i<current2+1;i++) smsframe[PHONE_SMSSubmit.Number+i]=buffer[current++];
938 }
939 smsframe[PHONE_SMSSubmit.TPPID] = buffer[current++];
940 smsframe[PHONE_SMSSubmit.TPDCS] = buffer[current++];
941 /* See GSM 03.40 9.2.3.3 - TPVP can not exist in frame */
942 if ((smsframe[12] & 0x18)!=0) current++; //TPVP is ignored now
943 smsframe[PHONE_SMSSubmit.TPUDL] = buffer[current++];
944 for(i=0;i<smsframe[PHONE_SMSSubmit.TPUDL];i++) smsframe[i+PHONE_SMSSubmit.Text]=buffer[current++];
945 GSM_DecodeSMSFrame(sms,smsframe,PHONE_SMSSubmit);
946 return ERR_NONE;
947 case 0x02:
948 smprintf(s, "SMS type - status report\n");
949 sms->PDU = SMS_Status_Report;
950 sms->Folder = 1;/*INBOX SIM*/
951 sms->InboxFolder = true;
952 smprintf(s, "TPMR is %02x\n",buffer[current]);
953 smsframe[PHONE_SMSStatusReport.TPMR] = buffer[current++];
954 current2=((buffer[current])+1)/2+1;
955 for(i=0;i<current2+1;i++) smsframe[PHONE_SMSStatusReport.Number+i]=buffer[current++];
956 for(i=0;i<7;i++) smsframe[PHONE_SMSStatusReport.DateTime+i]=buffer[current++];
957 for(i=0;i<7;i++) smsframe[PHONE_SMSStatusReport.SMSCTime+i]=buffer[current++];
958 smsframe[PHONE_SMSStatusReport.TPStatus]=buffer[current];
959 GSM_DecodeSMSFrame(sms,smsframe,PHONE_SMSStatusReport);
960 return ERR_NONE;
961 }
962 break;
963 case SMS_AT_TXT:
964 current = 0;
965 while (msg.Buffer[current]!='"') current++;
966 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
967 if (!strcmp(buffer,"\"0\"") || !strcmp(buffer,"\"REC UNREAD\"")) {
968 smprintf(s, "SMS type - deliver\n");
969 sms->State = SMS_UnRead;
970 sms->PDU = SMS_Deliver;
971 if (Priv->SMSMemory == MEM_SM) {
972 sms->Folder = 1; /*INBOX SIM*/
973 } else {
974 sms->Folder = 3; /*INBOX ME*/
975 }
976 sms->InboxFolder = true;
977 } else if (!strcmp(buffer,"\"1\"") || !strcmp(buffer,"\"REC READ\"")) {
978 smprintf(s, "SMS type - deliver\n");
979 sms->State = SMS_Read;
980 sms->PDU = SMS_Deliver;
981 if (Priv->SMSMemory == MEM_SM) {
982 sms->Folder = 1; /*INBOX SIM*/
983 } else {
984 sms->Folder = 3; /*INBOX ME*/
985 }
986 sms->InboxFolder = true;
987 } else if (!strcmp(buffer,"\"2\"") || !strcmp(buffer,"\"STO UNSENT\"")) {
988 smprintf(s, "SMS type - submit\n");
989 sms->State = SMS_UnSent;
990 sms->PDU = SMS_Submit;
991 if (Priv->SMSMemory == MEM_SM) {
992 sms->Folder = 2; /*OUTBOX SIM*/
993 } else {
994 sms->Folder = 4; /*OUTBOX ME*/
995 }
996 sms->InboxFolder = false;
997 } else if (!strcmp(buffer,"\"3\"") || !strcmp(buffer,"\"STO SENT\"")) {
998 smprintf(s, "SMS type - submit\n");
999 sms->State = SMS_Sent;
1000 sms->PDU = SMS_Submit;
1001 if (Priv->SMSMemory == MEM_SM) {
1002 sms->Folder = 2; /*OUTBOX SIM*/
1003 } else {
1004 sms->Folder = 4; /*OUTBOX ME*/
1005 }
1006 sms->InboxFolder = false;
1007 }
1008 current += ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1009 /* It's delivery report according to Nokia AT standards */
1010 if (sms->Folder==1 && buffer[0]!=0 && buffer[0]!='"') {
1011 /* ??? */
1012 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1013 /* format of sender number */
1014 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1015 /* Sender number */
1016 /* FIXME: support for all formats */
1017 EncodeUnicode(sms->Number,buffer+1,strlen(buffer)-2);
1018 smprintf(s, "Sender \"%s\"\n",DecodeUnicodeString(sms->Number));
1019 /* ??? */
1020 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1021 /* Sending datetime */
1022 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1023 i = strlen(buffer);
1024 buffer[i] = ',';
1025 i++;
1026 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer+i);
1027 smprintf(s, "\"%s\"\n",buffer);
1028 ATGEN_DecodeDateTime(&sms->DateTime, buffer+1);
1029 /* Date of SMSC response */
1030 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1031 i = strlen(buffer);
1032 buffer[i] = ',';
1033 i++;
1034 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer+i);
1035 smprintf(s, "\"%s\"\n",buffer);
1036 ATGEN_DecodeDateTime(&sms->SMSCTime, buffer+1);
1037 /* TPStatus */
1038 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1039 TPStatus=atoi(buffer);
1040 buffer[PHONE_SMSStatusReport.TPStatus] = TPStatus;
1041 error=GSM_DecodeSMSFrameStatusReportData(sms, buffer, PHONE_SMSStatusReport);
1042 if (error!=ERR_NONE) return error;
1043 /* NO SMSC number */
1044 sms->SMSC.Number[0]=0;
1045 sms->SMSC.Number[1]=0;
1046 sms->PDU = SMS_Status_Report;
1047 sms->ReplyViaSameSMSC=false;
1048 } else {
1049 /* Sender number */
1050 /* FIXME: support for all formats */
1051 EncodeUnicode(sms->Number,buffer+1,strlen(buffer)-2);
1052 /* Sender number in alphanumeric format ? */
1053 current += ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1054 if (strlen(buffer)!=0) EncodeUnicode(sms->Number,buffer+1,strlen(buffer)-2);
1055 smprintf(s, "Sender \"%s\"\n",DecodeUnicodeString(sms->Number));
1056 /* Sending datetime */
1057 if (sms->Folder==1 || sms->Folder==3) {
1058 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1059 /* FIXME: ATGEN_ExtractOneParameter() is broken as it doesn't respect
1060 * quoting of parameters and thus +FOO: "ab","cd,ef" will consider
1061 * as three arguments: "ab" >> "cd >> ef"
1062 */
1063 if (*buffer=='"') {
1064 i = strlen(buffer);
1065 buffer[i] = ',';
1066 i++;
1067 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer+i);
1068 }
1069 smprintf(s, "\"%s\"\n",buffer);
1070 if (*buffer)
1071 ATGEN_DecodeDateTime(&sms->DateTime, buffer+1);
1072 else {
1073 /* FIXME: What is the proper undefined GSM_DateTime ? */
1074 memset(&sms->DateTime, 0, sizeof(sms->DateTime));
1075 }
1076 ATGEN_DecodeDateTime(&sms->DateTime, buffer+1);
1077 }
1078 /* Sender number format */
1079 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1080 /* First byte */
1081 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1082 firstbyte=atoi(buffer);
1083 sms->ReplyViaSameSMSC=false;
1084 /* GSM 03.40 section 9.2.3.17 (TP-Reply-Path) */
1085 if ((firstbyte & 128)==128) sms->ReplyViaSameSMSC=true;
1086 /* TP PID */
1087 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1088 sms->ReplaceMessage = 0;
1089 if (atoi(buffer) > 0x40 && atoi(buffer) < 0x48) {
1090 sms->ReplaceMessage = atoi(buffer) - 0x40;
1091 }
1092 smprintf(s, "TPPID: %02x %i\n",atoi(buffer),atoi(buffer));
1093 /* TP DCS */
1094 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1095 TPDCS=atoi(buffer);
1096 if (sms->Folder==2 || sms->Folder==4) {
1097 /*TP VP */
1098 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1099 }
1100 /* SMSC number */
1101 /* FIXME: support for all formats */
1102 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1103 EncodeUnicode(sms->SMSC.Number,buffer+1,strlen(buffer)-2);
1104 /* Format of SMSC number */
1105 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1106 /* TPUDL */
1107 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1108 TPUDL=atoi(buffer);
1109 current++;
1110 sms->Coding = SMS_Coding_Default;
1111 /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme)
1112 * and GSM 03.38 section 4
1113 */
1114 if ((TPDCS & 0xf4) == 0xf4) sms->Coding=SMS_Coding_8bit;
1115 if ((TPDCS & 0x08) == 0x08) sms->Coding=SMS_Coding_Unicode;
1116 sms->Class = -1;
1117 if ((TPDCS & 0xF3)==0xF0) sms->Class = 0;
1118 if ((TPDCS & 0xF3)==0xF1) sms->Class = 1;
1119 if ((TPDCS & 0xF3)==0xF2) sms->Class = 2;
1120 if ((TPDCS & 0xF3)==0xF3) sms->Class = 3;
1121 smprintf(s, "SMS class: %i\n",sms->Class);
1122 switch (sms->Coding) {
1123 case SMS_Coding_Default:
1124 /* GSM 03.40 section 9.2.3.23 (TP-User-Data-Header-Indicator) */
1125 /* If not SMS with UDH, it's coded normal */
1126 /* If UDH available, treat it as Unicode or 8 bit */
1127 if ((firstbyte & 0x40)!=0x40) {
1128 sms->UDH.Type= UDH_NoUDH;
1129 sms->Length= TPUDL;
1130 EncodeUnicode(sms->Text,msg.Buffer+Priv->Lines.numbers[2*2],TPUDL);
1131 break;
1132 }
1133 case SMS_Coding_Unicode:
1134 case SMS_Coding_8bit:
1135 DecodeHexBin(buffer+PHONE_SMSDeliver.Text, msg.Buffer+current, TPUDL*2);
1136 buffer[PHONE_SMSDeliver.firstbyte] = firstbyte;
1137 buffer[PHONE_SMSDeliver.TPDCS] = TPDCS;
1138 buffer[PHONE_SMSDeliver.TPUDL] = TPUDL;
1139 return GSM_DecodeSMSFrameText(sms, buffer, PHONE_SMSDeliver);
1140 }
1141 }
1142 return ERR_NONE;
1143 default:
1144 break;
1145 }
1146 break;
1147 case AT_Reply_CMSError:
1148 if (Priv->ErrorCode == 320 || Priv->ErrorCode == 500) {
1149 return ERR_EMPTY;
1150 } else {
1151 return ATGEN_HandleCMSError(s);
1152 }
1153 case AT_Reply_CMEError:
1154 return ATGEN_HandleCMEError(s);
1155 case AT_Reply_Error:
1156 /* A2D returns Error with empty location */
1157 return ERR_EMPTY;
1158 default:
1159 break;
1160 }
1161 return ERR_UNKNOWNRESPONSE;
1162}
1163
1164GSM_Error ATGEN_GetSMS(GSM_StateMachine *s, GSM_MultiSMSMessage *sms)
1165{
1166 unsigned charreq[20], folderid;
1167 GSM_Errorerror;
1168 int location, getfolder, add = 0;
1169
1170 error=ATGEN_GetSMSLocation(s,&sms->SMS[0], &folderid, &location);
1171 if (error!=ERR_NONE) return error;
1172 if (s->Phone.Data.Priv.ATGEN.SMSMemory == MEM_ME && IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMSME900)) add = 899;
1173 sprintf(req, "AT+CMGR=%i\r", location + add);
1174
1175 error=ATGEN_GetSMSMode(s);
1176 if (error != ERR_NONE) return error;
1177
1178 error=ATGEN_GetManufacturer(s);
1179 if (error != ERR_NONE) return error;
1180
1181 s->Phone.Data.GetSMSMessage=sms;
1182 smprintf(s, "Getting SMS\n");
1183 error=GSM_WaitFor (s, req, strlen(req), 0x00, 5, ID_GetSMSMessage);
1184 if (error==ERR_NONE) {
1185 getfolder = sms->SMS[0].Folder;
1186 // if (getfolder != 0 && getfolder != sms->SMS[0].Folder) return ERR_EMPTY;
1187 ATGEN_SetSMSLocation(s, &sms->SMS[0], folderid, location);
1188 sms->SMS[0].Folder = getfolder;
1189 sms->SMS[0].Memory = MEM_SM;
1190 if (getfolder > 2) sms->SMS[0].Memory = MEM_ME;
1191 }
1192 return error;
1193}
1194
1195GSM_Error ATGEN_GetNextSMS(GSM_StateMachine *s, GSM_MultiSMSMessage *sms, bool start)
1196{
1197 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1198 GSM_Error error;
1199 int usedsms;
1200
1201 if (Priv->PhoneSMSMemory == 0) {
1202 error = ATGEN_SetSMSMemory(s, false);
1203 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) return error;
1204 }
1205 if (Priv->SIMSMSMemory == 0) {
1206 error = ATGEN_SetSMSMemory(s, true);
1207 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) return error;
1208 }
1209 if (Priv->SIMSMSMemory == AT_NOTAVAILABLE && Priv->PhoneSMSMemory == AT_NOTAVAILABLE) return ERR_NOTSUPPORTED;
1210
1211 if (start) {
1212 error=s->Phone.Functions->GetSMSStatus(s,&Priv->LastSMSStatus);
1213 if (error!=ERR_NONE) return error;
1214 Priv->LastSMSRead = 0;
1215 sms->SMS[0].Location = 0;
1216 }
1217 while (true) {
1218 sms->SMS[0].Location++;
1219 if (sms->SMS[0].Location < PHONE_MAXSMSINFOLDER) {
1220 if (Priv->SIMSMSMemory == AT_AVAILABLE) {
1221 usedsms = Priv->LastSMSStatus.SIMUsed;
1222 } else {
1223 usedsms = Priv->LastSMSStatus.PhoneUsed;
1224 }
1225
1226 if (Priv->LastSMSRead >= usedsms) {
1227 if (Priv->PhoneSMSMemory == AT_NOTAVAILABLE || Priv->LastSMSStatus.PhoneUsed==0) return ERR_EMPTY;
1228 Priv->LastSMSRead= 0;
1229 sms->SMS[0].Location = PHONE_MAXSMSINFOLDER + 1;
1230 }
1231 } else {
1232 if (Priv->PhoneSMSMemory == AT_NOTAVAILABLE) return ERR_EMPTY;
1233 if (Priv->LastSMSRead>=Priv->LastSMSStatus.PhoneUsed) return ERR_EMPTY;
1234 }
1235 sms->SMS[0].Folder = 0;
1236 error=s->Phone.Functions->GetSMS(s, sms);
1237 if (error==ERR_NONE) {
1238 Priv->LastSMSRead++;
1239 break;
1240 }
1241 if (error != ERR_EMPTY && error != ERR_INVALIDLOCATION) return error;
1242 }
1243 return error;
1244}
1245
1246GSM_Error ATGEN_ReplyGetSMSStatus(GSM_Protocol_Message msg, GSM_StateMachine *s)
1247{
1248 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1249 GSM_SMSMemoryStatus*SMSStatus = s->Phone.Data.SMSStatus;
1250 char *start;
1251 int current = 0;
1252 unsigned char buffer[50];
1253
1254 switch (Priv->ReplyState) {
1255 case AT_Reply_OK:
1256 smprintf(s, "SMS status received\n");
1257 start = strstr(msg.Buffer, "+CPMS: ") + 7;
1258 if (strstr(msg.Buffer,"ME")!=NULL) {
1259 SMSStatus->PhoneUsed = atoi(start);
1260 current+=ATGEN_ExtractOneParameter(start+current, buffer);
1261 current+=ATGEN_ExtractOneParameter(start+current, buffer);
1262 SMSStatus->PhoneSize= atoi(buffer);
1263 smprintf(s, "Used : %i\n",SMSStatus->PhoneUsed);
1264 smprintf(s, "Size : %i\n",SMSStatus->PhoneSize);
1265 } else {
1266 SMSStatus->SIMUsed = atoi(start);
1267 current+=ATGEN_ExtractOneParameter(start+current, buffer);
1268 current+=ATGEN_ExtractOneParameter(start+current, buffer);
1269 SMSStatus->SIMSize= atoi(buffer);
1270 smprintf(s, "Used : %i\n",SMSStatus->SIMUsed);
1271 smprintf(s, "Size : %i\n",SMSStatus->SIMSize);
1272 if (SMSStatus->SIMSize == 0) {
1273 smprintf(s, "Can't access SIM card\n");
1274 return ERR_SECURITYERROR;
1275 }
1276 }
1277 return ERR_NONE;
1278 case AT_Reply_Error:
1279 if (strstr(msg.Buffer,"SM")!=NULL) {
1280 smprintf(s, "Can't access SIM card\n");
1281 return ERR_SECURITYERROR;
1282 }
1283 return ERR_NOTSUPPORTED;
1284 case AT_Reply_CMSError:
1285 return ATGEN_HandleCMSError(s);
1286 default:
1287 break;
1288 }
1289 return ERR_UNKNOWNRESPONSE;
1290}
1291
1292GSM_Error ATGEN_GetSMSStatus(GSM_StateMachine *s, GSM_SMSMemoryStatus *status)
1293{
1294 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1295 GSM_Error error;
1296
1297 /* No templates at all */
1298 status->TemplatesUsed= 0;
1299
1300 status->SIMUsed = 0;
1301 status->SIMUnRead = 0;
1302 status->SIMSize = 0;
1303
1304 s->Phone.Data.SMSStatus=status;
1305
1306 if ((Priv->SIMSMSMemory == 0) || (Priv->PhoneSMSMemory == 0)) {
1307 /* We silently ignore error here, because when this fails, we can try to setmemory anyway */
1308 ATGEN_GetSMSMemories(s);
1309 }
1310
1311 if (Priv->PhoneSMSMemory == 0) {
1312 error = ATGEN_SetSMSMemory(s, false);
1313 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) return error;
1314 }
1315 if (Priv->SIMSMSMemory == 0) {
1316 error = ATGEN_SetSMSMemory(s, true);
1317 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) return error;
1318 }
1319
1320 if (Priv->SIMSMSMemory == AT_AVAILABLE) {
1321 smprintf(s, "Getting SIM SMS status\n");
1322 if (Priv->CanSaveSMS) {
1323 error=GSM_WaitFor (s, "AT+CPMS=\"SM\",\"SM\"\r", 18, 0x00, 4, ID_GetSMSStatus);
1324 } else {
1325 error=GSM_WaitFor (s, "AT+CPMS=\"SM\"\r", 13, 0x00, 4, ID_GetSMSStatus);
1326 }
1327 if (error!=ERR_NONE) return error;
1328 Priv->SMSMemory = MEM_SM;
1329 }
1330
1331 status->PhoneUsed= 0;
1332 status->PhoneUnRead = 0;
1333 status->PhoneSize= 0;
1334
1335 if (Priv->PhoneSMSMemory == AT_AVAILABLE) {
1336 smprintf(s, "Getting phone SMS status\n");
1337 if (Priv->CanSaveSMS) {
1338 error = GSM_WaitFor (s, "AT+CPMS=\"ME\",\"ME\"\r", 18, 0x00, 4, ID_GetSMSStatus);
1339 } else {
1340 error = GSM_WaitFor (s, "AT+CPMS=\"ME\"\r", 13, 0x00, 4, ID_GetSMSStatus);
1341 }
1342 if (error!=ERR_NONE) return error;
1343 Priv->SMSMemory = MEM_ME;
1344 }
1345
1346 return ERR_NONE;
1347}
1348
1349GSM_Error ATGEN_ReplyGetIMEI(GSM_Protocol_Message msg, GSM_StateMachine *s)
1350{
1351 CopyLineString(s->Phone.Data.IMEI, msg.Buffer, s->Phone.Data.Priv.ATGEN.Lines, 2);
1352 smprintf(s, "Received IMEI %s\n",s->Phone.Data.IMEI);
1353 return ERR_NONE;
1354}
1355
1356GSM_Error ATGEN_GetIMEI (GSM_StateMachine *s)
1357{
1358 if (s->Phone.Data.IMEI[0] != 0) return ERR_NONE;
1359 smprintf(s, "Getting IMEI\n");
1360 return GSM_WaitFor (s, "AT+CGSN\r", 8, 0x00, 2, ID_GetIMEI);
1361}
1362
1363GSM_Error ATGEN_ReplyAddSMSMessage(GSM_Protocol_Message msg, GSM_StateMachine *s)
1364{
1365 char *start;
1366 inti;
1367
1368 if (s->Protocol.Data.AT.EditMode) {
1369 if (s->Phone.Data.Priv.ATGEN.ReplyState != AT_Reply_SMSEdit) {
1370 return ATGEN_HandleCMSError(s);
1371 }
1372 s->Protocol.Data.AT.EditMode = false;
1373 return ERR_NONE;
1374 }
1375
1376 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
1377 case AT_Reply_OK:
1378 smprintf(s, "SMS saved OK\n");
1379 for(i=0;i<msg.Length;i++) {
1380 if (msg.Buffer[i] == 0x00) msg.Buffer[i] = 0x20;
1381 }
1382 start = strstr(msg.Buffer, "+CMGW: ");
1383 if (start == NULL) return ERR_UNKNOWN;
1384 s->Phone.Data.SaveSMSMessage->Location = atoi(start+7);
1385 smprintf(s, "Saved at location %i\n",s->Phone.Data.SaveSMSMessage->Location);
1386 return ERR_NONE;
1387 case AT_Reply_Error:
1388 smprintf(s, "Error\n");
1389 return ERR_NOTSUPPORTED;
1390 case AT_Reply_CMSError:
1391 /* This error occurs in case that phone couldn't save SMS */
1392 return ATGEN_HandleCMSError(s);
1393 default:
1394 break;
1395 }
1396 return ERR_UNKNOWNRESPONSE;
1397}
1398
1399GSM_Error ATGEN_MakeSMSFrame(GSM_StateMachine *s, GSM_SMSMessage *message, unsigned char *hexreq, int *current, int *length2)
1400{
1401 GSM_Error error;
1402 int i, length;
1403 unsigned char req[1000], buffer[1000];
1404 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1405 GSM_SMSC SMSC;
1406
1407 error=ATGEN_GetSMSMode(s);
1408 if (error != ERR_NONE) return error;
1409
1410 length = 0;
1411 *current = 0;
1412 switch (Priv->SMSMode) {
1413 case SMS_AT_PDU:
1414 if (message->PDU == SMS_Deliver) {
1415 smprintf(s, "SMS Deliver\n");
1416 error=PHONE_EncodeSMSFrame(s,message,buffer,PHONE_SMSDeliver,&length,true);
1417 if (error != ERR_NONE) return error;
1418 length = length - PHONE_SMSDeliver.Text;
1419 for (i=0;i<buffer[PHONE_SMSDeliver.SMSCNumber]+1;i++) {
1420 req[(*current)++]=buffer[PHONE_SMSDeliver.SMSCNumber+i];
1421 }
1422 req[(*current)++]=buffer[PHONE_SMSDeliver.firstbyte];
1423 for (i=0;i<((buffer[PHONE_SMSDeliver.Number]+1)/2+1)+1;i++) {
1424 req[(*current)++]=buffer[PHONE_SMSDeliver.Number+i];
1425 }
1426 req[(*current)++]=buffer[PHONE_SMSDeliver.TPPID];
1427 req[(*current)++]=buffer[PHONE_SMSDeliver.TPDCS];
1428 for(i=0;i<7;i++) req[(*current)++]=buffer[PHONE_SMSDeliver.DateTime+i];
1429 req[(*current)++]=buffer[PHONE_SMSDeliver.TPUDL];
1430 for(i=0;i<length;i++) req[(*current)++]=buffer[PHONE_SMSDeliver.Text+i];
1431 EncodeHexBin(hexreq, req, *current);
1432 *length2 = *current * 2;
1433 *current = *current - (req[PHONE_SMSDeliver.SMSCNumber]+1);
1434 } else {
1435 smprintf(s, "SMS Submit\n");
1436 error=PHONE_EncodeSMSFrame(s,message,buffer,PHONE_SMSSubmit,&length,true);
1437 if (error != ERR_NONE) return error;
1438 length = length - PHONE_SMSSubmit.Text;
1439 for (i=0;i<buffer[PHONE_SMSSubmit.SMSCNumber]+1;i++) {
1440 req[(*current)++]=buffer[PHONE_SMSSubmit.SMSCNumber+i];
1441 }
1442 req[(*current)++]=buffer[PHONE_SMSSubmit.firstbyte];
1443 req[(*current)++]=buffer[PHONE_SMSSubmit.TPMR];
1444 for (i=0;i<((buffer[PHONE_SMSSubmit.Number]+1)/2+1)+1;i++) {
1445 req[(*current)++]=buffer[PHONE_SMSSubmit.Number+i];
1446 }
1447 req[(*current)++]=buffer[PHONE_SMSSubmit.TPPID];
1448 req[(*current)++]=buffer[PHONE_SMSSubmit.TPDCS];
1449 req[(*current)++]=buffer[PHONE_SMSSubmit.TPVP];
1450 req[(*current)++]=buffer[PHONE_SMSSubmit.TPUDL];
1451 for(i=0;i<length;i++) req[(*current)++]=buffer[PHONE_SMSSubmit.Text+i];
1452 EncodeHexBin(hexreq, req, *current);
1453 *length2 = *current * 2;
1454 *current = *current - (req[PHONE_SMSSubmit.SMSCNumber]+1);
1455 }
1456 break;
1457 case SMS_AT_TXT:
1458 if (Priv->Manufacturer == 0) {
1459 error=ATGEN_GetManufacturer(s);
1460 if (error != ERR_NONE) return error;
1461 }
1462 if (Priv->Manufacturer != AT_Nokia) {
1463 if (message->Coding != SMS_Coding_Default) return ERR_NOTSUPPORTED;
1464 }
1465 error=PHONE_EncodeSMSFrame(s,message,req,PHONE_SMSDeliver,&i,true);
1466 if (error != ERR_NONE) return error;
1467 CopyUnicodeString(SMSC.Number,message->SMSC.Number);
1468 SMSC.Location=1;
1469 error=ATGEN_SetSMSC(s,&SMSC);
1470 if (error!=ERR_NONE) return error;
1471 sprintf(buffer, "AT+CSMP=%i,%i,%i,%i\r",
1472 req[PHONE_SMSDeliver.firstbyte],
1473 req[PHONE_SMSDeliver.TPVP],
1474 req[PHONE_SMSDeliver.TPPID],
1475 req[PHONE_SMSDeliver.TPDCS]);
1476 error=GSM_WaitFor (s, buffer, strlen(buffer), 0x00, 4, ID_SetSMSParameters);
1477 if (error==ERR_NOTSUPPORTED) {
1478 /* Nokia Communicator 9000i doesn't support <vp> parameter */
1479 sprintf(buffer, "AT+CSMP=%i,,%i,%i\r",
1480 req[PHONE_SMSDeliver.firstbyte],
1481 req[PHONE_SMSDeliver.TPPID],
1482 req[PHONE_SMSDeliver.TPDCS]);
1483 error=GSM_WaitFor (s, buffer, strlen(buffer), 0x00, 4, ID_SetSMSParameters);
1484 }
1485 if (error!=ERR_NONE) return error;
1486 switch (message->Coding) {
1487 case SMS_Coding_Default:
1488 /* If not SMS with UDH, it's as normal text */
1489 if (message->UDH.Type==UDH_NoUDH) {
1490 strcpy(hexreq,DecodeUnicodeString(message->Text));
1491 *length2 = UnicodeLength(message->Text);
1492 break;
1493 }
1494 case SMS_Coding_Unicode:
1495 case SMS_Coding_8bit:
1496 error=PHONE_EncodeSMSFrame(s,message,buffer,PHONE_SMSDeliver,current,true);
1497 if (error != ERR_NONE) return error;
1498 EncodeHexBin (hexreq, buffer+PHONE_SMSDeliver.Text, buffer[PHONE_SMSDeliver.TPUDL]);
1499 *length2 = buffer[PHONE_SMSDeliver.TPUDL] * 2;
1500 break;
1501 }
1502 break;
1503 }
1504 return ERR_NONE;
1505}
1506
1507GSM_Error ATGEN_AddSMS(GSM_StateMachine *s, GSM_SMSMessage *sms)
1508{
1509 GSM_Error error, error2;
1510 int state,Replies,reply, current, current2;
1511 unsigned char buffer[1000], hexreq[1000];
1512 GSM_Phone_Data *Phone = &s->Phone.Data;
1513 unsigned char *statetxt;
1514
1515 /* This phone supports only sent/unsent messages on SIM */
1516 if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMSONLYSENT)) {
1517 if (sms->Folder != 2) {
1518 smprintf(s, "This phone supports only folder = 2!\n");
1519 return ERR_NOTSUPPORTED;
1520 }
1521 }
1522
1523 sms->PDU = SMS_Submit;
1524 switch (sms->Folder) {
1525 case 1: sms->PDU = SMS_Deliver; /* Inbox SIM */
1526 error=ATGEN_SetSMSMemory(s, true);
1527 break;
1528 case 2: error=ATGEN_SetSMSMemory(s, true);/* Outbox SIM */
1529 break;
1530 case 3: sms->PDU = SMS_Deliver;
1531 error=ATGEN_SetSMSMemory(s, false);/* Inbox phone */
1532 break;
1533 case 4: error=ATGEN_SetSMSMemory(s, false);/* Outbox phone */
1534 break;
1535 default: return ERR_NOTSUPPORTED;
1536 }
1537 if (error!=ERR_NONE) return error;
1538
1539 error = ATGEN_MakeSMSFrame(s, sms, hexreq, &current, &current2);
1540 if (error != ERR_NONE) return error;
1541
1542 switch (Phone->Priv.ATGEN.SMSMode) {
1543 case SMS_AT_PDU:
1544 if (sms->PDU == SMS_Deliver) {
1545 state = 0;
1546 if (sms->State == SMS_Read || sms->State == SMS_Sent) state = 1;
1547 } else {
1548 state = 2;
1549 if (sms->State == SMS_Read || sms->State == SMS_Sent) state = 3;
1550 }
1551 /* Siemens M20 */
1552 if (IsPhoneFeatureAvailable(Phone->ModelInfo, F_M20SMS)) {
1553 /* No (good and 100% working) support for alphanumeric numbers */
1554 if (sms->Number[1]!='+' && (sms->Number[1]<'0' || sms->Number[1]>'9')) {
1555 EncodeUnicode(sms->Number,"123",3);
1556 error = ATGEN_MakeSMSFrame(s, sms, hexreq, &current, &current2);
1557 if (error != ERR_NONE) return error;
1558 }
1559 }
1560 sprintf(buffer, "AT+CMGW=%i,%i\r",current,state);
1561 break;
1562 case SMS_AT_TXT:
1563 if (sms->PDU == SMS_Deliver) {
1564 statetxt = "REC UNREAD";
1565 if (sms->State == SMS_Read || sms->State == SMS_Sent) statetxt = "REC READ";
1566 } else {
1567 statetxt = "STO UNSENT";
1568 if (sms->State == SMS_Read || sms->State == SMS_Sent) statetxt = "STO SENT";
1569 }
1570 /* Siemens M20 */
1571 if (IsPhoneFeatureAvailable(Phone->ModelInfo, F_M20SMS)) {
1572 /* No (good and 100% working) support for alphanumeric numbers */
1573 /* FIXME: Try to autodetect support for <stat> (statetxt) parameter although:
1574 * Siemens M20 supports +CMGW <stat> specification but on my model it just
1575 * reports ERROR (and <stat> is not respected).
1576 * Fortunately it will write "+CMGW: <index>\n" before and the message gets written
1577 */
1578 if (sms->Number[1]!='+' && (sms->Number[1]<'0' || sms->Number[1]>'9')) {
1579 sprintf(buffer, "AT+CMGW=\"123\",,\"%s\"\r",statetxt);
1580 } else {
1581 sprintf(buffer, "AT+CMGW=\"%s\",,\"%s\"\r",DecodeUnicodeString(sms->Number),statetxt);
1582 }
1583 } else {
1584 sprintf(buffer, "AT+CMGW=\"%s\",,\"%s\"\r",DecodeUnicodeString(sms->Number),statetxt);
1585 }
1586 }
1587
1588 Phone->SaveSMSMessage = sms;
1589
1590 for (reply=0;reply<s->ReplyNum;reply++) {
1591 if (reply!=0) {
1592 if (s->di.dl==DL_TEXT || s->di.dl==DL_TEXTALL || s->di.dl==DL_TEXTERROR ||
1593 s->di.dl==DL_TEXTDATE || s->di.dl==DL_TEXTALLDATE || s->di.dl==DL_TEXTERRORDATE) {
1594 smprintf(s, "[Retrying %i]\n", reply+1);
1595 }
1596 }
1597 s->Protocol.Data.AT.EditMode = true;
1598 Replies = s->ReplyNum;
1599 s->ReplyNum = 1;
1600 smprintf(s,"Waiting for modem prompt\n");
1601 error=GSM_WaitFor (s, buffer, strlen(buffer), 0x00, 3, ID_SaveSMSMessage);
1602 s->ReplyNum = Replies;
1603 if (error == ERR_NONE) {
1604 Phone->DispatchError = ERR_TIMEOUT;
1605 Phone->RequestID = ID_SaveSMSMessage;
1606 smprintf(s, "Saving SMS\n");
1607 error = s->Protocol.Functions->WriteMessage(s, hexreq, current2, 0x00);
1608 if (error!=ERR_NONE) return error;
1609 my_sleep(500);
1610 /* CTRL+Z ends entering */
1611 error = s->Protocol.Functions->WriteMessage(s, "\x1A", 1, 0x00);
1612 if (error!=ERR_NONE) return error;
1613 error = GSM_WaitForOnce(s, NULL, 0x00, 0x00, 4);
1614 if (error != ERR_TIMEOUT) return error;
1615 } else {
1616 smprintf(s, "Escaping SMS mode\n");
1617 error2 = s->Protocol.Functions->WriteMessage(s, "\x1B\r", 2, 0x00);
1618 if (error2 != ERR_NONE) return error2;
1619 return error;
1620 }
1621 }
1622
1623 return Phone->DispatchError;
1624}
1625
1626GSM_Error ATGEN_ReplySendSMS(GSM_Protocol_Message msg, GSM_StateMachine *s)
1627{
1628 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1629 char *start;
1630
1631 if (s->Protocol.Data.AT.EditMode) {
1632 if (s->Phone.Data.Priv.ATGEN.ReplyState != AT_Reply_SMSEdit) {
1633 return ERR_UNKNOWN;
1634 }
1635 s->Protocol.Data.AT.EditMode = false;
1636 return ERR_NONE;
1637 }
1638
1639 switch (Priv->ReplyState) {
1640 case AT_Reply_OK:
1641 smprintf(s, "SMS sent OK\n");
1642 if (s->User.SendSMSStatus!=NULL) {
1643 start = strstr(msg.Buffer, "+CMGW: ");
1644 if (start != NULL) {
1645 s->User.SendSMSStatus(s->CurrentConfig->Device,0,atoi(start+7));
1646 } else {
1647 s->User.SendSMSStatus(s->CurrentConfig->Device,0,0);
1648 }
1649 }
1650 return ERR_NONE;
1651 case AT_Reply_CMSError:
1652 smprintf(s, "Error %i\n",Priv->ErrorCode);
1653 if (s->User.SendSMSStatus!=NULL) s->User.SendSMSStatus(s->CurrentConfig->Device,Priv->ErrorCode,0);
1654 return ATGEN_HandleCMSError(s);
1655 case AT_Reply_Error:
1656 return ERR_UNKNOWN;
1657 default:
1658 return ERR_UNKNOWNRESPONSE;
1659 }
1660}
1661
1662GSM_Error ATGEN_SendSMS(GSM_StateMachine *s, GSM_SMSMessage *sms)
1663{
1664 GSM_Error error,error2;
1665 int current, current2, Replies;
1666 unsigned char buffer[1000], hexreq[1000];
1667 GSM_Phone_Data *Phone = &s->Phone.Data;
1668
1669 if (sms->PDU == SMS_Deliver) sms->PDU = SMS_Submit;
1670
1671 error = ATGEN_MakeSMSFrame(s, sms, hexreq, &current, &current2);
1672 if (error != ERR_NONE) return error;
1673
1674 switch (Phone->Priv.ATGEN.SMSMode) {
1675 case SMS_AT_PDU:
1676 sprintf(buffer, "AT+CMGS=%i\r",current);
1677 break;
1678 case SMS_AT_TXT:
1679 sprintf(buffer, "AT+CMGS=\"%s\"\r",DecodeUnicodeString(sms->Number));
1680 }
1681
1682 s->Protocol.Data.AT.EditMode = true;
1683 Replies = s->ReplyNum;
1684 s->ReplyNum = 1;
1685 smprintf(s,"Waiting for modem prompt\n");
1686 error=GSM_WaitFor (s, buffer, strlen(buffer), 0x00, 3, ID_IncomingFrame);
1687 s->ReplyNum = Replies;
1688 if (error == ERR_NONE) {
1689 smprintf(s, "Sending SMS\n");
1690 error = s->Protocol.Functions->WriteMessage(s, hexreq, current2, 0x00);
1691 if (error!=ERR_NONE) return error;
1692 my_sleep(500);
1693 /* CTRL+Z ends entering */
1694 error=s->Protocol.Functions->WriteMessage(s, "\x1A", 1, 0x00);
1695 my_sleep(100);
1696 return error;
1697 } else {
1698 smprintf(s, "Escaping SMS mode\n");
1699 error2=s->Protocol.Functions->WriteMessage(s, "\x1B\r", 2, 0x00);
1700 if (error2 != ERR_NONE) return error2;
1701 }
1702 return error;
1703}
1704
1705GSM_Error ATGEN_SendSavedSMS(GSM_StateMachine *s, int Folder, int Location)
1706{
1707 GSM_Error error;
1708 int location;
1709 unsigned charsmsfolder;
1710 unsigned charreq[100];
1711 GSM_MultiSMSMessagemsms;
1712
1713 msms.Number = 0;
1714 msms.SMS[0].Folder = Folder;
1715 msms.SMS[0].Location = Location;
1716
1717 /* By reading SMS we check if it is really inbox/outbox */
1718 error = ATGEN_GetSMS(s, &msms);
1719 if (error != ERR_NONE) return error;
1720
1721 /* Can not send from other folder that outbox */
1722 if (msms.SMS[0].Folder != 2 && msms.SMS[0].Folder != 4) return ERR_NOTSUPPORTED;
1723
1724 error=ATGEN_GetSMSLocation(s, &msms.SMS[0], &smsfolder, &location);
1725 if (error != ERR_NONE) return error;
1726
1727 sprintf(req, "AT+CMSS=%i\r",location);
1728 return s->Protocol.Functions->WriteMessage(s, req, strlen(req), 0x00);
1729}
1730
1731GSM_Error ATGEN_ReplyGetDateTime_Alarm(GSM_Protocol_Message msg, GSM_StateMachine *s)
1732{
1733 int current= 19;
1734 GSM_Phone_Data *Data = &s->Phone.Data;
1735
1736 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
1737 case AT_Reply_OK:
1738 if (msg.Buffer[current]==0x0d || msg.Buffer[current-1]==0x0d) {
1739 smprintf(s, "Not set in phone\n");
1740 return ERR_EMPTY;
1741 } else {
1742 if (Data->RequestID == ID_GetDateTime) {
1743 ATGEN_DecodeDateTime(Data->DateTime, msg.Buffer+current);
1744 } else {
1745 ATGEN_DecodeDateTime(&(Data->Alarm->DateTime), msg.Buffer+current);
1746 }
1747 return ERR_NONE;
1748 }
1749 case AT_Reply_Error:
1750 return ERR_NOTSUPPORTED;
1751 case AT_Reply_CMSError:
1752 return ATGEN_HandleCMSError(s);
1753 default:
1754 break;
1755 }
1756 return ERR_UNKNOWNRESPONSE;
1757}
1758
1759GSM_Error ATGEN_GetDateTime(GSM_StateMachine *s, GSM_DateTime *date_time)
1760{
1761 s->Phone.Data.DateTime=date_time;
1762 smprintf(s, "Getting date & time\n");
1763 return GSM_WaitFor (s, "AT+CCLK?\r", 9, 0x00, 4, ID_GetDateTime);
1764}
1765
1766GSM_Error ATGEN_SetDateTime(GSM_StateMachine *s, GSM_DateTime *date_time)
1767{
1768 char req[128];
1769
1770 sprintf(req, "AT+CCLK=\"%02i/%02i/%02i,%02i:%02i:%02i+00\"\r",
1771 date_time->Year-2000,date_time->Month,date_time->Day,
1772 date_time->Hour,date_time->Minute,date_time->Second);
1773
1774 smprintf(s, "Setting date & time\n");
1775 return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_SetDateTime);
1776}
1777
1778GSM_Error ATGEN_GetAlarm(GSM_StateMachine *s, GSM_Alarm *alarm)
1779{
1780 if (alarm->Location != 1) return ERR_NOTSUPPORTED;
1781
1782 alarm->Repeating = true;
1783 alarm->Text[0] = 0; alarm->Text[1] = 0;
1784
1785 s->Phone.Data.Alarm = alarm;
1786 smprintf(s, "Getting alarm\n");
1787 return GSM_WaitFor (s, "AT+CALA?\r", 9, 0x00, 4, ID_GetAlarm);
1788}
1789
1790GSM_Error ATGEN_ReplyGetSMSC(GSM_Protocol_Message msg, GSM_StateMachine *s)
1791{
1792 GSM_SMSC *SMSC = s->Phone.Data.SMSC;
1793 int current;
1794 int len;
1795 unsigned char buffer[100];
1796
1797 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
1798 case AT_Reply_OK:
1799 smprintf(s, "SMSC info received\n");
1800
1801 current = 0;
1802 while (msg.Buffer[current]!='"') current++;
1803
1804 /* SMSC number */
1805 /* FIXME: support for all formats */
1806 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1807 /*
1808 * Some phones return this as unicode encoded when they are
1809 * switched to UCS2 mode, so we try to solve this correctly.
1810 */
1811 len = strlen(buffer + 1) - 1;
1812 buffer[len + 1] = 0;
1813 if ((len > 20) && (len % 4 == 0) && (strchr(buffer + 1, '+') == NULL)) {
1814 /* This is probably unicode encoded number */
1815 DecodeHexUnicode(SMSC->Number,buffer + 1,len);
1816 } else {
1817 EncodeUnicode(SMSC->Number,buffer + 1,len);
1818 }
1819 smprintf(s, "Number: \"%s\"\n",DecodeUnicodeString(SMSC->Number));
1820
1821 /* Format of SMSC number */
1822 current+=ATGEN_ExtractOneParameter(msg.Buffer+current, buffer);
1823 smprintf(s, "Format %s\n",buffer);
1824 /* International number */
1825 if (!strcmp(buffer,"145")) {
1826 sprintf(buffer+1,"%s",DecodeUnicodeString(SMSC->Number));
1827 if (strlen(buffer+1)!=0 && buffer[1] != '+') {
1828 /* Sony Ericsson issue */
1829 /* International number is without + */
1830 buffer[0] = '+';
1831 EncodeUnicode(SMSC->Number,buffer,strlen(buffer));
1832 }
1833 }
1834
1835 SMSC->Format = SMS_FORMAT_Text;
1836 SMSC->Validity.Format = SMS_Validity_RelativeFormat;
1837 SMSC->Validity.Relative= SMS_VALID_Max_Time;
1838 SMSC->Name[0] = 0;
1839 SMSC->Name[1] = 0;
1840 SMSC->DefaultNumber[0]= 0;
1841 SMSC->DefaultNumber[1]= 0;
1842 return ERR_NONE;
1843 case AT_Reply_CMSError:
1844 return ATGEN_HandleCMSError(s);
1845 default:
1846 break;
1847 }
1848 return ERR_UNKNOWNRESPONSE;
1849}
1850
1851GSM_Error ATGEN_GetSMSC(GSM_StateMachine *s, GSM_SMSC *smsc)
1852{
1853 if (smsc->Location==0x00 || smsc->Location!=0x01) return ERR_INVALIDLOCATION;
1854
1855 s->Phone.Data.SMSC=smsc;
1856 smprintf(s, "Getting SMSC\n");
1857 return GSM_WaitFor (s, "AT+CSCA?\r", 9, 0x00, 4, ID_GetSMSC);
1858}
1859
1860GSM_Error ATGEN_ReplyGetNetworkLAC_CID(GSM_Protocol_Message msg, GSM_StateMachine *s)
1861{
1862 GSM_NetworkInfo *NetworkInfo = s->Phone.Data.NetworkInfo;
1863 GSM_Lines Lines;
1864 int i=0;
1865 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1866 char *answer;
1867
1868 if (s->Phone.Data.RequestID == ID_IncomingFrame) {
1869 smprintf(s, "Incoming LAC & CID info\n");
1870 return ERR_NONE;
1871 }
1872
1873 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
1874 case AT_Reply_OK:
1875 break;
1876 case AT_Reply_CMSError:
1877 return ATGEN_HandleCMSError(s);
1878 default:
1879 return ERR_UNKNOWNRESPONSE;
1880 }
1881
1882 SplitLines(GetLineString(msg.Buffer,Priv->Lines,2),
1883 strlen(GetLineString(msg.Buffer,Priv->Lines,2)),
1884 &Lines, ",", 1, true);
1885
1886 /* Find number of lines */
1887 while (Lines.numbers[i*2+1] != 0) {
1888 /* FIXME: handle special chars correctly */
1889 smprintf(s, "%i \"%s\"\n",i+1,GetLineString(GetLineString(msg.Buffer,Priv->Lines,2),Lines,i+1));
1890 i++;
1891 }
1892
1893 smprintf(s, "Network LAC & CID & state received\n");
1894 answer = GetLineString(GetLineString(msg.Buffer,Priv->Lines,2),Lines,2);
1895 while (*answer == 0x20) answer++;
1896#ifdef DEBUG
1897 switch (answer[0]) {
1898 case '0': smprintf(s, "Not registered into any network. Not searching for network\n"); break;
1899 case '1': smprintf(s, "Home network\n"); break;
1900 case '2': smprintf(s, "Not registered into any network. Searching for network\n"); break;
1901 case '3': smprintf(s, "Registration denied\n"); break;
1902 case '4': smprintf(s, "Unknown\n"); break;
1903 case '5': smprintf(s, "Registered in roaming network\n"); break;
1904 default : smprintf(s, "Unknown\n");
1905 }
1906#endif
1907 switch (answer[0]) {
1908 case '0': NetworkInfo->State = GSM_NoNetwork; break;
1909 case '1': NetworkInfo->State = GSM_HomeNetwork; break;
1910 case '2': NetworkInfo->State = GSM_RequestingNetwork; break;
1911 case '3': NetworkInfo->State = GSM_RegistrationDenied;break;
1912 case '4': NetworkInfo->State = GSM_NetworkStatusUnknown;break;
1913 case '5': NetworkInfo->State = GSM_RoamingNetwork; break;
1914 default : NetworkInfo->State = GSM_NetworkStatusUnknown;break;
1915 }
1916 if (NetworkInfo->State == GSM_HomeNetwork ||
1917 NetworkInfo->State == GSM_RoamingNetwork) {
1918 memset(NetworkInfo->CID,0,4);
1919 memset(NetworkInfo->LAC,0,4);
1920
1921 if (Lines.numbers[3*2+1]==0) return ERR_NONE;
1922
1923 answer = GetLineString(GetLineString(msg.Buffer,Priv->Lines,2),Lines,3);
1924 while (*answer == 0x20) answer++;
1925 sprintf(NetworkInfo->CID,"%c%c%c%c", answer[1], answer[2], answer[3], answer[4]);
1926
1927 answer = GetLineString(GetLineString(msg.Buffer,Priv->Lines,2),Lines,4);
1928 while (*answer == 0x20) answer++;
1929 sprintf(NetworkInfo->LAC,"%c%c%c%c", answer[1], answer[2], answer[3], answer[4]);
1930
1931 smprintf(s, "CID : %s\n",NetworkInfo->CID);
1932 smprintf(s, "LAC : %s\n",NetworkInfo->LAC);
1933 }
1934 return ERR_NONE;
1935}
1936
1937GSM_Error ATGEN_ReplyGetNetworkCode(GSM_Protocol_Message msg, GSM_StateMachine *s)
1938{
1939 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
1940 GSM_NetworkInfo *NetworkInfo = s->Phone.Data.NetworkInfo;
1941
1942 switch (Priv->ReplyState) {
1943 case AT_Reply_OK:
1944 smprintf(s, "Network code received\n");
1945 if (Priv->Manufacturer == AT_Falcom) {
1946 NetworkInfo->NetworkCode[0] = msg.Buffer[22];
1947 NetworkInfo->NetworkCode[1] = msg.Buffer[23];
1948 NetworkInfo->NetworkCode[2] = msg.Buffer[24];
1949 NetworkInfo->NetworkCode[3] = ' ';
1950 NetworkInfo->NetworkCode[4] = msg.Buffer[25];
1951 NetworkInfo->NetworkCode[5] = msg.Buffer[26];
1952 } else {
1953 NetworkInfo->NetworkCode[0] = msg.Buffer[23];
1954 NetworkInfo->NetworkCode[1] = msg.Buffer[24];
1955 NetworkInfo->NetworkCode[2] = msg.Buffer[25];
1956 NetworkInfo->NetworkCode[3] = ' ';
1957 NetworkInfo->NetworkCode[4] = msg.Buffer[26];
1958 NetworkInfo->NetworkCode[5] = msg.Buffer[27];
1959 }
1960 NetworkInfo->NetworkCode[6] = 0;
1961 smprintf(s, " Network code : %s\n", NetworkInfo->NetworkCode);
1962 smprintf(s, " Network name for Gammu : %s ",
1963 DecodeUnicodeString(GSM_GetNetworkName(NetworkInfo->NetworkCode)));
1964 smprintf(s, "(%s)\n",DecodeUnicodeString(GSM_GetCountryName(NetworkInfo->NetworkCode)));
1965 return ERR_NONE;
1966 case AT_Reply_CMSError:
1967 return ATGEN_HandleCMSError(s);
1968 default:
1969 break;
1970 }
1971 return ERR_UNKNOWNRESPONSE;
1972}
1973
1974GSM_Error ATGEN_GetNetworkInfo(GSM_StateMachine *s, GSM_NetworkInfo *netinfo)
1975{
1976 GSM_Error error;
1977
1978 s->Phone.Data.NetworkInfo=netinfo;
1979
1980 netinfo->NetworkName[0] = 0;
1981 netinfo->NetworkName[1] = 0;
1982 netinfo->NetworkCode[0] = 0;
1983
1984 smprintf(s, "Enable full network info\n");
1985 error=GSM_WaitFor(s, "AT+CREG=2\r", 10, 0x00, 4, ID_GetNetworkInfo);
1986 if ((error != ERR_NONE) &&
1987 (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Siemens) &&
1988 (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Ericsson)) return error;
1989
1990 smprintf(s, "Getting network LAC and CID and state\n");
1991 error=GSM_WaitFor(s, "AT+CREG?\r", 9, 0x00, 4, ID_GetNetworkInfo);
1992 if (error != ERR_NONE) return error;
1993
1994 if (netinfo->State == GSM_HomeNetwork || netinfo->State == GSM_RoamingNetwork) {
1995 smprintf(s, "Setting short network name format\n");
1996 error=GSM_WaitFor(s, "AT+COPS=3,2\r", 12, 0x00, 4, ID_GetNetworkInfo);
1997
1998 error=ATGEN_GetManufacturer(s);
1999 if (error != ERR_NONE) return error;
2000
2001 smprintf(s, "Getting network code\n");
2002 error=GSM_WaitFor(s, "AT+COPS?\r", 9, 0x00, 4, ID_GetNetworkInfo);
2003 }
2004 return error;
2005}
2006
2007GSM_Error ATGEN_ReplyGetPBKMemories(GSM_Protocol_Message msg, GSM_StateMachine *s)
2008{
2009 smprintf(s, "PBK memories received\n");
2010 if (strlen(msg.Buffer) > AT_PBK_MAX_MEMORIES) {
2011 smprintf(s, "ERROR: Too long phonebook memories information received! (Recevided %d, AT_PBK_MAX_MEMORIES is %d\n", strlen(msg.Buffer), AT_PBK_MAX_MEMORIES);
2012 return ERR_MOREMEMORY;
2013 }
2014 memcpy(s->Phone.Data.Priv.ATGEN.PBKMemories,msg.Buffer,strlen(msg.Buffer));
2015 return ERR_NONE;
2016}
2017
2018GSM_Error ATGEN_SetPBKMemory(GSM_StateMachine *s, GSM_MemoryType MemType)
2019{
2020 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2021 char req[] = "AT+CPBS=\"XX\"\r";
2022 GSM_Error error;
2023
2024 if (Priv->PBKMemory == MemType) return ERR_NONE;
2025
2026 /* Zero values that are for actual memory */
2027 Priv->MemorySize = 0;
2028 Priv->FirstMemoryEntry = 0;
2029 Priv->NextMemoryEntry = 0;
2030 Priv->TextLength = 0;
2031 Priv->NumberLength = 0;
2032
2033 if (Priv->PBKMemories[0] == 0) {
2034 error=GSM_WaitFor (s, "AT+CPBS=?\r", 10, 0x00, 3, ID_SetMemoryType);
2035 if (error != ERR_NONE) return error;
2036 }
2037
2038 switch (MemType) {
2039 case MEM_SM:
2040 req[9] = 'S'; req[10] = 'M';
2041 break;
2042 case MEM_ME:
2043 if (strstr(Priv->PBKMemories,"ME")==NULL) return ERR_NOTSUPPORTED;
2044 req[9] = 'M'; req[10] = 'E';
2045 break;
2046 case MEM_RC:
2047 if (strstr(Priv->PBKMemories,"RC")==NULL) return ERR_NOTSUPPORTED;
2048 req[9] = 'R'; req[10] = 'C';
2049 break;
2050 case MEM_MC:
2051 if (strstr(Priv->PBKMemories,"MC")==NULL) return ERR_NOTSUPPORTED;
2052 req[9] = 'M'; req[10] = 'C';
2053 break;
2054 case MEM_ON:
2055 if (strstr(Priv->PBKMemories,"ON")==NULL) return ERR_NOTSUPPORTED;
2056 req[9] = 'O'; req[10] = 'N';
2057 break;
2058 case MEM_FD:
2059 if (strstr(Priv->PBKMemories,"FD")==NULL) return ERR_NOTSUPPORTED;
2060 req[9] = 'F'; req[10] = 'D';
2061 break;
2062 case MEM_DC:
2063 if (strstr(Priv->PBKMemories,"DC")!=NULL) {
2064 req[9] = 'D'; req[10] = 'C';
2065 break;
2066 }
2067 if (strstr(Priv->PBKMemories,"LD")!=NULL) {
2068 req[9] = 'L'; req[10] = 'D';
2069 break;
2070 }
2071 return ERR_NOTSUPPORTED;
2072 break;
2073 default:
2074 return ERR_NOTSUPPORTED;
2075 }
2076
2077 smprintf(s, "Setting memory type\n");
2078 error=GSM_WaitFor (s, req, 13, 0x00, 3, ID_SetMemoryType);
2079 if (error == ERR_NONE) Priv->PBKMemory = MemType;
2080 return error;
2081}
2082
2083GSM_Error ATGEN_ReplyGetCPBSMemoryStatus(GSM_Protocol_Message msg, GSM_StateMachine *s)
2084{
2085 GSM_MemoryStatus*MemoryStatus = s->Phone.Data.MemoryStatus;
2086 char *start;
2087
2088 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
2089 case AT_Reply_OK:
2090 smprintf(s, "Memory status received\n");
2091 MemoryStatus->MemoryUsed = 0;
2092 MemoryStatus->MemoryFree = 0;
2093 start = strchr(msg.Buffer, ',');
2094 if (start) {
2095 start++;
2096 MemoryStatus->MemoryUsed = atoi(start);
2097 start = strchr(start, ',');
2098 if (start) {
2099 start++;
2100 MemoryStatus->MemoryFree = atoi(start) - MemoryStatus->MemoryUsed;
2101 return ERR_NONE;
2102 } else return ERR_UNKNOWN;
2103 } else return ERR_UNKNOWN;
2104 case AT_Reply_CMSError:
2105 return ATGEN_HandleCMSError(s);
2106 default:
2107 break;
2108 }
2109 return ERR_UNKNOWNRESPONSE;
2110}
2111
2112GSM_Error ATGEN_ReplyGetCPBRMemoryInfo(GSM_Protocol_Message msg, GSM_StateMachine *s)
2113{
2114 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2115 char *pos;
2116
2117 switch (Priv->ReplyState) {
2118 case AT_Reply_OK:
2119 smprintf(s, "Memory info received\n");
2120 /* Parse +CPBR: (first-last),max_number_len,max_name_len */
2121
2122 /* Parse first location */
2123 pos = strchr(msg.Buffer, '(');
2124 if (!pos) return ERR_UNKNOWN;
2125 pos++;
2126 Priv->FirstMemoryEntry = atoi(pos);
2127
2128 /* Parse last location*/
2129 pos = strchr(pos, '-');
2130 if (!pos) return ERR_UNKNOWN;
2131 pos++;
2132 Priv->MemorySize = atoi(pos) + 1 - Priv->FirstMemoryEntry;
2133
2134 /* Parse number length*/
2135 pos = strchr(pos, ',');
2136 if (!pos) return ERR_UNKNOWN;
2137 pos++;
2138 Priv->NumberLength = atoi(pos);
2139
2140 /* Parse text length*/
2141 pos = strchr(pos, ',');
2142 if (!pos) return ERR_UNKNOWN;
2143 pos++;
2144 Priv->TextLength = atoi(pos);
2145
2146 return ERR_NONE;
2147 case AT_Reply_Error:
2148 return ERR_UNKNOWN;
2149 case AT_Reply_CMSError:
2150 return ATGEN_HandleCMSError(s);
2151 default:
2152 return ERR_UNKNOWNRESPONSE;
2153 }
2154}
2155
2156GSM_Error ATGEN_ReplyGetCPBRMemoryStatus(GSM_Protocol_Message msg, GSM_StateMachine *s)
2157{
2158 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2159 GSM_MemoryStatus*MemoryStatus = s->Phone.Data.MemoryStatus;
2160 int line=0;
2161 char *str;
2162 int cur;
2163
2164 switch (Priv->ReplyState) {
2165 case AT_Reply_OK:
2166 smprintf(s, "Memory entries received\n");
2167 /* Walk through lines with +CPBR: */
2168 while (Priv->Lines.numbers[line*2+1]!=0) {
2169 str = GetLineString(msg.Buffer,Priv->Lines,line+1);
2170 if (strncmp(str, "+CPBR: ", 7) == 0) {
2171 MemoryStatus->MemoryUsed++;
2172 if (sscanf(str, "+CPBR: %d,", &cur) == 1) {
2173 cur -= Priv->FirstMemoryEntry - 1;
2174 if (cur == Priv->NextMemoryEntry || Priv->NextMemoryEntry == 0)
2175 Priv->NextMemoryEntry = cur + 1;
2176 }
2177 }
2178 line++;
2179 }
2180 return ERR_NONE;
2181 case AT_Reply_Error:
2182 return ERR_UNKNOWN;
2183 case AT_Reply_CMSError:
2184 return ATGEN_HandleCMSError(s);
2185 default:
2186 return ERR_UNKNOWNRESPONSE;
2187 }
2188}
2189
2190GSM_Error ATGEN_GetMemoryInfo(GSM_StateMachine *s, GSM_MemoryStatus *Status, GSM_AT_NeededMemoryInfo NeededInfo)
2191{
2192 GSM_Error error;
2193 char req[20];
2194 int start;
2195 int end;
2196 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2197
2198 smprintf(s, "Getting memory information\n");
2199
2200 Priv->MemorySize = 0;
2201 Priv->TextLength = 0;
2202 Priv->NumberLength = 0;
2203
2204 error = GSM_WaitFor (s, "AT+CPBR=?\r", 10, 0x00, 4, ID_GetMemoryStatus);
2205 if (error != ERR_NONE) return error;
2206 if (NeededInfo == AT_Total || NeededInfo == AT_Sizes || NeededInfo == AT_First) return ERR_NONE;
2207
2208 smprintf(s, "Getting memory status by reading values\n");
2209
2210 s->Phone.Data.MemoryStatus= Status;
2211 Status->MemoryUsed = 0;
2212 Status->MemoryFree = 0;
2213 start = Priv->FirstMemoryEntry;
2214 Priv->NextMemoryEntry = 0;
2215 while (1) {
2216 end= start + 20;
2217 if (end > Priv->MemorySize) end = Priv->MemorySize;
2218 sprintf(req, "AT+CPBR=%i,%i\r", start, end);
2219 error= GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetMemoryStatus);
2220 if (error != ERR_NONE) return error;
2221 if (NeededInfo == AT_NextEmpty && Priv->NextMemoryEntry != 0 && Priv->NextMemoryEntry != end + 1) return ERR_NONE;
2222 if (end == Priv->MemorySize) {
2223 Status->MemoryFree = Priv->MemorySize - Status->MemoryUsed;
2224 return ERR_NONE;
2225 }
2226 start = end + 1;
2227 }
2228}
2229
2230GSM_Error ATGEN_GetMemoryStatus(GSM_StateMachine *s, GSM_MemoryStatus *Status)
2231{
2232 GSM_Error error;
2233
2234 error = ATGEN_SetPBKMemory(s, Status->MemoryType);
2235 if (error != ERR_NONE) return error;
2236
2237 s->Phone.Data.MemoryStatus=Status;
2238
2239 /* in some phones doesn't work or doesn't return memory status inside */
2240 /* Some workaround for buggy mobile, that hangs after "AT+CPBS?" for other
2241 * memory than SM.
2242 */
2243 if (!IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_BROKENCPBS) || (Status->MemoryType == MEM_SM)) {
2244 smprintf(s, "Getting memory status\n");
2245 error=GSM_WaitFor (s, "AT+CPBS?\r", 9, 0x00, 4, ID_GetMemoryStatus);
2246 if (error == ERR_NONE) return ERR_NONE;
2247 }
2248
2249 return ATGEN_GetMemoryInfo(s, Status, AT_Status);
2250}
2251
2252GSM_Error ATGEN_SetPBKCharset(GSM_StateMachine *s, bool PreferUnicode)
2253{
2254 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
2255 GSM_Error error;
2256
2257 /* Have we already selected something? */
2258 if (Priv->PBKCharset!=0) {
2259 /* If we want unicode charset and we have it already or setting of it
2260 * failed, we have nothing to do. */
2261 if (PreferUnicode && (Priv->PBKCharset==AT_PBK_UCS2 || Priv->UCS2CharsetFailed)) return ERR_NONE;
2262
2263 /* If we don't need unicode charset and we have some (or have unicode
2264 * charset when other failed), we have nothing to do. */
2265 if (!PreferUnicode && (Priv->PBKCharset!=AT_PBK_UCS2 || Priv->NonUCS2CharsetFailed)) return ERR_NONE;
2266 }
2267
2268 error=ATGEN_GetManufacturer(s);
2269 if (error != ERR_NONE) return error;
2270
2271 if (PreferUnicode && !Priv->UCS2CharsetFailed) {
2272 smprintf(s, "Setting charset to UCS2\n");
2273 error=GSM_WaitFor (s, "AT+CSCS=\"UCS2\"\r", 15, 0x00, 3, ID_SetMemoryCharset);
2274 if (error == ERR_NONE) {
2275 Priv->PBKCharset = AT_PBK_UCS2;
2276 return ERR_NONE;
2277 } else {
2278 Priv->UCS2CharsetFailed = true;
2279 }
2280 }
2281
2282 smprintf(s, "Setting charset to HEX\n");
2283 error=GSM_WaitFor (s, "AT+CSCS=\"HEX\"\r", 14, 0x00, 3, ID_SetMemoryCharset);
2284 /* Falcom replies OK for HEX mode and send everything
2285 * in normal format */
2286 if (error == ERR_NONE && Priv->Manufacturer != AT_Falcom) {
2287 Priv->PBKCharset = AT_PBK_HEX;
2288 return ERR_NONE;
2289 }
2290
2291 smprintf(s, "Setting charset to GSM\n");
2292 error=GSM_WaitFor (s, "AT+CSCS=\"GSM\"\r", 14, 0x00, 3, ID_SetMemoryCharset);
2293 if (error == ERR_NONE) {
2294 Priv->PBKCharset = AT_PBK_GSM;
2295 return ERR_NONE;
2296 }
2297
2298 if (!Priv->UCS2CharsetFailed) {
2299 Priv->NonUCS2CharsetFailed = true;
2300 smprintf(s, "Setting charset to UCS2\n");
2301 error=GSM_WaitFor (s, "AT+CSCS=\"UCS2\"\r", 15, 0x00, 3, ID_SetMemoryCharset);
2302 if (error == ERR_NONE) {
2303 Priv->PBKCharset = AT_PBK_UCS2;
2304 return ERR_NONE;
2305 } else {
2306 Priv->UCS2CharsetFailed = true;
2307 }
2308 }
2309
2310 return error;
2311}
2312
2313GSM_Error ATGEN_ReplyGetMemory(GSM_Protocol_Message msg, GSM_StateMachine *s)
2314{
2315 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2316 GSM_MemoryEntry *Memory = s->Phone.Data.Memory;
2317 char *pos;
2318 unsigned char buffer[500],buffer2[500];
2319 int len;
2320
2321 switch (Priv->ReplyState) {
2322 case AT_Reply_OK:
2323 smprintf(s, "Phonebook entry received\n");
2324 Memory->EntriesNum = 0;
2325 if (Priv->Lines.numbers[4]==0) return ERR_EMPTY;
2326 pos = strstr(msg.Buffer, "+CPBR:");
2327 if (pos == NULL) return ERR_UNKNOWN;
2328 /* Go after +CPBR: */
2329 pos += 6;
2330
2331 /* Location */
2332 while (*pos && !isdigit(*pos)) pos++;
2333 Memory->Location = atoi(pos) + 1 - Priv->FirstMemoryEntry;
2334 smprintf(s, "Location: %d\n", Memory->Location);
2335
2336 /* Number */
2337 while (*pos != '"') pos++;
2338 pos += ATGEN_ExtractOneParameter(pos, buffer);
2339 smprintf(s, "Number: %s\n",buffer);
2340 Memory->EntriesNum++;
2341 Memory->Entries[0].EntryType = PBK_Number_General;
2342 Memory->Entries[0].VoiceTag = 0;
2343 Memory->Entries[0].SMSList[0] = 0;
2344
2345 len = strlen(buffer + 1) - 1;
2346 if (Priv->PBKCharset == AT_PBK_HEX && (len > 10) && (len % 2 == 0) && (strchr(buffer + 1, '+') == NULL)) {
2347 /* This is probably hex encoded number */
2348 DecodeHexBin(buffer2, buffer+1, len);
2349 DecodeDefault(Memory->Entries[0].Text ,buffer2, strlen(buffer2), false, NULL);
2350 } else if (Priv->PBKCharset == AT_PBK_UCS2 && (len > 20) && (len % 4 == 0) && (strchr(buffer + 1, '+') == NULL)) {
2351 /* This is probably unicode encoded number */
2352 DecodeHexUnicode(Memory->Entries[0].Text, buffer + 1,len);
2353 } else {
2354 EncodeUnicode(Memory->Entries[0].Text, buffer + 1, len);
2355 }
2356
2357 /* Number format */
2358 pos += ATGEN_ExtractOneParameter(pos, buffer);
2359 smprintf(s, "Number format: %s\n",buffer);
2360
2361 /* International number */
2362 if (!strcmp(buffer,"145")) {
2363 sprintf(buffer+1,"%s",DecodeUnicodeString(Memory->Entries[0].Text));
2364 if (strlen(buffer+1)!=0 && buffer[1] != '+') {
2365 /* Sony Ericsson issue */
2366 /* International number is without + */
2367 buffer[0] = '+';
2368 EncodeUnicode(Memory->Entries[0].Text,buffer,strlen(buffer));
2369 }
2370 }
2371
2372 /* Name */
2373 pos += ATGEN_ExtractOneParameter(pos, buffer);
2374 smprintf(s, "Name text: %s\n",buffer);
2375 Memory->EntriesNum++;
2376 Memory->Entries[1].EntryType=PBK_Text_Name;
2377 switch (Priv->PBKCharset) {
2378 case AT_PBK_HEX:
2379 DecodeHexBin(buffer2,buffer+1,strlen(buffer)-2);
2380 DecodeDefault(Memory->Entries[1].Text,buffer2,strlen(buffer2),false,NULL);
2381 break;
2382 case AT_PBK_GSM:
2383 DecodeDefault(Memory->Entries[1].Text,buffer+1,strlen(buffer)-2,false,NULL);
2384 break;
2385 case AT_PBK_UCS2:
2386 DecodeHexUnicode(Memory->Entries[1].Text,buffer+1,strlen(buffer+1) - 1);
2387 break;
2388 }
2389 return ERR_NONE;
2390 case AT_Reply_CMEError:
2391 return ATGEN_HandleCMEError(s);
2392 case AT_Reply_Error:
2393 smprintf(s, "Error - too high location ?\n");
2394 return ERR_INVALIDLOCATION;
2395 case AT_Reply_CMSError:
2396 return ATGEN_HandleCMSError(s);
2397 default:
2398 break;
2399 }
2400 return ERR_UNKNOWNRESPONSE;
2401}
2402
2403GSM_Error ATGEN_PrivGetMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry, int endlocation)
2404{
2405 GSM_Error error;
2406 unsigned char req[20];
2407 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
2408
2409 if (entry->Location==0x00) return ERR_INVALIDLOCATION;
2410
2411 if (entry->MemoryType == MEM_ME) {
2412 if (Priv->PBKSBNR == 0) {
2413 sprintf(req, "AT^SBNR=?\r");
2414 smprintf(s, "Checking availablity of SBNR\n");
2415 error=GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetMemory);
2416 switch (error) {
2417 case ERR_NONE:
2418 Priv->PBKSBNR = AT_SBNR_AVAILABLE;
2419 break;
2420 case ERR_UNKNOWN:
2421 case ERR_NOTSUPPORTED:
2422 Priv->PBKSBNR = AT_SBNR_NOTAVAILABLE;
2423 break;
2424 default:
2425 return error;
2426 }
2427 }
2428 if (Priv->PBKSBNR == AT_SBNR_AVAILABLE) {
2429 sprintf(req, "AT^SBNR=vcf,%i\r",entry->Location-1);
2430 s->Phone.Data.Memory=entry;
2431 smprintf(s, "Getting phonebook entry\n");
2432 return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetMemory);
2433 }
2434 }
2435
2436 error=ATGEN_GetManufacturer(s);
2437 if (error != ERR_NONE) return error;
2438
2439 error=ATGEN_SetPBKMemory(s, entry->MemoryType);
2440 if (error != ERR_NONE) return error;
2441
2442 if (Priv->FirstMemoryEntry == 0) {
2443 error = ATGEN_GetMemoryInfo(s, NULL, AT_First);
2444 if (error != ERR_NONE) return error;
2445 }
2446
2447
2448 error=ATGEN_SetPBKCharset(s, true); /* For reading we prefer unicode */
2449 if (error != ERR_NONE) return error;
2450
2451 if (endlocation == 0) {
2452 sprintf(req, "AT+CPBR=%i\r", entry->Location + Priv->FirstMemoryEntry - 1);
2453 } else {
2454 sprintf(req, "AT+CPBR=%i,%i\r", entry->Location + Priv->FirstMemoryEntry - 1, endlocation + Priv->FirstMemoryEntry - 1);
2455 }
2456
2457 s->Phone.Data.Memory=entry;
2458 smprintf(s, "Getting phonebook entry\n");
2459 return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetMemory);
2460}
2461
2462GSM_Error ATGEN_GetMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry)
2463{
2464 return ATGEN_PrivGetMemory(s, entry, 0);
2465}
2466
2467GSM_Error ATGEN_GetNextMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry, bool start)
2468{
2469 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
2470 GSM_Error error;
2471 int step = 0;
2472
2473 if (Priv->MemorySize == 0) {
2474 error = ATGEN_GetMemoryInfo(s, NULL, AT_Total);
2475 if (error != ERR_NONE) return error;
2476 }
2477
2478 if (start) {
2479 entry->Location = 1;
2480 } else {
2481 entry->Location++;
2482 }
2483 while ((error = ATGEN_PrivGetMemory(s, entry, step == 0 ? 0 : MIN(Priv->MemorySize, entry->Location + step))) == ERR_EMPTY) {
2484 entry->Location += step + 1;
2485 if (entry->Location > Priv->MemorySize) break;
2486 /* SNBR works only for one location */
2487 if (entry->MemoryType != MEM_ME || Priv->PBKSBNR != AT_SBNR_AVAILABLE) step = MIN(step + 2, 20);
2488 }
2489 if (error == ERR_INVALIDLOCATION) return ERR_EMPTY;
2490 return error;
2491}
2492
2493GSM_Error ATGEN_DeleteAllMemory(GSM_StateMachine *s, GSM_MemoryType type)
2494{
2495 GSM_Error error;
2496 unsigned char req[100];
2497 int i;
2498 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
2499
2500 error = ATGEN_SetPBKMemory(s, type);
2501 if (error != ERR_NONE) return error;
2502
2503 if (Priv->MemorySize == 0) {
2504 error = ATGEN_GetMemoryInfo(s, NULL, AT_Total);
2505 if (error != ERR_NONE) return error;
2506 }
2507
2508 if (Priv->FirstMemoryEntry == 0) {
2509 error = ATGEN_GetMemoryInfo(s, NULL, AT_First);
2510 if (error != ERR_NONE) return error;
2511 }
2512
2513
2514 smprintf(s, "Deleting all phonebook entries\n");
2515 for (i = Priv->FirstMemoryEntry; i < Priv->FirstMemoryEntry + Priv->MemorySize; i++) {
2516 sprintf(req, "AT+CPBW=%d\r",i);
2517 error = GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_SetMemory);
2518 if (error != ERR_NONE) return error;
2519 }
2520 return ERR_NONE;
2521}
2522
2523GSM_Error ATGEN_ReplyDialVoice(GSM_Protocol_Message msg, GSM_StateMachine *s)
2524{
2525 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
2526 case AT_Reply_OK:
2527 smprintf(s, "Dial voice OK\n");
2528 return ERR_NONE;
2529 case AT_Reply_Error:
2530 smprintf(s, "Dial voice error\n");
2531 return ERR_UNKNOWN;
2532 case AT_Reply_CMSError:
2533 return ATGEN_HandleCMSError(s);
2534 default:
2535 break;
2536 }
2537 return ERR_UNKNOWNRESPONSE;
2538}
2539
2540GSM_Error ATGEN_DialVoice(GSM_StateMachine *s, char *number, GSM_CallShowNumber ShowNumber)
2541{
2542 char req[39] = "ATDT";
2543
2544 if (ShowNumber != GSM_CALL_DefaultNumberPresence) return ERR_NOTSUPPORTED;
2545 if (strlen(number) > 32) return (ERR_UNKNOWN);
2546
2547 strcat(req, number);
2548 strcat(req, ";\r");
2549
2550 smprintf(s, "Making voice call\n");
2551 return GSM_WaitFor (s, req, 4+2+strlen(number), 0x00, 5, ID_DialVoice);
2552}
2553
2554GSM_Error ATGEN_ReplyEnterSecurityCode(GSM_Protocol_Message msg, GSM_StateMachine *s)
2555{
2556 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
2557 case AT_Reply_OK:
2558 smprintf(s, "Security code was OK\n");
2559 return ERR_NONE;
2560 case AT_Reply_Error:
2561 smprintf(s, "Incorrect security code\n");
2562 return ERR_SECURITYERROR;
2563 case AT_Reply_CMSError:
2564 return ATGEN_HandleCMSError(s);
2565 default:
2566 break;
2567 }
2568 return ERR_UNKNOWNRESPONSE;
2569}
2570
2571GSM_Error ATGEN_EnterSecurityCode(GSM_StateMachine *s, GSM_SecurityCode Code)
2572{
2573 unsigned char req[50];
2574
2575 switch (Code.Type) {
2576 case SEC_Pin :
2577 sprintf(req, "AT+CPIN=\"%s\"\r" , Code.Code);
2578 break;
2579 case SEC_Pin2 :
2580 if (s->Phone.Data.Priv.ATGEN.Manufacturer == AT_Siemens) {
2581 sprintf(req, "AT+CPIN2=\"%s\"\r", Code.Code);
2582 } else {
2583 sprintf(req, "AT+CPIN=\"%s\"\r" , Code.Code);
2584 }
2585 break;
2586 default : return ERR_NOTIMPLEMENTED;
2587 }
2588
2589 smprintf(s, "Entering security code\n");
2590 return GSM_WaitFor (s, req, strlen(req), 0x00, 6, ID_EnterSecurityCode);
2591}
2592
2593GSM_Error ATGEN_ReplyGetSecurityStatus(GSM_Protocol_Message msg, GSM_StateMachine *s)
2594{
2595 GSM_SecurityCodeType *Status = s->Phone.Data.SecurityStatus;
2596
2597 smprintf(s, "Security status received - ");
2598 if (strstr(msg.Buffer,"READY")) {
2599 *Status = SEC_None;
2600 smprintf(s, "nothing to enter\n");
2601 return ERR_NONE;
2602 }
2603 if (strstr(msg.Buffer,"PH_SIM PIN")) {
2604 smprintf(s, "no SIM inside or other error\n");
2605 return ERR_UNKNOWN;
2606 }
2607 if (strstr(msg.Buffer,"SIM PIN2")) {
2608 *Status = SEC_Pin2;
2609 smprintf(s, "waiting for PIN2\n");
2610 return ERR_NONE;
2611 }
2612 if (strstr(msg.Buffer,"SIM PUK2")) {
2613 *Status = SEC_Puk2;
2614 smprintf(s, "waiting for PUK2\n");
2615 return ERR_NONE;
2616 }
2617 if (strstr(msg.Buffer,"SIM PIN")) {
2618 *Status = SEC_Pin;
2619 smprintf(s, "waiting for PIN\n");
2620 return ERR_NONE;
2621 }
2622 if (strstr(msg.Buffer,"SIM PUK")) {
2623 *Status = SEC_Puk;
2624 smprintf(s, "waiting for PUK\n");
2625 return ERR_NONE;
2626 }
2627 smprintf(s, "unknown\n");
2628 return ERR_UNKNOWNRESPONSE;
2629}
2630
2631GSM_Error ATGEN_GetSecurityStatus(GSM_StateMachine *s, GSM_SecurityCodeType *Status)
2632{
2633 s->Phone.Data.SecurityStatus=Status;
2634
2635 smprintf(s, "Getting security code status\n");
2636 /* Please note, that A2D doesn't return OK on the end.
2637 * Because of it ReplyGetSecurityStatus is called after receiving line
2638 * with +CPIN:
2639 */
2640 return GSM_WaitFor (s, "AT+CPIN?\r", 9, 0x00, 4, ID_GetSecurityStatus);
2641}
2642
2643GSM_Error ATGEN_AnswerCall(GSM_StateMachine *s, int ID, bool all)
2644{
2645 if (all) {
2646 smprintf(s, "Answering all calls\n");
2647 return GSM_WaitFor (s, "ATA\r", 4, 0x00, 4, ID_AnswerCall);
2648 }
2649 return ERR_NOTSUPPORTED;
2650}
2651
2652GSM_Error ATGEN_ReplyCancelCall(GSM_Protocol_Message msg, GSM_StateMachine *s)
2653{
2654 GSM_Call call;
2655
2656 switch(s->Phone.Data.Priv.ATGEN.ReplyState) {
2657 case AT_Reply_OK:
2658 smprintf(s, "Calls canceled\n");
2659 call.CallIDAvailable = false;
2660 call.Status = GSM_CALL_CallLocalEnd;
2661 if (s->User.IncomingCall) s->User.IncomingCall(s->CurrentConfig->Device, call);
2662
2663 return ERR_NONE;
2664 case AT_Reply_CMSError:
2665 return ATGEN_HandleCMSError(s);
2666 default:
2667 return ERR_UNKNOWN;
2668 }
2669}
2670
2671GSM_Error ATGEN_CancelCall(GSM_StateMachine *s, int ID, bool all)
2672{
2673 GSM_Error error;
2674
2675 if (all) {
2676 smprintf(s, "Dropping all calls\n");
2677 error = GSM_WaitFor (s, "ATH\r", 4, 0x00, 4, ID_CancelCall);
2678 if (error == ERR_UNKNOWN) {
2679 return GSM_WaitFor (s, "AT+CHUP\r", 8, 0x00, 4, ID_CancelCall);
2680 }
2681 return error;
2682 }
2683 return ERR_NOTSUPPORTED;
2684}
2685
2686GSM_Error ATGEN_ReplyReset(GSM_Protocol_Message msg, GSM_StateMachine *s)
2687{
2688 smprintf(s, "Reset done\n");
2689 return ERR_NONE;
2690}
2691
2692GSM_Error ATGEN_Reset(GSM_StateMachine *s, bool hard)
2693{
2694 GSM_Error error;
2695
2696 if (!hard) return ERR_NOTSUPPORTED;
2697
2698 smprintf(s, "Resetting device\n");
2699 /* Siemens 35 */
2700 error=GSM_WaitFor (s, "AT+CFUN=1,1\r", 12, 0x00, 8, ID_Reset);
2701 if (error != ERR_NONE) {
2702 /* Siemens M20 */
2703 error=GSM_WaitFor (s, "AT^SRESET\r", 10, 0x00, 8, ID_Reset);
2704 }
2705 return error;
2706}
2707
2708GSM_Error ATGEN_ReplyResetPhoneSettings(GSM_Protocol_Message msg, GSM_StateMachine *s)
2709{
2710 smprintf(s, "Reset done\n");
2711 return ERR_NONE;
2712}
2713
2714GSM_Error ATGEN_ResetPhoneSettings(GSM_StateMachine *s, GSM_ResetSettingsType Type)
2715{
2716 smprintf(s, "Resetting settings to default\n");
2717 return GSM_WaitFor (s, "AT&F\r", 5, 0x00, 4, ID_ResetPhoneSettings);
2718}
2719
2720GSM_Error ATGEN_SetAutoNetworkLogin(GSM_StateMachine *s)
2721{
2722 smprintf(s, "Enabling automatic network login\n");
2723 return GSM_WaitFor (s, "AT+COPS=0\r", 10, 0x00, 4, ID_SetAutoNetworkLogin);
2724}
2725
2726GSM_Error ATGEN_SendDTMF(GSM_StateMachine *s, char *sequence)
2727{
2728 unsigned char req[80] = "AT+VTS=";
2729 int n;
2730
2731 for (n = 0; n < 32; n++) {
2732 if (sequence[n] == '\0') break;
2733 if (n != 0) req[6 + 2 * n] = ',';
2734 req[7 + 2 * n] = sequence[n];
2735 }
2736
2737 strcat(req, ";\r");
2738
2739 smprintf(s, "Sending DTMF\n");
2740 return GSM_WaitFor (s, req, 7+2+2*strlen(sequence), 0x00, 4, ID_SendDTMF);
2741}
2742
2743GSM_Error ATGEN_ReplyDeleteSMSMessage(GSM_Protocol_Message msg, GSM_StateMachine *s)
2744{
2745 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
2746 case AT_Reply_OK:
2747 smprintf(s, "SMS deleted OK\n");
2748 return ERR_NONE;
2749 case AT_Reply_Error:
2750 smprintf(s, "Invalid location\n");
2751 return ERR_INVALIDLOCATION;
2752 case AT_Reply_CMSError:
2753 return ATGEN_HandleCMSError(s);
2754 default:
2755 break;
2756 }
2757 return ERR_UNKNOWNRESPONSE;
2758}
2759
2760GSM_Error ATGEN_DeleteSMS(GSM_StateMachine *s, GSM_SMSMessage *sms)
2761{
2762 unsigned char req[20], folderid;
2763 GSM_Error error;
2764 int location;
2765 GSM_MultiSMSMessagemsms;
2766
2767 msms.Number = 0;
2768 msms.SMS[0] = *sms;
2769
2770 /* By reading SMS we check if it is really inbox/outbox */
2771 error = ATGEN_GetSMS(s, &msms);
2772 if (error != ERR_NONE) return error;
2773
2774 error = ATGEN_GetSMSLocation(s, sms, &folderid, &location);
2775 if (error != ERR_NONE) return error;
2776
2777 sprintf(req, "AT+CMGD=%i\r",location);
2778
2779 smprintf(s, "Deleting SMS\n");
2780 return GSM_WaitFor (s, req, strlen(req), 0x00, 5, ID_DeleteSMSMessage);
2781}
2782
2783GSM_Error ATGEN_GetSMSFolders(GSM_StateMachine *s, GSM_SMSFolders *folders)
2784{
2785 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2786 GSM_Error error;
2787 int used = 0;
2788
2789 if (Priv->PhoneSMSMemory == 0) {
2790 error = ATGEN_SetSMSMemory(s, false);
2791 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) return error;
2792 }
2793 if (Priv->SIMSMSMemory == 0) {
2794 error = ATGEN_SetSMSMemory(s, true);
2795 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) return error;
2796 }
2797
2798 folders->Number = 0;
2799 if (Priv->PhoneSMSMemory == AT_NOTAVAILABLE && Priv->SIMSMSMemory == AT_NOTAVAILABLE) {
2800 return ERR_NONE;
2801 }
2802
2803 PHONE_GetSMSFolders(s,folders);
2804
2805 if (Priv->SIMSMSMemory == AT_AVAILABLE) {
2806 used = 2;
2807 }
2808
2809 if (Priv->PhoneSMSMemory == AT_AVAILABLE) {
2810 if (used != 0) {
2811 CopyUnicodeString(folders->Folder[used ].Name,folders->Folder[0].Name);
2812 CopyUnicodeString(folders->Folder[used + 1].Name,folders->Folder[1].Name);
2813 folders->Folder[used ].InboxFolder = true;
2814 folders->Folder[used + 1].InboxFolder = false;
2815 }
2816 folders->Folder[used ].Memory = MEM_ME;
2817 folders->Folder[used + 1].Memory = MEM_ME;
2818 folders->Number += 2;
2819 used += 2;
2820 }
2821
2822 return ERR_NONE;
2823}
2824
2825GSM_Error ATGEN_ReplySetMemory(GSM_Protocol_Message msg, GSM_StateMachine *s)
2826{
2827 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
2828 case AT_Reply_OK:
2829 smprintf(s, "Phonebook entry written OK\n");
2830 return ERR_NONE;
2831 case AT_Reply_CMSError:
2832 return ATGEN_HandleCMSError(s);
2833 case AT_Reply_CMEError:
2834 return ATGEN_HandleCMEError(s);
2835 case AT_Reply_Error:
2836 return ERR_INVALIDDATA;
2837 default:
2838 return ERR_UNKNOWNRESPONSE;
2839 }
2840}
2841
2842GSM_Error ATGEN_DeleteMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
2843{
2844 GSM_Error error;
2845 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
2846 unsigned char req[100];
2847
2848 if (entry->Location < 1) return ERR_INVALIDLOCATION;
2849
2850 error = ATGEN_SetPBKMemory(s, entry->MemoryType);
2851 if (error != ERR_NONE) return error;
2852
2853 if (Priv->FirstMemoryEntry == 0) {
2854 error = ATGEN_GetMemoryInfo(s, NULL, AT_First);
2855 if (error != ERR_NONE) return error;
2856 }
2857
2858 sprintf(req, "AT+CPBW=%d\r",entry->Location + Priv->FirstMemoryEntry - 1);
2859
2860 smprintf(s, "Deleting phonebook entry\n");
2861 return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_SetMemory);
2862}
2863
2864GSM_Error ATGEN_PrivSetMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
2865{
2866 /* REQUEST_SIZE should be big enough to handle all possibl cases
2867 * correctly, especially with unicode entries */
2868 #define REQUEST_SIZE((4 * GSM_PHONEBOOK_TEXT_LENGTH) + 30)
2869 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
2870 int Group, Name, Number,NumberType=0, len;
2871 GSM_Error error;
2872 unsigned char req[REQUEST_SIZE + 1];
2873 unsigned char name[2*(GSM_PHONEBOOK_TEXT_LENGTH + 1)];
2874 unsigned char uname[2*(GSM_PHONEBOOK_TEXT_LENGTH + 1)];
2875 unsigned char number[GSM_PHONEBOOK_TEXT_LENGTH + 1];
2876 int reqlen;
2877 bool PreferUnicode = false;
2878
2879 if (entry->Location == 0) return ERR_INVALIDLOCATION;
2880
2881 error = ATGEN_SetPBKMemory(s, entry->MemoryType);
2882 if (error != ERR_NONE) return error;
2883
2884 GSM_PhonebookFindDefaultNameNumberGroup(entry, &Name, &Number, &Group);
2885
2886 name[0] = 0;
2887 if (Name != -1) {
2888 len = UnicodeLength(entry->Entries[Name].Text);
2889
2890 /* Compare if we would loose some information when not using
2891 * unicode */
2892 EncodeDefault(name, entry->Entries[Name].Text, &len, true, NULL);
2893 DecodeDefault(uname, name, len, true, NULL);
2894 if (!mywstrncmp(uname, entry->Entries[Name].Text, len)) {
2895 /* Get maximal text length */
2896 if (Priv->TextLength == 0) {
2897 ATGEN_GetMemoryInfo(s, NULL, AT_Sizes);
2898 }
2899
2900 /* I char stored in GSM alphabet takes 7 bits, one
2901 * unicode 16, if storing in unicode would truncate
2902 * text, do not use it, otherwise we will use it */
2903 if ((Priv->TextLength != 0) && ((Priv->TextLength * 7 / 16) <= len)) {
2904 PreferUnicode = false;
2905 } else {
2906 PreferUnicode = true;
2907 }
2908 }
2909
2910 error = ATGEN_SetPBKCharset(s, PreferUnicode);
2911 if (error != ERR_NONE) return error;
2912
2913 switch (Priv->PBKCharset) {
2914 case AT_PBK_HEX:
2915 EncodeHexBin(name, DecodeUnicodeString(entry->Entries[Name].Text), UnicodeLength(entry->Entries[Name].Text));
2916 len = strlen(name);
2917 break;
2918 case AT_PBK_GSM:
2919 smprintf(s, "str: %s\n", DecodeUnicodeString(entry->Entries[Name].Text));
2920 len = UnicodeLength(entry->Entries[Name].Text);
2921 EncodeDefault(name, entry->Entries[Name].Text, &len, true, NULL);
2922 break;
2923 case AT_PBK_UCS2:
2924 EncodeHexUnicode(name, entry->Entries[Name].Text, UnicodeLength(entry->Entries[Name].Text));
2925 len = strlen(name);
2926 break;
2927 }
2928 } else {
2929 smprintf(s, "WARNING: No usable name found!\n");
2930 len = 0;
2931 }
2932
2933 if (Number != -1) {
2934 GSM_PackSemiOctetNumber(entry->Entries[Number].Text, number, false);
2935 NumberType = number[0];
2936 sprintf(number,"%s",DecodeUnicodeString(entry->Entries[Number].Text));
2937 } else {
2938 smprintf(s, "WARNING: No usable number found!\n");
2939 number[0] = 0;
2940 }
2941
2942 if (Priv->FirstMemoryEntry == 0) {
2943 error = ATGEN_GetMemoryInfo(s, NULL, AT_First);
2944 if (error != ERR_NONE) return error;
2945 }
2946
2947 /* We can't use here:
2948 * sprintf(req, "AT+CPBW=%d, \"%s\", %i, \"%s\"\r",
2949 * entry->Location, number, NumberType, name);
2950 * because name can contain 0 when using GSM alphabet.
2951 */
2952 sprintf(req, "AT+CPBW=%d, \"%s\", %i, \"", entry->Location + Priv->FirstMemoryEntry - 1, number, NumberType);
2953 reqlen = strlen(req);
2954 if (reqlen + len > REQUEST_SIZE - 2) {
2955 smprintf(s, "WARNING: Text truncated to fit in buffer!\n");
2956 len = REQUEST_SIZE - 2 - reqlen;
2957 }
2958 memcpy(req + reqlen, name, len);
2959 reqlen += len;
2960 memcpy(req + reqlen, "\"\r", 2);
2961 reqlen += 2;
2962
2963 smprintf(s, "Writing phonebook entry\n");
2964 return GSM_WaitFor (s, req, reqlen, 0x00, 4, ID_SetMemory);
2965#undef REQUEST_SIZE
2966}
2967
2968GSM_Error ATGEN_SetMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
2969{
2970 if (entry->Location == 0) return ERR_INVALIDLOCATION;
2971 return ATGEN_PrivSetMemory(s, entry);
2972}
2973
2974GSM_Error ATGEN_AddMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
2975{
2976 GSM_Error error;
2977 GSM_MemoryStatusStatus;
2978 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
2979
2980 /* Find out empty location */
2981 error = ATGEN_GetMemoryInfo(s, &Status, AT_NextEmpty);
2982 if (error != ERR_NONE) return error;
2983 if (Priv->NextMemoryEntry == 0) return ERR_FULL;
2984 entry->Location = Priv->NextMemoryEntry;
2985
2986 return ATGEN_PrivSetMemory(s, entry);
2987}
2988
2989/* Use ATGEN_ExtractOneParameter ?? */
2990void Extract_CLIP_number(char *dest, char *buf)
2991{
2992 char *start, *stop;
2993 int i = 0;
2994
2995 stop = strstr(buf, ",");
2996 if (stop != NULL) {
2997 start = strstr(buf, ":");
2998 if (start != NULL) {
2999 for (start = start + 2; start + i < stop; i++)
3000 dest[i] = start[i];
3001 }
3002 }
3003 dest[i] = 0; /* end the number */
3004
3005 return;
3006}
3007
3008GSM_Error ATGEN_ReplyIncomingCallInfo(GSM_Protocol_Message msg, GSM_StateMachine *s)
3009{
3010 char num[128];
3011 GSM_Call call;
3012
3013 smprintf(s, "Incoming call info\n");
3014 if (s->Phone.Data.EnableIncomingCall && s->User.IncomingCall!=NULL) {
3015 call.CallIDAvailable = false;
3016 num[0] = 0;
3017 if (strstr(msg.Buffer, "RING")) {
3018 call.Status = GSM_CALL_IncomingCall;
3019 Extract_CLIP_number(num, msg.Buffer);
3020 } else if (strstr(msg.Buffer, "NO CARRIER")) {
3021 call.Status = GSM_CALL_CallEnd;
3022 } else if (strstr(msg.Buffer, "COLP:")) {
3023 call.Status = GSM_CALL_CallStart;
3024 Extract_CLIP_number(num, msg.Buffer);
3025 } else {
3026 smprintf(s, "CLIP: error\n");
3027 return ERR_NONE;
3028 }
3029 EncodeUnicode(call.PhoneNumber, num, strlen(num));
3030
3031 s->User.IncomingCall(s->CurrentConfig->Device, call);
3032 }
3033
3034 return ERR_NONE;
3035}
3036
3037GSM_Error ATGEN_IncomingGPRS(GSM_Protocol_Message msg, GSM_StateMachine *s)
3038{
3039 /* "+CGREG: 1,1" */
3040 smprintf(s, "GPRS change\n");
3041 return ERR_NONE;
3042}
3043
3044GSM_Error ATGEN_IncomingBattery(GSM_Protocol_Message msg, GSM_StateMachine *s)
3045{
3046 int level = 0;
3047 char *p;
3048
3049 /* "_OBS: 92,1" */
3050 p = strstr(msg.Buffer, "_OBS:");
3051 if (p) level = atoi(p + 5);
3052 smprintf(s, "Battery level changed to %d\n", level);
3053 return ERR_NONE;
3054}
3055
3056GSM_Error ATGEN_IncomingNetworkLevel(GSM_Protocol_Message msg, GSM_StateMachine *s)
3057{
3058 int level = 0;
3059 char *p;
3060
3061 /* "_OSIGQ: 12,0" */
3062 p = strstr(msg.Buffer, "_OSIGQ: ");
3063 if (p) level = atoi(p + 7);
3064 smprintf(s, "Network level changed to %d\n", level);
3065 return ERR_NONE;
3066}
3067
3068GSM_Error ATGEN_ReplyGetSIMIMSI(GSM_Protocol_Message msg, GSM_StateMachine *s)
3069{
3070 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3071 GSM_Phone_Data *Data = &s->Phone.Data;
3072 char *c;
3073
3074 switch (Priv->ReplyState) {
3075 case AT_Reply_OK:
3076 CopyLineString(Data->PhoneString, msg.Buffer, Priv->Lines, 2);
3077
3078 /* Read just IMSI also on phones that prepend it by "<IMSI>:" (Alcatel BE5) */
3079 c = strstr(Data->PhoneString, "<IMSI>:");
3080 if (c != NULL) {
3081 c += 7;
3082 memmove(Data->PhoneString, c, strlen(c) + 1);
3083 }
3084
3085 smprintf(s, "Received IMSI %s\n",Data->PhoneString);
3086 return ERR_NONE;
3087 case AT_Reply_Error:
3088 smprintf(s, "No access to SIM card or not supported by device\n");
3089 return ERR_SECURITYERROR;
3090 case AT_Reply_CMEError:
3091 return ATGEN_HandleCMEError(s);
3092 case AT_Reply_CMSError:
3093 return ATGEN_HandleCMSError(s);
3094 default:
3095 break;
3096 }
3097 return ERR_UNKNOWNRESPONSE;
3098}
3099
3100GSM_Error ATGEN_GetSIMIMSI(GSM_StateMachine *s, char *IMSI)
3101{
3102 s->Phone.Data.PhoneString = IMSI;
3103 smprintf(s, "Getting SIM IMSI\n");
3104 return GSM_WaitFor (s, "AT+CIMI\r", 8, 0x00, 4, ID_GetSIMIMSI);
3105}
3106
3107GSM_Error ATGEN_GetDisplayStatus(GSM_StateMachine *s, GSM_DisplayFeatures *features)
3108{
3109 return ERR_NOTSUPPORTED;
3110
3111 s->Phone.Data.DisplayFeatures = features;
3112 smprintf(s, "Getting display status\n");
3113 return GSM_WaitFor (s, "AT+CIND?\r",9, 0x00, 4, ID_GetDisplayStatus);
3114}
3115
3116GSM_Error ATGEN_IncomingSMSCInfo(GSM_Protocol_Message msg, GSM_StateMachine *s)
3117{
3118 return ERR_NONE;
3119}
3120
3121GSM_Error ATGEN_ReplyGetBatteryCharge(GSM_Protocol_Message msg, GSM_StateMachine *s)
3122{
3123 GSM_Phone_Data *Data = &s->Phone.Data;
3124 int i;
3125
3126 Data->BatteryCharge->BatteryPercent = -1;
3127 Data->BatteryCharge->ChargeState = 0;
3128
3129 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
3130 case AT_Reply_OK:
3131 smprintf(s, "Battery level received\n");
3132 Data->BatteryCharge->BatteryPercent = atoi(msg.Buffer+17);
3133 i = atoi(msg.Buffer+14);
3134 if (i >= 0 && i <= 3) {
3135 Data->BatteryCharge->ChargeState = i + 1;
3136 }
3137 return ERR_NONE;
3138 case AT_Reply_Error:
3139 smprintf(s, "Can't get battery level\n");
3140 return ERR_UNKNOWN;
3141 case AT_Reply_CMSError:
3142 smprintf(s, "Can't get battery level\n");
3143 return ATGEN_HandleCMSError(s);
3144 default:
3145 break;
3146 }
3147 return ERR_UNKNOWNRESPONSE;
3148}
3149
3150GSM_Error ATGEN_GetBatteryCharge(GSM_StateMachine *s, GSM_BatteryCharge *bat)
3151{
3152 s->Phone.Data.BatteryCharge = bat;
3153 smprintf(s, "Getting battery charge\n");
3154 return GSM_WaitFor (s, "AT+CBC\r", 7, 0x00, 4, ID_GetBatteryCharge);
3155}
3156
3157GSM_Error ATGEN_ReplyGetSignalQuality(GSM_Protocol_Message msg, GSM_StateMachine *s)
3158{
3159 GSM_SignalQuality*Signal = s->Phone.Data.SignalQuality;
3160 int i;
3161 char *pos;
3162
3163 Signal->SignalStrength = -1;
3164 Signal->SignalPercent = -1;
3165 Signal->BitErrorRate = -1;
3166
3167 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
3168 case AT_Reply_OK:
3169 smprintf(s, "Signal quality info received\n");
3170 i = atoi(msg.Buffer+15);
3171 if (i != 99) {
3172 /* from GSM 07.07 section 8.5 */
3173 Signal->SignalStrength = 2 * i - 113;
3174
3175 /* FIXME: this is wild guess and probably will be phone dependant */
3176 Signal->SignalPercent = 15 * i;
3177 if (Signal->SignalPercent > 100) Signal->SignalPercent = 100;
3178 }
3179 pos = strchr(msg.Buffer + 15, ',');
3180 if (pos != NULL) {
3181 i = atoi(pos + 1);
3182 /* from GSM 05.08 section 8.2.4 */
3183 switch (i) {
3184 case 0: Signal->BitErrorRate = 0; break; /* 0.14 */
3185 case 1: Signal->BitErrorRate = 0; break; /* 0.28 */
3186 case 2: Signal->BitErrorRate = 1; break; /* 0.57 */
3187 case 3: Signal->BitErrorRate = 1; break; /* 1.13 */
3188 case 4: Signal->BitErrorRate = 2; break; /* 2.26 */
3189 case 5: Signal->BitErrorRate = 5; break; /* 4.53 */
3190 case 6: Signal->BitErrorRate = 9; break; /* 9.05 */
3191 case 7: Signal->BitErrorRate = 18; break; /* 18.10 */
3192 }
3193 }
3194 return ERR_NONE;
3195 case AT_Reply_CMSError:
3196 return ATGEN_HandleCMSError(s);
3197 default:
3198 break;
3199 }
3200 return ERR_UNKNOWNRESPONSE;
3201}
3202
3203GSM_Error ATGEN_GetSignalQuality(GSM_StateMachine *s, GSM_SignalQuality *sig)
3204{
3205 s->Phone.Data.SignalQuality = sig;
3206 smprintf(s, "Getting signal quality info\n");
3207 return GSM_WaitFor (s, "AT+CSQ\r", 7, 0x00, 4, ID_GetSignalQuality);
3208}
3209
3210/* When use AT+CPIN?, A2D returns it without OK and because of it Gammu
3211 parses answer without it.
3212 MC35 and other return OK after answer for AT+CPIN?. Here we handle it.
3213 Any better idea ?
3214 */
3215GSM_Error ATGEN_ReplyOK(GSM_Protocol_Message msg, GSM_StateMachine *s)
3216{
3217 return ERR_NONE;
3218}
3219
3220static GSM_Error ATGEN_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start)
3221{
3222 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
3223
3224 if (Priv->Manufacturer==AT_Siemens ) return SIEMENS_GetNextCalendar(s,Note,start);
3225 if (Priv->Manufacturer==AT_Ericsson) return SONYERIC_GetNextCalendar(s,Note,start);
3226 return ERR_NOTSUPPORTED;
3227}
3228
3229GSM_Error ATGEN_Terminate(GSM_StateMachine *s)
3230{
3231 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3232
3233 free(Priv->file.Buffer);
3234 return ERR_NONE;
3235}
3236
3237GSM_Error ATGEN_AddCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note)
3238{
3239 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3240
3241 if (Priv->Manufacturer==AT_Siemens) return SIEMENS_AddCalendarNote(s, Note);
3242 if (Priv->Manufacturer==AT_Ericsson) return SONYERIC_AddCalendarNote(s, Note);
3243 return ERR_NOTSUPPORTED;
3244}
3245
3246GSM_Error ATGEN_DelCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note)
3247{
3248 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
3249
3250 if (Priv->Manufacturer==AT_Siemens) return SIEMENS_DelCalendarNote(s, Note);
3251 if (Priv->Manufacturer==AT_Ericsson) return SONYERIC_DelCalendarNote(s, Note);
3252 return ERR_NOTSUPPORTED;
3253}
3254
3255GSM_Error ATGEN_PressKey(GSM_StateMachine *s, GSM_KeyCode Key, bool Press)
3256{
3257 GSM_Errorerror;
3258 unsigned char Frame[] = "AT+CKPD=\"?\"\r";
3259
3260 if (Press) {
3261 switch (Key) {
3262 case GSM_KEY_1 : Frame[9] = '1'; break;
3263 case GSM_KEY_2 : Frame[9] = '2'; break;
3264 case GSM_KEY_3 : Frame[9] = '3'; break;
3265 case GSM_KEY_4 : Frame[9] = '4'; break;
3266 case GSM_KEY_5 : Frame[9] = '5'; break;
3267 case GSM_KEY_6 : Frame[9] = '6'; break;
3268 case GSM_KEY_7 : Frame[9] = '7'; break;
3269 case GSM_KEY_8 : Frame[9] = '8'; break;
3270 case GSM_KEY_9 : Frame[9] = '9'; break;
3271 case GSM_KEY_0 : Frame[9] = '0'; break;
3272 case GSM_KEY_HASH : Frame[9] = '#'; break;
3273 case GSM_KEY_ASTERISK : Frame[9] = '*'; break;
3274 case GSM_KEY_POWER : return ERR_NOTSUPPORTED;
3275 case GSM_KEY_GREEN : Frame[9] = 'S'; break;
3276 case GSM_KEY_RED : Frame[9] = 'E'; break;
3277 case GSM_KEY_INCREASEVOLUME: Frame[9] = 'U'; break;
3278 case GSM_KEY_DECREASEVOLUME: Frame[9] = 'D'; break;
3279 case GSM_KEY_UP : Frame[9] = '^'; break;
3280 case GSM_KEY_DOWN : Frame[9] = 'V'; break;
3281 case GSM_KEY_MENU : Frame[9] = 'F'; break;
3282 case GSM_KEY_NAMES : Frame[9] = 'C'; break;
3283 default : return ERR_NOTSUPPORTED;
3284 }
3285 smprintf(s, "Pressing key\n");
3286 error = GSM_WaitFor (s, Frame, 12, 0x00, 4, ID_PressKey);
3287 if (error != ERR_NONE) return error;
3288
3289 /* Strange. My T310 needs it */
3290 return GSM_WaitFor (s, "ATE1\r", 5, 0x00, 4, ID_EnableEcho);
3291 } else {
3292 return ERR_NONE;
3293 }
3294}
3295
3296#ifdef GSM_ENABLE_CELLBROADCAST
3297
3298GSM_Error ATGEN_ReplyIncomingCB(GSM_Protocol_Message msg, GSM_StateMachine *s)
3299{
3300 GSM_CBMessage CB;
3301 int i,j;
3302 char Buffer[300],Buffer2[300];
3303
3304 smprintf(s, "CB received\n");
3305 return ERR_NONE;
3306
3307 DecodeHexBin (Buffer,msg.Buffer+6,msg.Length-6);
3308 DumpMessage(stdout, di.dl ,Buffer,msg.Length-6);
3309
3310 CB.Channel = Buffer[4];
3311
3312 for (j=0;j<msg.Length;j++) {
3313 smprintf(s, "j=%i\n",j);
3314 i=GSM_UnpackEightBitsToSeven(0, msg.Buffer[6], msg.Buffer[6], msg.Buffer+j, Buffer2);
3315 //i = msg.Buffer[6] - 1;
3316 //while (i!=0) {
3317 // if (Buffer[i] == 13) i = i - 1; else break;
3318 //}
3319 DecodeDefault(CB.Text, Buffer2, msg.Buffer[6], false, NULL);
3320 smprintf(s, "Channel %i, text \"%s\"\n",CB.Channel,DecodeUnicodeString(CB.Text));
3321 }
3322 if (s->Phone.Data.EnableIncomingCB && s->User.IncomingCB!=NULL) {
3323 s->User.IncomingCB(s->CurrentConfig->Device,CB);
3324 }
3325 return ERR_NONE;
3326}
3327
3328#endif
3329
3330GSM_Error ATGEN_SetIncomingCB(GSM_StateMachine *s, bool enable)
3331{
3332#ifdef GSM_ENABLE_CELLBROADCAST
3333 if (s->Phone.Data.EnableIncomingCB!=enable) {
3334 s->Phone.Data.EnableIncomingCB = enable;
3335 if (enable) {
3336 smprintf(s, "Enabling incoming CB\n");
3337 return GSM_WaitFor(s, "AT+CNMI=3,,2\r", 13, 0x00, 4, ID_SetIncomingCB);
3338 } else {
3339 smprintf(s, "Disabling incoming CB\n");
3340 return GSM_WaitFor(s, "AT+CNMI=3,,0\r", 13, 0x00, 4, ID_SetIncomingCB);
3341 }
3342 }
3343 return ERR_NONE;
3344#else
3345 return ERR_SOURCENOTAVAILABLE;
3346#endif
3347}
3348
3349GSM_Error ATGEN_IncomingSMSInfo(GSM_Protocol_Message msg, GSM_StateMachine *s)
3350{
3351 smprintf(s, "Incoming SMS\n");
3352 return ERR_NONE;
3353}
3354
3355GSM_Error ATGEN_IncomingSMSDeliver(GSM_Protocol_Message msg, GSM_StateMachine *s)
3356{
3357 GSM_Phone_Data *Data = &s->Phone.Data;
3358 GSM_SMSMessage sms;
3359 int current = 0, current2, i=0;
3360 unsigned char buffer[300],smsframe[800];
3361
3362 smprintf(s, "Incoming SMS received (Deliver)\n");
3363 if (Data->EnableIncomingSMS && s->User.IncomingSMS!=NULL) {
3364 sms.State = SMS_UnRead;
3365 sms.InboxFolder = true;
3366 sms.PDU = SMS_Deliver;
3367
3368 /* T310 with larger SMS goes crazy and mix this incoming
3369 * frame with normal answers. PDU is always last frame
3370 * We find its' number and parse it */
3371 while (Data->Priv.ATGEN.Lines.numbers[i*2+1] != 0) {
3372 /* FIXME: handle special chars correctly */
3373 i++;
3374 }
3375 DecodeHexBin (buffer,
3376 GetLineString(msg.Buffer,Data->Priv.ATGEN.Lines,i),
3377 strlen(GetLineString(msg.Buffer,Data->Priv.ATGEN.Lines,i)));
3378
3379 /* We use locations from SMS layouts like in ../phone2.c(h) */
3380 for(i=0;i<buffer[0]+1;i++) smsframe[i]=buffer[current++];
3381 smsframe[12]=buffer[current++];
3382
3383 current2=((buffer[current])+1)/2+1;
3384 for(i=0;i<current2+1;i++) smsframe[PHONE_SMSDeliver.Number+i]=buffer[current++];
3385 smsframe[PHONE_SMSDeliver.TPPID] = buffer[current++];
3386 smsframe[PHONE_SMSDeliver.TPDCS] = buffer[current++];
3387 for(i=0;i<7;i++) smsframe[PHONE_SMSDeliver.DateTime+i]=buffer[current++];
3388 smsframe[PHONE_SMSDeliver.TPUDL] = buffer[current++];
3389 for(i=0;i<smsframe[PHONE_SMSDeliver.TPUDL];i++) smsframe[i+PHONE_SMSDeliver.Text]=buffer[current++];
3390 GSM_DecodeSMSFrame(&sms,smsframe,PHONE_SMSDeliver);
3391
3392 s->User.IncomingSMS(s->CurrentConfig->Device,sms);
3393 }
3394 return ERR_NONE;
3395}
3396
3397/* I don't have phone able to do it and can't fill it */
3398GSM_Error ATGEN_IncomingSMSReport(GSM_Protocol_Message msg, GSM_StateMachine *s)
3399{
3400 smprintf(s, "Incoming SMS received (Report)\n");
3401 return ERR_NONE;
3402}
3403
3404GSM_Error ATGEN_SetIncomingSMS(GSM_StateMachine *s, bool enable)
3405{
3406 /* Nokia returns OK, but doesn't return anything */
3407 if (s->Phone.Data.Priv.ATGEN.Manufacturer == AT_Nokia) return ERR_NOTSUPPORTED;
3408
3409 if (s->Phone.Data.EnableIncomingSMS!=enable) {
3410 s->Phone.Data.EnableIncomingSMS = enable;
3411 if (enable) {
3412 smprintf(s, "Enabling incoming SMS\n");
3413
3414 /* Delivery reports */
3415 GSM_WaitFor(s, "AT+CNMI=3,,,1\r", 14, 0x00, 4, ID_SetIncomingSMS);
3416
3417 /* SMS deliver */
3418 return GSM_WaitFor(s, "AT+CNMI=3,3\r", 12, 0x00, 4, ID_SetIncomingSMS);
3419 } else {
3420 smprintf(s, "Disabling incoming SMS\n");
3421 return GSM_WaitFor(s, "AT+CNMI=3,0\r", 12, 0x00, 4, ID_SetIncomingSMS);
3422 }
3423 }
3424 return ERR_NONE;
3425}
3426
3427GSM_Reply_Function ATGENReplyFunctions[] = {
3428 {ATGEN_GenericReply, "AT\r" ,0x00,0x00,ID_IncomingFrame },
3429 {ATGEN_GenericReply, "ATE1" ,0x00,0x00,ID_EnableEcho },
3430 {ATGEN_GenericReply, "AT+CMEE=" ,0x00,0x00,ID_EnableErrorInfo },
3431 {ATGEN_GenericReply, "AT+CKPD=" ,0x00,0x00,ID_PressKey },
3432 {ATGEN_ReplyGetSIMIMSI, "AT+CIMI" ,0x00,0x00,ID_GetSIMIMSI },
3433 {ATGEN_GenericReply, "AT*EOBEX" ,0x00,0x00,ID_SetOBEX },
3434
3435#ifdef GSM_ENABLE_CELLBROADCAST
3436 {ATGEN_ReplyIncomingCB, "+CBM:" ,0x00,0x00,ID_IncomingFrame },
3437 {ATGEN_GenericReply, "AT+CNMI" ,0x00,0x00,ID_SetIncomingCB },
3438#endif
3439
3440 {ATGEN_IncomingBattery, "_OBS:" ,0x00,0x00,ID_IncomingFrame },
3441 {ATGEN_ReplyGetBatteryCharge, "AT+CBC" ,0x00,0x00,ID_GetBatteryCharge },
3442
3443 {ATGEN_ReplyGetModel, "AT+CGMM" ,0x00,0x00,ID_GetModel },
3444 {ATGEN_ReplyGetManufacturer, "AT+CGMI" ,0x00,0x00,ID_GetManufacturer },
3445 {ATGEN_ReplyGetFirmwareCGMR, "AT+CGMR" ,0x00,0x00,ID_GetFirmware },
3446 {ATGEN_ReplyGetFirmwareATI, "ATI" ,0x00,0x00,ID_GetFirmware },
3447 {ATGEN_ReplyGetIMEI, "AT+CGSN" ,0x00,0x00,ID_GetIMEI },
3448
3449 {ATGEN_ReplySendSMS, "AT+CMGS" ,0x00,0x00,ID_IncomingFrame },
3450 {ATGEN_ReplySendSMS, "AT+CMSS" ,0x00,0x00,ID_IncomingFrame },
3451 {ATGEN_GenericReply, "AT+CNMI" ,0x00,0x00,ID_SetIncomingSMS },
3452 {ATGEN_GenericReply, "AT+CMGF" ,0x00,0x00,ID_GetSMSMode },
3453 {ATGEN_GenericReply, "AT+CSDH" ,0x00,0x00,ID_GetSMSMode },
3454 {ATGEN_ReplyGetSMSMessage, "AT+CMGR" ,0x00,0x00,ID_GetSMSMessage },
3455 {ATGEN_GenericReply, "AT+CPMS" ,0x00,0x00,ID_SetMemoryType },
3456 {ATGEN_ReplyGetSMSStatus, "AT+CPMS" ,0x00,0x00,ID_GetSMSStatus },
3457 {ATGEN_ReplyGetSMSMemories, "AT+CPMS=?" ,0x00,0x00,ID_GetSMSMemories },
3458 {ATGEN_ReplyAddSMSMessage, "AT+CMGW" ,0x00,0x00,ID_SaveSMSMessage },
3459 {ATGEN_GenericReply, "AT+CSMP" ,0x00,0x00,ID_SetSMSParameters },
3460 {ATGEN_GenericReply, "AT+CSCA" ,0x00,0x00,ID_SetSMSC },
3461 {ATGEN_ReplyGetSMSC, "AT+CSCA?" ,0x00,0x00,ID_GetSMSC },
3462 {ATGEN_ReplyDeleteSMSMessage, "AT+CMGD" ,0x00,0x00,ID_DeleteSMSMessage },
3463 {ATGEN_GenericReply, "ATE1" ,0x00,0x00,ID_SetSMSParameters },
3464 {ATGEN_GenericReply, "\x1b\x0D" ,0x00,0x00,ID_SetSMSParameters },
3465 {ATGEN_IncomingSMSInfo, "+CMTI:" ,0x00,0x00,ID_IncomingFrame },
3466 {ATGEN_IncomingSMSDeliver, "+CMT:" ,0x00,0x00,ID_IncomingFrame },
3467 {ATGEN_IncomingSMSReport, "+CDS:" ,0x00,0x00,ID_IncomingFrame },
3468 {ATGEN_IncomingSMSCInfo, "^SCN:" ,0x00,0x00,ID_IncomingFrame },
3469
3470 {ATGEN_ReplyGetDateTime_Alarm, "AT+CCLK?" ,0x00,0x00,ID_GetDateTime },
3471 {ATGEN_GenericReply, "AT+CCLK=" ,0x00,0x00,ID_SetDateTime },
3472 {ATGEN_ReplyGetDateTime_Alarm, "AT+CALA?" ,0x00,0x00,ID_GetAlarm },
3473
3474 {ATGEN_ReplyGetNetworkLAC_CID, "AT+CREG?" ,0x00,0x00,ID_GetNetworkInfo },
3475 {ATGEN_GenericReply, "AT+CREG=2" ,0x00,0x00,ID_GetNetworkInfo },
3476 {ATGEN_GenericReply, "AT+COPS=" ,0x00,0x00,ID_GetNetworkInfo },
3477 {ATGEN_GenericReply, "AT+COPS=" ,0x00,0x00,ID_SetAutoNetworkLogin},
3478 {ATGEN_ReplyGetNetworkCode, "AT+COPS" ,0x00,0x00,ID_GetNetworkInfo },
3479 {ATGEN_ReplyGetSignalQuality, "AT+CSQ" ,0x00,0x00,ID_GetSignalQuality },
3480 {ATGEN_IncomingNetworkLevel, "_OSIGQ:" ,0x00,0x00,ID_IncomingFrame },
3481 {ATGEN_IncomingGPRS, "+CGREG:" ,0x00,0x00,ID_IncomingFrame },
3482 {ATGEN_ReplyGetNetworkLAC_CID, "+CREG:" ,0x00,0x00,ID_IncomingFrame },
3483
3484 {ATGEN_ReplyGetPBKMemories, "AT+CPBS=?" ,0x00,0x00,ID_SetMemoryType },
3485 {ATGEN_GenericReply, "AT+CPBS=" ,0x00,0x00,ID_SetMemoryType },
3486 {ATGEN_ReplyGetCPBSMemoryStatus,"AT+CPBS?" ,0x00,0x00,ID_GetMemoryStatus },
3487 {ATGEN_ReplyGetCPBRMemoryInfo, "AT+CPBR=?" ,0x00,0x00,ID_GetMemoryStatus },
3488 {ATGEN_ReplyGetCPBRMemoryStatus,"AT+CPBR=" ,0x00,0x00,ID_GetMemoryStatus },
3489 {ATGEN_GenericReply, "AT+CSCS=" ,0x00,0x00,ID_SetMemoryCharset },
3490 {ATGEN_ReplyGetMemory, "AT+CPBR=" ,0x00,0x00,ID_GetMemory },
3491 {ATGEN_GenericReply, "AT^SBNR=?" ,0x00,0x00,ID_GetMemory },
3492 {ATGEN_SL45ReplyGetMemory, "AT^SBNR" ,0x00,0x00,ID_GetMemory },
3493 {ATGEN_ReplySetMemory, "AT+CPBW" ,0x00,0x00,ID_SetMemory },
3494
3495 {ATGEN_CMS35ReplyGetBitmap, "AT^SBNR=\"bmp\"" ,0x00,0x00,ID_GetBitmap },
3496 {ATGEN_CMS35ReplySetBitmap, "AT^SBNW=\"bmp\"" ,0x00,0x00,ID_SetBitmap },
3497
3498 {ATGEN_CMS35ReplyGetRingtone, "AT^SBNR=\"mid\"" ,0x00,0x00,ID_GetRingtone },
3499 {ATGEN_CMS35ReplySetRingtone, "AT^SBNW=\"mid\"" ,0x00,0x00,ID_SetRingtone },
3500
3501 {ATGEN_CMS35ReplyGetNextCal, "AT^SBNR=\"vcs\"" ,0x00,0x00,ID_GetCalendarNote },
3502 {ATGEN_CMS35ReplySetCalendar, "AT^SBNW=\"vcs\"" ,0x00,0x00,ID_SetCalendarNote },
3503 {ATGEN_CMS35ReplyDeleteCalendar,"AT^SBNW=\"vcs\"",0x00,0x00,ID_DeleteCalendarNote },
3504
3505 {ATGEN_ReplyEnterSecurityCode, "AT+CPIN=" ,0x00,0x00,ID_EnterSecurityCode },
3506 {ATGEN_ReplyEnterSecurityCode, "AT+CPIN2=" ,0x00,0x00,ID_EnterSecurityCode },
3507 {ATGEN_ReplyGetSecurityStatus, "AT+CPIN?" ,0x00,0x00,ID_GetSecurityStatus },
3508 {ATGEN_ReplyOK, "OK" ,0x00,0x00,ID_IncomingFrame },
3509
3510 {ATGEN_GenericReply, "AT+VTS" ,0x00,0x00,ID_SendDTMF },
3511 {ATGEN_ReplyCancelCall, "AT+CHUP" ,0x00,0x00,ID_CancelCall },
3512 {ATGEN_ReplyDialVoice, "ATDT" ,0x00,0x00,ID_DialVoice },
3513 {ATGEN_ReplyCancelCall, "ATH" ,0x00,0x00,ID_CancelCall },
3514 {ATGEN_GenericReply, "AT+CLIP=1" ,0x00,0x00,ID_IncomingFrame },
3515 {ATGEN_ReplyIncomingCallInfo, "+CLIP" ,0x00,0x00,ID_IncomingFrame },
3516 {ATGEN_ReplyIncomingCallInfo, "+COLP" ,0x00,0x00,ID_IncomingFrame },
3517 {ATGEN_ReplyIncomingCallInfo, "RING" ,0x00,0x00,ID_IncomingFrame },
3518 {ATGEN_ReplyIncomingCallInfo, "NO CARRIER" ,0x00,0x00,ID_IncomingFrame },
3519
3520 {ATGEN_ReplyReset, "AT^SRESET" ,0x00,0x00,ID_Reset },
3521 {ATGEN_ReplyReset, "AT+CFUN=1,1" ,0x00,0x00,ID_Reset },
3522 {ATGEN_ReplyResetPhoneSettings, "AT&F" ,0x00,0x00,ID_ResetPhoneSettings },
3523
3524#ifdef GSM_ENABLE_ALCATEL
3525/* Why do I give Alcatel specific things here? It's simple, Alcatel needs
3526 * some AT commands to start it's binary mode, so this needs to be in AT
3527 * related stuff.
3528 *
3529 * XXX: AT+IFC could later move outside this ifdef, because it is not Alcatel
3530 * specific and it's part of ETSI specifications
3531 */
3532 {ATGEN_GenericReply, "AT+IFC" ,0x00,0x00,ID_SetFlowControl },
3533 {ALCATEL_ProtocolVersionReply, "AT+CPROT=?" ,0x00,0x00,ID_AlcatelProtocol },
3534 {ATGEN_GenericReply, "AT+CPROT" ,0x00,0x00,ID_AlcatelConnect },
3535#endif
3536
3537 {NULL, "\x00" ,0x00,0x00,ID_None }
3538};
3539
3540GSM_Phone_Functions ATGENPhone = {
3541 "A2D|iPAQ|at|M20|S25|MC35|C35i|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",
3542 ATGENReplyFunctions,
3543 ATGEN_Initialise,
3544 ATGEN_Terminate,
3545 ATGEN_DispatchMessage,
3546 NOTSUPPORTED, /* ShowStartInfo */
3547 ATGEN_GetManufacturer,
3548 ATGEN_GetModel,
3549 ATGEN_GetFirmware,
3550 ATGEN_GetIMEI,
3551 NOTSUPPORTED, /* GetOriginalIMEI */
3552 NOTSUPPORTED, /* GetManufactureMonth*/
3553 NOTSUPPORTED, /* GetProductCode */
3554 NOTSUPPORTED, /* GetHardware */
3555 NOTSUPPORTED, /* GetPPM */
3556 ATGEN_GetSIMIMSI,
3557 ATGEN_GetDateTime,
3558 ATGEN_SetDateTime,
3559 ATGEN_GetAlarm,
3560 NOTIMPLEMENTED, /* SetAlarm */
3561 NOTSUPPORTED, /* GetLocale */
3562 NOTSUPPORTED, /* SetLocale */
3563 ATGEN_PressKey,
3564 ATGEN_Reset,
3565 ATGEN_ResetPhoneSettings,
3566 ATGEN_EnterSecurityCode,
3567 ATGEN_GetSecurityStatus,
3568 ATGEN_GetDisplayStatus,
3569 ATGEN_SetAutoNetworkLogin,
3570 ATGEN_GetBatteryCharge,
3571 ATGEN_GetSignalQuality,
3572 ATGEN_GetNetworkInfo,
3573 NOTSUPPORTED, /* GetCategory */
3574 NOTSUPPORTED, /* AddCategory */
3575 NOTSUPPORTED, /* GetCategoryStatus */
3576 ATGEN_GetMemoryStatus,
3577 ATGEN_GetMemory,
3578 ATGEN_GetNextMemory,
3579 ATGEN_SetMemory,
3580 ATGEN_AddMemory,
3581 ATGEN_DeleteMemory,
3582 ATGEN_DeleteAllMemory,
3583 NOTSUPPORTED, /* GetSpeedDial */
3584 NOTSUPPORTED, /* SetSpeedDial */
3585 ATGEN_GetSMSC,
3586 ATGEN_SetSMSC,
3587 ATGEN_GetSMSStatus,
3588 ATGEN_GetSMS,
3589 ATGEN_GetNextSMS,
3590 NOTSUPPORTED, /* SetSMS */
3591 ATGEN_AddSMS,
3592 ATGEN_DeleteSMS,
3593 ATGEN_SendSMS,
3594 ATGEN_SendSavedSMS,
3595 ATGEN_SetIncomingSMS,
3596 ATGEN_SetIncomingCB,
3597 ATGEN_GetSMSFolders,
3598 NOTSUPPORTED, /* AddSMSFolder */
3599 NOTSUPPORTED, /* DeleteSMSFolder */
3600 ATGEN_DialVoice,
3601 ATGEN_AnswerCall,
3602 ATGEN_CancelCall,
3603 NOTSUPPORTED, /* HoldCall */
3604 NOTSUPPORTED, /* UnholdCall */
3605 NOTSUPPORTED, /* ConferenceCall */
3606 NOTSUPPORTED, /* SplitCall */
3607 NOTSUPPORTED, /* TransferCall */
3608 NOTSUPPORTED, /* SwitchCall */
3609 NOTSUPPORTED, /* GetCallDivert */
3610 NOTSUPPORTED, /* SetCallDivert */
3611 NOTSUPPORTED, /* CancelAllDiverts*/
3612 NONEFUNCTION, /* SetIncomingCall */
3613 NOTSUPPORTED, /* SetIncomingUSSD */
3614 ATGEN_SendDTMF,
3615 ATGEN_GetRingtone,
3616 ATGEN_SetRingtone,
3617 NOTSUPPORTED, /* GetRingtonesInfo*/
3618 NOTSUPPORTED, /* DeleteUserRingtones*/
3619 NOTSUPPORTED, /* PlayTone */
3620 NOTSUPPORTED, /* GetWAPBookmark */
3621 NOTSUPPORTED, /* SetWAPBookmark */
3622 NOTSUPPORTED, /* DeleteWAPBookmark */
3623 NOTSUPPORTED, /* GetWAPSettings */
3624 NOTSUPPORTED, /* SetWAPSettings */
3625 NOTSUPPORTED, /* GetMMSSettings */
3626 NOTSUPPORTED, /* SetMMSSettings */
3627 NOTSUPPORTED, /* GetSyncMLSettings*/
3628 NOTSUPPORTED, /* SetSyncMLSettings*/
3629 NOTSUPPORTED, /* GetChatSettings */
3630 NOTSUPPORTED, /* SetChatSettings */
3631 ATGEN_GetBitmap, /* GetBitmap */
3632 ATGEN_SetBitmap, /* SetBitmap */
3633 SONYERIC_GetToDoStatus,
3634 NOTSUPPORTED, /* GetToDo */
3635 SONYERIC_GetNextToDo,
3636 NOTSUPPORTED, /* SetToDo */
3637 SONYERIC_AddToDo,
3638 NOTSUPPORTED, /* DeleteToDo */
3639 SONYERIC_DeleteAllToDo,
3640 SONYERIC_GetCalendarStatus,
3641 NOTIMPLEMENTED, /* GetCalendar */
3642 ATGEN_GetNextCalendar,
3643 NOTIMPLEMENTED, /* SetCalendar */
3644 ATGEN_AddCalendarNote,
3645 ATGEN_DelCalendarNote,
3646 NOTIMPLEMENTED, /* DeleteAllCalendar*/
3647 NOTSUPPORTED, /* GetCalendarSettings*/
3648 NOTSUPPORTED, /* SetCalendarSettings*/
3649 NOTSUPPORTED, /* GetNote */
3650 NOTSUPPORTED, /* GetProfile */
3651 NOTSUPPORTED, /* SetProfile */
3652 NOTSUPPORTED, /* GetFMStation */
3653 NOTSUPPORTED, /* SetFMStation */
3654 NOTSUPPORTED, /* ClearFMStations */
3655 NOTSUPPORTED, /* GetNextFileFolder*/
3656 NOTSUPPORTED, /* GetFilePart */
3657 NOTSUPPORTED, /* AddFile */
3658 NOTSUPPORTED, /* GetFileSystemStatus*/
3659 NOTSUPPORTED, /* DeleteFile */
3660 NOTSUPPORTED, /* AddFolder */
3661 NOTSUPPORTED, /* GetGPRSAccessPoint*/
3662 NOTSUPPORTED /* SetGPRSAccessPoint*/
3663};
3664
3665#endif
3666
3667/* How should editor hadle tabs in this file? Add editor commands here.
3668 * vim: noexpandtab sw=8 ts=8 sts=8:
3669 */
diff --git a/gammu/emb/common/phone/at/atgen.h b/gammu/emb/common/phone/at/atgen.h
new file mode 100644
index 0000000..0e08ee4
--- a/dev/null
+++ b/gammu/emb/common/phone/at/atgen.h
@@ -0,0 +1,110 @@
1/* (c) 2002-2004 by Marcin Wiacek and Michal Cihar */
2
3#ifndef atgen_h
4#define atgen_h
5
6#include "../../gsmcomon.h"
7#include "../../gsmstate.h"
8#include "../../service/sms/gsmsms.h"
9
10#ifndef GSM_USED_AT
11# define GSM_USED_AT
12#endif
13#ifndef GSM_USED_BLUEAT
14# define GSM_USED_BLUEAT
15#endif
16#ifndef GSM_USED_IRDAAT
17# define GSM_USED_IRDAAT
18#endif
19
20#define MAX_VCALENDAR_LOCATION 50
21
22typedef enum {
23 SMS_AT_PDU = 1,
24 SMS_AT_TXT
25} GSM_AT_SMS_Modes;
26
27typedef enum {
28 AT_Reply_OK = 1,
29 AT_Reply_Connect,
30 AT_Reply_Error,
31 AT_Reply_Unknown,
32 AT_Reply_CMSError,
33 AT_Reply_CMEError,
34 AT_Reply_SMSEdit
35} GSM_AT_Reply_State;
36
37typedef enum {
38 AT_Nokia = 1,
39 AT_Alcatel,
40 AT_Siemens,
41 AT_HP,
42 AT_Falcom,
43 AT_Ericsson,
44 AT_Sagem,
45 AT_Unknown
46} GSM_AT_Manufacturer;
47
48typedef enum {
49 AT_PBK_HEX = 1,
50 AT_PBK_GSM,
51 AT_PBK_UCS2
52} GSM_AT_PBK_Charset;
53
54typedef enum {
55 AT_AVAILABLE = 1,
56 AT_NOTAVAILABLE
57} GSM_AT_SMSMemory;
58
59typedef enum {
60 AT_SBNR_AVAILABLE = 1,
61 AT_SBNR_NOTAVAILABLE
62} GSM_AT_SBNR;
63
64typedef enum {
65 AT_Status,
66 AT_NextEmpty,
67 AT_Total,
68 AT_First,
69 AT_Sizes
70} GSM_AT_NeededMemoryInfo;
71
72 #define AT_PBK_MAX_MEMORIES200
73
74typedef struct {
75 GSM_AT_Manufacturer Manufacturer; /* Who is manufacturer */
76 GSM_Lines Lines; /* Allow to simply get each line in response */
77 GSM_AT_Reply_State ReplyState; /* What response type - error, OK, etc. */
78 int ErrorCode; /* Error codes from responses */
79 char *ErrorText; /* Error description */
80
81 GSM_MemoryType PBKMemory; /* Last read PBK memory */
82 char PBKMemories[AT_PBK_MAX_MEMORIES + 1]; /* Supported by phone PBK memories */
83 int NextMemoryEntry; /* Next empty memory entry */
84 int FirstMemoryEntry; /* First memory entry to be read */
85 GSM_AT_PBK_Charset PBKCharset; /* Last read PBK charset */
86 bool UCS2CharsetFailed; /* Whether setting of UCS2 charset has already failed */
87 bool NonUCS2CharsetFailed; /* Whether setting of non-UCS2 charset has already failed */
88 GSM_AT_SBNR PBKSBNR;
89 int NumberLength;
90 int TextLength;
91 int MemorySize;
92
93 GSM_SMSMemoryStatusLastSMSStatus;
94 int LastSMSRead;
95 int FirstCalendarPos;
96 bool CanSaveSMS;
97 GSM_AT_SMSMemory PhoneSMSMemory; /* Is phone SMS memory available ? */
98 GSM_AT_SMSMemory SIMSMSMemory; /* Is SIM SMS memory available ? */
99 GSM_MemoryType SMSMemory; /* Last read SMS memory */
100 GSM_AT_SMS_Modes SMSMode; /* PDU or TEXT mode for SMS ? */
101
102 bool OBEX;
103 GSM_File file;
104} GSM_Phone_ATGENData;
105
106#endif
107
108/* How should editor hadle tabs in this file? Add editor commands here.
109 * vim: noexpandtab sw=8 ts=8 sts=8:
110 */
diff --git a/gammu/emb/common/phone/at/siemens.c b/gammu/emb/common/phone/at/siemens.c
new file mode 100644
index 0000000..ab7dd2c
--- a/dev/null
+++ b/gammu/emb/common/phone/at/siemens.c
@@ -0,0 +1,320 @@
1/* (c) 2002-2003 by Walek */
2
3#include "../../gsmstate.h"
4
5#ifdef GSM_ENABLE_ATGEN
6
7#include <string.h>
8#include <time.h>
9#include <ctype.h>
10
11#include "../../misc/coding/coding.h"
12#include "../../gsmcomon.h"
13#include "../../service/sms/gsmsms.h"
14#include "../pfunc.h"
15
16extern GSM_Error ATGEN_HandleCMSError(GSM_StateMachine *s);
17
18GSM_Error ATGEN_CMS35ReplySetFunction (GSM_Protocol_Message msg, GSM_StateMachine *s,char *function)
19{
20 if (s->Protocol.Data.AT.EditMode) {
21 s->Protocol.Data.AT.EditMode = false;
22 return ERR_NONE;
23 }
24 dbgprintf ("Written %s",function);
25 if (s->Phone.Data.Priv.ATGEN.ReplyState == AT_Reply_OK){
26 dbgprintf (" - OK\n");
27 return ERR_NONE;
28 } else {
29 dbgprintf (" - error\n");
30 return ERR_UNKNOWN;
31 }
32}
33
34GSM_Error GetSiemensFrame(GSM_Protocol_Message msg, GSM_StateMachine *s, char *templ,
35 unsigned char *buffer, int *len)
36{
37 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
38 int i=2, pos=0, length=0;
39 unsigned char buf[512];
40
41 if (strstr(GetLineString(msg.Buffer,Priv->Lines,2),"OK")) return ERR_EMPTY;
42 if (!strstr(GetLineString(msg.Buffer,Priv->Lines,2),templ)) return ERR_UNKNOWN;
43
44 while (1) {
45 if (Priv->Lines.numbers[i*2+1]==0) break;
46 if ((!strstr(GetLineString(msg.Buffer,Priv->Lines,i+1),templ)) &&
47 (strstr(GetLineString(msg.Buffer,Priv->Lines,i),templ))){
48 length = strlen(GetLineString(msg.Buffer,Priv->Lines,i+1));
49 DecodeHexBin(buf, GetLineString(msg.Buffer,Priv->Lines,i+1),length);
50 length = length/2;
51 memcpy (buffer+pos,buf,length);
52 pos+=length;
53 }
54 i++;
55 }
56 *len = pos;
57 return ERR_NONE;
58}
59
60GSM_Error SetSiemensFrame (GSM_StateMachine *s, unsigned char *buff, char *templ,
61 int Location, GSM_Phone_RequestID RequestID, int len)
62{
63 GSM_Phone_Data *Phone = &s->Phone.Data;
64 GSM_Error error;
65 unsigned char req[20],req1[512],hexreq[2096];
66 int MaxFrame,CurrentFrame,size,sz,pos=0;
67
68 EncodeHexBin(hexreq,buff,len);
69 size = len * 2;
70 MaxFrame = size / 352;
71 if (size % 352) MaxFrame++;
72
73 for (CurrentFrame=0;CurrentFrame<MaxFrame;CurrentFrame++) {
74 pos=CurrentFrame*352;
75 if (pos+352 < size) sz = 352; else sz = size - pos;
76 sprintf(req, "AT^SBNW=\"%s\",%i,%i,%i\r",templ,Location,CurrentFrame+1,MaxFrame);
77 s->Protocol.Data.AT.EditMode = true;
78 error = GSM_WaitFor (s, req, strlen(req), 0x00, 3, RequestID);
79 s->Phone.Data.DispatchError=ERR_TIMEOUT;
80 s->Phone.Data.RequestID=RequestID;
81 if (error!=ERR_NONE) return error;
82 memcpy (req1,hexreq+pos,sz);
83 error = s->Protocol.Functions->WriteMessage(s, req1, sz, 0x00);
84 if (error!=ERR_NONE) return error;
85 error = s->Protocol.Functions->WriteMessage(s,"\x1A", 1, 0x00);
86 if (error!=ERR_NONE) return error;
87 error = GSM_WaitForOnce(s, NULL, 0x00, 0x00, 4);
88 if (error == ERR_TIMEOUT) return error;
89 }
90 return Phone->DispatchError;
91}
92
93GSM_Error ATGEN_CMS35ReplyGetBitmap(GSM_Protocol_Message msg, GSM_StateMachine *s)
94{
95 unsigned char buffer[4096];
96 int length;
97 GSM_Error error;
98
99 error = GetSiemensFrame(msg,s,"bmp",buffer,&length);
100 if (error!=ERR_NONE) return error;
101 dbgprintf ("Operator logo received lenght=%i\n",length);
102 error = BMP2Bitmap (buffer,NULL,s->Phone.Data.Bitmap);
103 if (error==ERR_NONE) return error;
104 else return ERR_UNKNOWN;
105}
106
107GSM_Error ATGEN_CMS35ReplySetBitmap(GSM_Protocol_Message msg, GSM_StateMachine *s)
108{
109 return ATGEN_CMS35ReplySetFunction (msg, s, "Operator Logo");
110}
111
112GSM_Error ATGEN_GetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap)
113{
114 unsigned char req[32];
115
116 if (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED;
117 if (Bitmap->Type!=GSM_OperatorLogo) return ERR_NOTSUPPORTED;
118 if (Bitmap->Location-1 < 0) Bitmap->Location++;
119 s->Phone.Data.Bitmap=Bitmap;
120 sprintf(req, "AT^SBNR=\"bmp\",%i\r", Bitmap->Location-1);
121 smprintf(s, "Getting Bitmap\n");
122 return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetBitmap);
123}
124
125GSM_Error ATGEN_SetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap)
126{
127 unsigned char buffer[4096];
128 int length;
129 GSM_Errorerror;
130
131 if (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED;
132 if (Bitmap->Type!=GSM_OperatorLogo) return ERR_NOTSUPPORTED;
133
134 error = Bitmap2BMP (buffer,NULL,Bitmap);
135 if (error!=ERR_NONE) return error;
136 length = 0x100 * buffer[3] + buffer[2];
137 buffer[58]=0xff; buffer[59]=0xff; buffer[60]=0xff;
138 if (Bitmap->Location-1 < 0) Bitmap->Location++;
139 s->Phone.Data.Bitmap=Bitmap;
140 return SetSiemensFrame(s, buffer,"bmp",Bitmap->Location-1,
141 ID_SetBitmap,length);
142}
143
144GSM_Error ATGEN_CMS35ReplyGetRingtone(GSM_Protocol_Message msg, GSM_StateMachine *s)
145{
146 unsigned char buffer[32];
147 int length;
148 GSM_Error error;
149
150 error = GetSiemensFrame(msg,s,"mid",s->Phone.Data.Ringtone->NokiaBinary.Frame,&length);
151 if (error!=ERR_NONE) return error;
152 dbgprintf ("Midi ringtone received\n");
153
154 s->Phone.Data.Ringtone->Format = RING_MIDI;
155 s->Phone.Data.Ringtone->NokiaBinary.Length= length;
156 sprintf(buffer,"Individual");
157 EncodeUnicode (s->Phone.Data.Ringtone->Name,buffer,strlen(buffer));
158 return ERR_NONE;
159}
160
161GSM_Error ATGEN_GetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, bool PhoneRingtone)
162{
163 unsigned char req[32];
164
165 if (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED;
166
167 s->Phone.Data.Ringtone=Ringtone;
168 sprintf(req, "AT^SBNR=\"mid\",%i\r", Ringtone->Location-1);
169 smprintf(s, "Getting RingTone\n");
170 return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetRingtone);
171}
172
173GSM_Error ATGEN_CMS35ReplySetRingtone(GSM_Protocol_Message msg, GSM_StateMachine *s)
174{
175 return ATGEN_CMS35ReplySetFunction (msg, s, "Ringtone");
176}
177
178GSM_Error ATGEN_SetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, int *maxlength)
179{
180 GSM_Phone_Data *Phone = &s->Phone.Data;
181
182 if (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED;
183
184 if (Ringtone->Location==255) Ringtone->Location=1;
185 if (Ringtone->Location-1 > 1) return ERR_INVALIDLOCATION;
186
187 s->Phone.Data.Ringtone= Ringtone;
188 Phone->Ringtone = Ringtone;
189 return SetSiemensFrame(s, Ringtone->NokiaBinary.Frame,"mid",Ringtone->Location-1,
190 ID_SetRingtone,Ringtone->NokiaBinary.Length);
191}
192
193GSM_Error ATGEN_CMS35ReplyGetNextCal(GSM_Protocol_Message msg, GSM_StateMachine *s)
194{
195 GSM_Phone_Data *Data = &s->Phone.Data;
196 GSM_CalendarEntry*Calendar = Data->Cal;
197 GSM_ToDoEntry ToDo;
198 GSM_Error error;
199 unsigned char buffer[354];
200 int len, pos=0;
201
202 if (Data->Priv.ATGEN.ReplyState != AT_Reply_OK) return ERR_UNKNOWN;
203
204 error = GetSiemensFrame(msg,s,"vcs",buffer,&len);
205 if (error!=ERR_NONE) return error;
206 error=GSM_DecodeVCALENDAR_VTODO(buffer,&pos,Calendar,&ToDo,Siemens_VCalendar,0);
207
208 return error;
209}
210
211GSM_Error SIEMENS_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start)
212{
213 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
214 GSM_Error error;
215 unsigned char req[32];
216 int Location;
217
218 if (Priv->Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED;
219
220 if (start) Note->Location=Priv->FirstCalendarPos;
221 s->Phone.Data.Cal = Note;
222 Note->EntriesNum = 0;
223 smprintf(s, "Getting VCALENDAR\n");
224 Location = Note->Location;
225 while (1){
226 Location++;
227 sprintf(req, "AT^SBNR=\"vcs\",%i\r",Location);
228 error = GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_GetCalendarNote);
229 if ((error!=ERR_NONE) && (error!=ERR_EMPTY)) return ERR_INVALIDLOCATION;
230 Note->Location = Location;
231 Priv->FirstCalendarPos = Location;
232 if (Location > MAX_VCALENDAR_LOCATION) return ERR_EMPTY;
233 if (error==ERR_NONE) return error;
234 }
235 return error;
236}
237
238GSM_Error ATGEN_CMS35ReplySetCalendar(GSM_Protocol_Message msg, GSM_StateMachine *s)
239{
240 return ATGEN_CMS35ReplySetFunction (msg, s, "Calendar Note");
241}
242
243GSM_Error ATGEN_CMS35ReplyDeleteCalendar(GSM_Protocol_Message msg, GSM_StateMachine *s)
244{
245 GSM_Phone_Data *Data = &s->Phone.Data;
246
247 if (Data->Cal->Location > MAX_VCALENDAR_LOCATION) return ERR_UNKNOWN;
248
249 if (Data->Priv.ATGEN.ReplyState== AT_Reply_OK) {
250 smprintf(s, "Calendar note deleted\n");
251 return ERR_NONE;
252 } else {
253 smprintf(s, "Can't delete calendar note\n");
254 return ERR_UNKNOWN;
255 }
256}
257
258GSM_Error SIEMENS_DelCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note)
259{
260 unsigned char req[32];
261
262 if (s->Phone.Data.Priv.ATGEN.Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED;
263 s->Phone.Data.Cal = Note;
264 sprintf(req, "AT^SBNW=\"vcs\",%i,0\r",Note->Location);
265 smprintf(s, "Deleting calendar note\n");
266 return GSM_WaitFor (s, req, strlen(req), 0x00, 4, ID_DeleteCalendarNote);
267}
268
269GSM_Error SIEMENS_AddCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note)
270{
271 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
272 GSM_Error error;
273 unsigned char req[500];
274 int size=0;
275
276 if (Priv->Manufacturer!=AT_Siemens) return ERR_NOTSUPPORTED;
277 // if (Note->Location==0x00) return ERR_INVALIDLOCATION;
278
279 s->Phone.Data.Cal = Note;
280 error=GSM_EncodeVCALENDAR(req,&size,Note,true,Siemens_VCalendar);
281
282 return SetSiemensFrame (s,req,"vcs",Note->Location,ID_SetCalendarNote,size);
283}
284
285/* (c) by Timo Teras */
286GSM_Error ATGEN_SL45ReplyGetMemory(GSM_Protocol_Message msg, GSM_StateMachine *s)
287{
288#ifndef ENABLE_LGPL
289 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
290 GSM_MemoryEntry *Memory = s->Phone.Data.Memory;
291 unsigned char buffer[500],buffer2[500];
292
293 switch (Priv->ReplyState) {
294 case AT_Reply_OK:
295 smprintf(s, "Phonebook entry received\n");
296 CopyLineString(buffer, msg.Buffer, Priv->Lines, 3);
297 DecodeHexBin(buffer2,buffer,strlen(buffer));
298 Memory->EntriesNum = 0;
299 DecodeVCARD21Text(buffer2, Memory);
300 if (Memory->EntriesNum == 0) return ERR_EMPTY;
301 return ERR_NONE;
302 case AT_Reply_Error:
303 smprintf(s, "Error - too high location ?\n");
304 return ERR_INVALIDLOCATION;
305 case AT_Reply_CMSError:
306 return ATGEN_HandleCMSError(s);
307 default:
308 break;
309 }
310 return ERR_UNKNOWNRESPONSE;
311#else
312 return ERR_NOTIMPLEMENTED;
313#endif
314}
315
316#endif
317
318/* How should editor hadle tabs in this file? Add editor commands here.
319 * vim: noexpandtab sw=8 ts=8 sts=8:
320 */
diff --git a/gammu/emb/common/phone/at/sonyeric.c b/gammu/emb/common/phone/at/sonyeric.c
new file mode 100644
index 0000000..4b2670a
--- a/dev/null
+++ b/gammu/emb/common/phone/at/sonyeric.c
@@ -0,0 +1,411 @@
1/* (c) 2003 by Marcin Wiacek */
2
3#include "../../gsmstate.h"
4
5#ifdef GSM_ENABLE_ATGEN
6
7#include <string.h>
8#include <time.h>
9#include <ctype.h>
10
11#include "../../gsmcomon.h"
12#include "../../misc/coding/coding.h"
13
14 extern GSM_Reply_Function ATGENReplyFunctions[];
15 extern GSM_Error ATGEN_DispatchMessage(GSM_StateMachine *s);
16
17#ifdef GSM_ENABLE_OBEXGEN
18
19 extern GSM_Reply_Function OBEXGENReplyFunctions[];
20 extern GSM_Error OBEXGEN_GetFilePart(GSM_StateMachine *s, GSM_File *File);
21 extern GSM_Error OBEXGEN_AddFilePart(GSM_StateMachine *s, GSM_File *File, int *Pos);
22 extern GSM_Error OBEXGEN_Disconnect(GSM_StateMachine *s);
23
24#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX)
25
26static GSM_Error SONYERIC_SetOBEXMode(GSM_StateMachine *s)
27{
28 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
29 GSM_Error error;
30
31 if (Priv->OBEX) return ERR_NONE;
32
33 dbgprintf ("Changing to OBEX\n");
34
35 error=GSM_WaitFor (s, "AT*EOBEX\r", 9, 0x00, 4, ID_SetOBEX);
36 if (error != ERR_NONE) return error;
37
38 error = s->Protocol.Functions->Terminate(s);
39 if (error != ERR_NONE) return error;
40
41 s->Protocol.Functions = &OBEXProtocol;
42 error = s->Protocol.Functions->Initialise(s);
43 if (error != ERR_NONE) {
44 s->Protocol.Functions = &ATProtocol;
45 return error;
46 }
47 strcpy(s->CurrentConfig->Model,"seobex");
48 s->Phone.Data.Priv.OBEXGEN.Service = 0;
49 s->Phone.Functions->DispatchMessage= GSM_DispatchMessage;
50 s->Phone.Functions->ReplyFunctions= OBEXGENReplyFunctions;
51 Priv->OBEX = true;
52 return ERR_NONE;
53}
54
55static GSM_Error SONYERIC_SetATMode(GSM_StateMachine *s)
56{
57 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
58 GSM_Error error;
59
60 if (!Priv->OBEX) return ERR_NONE;
61
62 dbgprintf ("Changing to AT\n");
63
64 error = OBEXGEN_Disconnect(s);
65 if (error != ERR_NONE) return error;
66
67 error = s->Protocol.Functions->Terminate(s);
68 if (error != ERR_NONE) return error;
69
70 s->Protocol.Functions = &ATProtocol;
71 error = s->Protocol.Functions->Initialise(s);
72 if (error != ERR_NONE) {
73 s->Protocol.Functions = &OBEXProtocol;
74 return error;
75 }
76 strcpy(s->CurrentConfig->Model,"at");
77 s->Phone.Functions->DispatchMessage= ATGEN_DispatchMessage;
78 s->Phone.Functions->ReplyFunctions= ATGENReplyFunctions;
79 Priv->OBEX = false;
80 return ERR_NONE;
81}
82
83static GSM_Error SONYERIC_GetFile(GSM_StateMachine *s, GSM_File *File, unsigned char *FileName)
84{
85 GSM_Error error;
86
87 strcpy(File->ID_FullName,FileName);
88 File->Used = 0;
89 if (File->Buffer != NULL) free(File->Buffer);
90 File->Buffer = NULL;
91
92 error = SONYERIC_SetOBEXMode(s);
93 if (error != ERR_NONE) return error;
94
95 error = ERR_NONE;
96 while (error == ERR_NONE) error = OBEXGEN_GetFilePart(s,File);
97 if (error != ERR_EMPTY) return error;
98
99 return SONYERIC_SetATMode(s);
100}
101
102static GSM_Error SONYERIC_SetFile(GSM_StateMachine *s, unsigned char *FileName, unsigned char *Buffer, int Length)
103{
104 GSM_Errorerror;
105 GSM_File File;
106 int Pos = 0;
107
108 error = SONYERIC_SetOBEXMode(s);
109 if (error != ERR_NONE) return error;
110
111 strcpy(File.ID_FullName,FileName);
112 EncodeUnicode(File.Name,FileName,strlen(FileName));
113 File.Used = Length;
114 File.Buffer = malloc(Length);
115 memcpy(File.Buffer,Buffer,Length);
116
117 error = ERR_NONE;
118 while (error == ERR_NONE) error = OBEXGEN_AddFilePart(s,&File,&Pos);
119 free(File.Buffer);
120 if (error != ERR_EMPTY) return error;
121
122 return SONYERIC_SetATMode(s);
123}
124
125#endif
126
127GSM_Error SONYERIC_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start)
128{
129#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX)
130 GSM_Error error;
131 GSM_ToDoEntry ToDo;
132 int Pos, num, Loc;
133 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
134
135 if (start) {
136 error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs");
137 if (error != ERR_NONE) return error;
138
139 Note->Location = 1;
140 } else {
141 Note->Location++;
142 }
143 smprintf(s, "Getting calendar note %i\n",Note->Location);
144
145 Loc = Note->Location;
146 Pos = 0;
147 num = 0;
148 while (1) {
149 error = GSM_DecodeVCALENDAR_VTODO(Priv->file.Buffer, &Pos, Note, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo);
150 if (error == ERR_EMPTY) break;
151 if (error != ERR_NONE) return error;
152 if (Note->EntriesNum != 0) {
153 num++;
154 if (num == Loc) return ERR_NONE;
155 }
156 }
157 return ERR_EMPTY;
158#else
159 return ERR_SOURCENOTAVAILABLE;
160#endif
161}
162
163GSM_Error SONYERIC_GetNextToDo(GSM_StateMachine *s, GSM_ToDoEntry *ToDo, bool start)
164{
165#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX)
166 GSM_Error error;
167 GSM_CalendarEntryCalendar;
168 int Pos, num, Loc;
169 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
170
171 if (Priv->Manufacturer!=AT_Ericsson) return ERR_NOTSUPPORTED;
172
173 if (start) {
174 error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs");
175 if (error != ERR_NONE) return error;
176
177 ToDo->Location = 1;
178 } else {
179 ToDo->Location++;
180 }
181 smprintf(s,"Getting ToDo %i\n",ToDo->Location);
182
183 Loc = ToDo->Location;
184 Pos = 0;
185 num = 0;
186 while (1) {
187 error = GSM_DecodeVCALENDAR_VTODO(Priv->file.Buffer, &Pos, &Calendar, ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo);
188 if (error == ERR_EMPTY) break;
189 if (error != ERR_NONE) return error;
190 if (ToDo->EntriesNum != 0) {
191 num++;
192 if (num == Loc) return ERR_NONE;
193 }
194 }
195
196 return ERR_EMPTY;
197#else
198 return ERR_SOURCENOTAVAILABLE;
199#endif
200}
201
202GSM_Error SONYERIC_GetToDoStatus(GSM_StateMachine *s, GSM_ToDoStatus *status)
203{
204#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX)
205 GSM_Error error;
206 GSM_ToDoEntry ToDo;
207 GSM_CalendarEntry Calendar;
208 int Pos;
209 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
210
211 if (Priv->Manufacturer!=AT_Ericsson) return ERR_NOTSUPPORTED;
212
213 smprintf(s,"Getting ToDo status\n");
214
215 error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs");
216 if (error != ERR_NONE) return error;
217
218 status->Used = 0;
219 Pos = 0;
220 while (1) {
221 error = GSM_DecodeVCALENDAR_VTODO(Priv->file.Buffer, &Pos, &Calendar, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo);
222 if (error == ERR_EMPTY) break;
223 if (error != ERR_NONE) return error;
224 if (ToDo.EntriesNum != 0) status->Used++;
225 }
226
227 return ERR_NONE;
228#else
229 return ERR_SOURCENOTAVAILABLE;
230#endif
231}
232
233GSM_Error SONYERIC_AddCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note)
234{
235#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX)
236 unsigned char req[5000];
237 int size=0;
238
239 smprintf(s,"Adding calendar note\n");
240
241 GSM_EncodeVCALENDAR(req,&size,Note,true,SonyEricsson_VCalendar);
242
243 return SONYERIC_SetFile(s, "telecom/cal/luid/.vcs", req, size);
244#else
245 return ERR_SOURCENOTAVAILABLE;
246#endif
247}
248
249GSM_Error SONYERIC_AddToDo(GSM_StateMachine *s, GSM_ToDoEntry *ToDo)
250{
251#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX)
252 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
253 unsigned char req[5000];
254 int size=0;
255
256 if (Priv->Manufacturer!=AT_Ericsson) return ERR_NOTSUPPORTED;
257
258 smprintf(s,"Adding ToDo\n");
259
260 GSM_EncodeVTODO(req,&size,ToDo,true,SonyEricsson_VToDo);
261
262 return SONYERIC_SetFile(s, "telecom/cal/luid/.vcs", req, size);
263#else
264 return ERR_SOURCENOTAVAILABLE;
265#endif
266}
267
268GSM_Error SONYERIC_DeleteAllToDo(GSM_StateMachine *s)
269{
270#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX)
271 GSM_Error error;
272 int Pos,Level = 0,Used;
273 unsigned char *Buf;
274 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
275 unsigned char Line[2000];
276
277 if (Priv->Manufacturer!=AT_Ericsson) return ERR_NOTSUPPORTED;
278
279 smprintf(s,"Deleting all ToDo\n");
280
281 error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs");
282 if (error != ERR_NONE) return error;
283
284 Pos = 0;
285 Buf = NULL;
286 Used = 0;
287 while (1) {
288 MyGetLine(Priv->file.Buffer, &Pos, Line, Priv->file.Used);
289 if (strlen(Line) == 0) break;
290 dbgprintf("Line is %s,%i,%i\n",Line,Priv->file.Used,Pos);
291 switch (Level) {
292 case 0:
293 if (strstr(Line,"BEGIN:VTODO")) {
294 Level = 2;
295 break;
296 }
297 Buf=(unsigned char *)realloc(Buf,Used+strlen(Line)+3);
298 strcpy(Buf+Used,Line);
299 Used=Used+strlen(Line)+3;
300 Buf[Used-3] = 13;
301 Buf[Used-2] = 10;
302 Buf[Used-1] = 0x00;
303 break;
304 case 2: /* ToDo note */
305 if (strstr(Line,"END:VTODO")) {
306 Level = 0;
307 }
308 break;
309 }
310 }
311
312 error = SONYERIC_SetFile(s, "telecom/cal.vcs", Buf, Used);
313 //if (Buf != NULL) free(Buf);
314 return error;
315#else
316 return ERR_SOURCENOTAVAILABLE;
317#endif
318}
319
320GSM_Error SONYERIC_DelCalendarNote(GSM_StateMachine *s, GSM_CalendarEntry *Note)
321{
322#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX)
323 GSM_Error error;
324 int Pos,Level = 0,Loc=0,Used;
325 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
326 unsigned char Line[2000];
327 unsigned char *Buf;
328
329 smprintf(s, "Deleting calendar note %i\n",Note->Location);
330
331 error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs");
332 if (error != ERR_NONE) return error;
333
334 Pos = 0;
335 Buf = NULL;
336 Used = 0;
337 while (1) {
338 MyGetLine(Priv->file.Buffer, &Pos, Line, Priv->file.Used);
339 if (strlen(Line) == 0) break;
340 dbgprintf("Line is %s,%i,%i\n",Line,Priv->file.Used,Pos);
341 switch (Level) {
342 case 0:
343 if (strstr(Line,"BEGIN:VEVENT")) {
344 Loc++;
345 if (Loc == Note->Location) {
346 Level = 1;
347 break;
348 }
349 }
350 Buf=(unsigned char *)realloc(Buf,Used+strlen(Line)+3);
351 strcpy(Buf+Used,Line);
352 Used=Used+strlen(Line)+3;
353 Buf[Used-3] = 13;
354 Buf[Used-2] = 10;
355 Buf[Used-1] = 0x00;
356 break;
357 case 1: /* Calendar note */
358 if (strstr(Line,"END:VEVENT")) {
359 Level = 0;
360 }
361 break;
362 }
363 }
364
365 DumpMessage(s->di.df, s->di.dl, Buf, Used);
366
367 error = SONYERIC_SetFile(s, "telecom/cal.vcs", Buf, Used);
368 if (Buf != NULL) free(Buf);
369 return error;
370#else
371 return ERR_SOURCENOTAVAILABLE;
372#endif
373}
374
375GSM_Error SONYERIC_GetCalendarStatus(GSM_StateMachine *s, GSM_CalendarStatus *Status)
376{
377#if defined(GSM_ENABLE_BLUEOBEX) || defined(GSM_ENABLE_IRDAOBEX)
378 GSM_Error error;
379 GSM_ToDoEntry ToDo;
380 GSM_CalendarEntry Calendar;
381 int Pos;
382 GSM_Phone_ATGENData*Priv = &s->Phone.Data.Priv.ATGEN;
383
384 if (Priv->Manufacturer!=AT_Ericsson) return ERR_NOTSUPPORTED;
385
386 smprintf(s, "Getting calendar status\n");
387
388 error = SONYERIC_GetFile(s, &Priv->file, "telecom/cal.vcs");
389 if (error != ERR_NONE) return error;
390
391 Status->Used = 0;
392 Pos = 0;
393 while (1) {
394 error = GSM_DecodeVCALENDAR_VTODO(Priv->file.Buffer, &Pos, &Calendar, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo);
395 if (error == ERR_EMPTY) break;
396 if (error != ERR_NONE) return error;
397 if (Calendar.EntriesNum != 0) Status->Used++;
398 }
399
400 return ERR_NONE;
401#else
402 return ERR_SOURCENOTAVAILABLE;
403#endif
404}
405
406#endif
407#endif
408
409/* How should editor hadle tabs in this file? Add editor commands here.
410 * vim: noexpandtab sw=8 ts=8 sts=8:
411 */