1 /* (c) 2002-2008 by Marcin Wiacek and Michal Cihar */
2
3 /**
4 * @file atgen.c
5 * @author Michal Čihař
6 * @author Marcin Wiacek
7 */
8 /**
9 * @ingroup Phone
10 * @{
11 */
12 /**
13 * @addtogroup ATPhone
14 * @{
15 */
16
17 #include "gammu-error.h"
18 #define _GNU_SOURCE
19 #include <gammu-config.h>
20
21 #ifdef GSM_ENABLE_ATGEN
22
23 #include <string.h>
24 #include <time.h>
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <assert.h>
28
29 #include "../../gsmcomon.h"
30 #include "../../gsmphones.h"
31 #include "../../misc/coding/coding.h"
32 #include "../../service/gsmpbk.h"
33 #include "../pfunc.h"
34
35 #include "atgen.h"
36 #include "atfunc.h"
37
38 #include "../../../libgammu/misc/string.h"
39
ATGEN_SetSMSC(GSM_StateMachine * s,GSM_SMSC * smsc)40 GSM_Error ATGEN_SetSMSC(GSM_StateMachine *s, GSM_SMSC *smsc)
41 {
42 GSM_Error error;
43 /*
44 * String value.
45 * It indicates the SMSC number.
46 * The numberr is composed '*', '#', '0'-'9'
47 * The number contains 20 characters at most.
48 */
49 unsigned char smscCmdReq[GSM_MAX_NUMBER_LENGTH + 12]={'\0'};
50
51 if (smsc->Location != 1) {
52 return ERR_INVALIDLOCATION;
53 }
54 smprintf(s, "Setting SMSC\n");
55 sprintf(smscCmdReq, "AT+CSCA=\"%s\"\r",DecodeUnicodeString(smsc->Number));
56 error = ATGEN_WaitForAutoLen(s, smscCmdReq, 0x00, 40, ID_SetSMSC);
57 return error;
58 }
59
ATGEN_ReplyGetSMSMemories(GSM_Protocol_Message * msg,GSM_StateMachine * s)60 GSM_Error ATGEN_ReplyGetSMSMemories(GSM_Protocol_Message *msg, GSM_StateMachine *s)
61 {
62 char *pos_start = NULL, *pos_end = NULL, *pos_tmp = NULL;
63 const char *Line;
64 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
65
66 switch (Priv->ReplyState) {
67 case AT_Reply_OK:
68 /* Reply here is:
69 * (memories for reading)[, (memories for writing)[, (memories for storing received messages)]]
70 * each memory is in quotes,
71 * Example: ("SM"), ("SM"), ("SM")
72 *
73 * TODO: Reply can be also "SM", "SM", "SM"
74 *
75 * We need to get from this supported memories. For this case
76 * we assume, that just appearence of memory makes it
77 * available for everything. Then we need to find out whether
78 * phone supports writing to memory. This is done by searching
79 * for "), (", which will appear between lists.
80 *
81 * @todo: Add support for BM (broadcast messages).
82 */
83 Priv->PhoneSaveSMS = AT_NOTAVAILABLE;
84 Priv->SIMSaveSMS = AT_NOTAVAILABLE;
85 Priv->SRSaveSMS = AT_NOTAVAILABLE;
86
87 Line = GetLineString(msg->Buffer, &Priv->Lines, 2);
88 /* Skip empty line in response */
89 if (strcmp(Line, "") == 0) {
90 Line = GetLineString(msg->Buffer, &Priv->Lines, 3);
91 }
92 if (strcmp(Line, "+CPMS: ") == 0 && Priv->Manufacturer == AT_Samsung) {
93 smprintf(s, "Assuming broken Samsung response, both memories available!\n");
94 Priv->PhoneSMSMemory = AT_AVAILABLE;
95 Priv->SIMSMSMemory = AT_AVAILABLE;
96 Priv->PhoneSaveSMS = AT_AVAILABLE;
97 Priv->SIMSaveSMS = AT_AVAILABLE;
98 goto completed;
99 }
100
101 if (strchr(msg->Buffer, '(') == NULL) {
102 smprintf(s, "Assuming broken iWOW style response, no lists!\n");
103 pos_start = strstr(msg->Buffer, "\", \"");
104
105 if (pos_start == NULL) {
106 pos_start = strstr(msg->Buffer, "\",\"");
107 }
108 } else {
109 pos_start = strstr(msg->Buffer, "), (");
110
111 if (pos_start == NULL) {
112 pos_start = strstr(msg->Buffer, "),(");
113 }
114 }
115 if (pos_start != NULL) {
116 /* Detect which memories we can use for saving */
117 pos_end = strchrnul(pos_start + 1, ')');
118 pos_tmp = strstr(pos_start, "\"SM\"");
119
120 if (pos_tmp != NULL && pos_tmp < pos_end) {
121 Priv->SIMSaveSMS = AT_AVAILABLE;
122 }
123 pos_tmp = strstr(pos_start, "\"ME\"");
124
125 if (pos_tmp != NULL && pos_tmp < pos_end) {
126 Priv->PhoneSaveSMS = AT_AVAILABLE;
127 }
128
129 pos_tmp = strstr(pos_start, "\"SR\"");
130
131 if (pos_tmp != NULL && pos_tmp < pos_end) {
132 Priv->SRSaveSMS = AT_AVAILABLE;
133 }
134 }
135 if (strstr(msg->Buffer, "\"SM\"") != NULL) {
136 Priv->SIMSMSMemory = AT_AVAILABLE;
137 } else {
138 Priv->SIMSMSMemory = AT_NOTAVAILABLE;
139 }
140 if (strstr(msg->Buffer, "\"SR\"") != NULL) {
141 Priv->SRSMSMemory = AT_AVAILABLE;
142 } else {
143 Priv->SRSMSMemory = AT_NOTAVAILABLE;
144 }
145 if (strstr(msg->Buffer, "\"ME\"") != NULL) {
146 Priv->PhoneSMSMemory = AT_AVAILABLE;
147 } else {
148 Priv->PhoneSMSMemory = AT_NOTAVAILABLE;
149
150 /* Check for Motorola style folders */
151 if (strstr(msg->Buffer, "\"MT\"") != NULL && strstr(msg->Buffer, "\"OM\"") != NULL) {
152 Priv->PhoneSMSMemory = AT_AVAILABLE;
153 Priv->PhoneSaveSMS = AT_AVAILABLE;
154 Priv->MotorolaSMS = TRUE;
155 }
156
157 }
158 completed:
159 smprintf(s, "Available SMS memories received: read: ME : %s, SM : %s, SR : %s save: ME : %s, SM : %s, SR : %s, Motorola = %s\n",
160 Priv->PhoneSMSMemory == AT_AVAILABLE ? "ok" : "N/A",
161 Priv->SIMSMSMemory == AT_AVAILABLE ? "ok" : "N/A",
162 Priv->SRSMSMemory == AT_AVAILABLE ? "ok" : "N/A",
163 Priv->PhoneSaveSMS == AT_AVAILABLE ? "ok" : "N/A",
164 Priv->SIMSaveSMS == AT_AVAILABLE ? "ok" : "N/A",
165 Priv->SRSaveSMS == AT_AVAILABLE ? "ok" : "N/A",
166 Priv->MotorolaSMS ? "yes" : "no"
167 );
168
169 return ERR_NONE;
170 case AT_Reply_Error:
171 return ERR_NOTSUPPORTED;
172 case AT_Reply_CMSError:
173 return ATGEN_HandleCMSError(s);
174 case AT_Reply_CMEError:
175 return ATGEN_HandleCMEError(s);
176 default:
177 return ERR_UNKNOWNRESPONSE;
178 }
179 }
180
ATGEN_GetSMSMemories(GSM_StateMachine * s)181 GSM_Error ATGEN_GetSMSMemories(GSM_StateMachine *s)
182 {
183 GSM_Error error;
184 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
185
186 smprintf(s, "Getting available SMS memories\n");
187 error = ATGEN_WaitForAutoLen(s, "AT+CPMS=?\r", 0x00, 200, ID_GetSMSMemories);
188
189 if (error != ERR_NONE) {
190 return error;
191 }
192
193 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMS_SM)) {
194 smprintf(s, "Forcing support for SM storage!\n");
195 Priv->SIMSaveSMS = AT_AVAILABLE;
196 Priv->SIMSMSMemory = AT_AVAILABLE;
197 }
198 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMS_ME)) {
199 smprintf(s, "Forcing support for ME storage!\n");
200 Priv->PhoneSMSMemory = AT_AVAILABLE;
201 Priv->PhoneSaveSMS = AT_AVAILABLE;
202 }
203 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMS_SR)) {
204 smprintf(s, "Forcing support for SR storage!\n");
205 Priv->SRSMSMemory = AT_AVAILABLE;
206 }
207 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMS_NO_SR)) {
208 smprintf(s, "Forcing to disable SR storage!\n");
209 Priv->SRSMSMemory = AT_NOTAVAILABLE;
210 }
211 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMS_NO_ME)) {
212 smprintf(s, "Forcing to disable ME storage!\n");
213 Priv->PhoneSMSMemory = AT_NOTAVAILABLE;
214 Priv->PhoneSaveSMS = AT_NOTAVAILABLE;
215 }
216 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMS_NO_SM)) {
217 smprintf(s, "Forcing to disable SM storage!\n");
218 Priv->SIMSMSMemory = AT_NOTAVAILABLE;
219 Priv->SIMSaveSMS = AT_NOTAVAILABLE;
220 }
221
222 // count standard folders
223 Priv->NumFolders = 0;
224 if(ATGEN_IsMemoryAvailable(Priv, MEM_SM))
225 Priv->NumFolders++;
226
227 if(ATGEN_IsMemoryAvailable(Priv, MEM_ME))
228 Priv->NumFolders++;
229
230 return ERR_NONE;
231 }
232
ATGEN_SetSMSMemory(GSM_StateMachine * s,gboolean SIM,gboolean for_write,gboolean outbox)233 GSM_Error ATGEN_SetSMSMemory(GSM_StateMachine *s, gboolean SIM, gboolean for_write, gboolean outbox)
234 {
235 GSM_Error error;
236 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
237
238 /*
239 * Store message to memory.
240 */
241 unsigned char cpmsCmdReq[] = "AT+CPMS=\"XX\",\"XX\"\r";
242 size_t cpmsCmdReqLength = strlen(cpmsCmdReq);
243
244 /* If phone encodes also values in command, we need normal charset */
245 if (Priv->EncodedCommands) {
246 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_NORMAL);
247
248 if (error != ERR_NONE) {
249 return error;
250 }
251 }
252 if ((SIM && Priv->SIMSMSMemory == 0) || (!SIM && Priv->PhoneSMSMemory == 0)) {
253 /* We silently ignore error here, because when this fails, we can try to setmemory anyway */
254 ATGEN_GetSMSMemories(s);
255 }
256
257 /* If phone can not save SMS, don't try to set memory for saving */
258 if (for_write) {
259 if (SIM && Priv->SIMSaveSMS == AT_NOTAVAILABLE) {
260 smprintf(s, "Saving SMS not supported!\n");
261 return ERR_NOTSUPPORTED;
262 }
263 if (!SIM && Priv->PhoneSaveSMS == AT_NOTAVAILABLE) {
264 smprintf(s, "Saving SMS not supported!\n");
265 return ERR_NOTSUPPORTED;
266 }
267 } else {
268 /* No need to set memory for writing */
269 cpmsCmdReq[12] = '\r';
270 cpmsCmdReqLength = 13;
271 }
272 if (SIM) {
273 if (Priv->SMSMemory == MEM_SM && (Priv->SMSMemoryWrite || !for_write)) {
274 return ERR_NONE;
275 }
276 if (Priv->SIMSMSMemory == AT_NOTAVAILABLE) {
277 return ERR_NOTSUPPORTED;
278 }
279 cpmsCmdReq[9] = 'S'; cpmsCmdReq[10] = 'M';
280 cpmsCmdReq[14] = 'S'; cpmsCmdReq[15] = 'M';
281
282 smprintf(s, "Setting SMS memory type to SM\n");
283 error = ATGEN_WaitFor(s, cpmsCmdReq, cpmsCmdReqLength, 0x00, 20, ID_SetMemoryType);
284
285 if (Priv->SIMSMSMemory == 0 && error != ERR_NONE) {
286 Priv->SIMSMSMemory = AT_AVAILABLE;
287 }
288 if (error == ERR_NOTSUPPORTED) {
289 smprintf(s, "Can't access SIM card?\n");
290 return ERR_SECURITYERROR;
291 }
292 if (error != ERR_NONE) {
293 return error;
294 }
295 Priv->SMSMemory = MEM_SM;
296 Priv->SMSMemoryWrite = for_write;
297 } else {
298 if (Priv->SMSMemory == MEM_ME && (Priv->SMSMemoryWrite || !for_write)) {
299 return ERR_NONE;
300 }
301 if (Priv->PhoneSMSMemory == AT_NOTAVAILABLE) {
302 return ERR_NOTSUPPORTED;
303 }
304 if (Priv->MotorolaSMS) {
305 cpmsCmdReq[9] = 'M'; cpmsCmdReq[10] = 'T';
306
307 if (outbox) {
308 cpmsCmdReq[14] = 'O'; cpmsCmdReq[15] = 'M';
309 } else {
310 cpmsCmdReq[14] = 'I'; cpmsCmdReq[15] = 'M';
311 }
312 } else {
313 cpmsCmdReq[9] = 'M'; cpmsCmdReq[10] = 'E';
314 cpmsCmdReq[14] = 'M'; cpmsCmdReq[15] = 'E';
315 }
316 smprintf(s, "Setting SMS memory type to ME\n");
317 error = ATGEN_WaitFor(s, cpmsCmdReq, cpmsCmdReqLength, 0x00, 200, ID_SetMemoryType);
318
319 if (Priv->PhoneSMSMemory == 0 && error == ERR_NONE) {
320 Priv->PhoneSMSMemory = AT_AVAILABLE;
321 }
322 if (error != ERR_NONE) {
323 return error;
324 }
325 Priv->SMSMemory = MEM_ME;
326 Priv->SMSMemoryWrite = for_write;
327 }
328 return error;
329 }
330
ATGEN_SetSMSMode(GSM_StateMachine * s,int mode)331 GSM_Error ATGEN_SetSMSMode(GSM_StateMachine *s, int mode)
332 {
333 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
334 GSM_Error error = ERR_NONE;
335 if (mode == SMS_AT_PDU)
336 {
337 error = ATGEN_WaitForAutoLen(s, "AT+CMGF=0\r", 0x00, 9, ID_GetSMSMode);
338 if (error == ERR_NONE) {
339 Priv->SMSMode = SMS_AT_PDU;
340 }
341 return error;
342 } else {
343 error = ATGEN_WaitForAutoLen(s, "AT+CMGF=1\r", 0x00, 9, ID_GetSMSMode);
344 if (error == ERR_NONE) {
345 Priv->SMSMode = SMS_AT_TXT;
346 error = ATGEN_WaitForAutoLen(s, "AT+CSDH=1\r", 0x00, 3, ID_GetSMSMode);
347
348 if (error == ERR_NONE) {
349 Priv->SMSTextDetails = TRUE;
350 } else {
351 error = ERR_NONE;
352 }
353 }
354 return error;
355 }
356
357 }
358
ATGEN_GetSMSMode(GSM_StateMachine * s)359 GSM_Error ATGEN_GetSMSMode(GSM_StateMachine *s)
360 {
361 GSM_Error error = ERR_NONE;
362 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
363
364 if (Priv->SMSMode != 0) {
365 return ERR_NONE;
366 }
367
368 /* Prefer PDU mode for most phones */
369 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_USE_SMSTEXTMODE)) {
370 smprintf(s, "Forcibily enabled SMS text mode\n");
371 } else {
372 smprintf(s, "Trying SMS PDU mode\n");
373 if (ATGEN_SetSMSMode(s, SMS_AT_PDU) == ERR_NONE) {
374 return ERR_NONE;
375 }
376 }
377 smprintf(s, "Trying SMS text mode\n");
378 ATGEN_SetSMSMode(s, SMS_AT_TXT);
379 return error;
380 }
381
ATGEN_SetRequestedSMSMemory(GSM_StateMachine * s,GSM_MemoryType memoryType,gboolean writeable,GSM_Phone_RequestID requestId)382 GSM_Error ATGEN_SetRequestedSMSMemory(GSM_StateMachine *s, GSM_MemoryType memoryType, gboolean writeable,
383 GSM_Phone_RequestID requestId)
384 {
385 GSM_Error error;
386 unsigned char command[20];
387 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
388
389 if (!memoryType || memoryType == MEM_INVALID) {
390 smprintf_level(s, D_ERROR, "SMS memory type not set or invalid.\n");
391 return ERR_INVALID_OPERATION;
392 }
393
394 if (!ATGEN_IsMemoryAvailable(Priv, memoryType) ||
395 (writeable && !ATGEN_IsMemoryWriteable(Priv, memoryType)))
396 {
397 smprintf_level(s, D_ERROR, "Requested memory not available for %s: %s (%d)\n",
398 writeable ? "writing" : "reading",
399 GSM_MemoryTypeToString(memoryType), memoryType);
400 return ERR_MEMORY_NOT_AVAILABLE;
401 }
402
403 if (Priv->SMSMemory == memoryType && Priv->SMSMemoryWrite == writeable) {
404 smprintf(s, "Requested memory type already set: %s\n",
405 GSM_MemoryTypeToString(memoryType));
406 return ERR_NONE;
407 }
408
409 snprintf(command, 20, "AT+CPMS=\"%s\"\r", GSM_MemoryTypeToString(memoryType));
410 if (writeable) {
411 // if it's writeable we assume it's also readable
412 snprintf(command + 12, 8, ",\"%s\"\r", GSM_MemoryTypeToString(memoryType));
413 }
414
415 /* If phone encodes also values in command, we need normal charset */
416 if (Priv->EncodedCommands) {
417 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_NORMAL);
418
419 if (error != ERR_NONE) {
420 return error;
421 }
422 }
423
424 smprintf(s, "Setting SMS memory to %s\n", command + 8);
425 error = ATGEN_WaitFor(s, command, strlen(command), 0x00, 20, requestId);
426
427 if(error == ERR_NONE) {
428 Priv->SMSMemory = memoryType;
429 Priv->SMSMemoryWrite = writeable;
430 }
431 return error;
432 }
433
ATGEN_GetSMSLocation(GSM_StateMachine * s,GSM_SMSMessage * sms,unsigned char * folderid,int * location,gboolean for_write)434 GSM_Error ATGEN_GetSMSLocation(GSM_StateMachine *s, GSM_SMSMessage *sms, unsigned char *folderid, int *location, gboolean for_write)
435 {
436 GSM_Error error;
437 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
438 int ifolderid = 0, maxfolder = 0;
439
440 if (Priv->PhoneSMSMemory == 0 || Priv->SIMSMSMemory == 0 || Priv->SRSMSMemory == 0) {
441 error = ATGEN_GetSMSMemories(s);
442 if(error != ERR_NONE)
443 return error;
444 }
445
446 if (Priv->SIMSMSMemory != AT_AVAILABLE && Priv->PhoneSMSMemory != AT_AVAILABLE) {
447 smprintf(s, "No SMS memory at all!\n");
448 return ERR_NOTSUPPORTED;
449 }
450 if (Priv->SIMSMSMemory == AT_AVAILABLE && Priv->PhoneSMSMemory == AT_AVAILABLE) {
451 /* Both available */
452 maxfolder = 4;
453 } else {
454 /* One available */
455 maxfolder = 2;
456 }
457
458 /* simulate flat SMS memory */
459 if (sms->Folder == 0x00) {
460 ifolderid = sms->Location / GSM_PHONE_MAXSMSINFOLDER;
461
462 if (ifolderid + 1 > maxfolder) {
463 smprintf(s, "Too high location for flat folder: %d (folder=%d, maxfolder=%d)\n",
464 sms->Location,
465 ifolderid + 1,
466 maxfolder);
467 return ERR_NOTSUPPORTED;
468 }
469 *folderid = ifolderid + 1;
470 *location = sms->Location - ifolderid * GSM_PHONE_MAXSMSINFOLDER;
471 } else {
472 if (sms->Folder > 2 * maxfolder) {
473 smprintf(s, "Too high folder: folder=%d, maxfolder=%d\n",
474 sms->Folder,
475 maxfolder);
476 return ERR_NOTSUPPORTED;
477 }
478 *folderid = sms->Folder <= 2 ? 1 : 2;
479 *location = sms->Location;
480 }
481
482 /* Some phones start locations from 0, handle them here */
483 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMS_LOCATION_0)) {
484 (*location)--;
485 }
486 smprintf(s, "SMS folder %i & location %i -> ATGEN folder %i & location %i\n",
487 sms->Folder, sms->Location, *folderid, *location);
488
489 // if needed memory type already set, use it
490 if(sms->Memory && sms->Memory != MEM_INVALID) {
491 return ATGEN_SetRequestedSMSMemory(s, sms->Memory, for_write, ID_SetMemoryType);
492 }
493
494 /* Set the needed memory type */
495 if (Priv->SIMSMSMemory == AT_AVAILABLE &&
496 *folderid == 1) {
497 sms->Memory = MEM_SM;
498 return ATGEN_SetSMSMemory(s, TRUE, for_write, (sms->Folder % 2) == 0);
499 } else {
500 sms->Memory = MEM_ME;
501 return ATGEN_SetSMSMemory(s, FALSE, for_write, (sms->Folder % 2) == 0);
502 }
503 }
504
505 /**
506 * Converts location from AT internal to Gammu API. We need to ensure
507 * locations in API are sequential over all folders.
508 */
ATGEN_SetSMSLocation(GSM_StateMachine * s,GSM_SMSMessage * sms,unsigned char folderid,int location)509 void ATGEN_SetSMSLocation(GSM_StateMachine *s, GSM_SMSMessage *sms, unsigned char folderid, int location)
510 {
511 sms->Folder = 0; /* Flat memory */
512 sms->Location = (folderid - 1) * GSM_PHONE_MAXSMSINFOLDER + location;
513
514 /* Some phones start locations from 0, handle them here */
515 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMS_LOCATION_0)) {
516 sms->Location++;
517 }
518 smprintf(s, "ATGEN folder %i & location %i -> SMS folder %i & location %i\n",
519 folderid, location, sms->Folder, sms->Location);
520 }
521
ATGEN_DecodePDUMessage(GSM_StateMachine * s,const char * PDU,const int state)522 GSM_Error ATGEN_DecodePDUMessage(GSM_StateMachine *s, const char *PDU, const int state)
523 {
524 GSM_Error error;
525 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
526 GSM_SMSMessage *sms = &s->Phone.Data.GetSMSMessage->SMS[0];
527 unsigned char *buffer;
528 size_t parse_len = 0, length = 0;
529
530 length = strlen(PDU);
531
532 /* Special dummy message used by Siemens MC35i to fill up memory when using MT storage */
533 if (strcmp(PDU, "00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") == 0) {
534 return ERR_CORRUPTED;
535 } else if (strcmp(PDU, "00") == 0) {
536 return ERR_EMPTY;
537 }
538
539 /* Allocate memory for binary data */
540 buffer = (unsigned char*)malloc((length / 2) + 1);
541 if (buffer == NULL) {
542 return ERR_MOREMEMORY;
543 }
544
545 /*
546 * Strip possible ,0 at the end of reply.
547 * It actually should not be there, but it simply happens with some phones.
548 */
549 while (length >= 2 && PDU[length - 1] == '0' && PDU[length - 2] == ',') {
550 length -= 2;
551 }
552
553 /* Decode hex encoded binary data */
554 if (!DecodeHexBin(buffer, PDU, length)) {
555 smprintf(s, "Failed to decode hex string!\n");
556 free(buffer);
557 return ERR_CORRUPTED;
558 }
559
560 /* We decoded hex -> binary */
561 length /= 2;
562
563 /* Set message state */
564 switch (state) {
565 case 0:
566 sms->State = SMS_UnRead;
567 break;
568 case 1:
569 sms->State = SMS_Read;
570 break;
571 case 2:
572 sms->State = SMS_UnSent;
573 break;
574 default:
575 sms->State = SMS_Sent;
576 break;
577 }
578
579 /* Decode PDU */
580 error = GSM_DecodePDUFrame(&(s->di), sms, buffer, length, &parse_len, TRUE);
581
582 if (error != ERR_NONE) {
583 free(buffer);
584 return error;
585 }
586 if (parse_len != length) {
587 smprintf(s, "Did not parse all PDU data (%u, %u)!\n", (unsigned int)parse_len, (unsigned int)length);
588
589 if (buffer[parse_len] == 0xff) {
590 smprintf(s, "Assuming broken phone which pads SMS data with FF\n");
591 } else if (buffer[parse_len] == 0x89) {
592 /* Not sure what the data here means, see tests/at-sms/39.dump */
593 smprintf(s, "Assuming we can ignore anything starting with 0x89\n");
594 } else if(sms->PDU == SMS_Status_Report) {
595 smprintf(s, "Assuming we can ignore extra data after successfully parsing status report\n");
596 }
597 else {
598 free(buffer);
599 return ERR_UNKNOWN;
600 }
601 }
602 free(buffer);
603
604 /* Set folder */
605 switch (sms->PDU) {
606 case SMS_Deliver:
607 /* Fix possibly wrong state */
608 if (sms->State == SMS_Sent) {
609 sms->State = SMS_Read;
610 }
611 /* @bug Broken when MEM_SM is not available */
612 if (Priv->SMSMemory == MEM_SM) {
613 sms->Folder = 1; /*INBOX SIM*/
614 } else {
615 sms->Folder = 3; /*INBOX ME*/
616 }
617 sms->InboxFolder = TRUE;
618 break;
619 case SMS_Submit:
620 /* @bug Broken when MEM_SM is not available */
621 if (Priv->SMSMemory == MEM_SM) {
622 sms->Folder = 2; /*OUTBOX SIM*/
623 smprintf(s, "Outbox SIM\n");
624 } else {
625 sms->Folder = 4; /*OUTBOX ME*/
626 }
627 sms->InboxFolder = FALSE;
628 break;
629 case SMS_Status_Report:
630 sms->PDU = SMS_Status_Report;
631 sms->Folder = 1; /*INBOX SIM*/
632 sms->InboxFolder = TRUE;
633 break;
634 }
635 return ERR_NONE;
636 }
637
ATGEN_ReadSMSText(GSM_Protocol_Message * msg,GSM_StateMachine * s,GSM_SMSMessage * sms)638 GSM_Error ATGEN_ReadSMSText(GSM_Protocol_Message *msg, GSM_StateMachine *s, GSM_SMSMessage *sms)
639 {
640 int i;
641 const char *line;
642 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
643 size_t length = 0;
644 GSM_Error error;
645
646 /* Go trough all lines till OK */
647 for (i = 3; strcmp(line = GetLineString(msg->Buffer, &Priv->Lines, i), "OK") != 0; i++) {
648 if (i > 3) {
649 /* Include new line */
650 sms->Text[(2 * sms->Length) + 0] = 0;
651 sms->Text[(2 * sms->Length) + 1] = '\n';
652 sms->Text[(2 * sms->Length) + 2] = 0;
653 sms->Text[(2 * sms->Length) + 3] = 0;
654 sms->Length++;
655 }
656 length = GetLineLength(msg->Buffer, &Priv->Lines, i);
657 error = ATGEN_DecodeText(s, line, length,
658 sms->Text + (2 * sms->Length),
659 sizeof(sms->Text) - (2 * sms->Length),
660 TRUE, FALSE);
661 if (error != ERR_NONE) {
662 return error;
663 }
664 sms->Length += length;
665 }
666 return ERR_NONE;
667 }
668
ATGEN_ReplyGetSMSMessage(GSM_Protocol_Message * msg,GSM_StateMachine * s)669 GSM_Error ATGEN_ReplyGetSMSMessage(GSM_Protocol_Message *msg, GSM_StateMachine *s)
670 {
671 GSM_Error error = ERR_UNKNOWN;
672 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
673 GSM_SMSMessage *sms = &s->Phone.Data.GetSMSMessage->SMS[0];
674 unsigned char buffer[3000] = {'\0'}, firstbyte = 0, TPDCS = 0, TPUDL = 0, TPStatus = 0, TPPID = 0;
675 int current = 0, i = 0;
676 int state = 0;
677 unsigned char *ptr;
678 char *comma;
679 char *expected_comma;
680
681 switch (Priv->ReplyState) {
682 case AT_Reply_OK:
683 if (Priv->Lines.numbers[4] == 0x00) return ERR_EMPTY;
684 s->Phone.Data.GetSMSMessage->Number = 1;
685 s->Phone.Data.GetSMSMessage->SMS[0].Name[0] = 0;
686 s->Phone.Data.GetSMSMessage->SMS[0].Name[1] = 0;
687
688 switch (Priv->SMSMode) {
689 case SMS_AT_PDU:
690 CopyLineString(buffer, msg->Buffer, &Priv->Lines, 2);
691
692 /* Parse reply */
693 error = ATGEN_ParseReply(s, buffer, "+CMGR: @i, @0", &state);
694 if (error == ERR_UNKNOWNRESPONSE) {
695 error = ATGEN_ParseReply(s, buffer, "+CMGR: ,@0");
696 }
697 if (error == ERR_UNKNOWNRESPONSE) {
698 /* Some phones like ES75 lack state information, which we ignore anywa */
699 error = ATGEN_ParseReply(s, buffer, "+CMGR: @i", &state);
700 }
701 if (error == ERR_UNKNOWNRESPONSE) {
702 /* Some phones like QUALCOMM lack state information */
703 error = ATGEN_ParseReply(s, buffer, "+CMGR: ,,@i", &state);
704 }
705 if (error != ERR_NONE) {
706 return error;
707 }
708
709 /* Siemens MC35 (only ?) */
710 if (strcmp(buffer, "+CMGR: 0,,0") == 0) {
711 return ERR_EMPTY;
712 }
713
714 error = ATGEN_DecodePDUMessage(s, GetLineString(msg->Buffer,&Priv->Lines,3), state);
715 return error;
716 case SMS_AT_TXT:
717 GSM_SetDefaultReceivedSMSData(sms);
718
719 /*
720 * This is just a hack until proper parsing of text mode is done.
721 * It uses old style of manual parsing, to skip entries parsed above.
722 */
723 current = 0;
724
725 /* Skip to first : */
726 while (msg->Buffer[current] != ':') {
727 current++;
728 }
729 current++;
730 /* Skip any spaces */
731 while (msg->Buffer[current] == ' ') {
732 current++;
733 }
734
735 /* Grab first parameter */
736 current += ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
737
738 /* Remove leading " */
739 for (ptr = buffer; *ptr == '"'; ptr++);
740 if (ptr != buffer) {
741 memmove (buffer, ptr, strlen (ptr) + 1);
742 }
743
744 /* Go to the end of string */
745 for (ptr = buffer; *ptr; ptr++);
746 /* Remove trailing " */
747 ptr--;
748 while (ptr >= buffer && *ptr == '"') {
749 ptr--;
750 }
751 ptr++;
752 *ptr = 0;
753
754 smprintf(s, "Message type: %s\n", buffer);
755
756 /* Check message type */
757 if (!strcmp(buffer,"0") || !strcmp(buffer,"REC UNREAD")) {
758 smprintf(s, "SMS type - deliver\n");
759 sms->State = SMS_UnRead;
760 sms->PDU = SMS_Deliver;
761
762 if (Priv->SMSMemory == MEM_SM) {
763 sms->Folder = 1; /*INBOX SIM*/
764 } else {
765 sms->Folder = 3; /*INBOX ME*/
766 }
767 sms->InboxFolder = TRUE;
768 } else if (!strcmp(buffer,"1") || !strcmp(buffer,"REC READ")) {
769 smprintf(s, "SMS type - deliver\n");
770 sms->State = SMS_Read;
771 sms->PDU = SMS_Deliver;
772
773 if (Priv->SMSMemory == MEM_SM) {
774 sms->Folder = 1; /*INBOX SIM*/
775 } else {
776 sms->Folder = 3; /*INBOX ME*/
777 }
778 sms->InboxFolder = TRUE;
779 } else if (!strcmp(buffer,"2") || !strcmp(buffer,"STO UNSENT")) {
780 smprintf(s, "SMS type - submit\n");
781 sms->State = SMS_UnSent;
782 sms->PDU = SMS_Submit;
783
784 if (Priv->SMSMemory == MEM_SM) {
785 sms->Folder = 2; /*OUTBOX SIM*/
786 } else {
787 sms->Folder = 4; /*OUTBOX ME*/
788 }
789 sms->InboxFolder = FALSE;
790 } else if (!strcmp(buffer,"3") || !strcmp(buffer,"STO SENT")) {
791 smprintf(s, "SMS type - submit\n");
792 sms->State = SMS_Sent;
793 sms->PDU = SMS_Submit;
794
795 if (Priv->SMSMemory == MEM_SM) {
796 sms->Folder = 2; /*OUTBOX SIM*/
797 } else {
798 sms->Folder = 4; /*OUTBOX ME*/
799 }
800 sms->InboxFolder = FALSE;
801 } else {
802 smprintf(s, "Uknown message state: %s\n", buffer);
803 return ERR_UNKNOWN;
804 }
805
806 /* Do we have detailed format? */
807 if (Priv->SMSTextDetails == FALSE) {
808 sms->Class = 1;
809 sms->Coding = SMS_Coding_Default_No_Compression;
810 sms->UDH.Type = UDH_NoUDH;
811 sms->Length = 0;
812 sms->SMSC.Number[0]=0;
813 sms->SMSC.Number[1]=0;
814 sms->ReplyViaSameSMSC = FALSE;
815
816 return ATGEN_ReadSMSText(msg, s, sms);
817 }
818
819 current += ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
820 /* It's delivery report according to Nokia AT standards */
821 if ((sms->Folder == 1 || sms->Folder == 3) && buffer[0]!=0 && buffer[0]!='"') {
822 /* ??? */
823 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
824
825 /* Sender number */
826 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
827
828 /* FIXME: support for all formats */
829 EncodeUnicode(sms->Number,buffer+1,strlen(buffer)-2);
830 smprintf(s, "Sender \"%s\"\n",DecodeUnicodeString(sms->Number));
831
832 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
833 firstbyte = atoi(buffer);
834
835 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer+i);
836 smprintf(s, "\"%s\"\n",buffer);
837 error = ATGEN_DecodeDateTime(s, &sms->DateTime, buffer);
838
839 if (error != ERR_NONE) {
840 return error;
841 }
842 /* Date of SMSC response */
843 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
844 i = strlen(buffer);
845 buffer[i] = ',';
846 i++;
847 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer+i);
848 smprintf(s, "\"%s\"\n",buffer);
849 error = ATGEN_DecodeDateTime(s, &sms->SMSCTime, buffer);
850
851 if (error != ERR_NONE) {
852 return error;
853 }
854 /* TPStatus */
855 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
856 TPStatus = atoi(buffer);
857 buffer[PHONE_SMSDeliver.firstbyte] = firstbyte;
858 buffer[PHONE_SMSStatusReport.TPStatus] = TPStatus;
859 error = GSM_DecodeSMSFrameStatusReportData(&(s->di), sms, buffer, PHONE_SMSStatusReport);
860
861 if (error != ERR_NONE) {
862 return error;
863 }
864 /* NO SMSC number */
865 sms->SMSC.Number[0]=0;
866 sms->SMSC.Number[1]=0;
867 sms->PDU = SMS_Status_Report;
868 sms->ReplyViaSameSMSC = FALSE;
869 } else {
870 /* FIXME: support for all formats */
871 EncodeUnicode(sms->Number,buffer+1,strlen(buffer)-2);
872
873 if (strlen(buffer)!=0) {
874 EncodeUnicode(sms->Number,buffer+1,strlen(buffer)-2);
875 }
876 smprintf(s, "Sender \"%s\"\n",DecodeUnicodeString(sms->Number));
877 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
878
879 /* Sending datetime */
880
881 if (sms->Folder == 1 || sms->Folder == 3) {
882 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
883
884 smprintf(s, "\"%s\"\n",buffer);
885
886 if (*buffer) {
887 error = ATGEN_DecodeDateTime(s, &sms->DateTime, buffer);
888 if (error != ERR_NONE) {
889 return error;
890 }
891 } else {
892 /* FIXME: What is the proper undefined GSM_DateTime ? */
893 memset(&sms->DateTime, 0, sizeof(sms->DateTime));
894 }
895 error = ATGEN_DecodeDateTime(s, &sms->DateTime, buffer);
896
897 if (error != ERR_NONE) {
898 return error;
899 }
900 }
901
902 /* address type */
903 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
904
905 /* First byte */
906 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
907 firstbyte = atoi(buffer);
908 sms->ReplyViaSameSMSC = FALSE;
909 smprintf (s, "buffer firstbyte:%s\n", buffer);
910
911 /* TP PID */
912 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
913 sms->ReplaceMessage = 0;
914
915 TPPID = atoi(buffer);
916
917 /* TP DCS */
918 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
919 TPDCS = atoi(buffer);
920 smprintf(s, "TPDCS: %02x\n", TPDCS);
921 /* SMSC number */
922 /* FIXME: support for all formats */
923 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
924
925 if (buffer[0] != '"' && buffer[0]) {
926 /*TP VP */
927 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
928 }
929
930 EncodeUnicode(sms->SMSC.Number,buffer+1,strlen(buffer)-2);
931
932 /* GSM 03.40 section 9.2.3.17 (TP-Reply-Path) */
933 if ((firstbyte & 128)==128) {
934 sms->ReplyViaSameSMSC = TRUE;
935 }
936
937 if (TPPID > 0x40 && TPPID < 0x48) {
938 sms->ReplaceMessage = TPPID - 0x40;
939 }
940 smprintf(s, "TPPID: %02x %i\n", TPPID, TPPID);
941
942 /* Format of SMSC number */
943 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
944
945 /* TPUDL */
946 current+=ATGEN_ExtractOneParameter(msg->Buffer+current, buffer);
947 TPUDL = atoi(buffer);
948 current++;
949 sms->Coding = GSM_GetMessageCoding(&(s->di), TPDCS);
950 sms->Class = -1;
951 /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
952 if ((TPDCS & 0xD0) == 0x10 || (TPDCS & 0xF0) == 0xF0) {
953 sms->Class = TPDCS & 3;
954 }
955
956 smprintf(s, "SMS class: %i\n",sms->Class);
957
958 switch (sms->Coding) {
959 case SMS_Coding_Default_No_Compression:
960 /* GSM 03.40 section 9.2.3.23 (TP-User-Data-Header-Indicator) */
961 /* If not SMS with UDH, it's coded normal */
962 /* If UDH available, treat it as Unicode or 8 bit */
963 if ((firstbyte & 0x40)!=0x40) {
964 sms->UDH.Type = UDH_NoUDH;
965 error = ATGEN_ReadSMSText(msg, s, sms);
966 if (sms->Length == TPUDL + 4) {
967 char *tail;
968 tail = sms->Text + 2 * (UnicodeLength (sms->Text) - 4);
969 if (tail[0] == 0 && tail[1] == ',' && tail[4] == 0 && tail[5] == ',') {
970 tail[1] = 0;
971 sms->Length = TPUDL;
972 }
973 }
974 if (sms->Length != TPUDL) {
975 smprintf(s, "WARNING: Indicated message length (%d) does not match real (%d)\n", TPUDL, sms->Length);
976 }
977 break;
978 }
979 FALLTHROUGH
980 case SMS_Coding_Unicode_No_Compression:
981 case SMS_Coding_8bit:
982 if ((firstbyte & 0x40)==0x40 && GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMS_UTF8_ENCODED)) {
983 comma = strchr (msg->Buffer+current, ',');
984
985 if (sms->Coding == SMS_Coding_Default_No_Compression) {
986 expected_comma = (char *)msg->Buffer+current + ((7 * TPUDL + 7) / 8) * 2;
987 } else {
988 expected_comma = (char *)msg->Buffer+current + TPUDL * 2;
989 }
990 if (comma == expected_comma || !comma) {
991 comma = expected_comma;
992 } else {
993 smprintf (s, "UDL fix: %d,", TPUDL);
994 if (sms->Coding == SMS_Coding_Default_No_Compression) {
995 TPUDL = ((comma - ((char *)msg->Buffer+current)) * 4) / 7;
996 } else {
997 TPUDL = (comma - ((char *)msg->Buffer+current)) / 2;
998 }
999 smprintf (s, "%d\n", TPUDL);
1000 }
1001 DecodeHexBin(buffer+PHONE_SMSDeliver.Text, msg->Buffer+current, comma - (char *) (msg->Buffer+current));
1002 buffer[PHONE_SMSDeliver.firstbyte] = firstbyte;
1003 buffer[PHONE_SMSDeliver.TPDCS] = TPDCS;
1004 buffer[PHONE_SMSDeliver.TPUDL] = TPUDL;
1005 return GSM_DecodeSMSFrameText(&(s->di), sms, buffer, PHONE_SMSDeliver);
1006 }
1007
1008 if (sms->Coding == SMS_Coding_Unicode_No_Compression && GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMS_UTF8_ENCODED)) {
1009 DecodeUTF8(buffer+PHONE_SMSDeliver.Text, msg->Buffer+current, TPUDL);
1010 TPUDL = 2 * UnicodeLength (buffer+PHONE_SMSDeliver.Text);
1011 } else {
1012 DecodeHexBin(buffer+PHONE_SMSDeliver.Text, msg->Buffer+current, TPUDL*2);
1013 }
1014 buffer[PHONE_SMSDeliver.firstbyte] = firstbyte;
1015 buffer[PHONE_SMSDeliver.TPDCS] = TPDCS;
1016 buffer[PHONE_SMSDeliver.TPUDL] = TPUDL;
1017 return GSM_DecodeSMSFrameText(&(s->di), sms, buffer, PHONE_SMSDeliver);
1018 default:
1019 break;
1020 }
1021 }
1022 return ERR_NONE;
1023 default:
1024 smprintf(s, "Internal error - SMS mode not set!\n");
1025 return ERR_BUG;
1026 }
1027 break;
1028 case AT_Reply_CMSError:
1029 if (Priv->ErrorCode == 320 || Priv->ErrorCode == 500) {
1030 return ERR_EMPTY;
1031 } else {
1032 return ATGEN_HandleCMSError(s);
1033 }
1034 case AT_Reply_CMEError:
1035 return ATGEN_HandleCMEError(s);
1036 case AT_Reply_Error:
1037 /* A2D returns Error with empty location */
1038 return ERR_EMPTY;
1039 default:
1040 break;
1041 }
1042 return ERR_UNKNOWNRESPONSE;
1043 }
1044
ATGEN_GetSMS(GSM_StateMachine * s,GSM_MultiSMSMessage * sms)1045 GSM_Error ATGEN_GetSMS(GSM_StateMachine *s, GSM_MultiSMSMessage *sms)
1046 {
1047 GSM_Error error;
1048 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1049 unsigned char req[20] = {'\0'}, folderid = 0;
1050 int location = 0, getfolder = 0, add = 0, length = 0;
1051 GSM_AT_SMS_Modes oldmode;
1052
1053 /* Set mode of SMS */
1054 error = ATGEN_GetSMSMode(s);
1055 if (error != ERR_NONE) {
1056 return error;
1057 }
1058
1059 oldmode = Priv->SMSMode;
1060
1061 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_READ_SMSTEXTMODE)) {
1062 ATGEN_SetSMSMode(s, SMS_AT_TXT);
1063 }
1064
1065 /* Clear SMS structure of any possible junk */
1066 GSM_SetDefaultReceivedSMSData(&sms->SMS[0]);
1067 error = ATGEN_GetSMSLocation(s, &sms->SMS[0], &folderid, &location, FALSE);
1068
1069 if (error != ERR_NONE) {
1070 goto fail;
1071 }
1072 if (Priv->SMSMemory == MEM_ME && GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMSME900)) {
1073 add = 899;
1074 }
1075 length = sprintf(req, "AT+CMGR=%i\r", location + add);
1076
1077 /* There is possibility that date will be encoded in text mode */
1078 if (Priv->SMSMode == SMS_AT_TXT) {
1079 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_NORMAL);
1080
1081 if (error != ERR_NONE) {
1082 goto fail;
1083 }
1084 }
1085 s->Phone.Data.GetSMSMessage = sms;
1086 smprintf(s, "Getting SMS\n");
1087 error = ATGEN_WaitFor(s, req, length, 0x00, 50, ID_GetSMSMessage);
1088
1089 if (error == ERR_NONE || error == ERR_CORRUPTED) {
1090 getfolder = sms->SMS[0].Folder;
1091 ATGEN_SetSMSLocation(s, &sms->SMS[0], folderid, location);
1092 sms->SMS[0].Folder = getfolder;
1093 if(sms->SMS[0].Memory != MEM_SR) {
1094 sms->SMS[0].Memory = MEM_SM;
1095 if (getfolder > 2) sms->SMS[0].Memory = MEM_ME;
1096 }
1097 }
1098 fail:
1099 if (oldmode != Priv->SMSMode) {
1100 ATGEN_SetSMSMode(s, oldmode);
1101 }
1102
1103 return error;
1104
1105 }
1106
ATGEN_ReplyGetMessageList(GSM_Protocol_Message * msg,GSM_StateMachine * s)1107 GSM_Error ATGEN_ReplyGetMessageList(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1108 {
1109 GSM_Error error;
1110 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1111 GSM_SMSMessage sms;
1112 int line = 1, cur = 0, allocsize = 0;
1113 char *tmp = NULL;
1114 const char *str;
1115
1116 switch (Priv->ReplyState) {
1117 case AT_Reply_OK:
1118 break;
1119 case AT_Reply_Error:
1120 return ERR_NOTSUPPORTED;
1121 case AT_Reply_CMSError:
1122 if (Priv->ErrorCode == 320 || Priv->ErrorCode == 500) {
1123 return ERR_EMPTY;
1124 } else {
1125 return ATGEN_HandleCMSError(s);
1126 }
1127 case AT_Reply_CMEError:
1128 return ATGEN_HandleCMEError(s);
1129 default:
1130 return ERR_UNKNOWNRESPONSE;
1131 }
1132 smprintf(s, "SMS listing received\n");
1133 Priv->SMSCount = 0;
1134 Priv->SMSCache = NULL;
1135
1136 /* Walk through lines with +CMGL: */
1137 /* First line is our command so we can skip it */
1138 for (line = 2; strcmp("OK", str = GetLineString(msg->Buffer, &Priv->Lines, line)) != 0; line++) {
1139 /*
1140 * Find +CMGL, it should be on beginning, but it does not have to (see
1141 * corruption mentioned at the end of loop.
1142 */
1143 str = strstr(str, "+CMGL:");
1144
1145 if (str == NULL) {
1146 /*
1147 * Sometimes an SMS message will contain a line break. In SMS text
1148 * mode we skip to the next line and try again to find +CMGL.
1149 * FIXME: Can we do the same for SMS PDU mode?
1150 */
1151 if (Priv->SMSMode == SMS_AT_PDU) {
1152 smprintf(s, "Can not find +CMGL:!\n");
1153 return ERR_UNKNOWN;
1154 }
1155 continue;
1156 }
1157
1158 /* Parse reply */
1159 error = ATGEN_ParseReply(s, str, "+CMGL: @i, @0", &cur);
1160
1161 if (error != ERR_NONE) {
1162 return error;
1163 }
1164 Priv->SMSCount++;
1165
1166 /* Reallocate buffer if needed */
1167 if (allocsize <= Priv->SMSCount) {
1168 allocsize += 20;
1169 Priv->SMSCache = (GSM_AT_SMS_Cache *)realloc(Priv->SMSCache, allocsize * sizeof(GSM_AT_SMS_Cache));
1170
1171 if (Priv->SMSCache == NULL) {
1172 return ERR_MOREMEMORY;
1173 }
1174 }
1175
1176 /* Should we use index instead of location? Samsung P900 needs this hack. */
1177 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_BROKEN_CMGL)) {
1178 ATGEN_SetSMSLocation(s, &sms, Priv->SMSReadFolder, Priv->SMSCount);
1179 } else {
1180 ATGEN_SetSMSLocation(s, &sms, Priv->SMSReadFolder, cur);
1181 }
1182 Priv->SMSCache[Priv->SMSCount - 1].Location = sms.Location;
1183 Priv->SMSCache[Priv->SMSCount - 1].State = -1;
1184
1185 /* Go to PDU/Text data */
1186 line++;
1187
1188 /* Fill in cache of PDU data */
1189 if (Priv->SMSMode == SMS_AT_PDU) {
1190 error = ATGEN_ParseReply(s, str, "+CMGL: @i, @i, @0",
1191 &cur,
1192 &Priv->SMSCache[Priv->SMSCount - 1].State);
1193
1194 if (error != ERR_NONE) {
1195 smprintf(s, "Failed to parse reply, not using cache!\n");
1196 Priv->SMSCache[Priv->SMSCount - 1].State = -1;
1197 }
1198 /* Get next line (PDU data) */
1199 str = GetLineString(msg->Buffer, &Priv->Lines, line);
1200
1201 if (strlen(str) >= GSM_AT_MAXPDULEN) {
1202 smprintf(s, "PDU (%s) too long for cache, skipping!\n", str);
1203 Priv->SMSCache[Priv->SMSCount - 1].State = -1;
1204 } else {
1205 strcpy(Priv->SMSCache[Priv->SMSCount - 1].PDU, str);
1206
1207 /* Some phones corrupt output and do not put new line before +CMGL occassionally */
1208 tmp = strstr(Priv->SMSCache[Priv->SMSCount - 1].PDU, "+CMGL:");
1209
1210 if (tmp != NULL) {
1211 smprintf(s, "WARNING: Line should contain PDU data, but contains +CMGL, stripping it!\n");
1212 *tmp = 0;
1213
1214 /* Go line back, because we have to process this line again */
1215 line--;
1216 }
1217 }
1218 }
1219
1220 }
1221 smprintf(s, "Read %d SMS locations\n", Priv->SMSCount);
1222 return ERR_NONE;
1223 }
1224
ATGEN_GetSMSList(GSM_StateMachine * s,gboolean first)1225 GSM_Error ATGEN_GetSMSList(GSM_StateMachine *s, gboolean first)
1226 {
1227 GSM_Error error;
1228 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1229 int used = 0;
1230
1231 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_DISABLE_CMGL)) {
1232 return ERR_NOTSUPPORTED;
1233 }
1234
1235 /* Set mode of SMS */
1236 error = ATGEN_GetSMSMode(s);
1237
1238 if (error != ERR_NONE) {
1239 return error;
1240 }
1241
1242 /* Get number of messages */
1243 error = ATGEN_GetSMSStatus(s,&Priv->LastSMSStatus);
1244
1245 if (error != ERR_NONE) {
1246 return error;
1247 }
1248 if (first) {
1249 Priv->SMSReadFolder = 1;
1250
1251 if (Priv->SIMSMSMemory == AT_AVAILABLE) {
1252 error = ATGEN_SetSMSMemory(s, TRUE, FALSE, FALSE);
1253
1254 if (error != ERR_NONE) {
1255 return error;
1256 }
1257 used = Priv->LastSMSStatus.SIMUsed;
1258 } else if (Priv->PhoneSMSMemory == AT_AVAILABLE) {
1259 error = ATGEN_SetSMSMemory(s, FALSE, FALSE, FALSE);
1260
1261 if (error != ERR_NONE) {
1262 return error;
1263 }
1264 used = Priv->LastSMSStatus.PhoneUsed;
1265 } else {
1266 return ERR_NOTSUPPORTED;
1267 }
1268 } else {
1269 Priv->SMSReadFolder = 2;
1270
1271 if (Priv->PhoneSMSMemory == AT_AVAILABLE) {
1272 error = ATGEN_SetSMSMemory(s, FALSE, FALSE, FALSE);
1273
1274 if (error != ERR_NONE) {
1275 return error;
1276 }
1277 used = Priv->LastSMSStatus.PhoneUsed;
1278 } else {
1279 return ERR_NOTSUPPORTED;
1280 }
1281 }
1282 Priv->LastSMSRead = 0;
1283 Priv->SMSCount = 0;
1284
1285 if (Priv->SMSCache != NULL) {
1286 free(Priv->SMSCache);
1287 Priv->SMSCache = NULL;
1288 }
1289 smprintf(s, "Getting SMS locations\n");
1290
1291 if (Priv->SMSMode == SMS_AT_TXT) {
1292 error = ATGEN_WaitForAutoLen(s, "AT+CMGL=\"ALL\"\r", 0x00, 500, ID_GetSMSMessage);
1293 } else {
1294 error = ATGEN_WaitForAutoLen(s, "AT+CMGL=4\r", 0x00, 500, ID_GetSMSMessage);
1295 }
1296 if (error == ERR_NOTSUPPORTED) {
1297 error = ATGEN_WaitForAutoLen(s, "AT+CMGL\r", 0x00, 500, ID_GetSMSMessage);
1298 }
1299 /*
1300 * We did not read anything, but it is correct, indicate that
1301 * cache should be used (even if it is empty).
1302 */
1303 if (error == ERR_NONE && Priv->SMSCache == NULL) {
1304 Priv->SMSCache = (GSM_AT_SMS_Cache *)realloc(Priv->SMSCache, sizeof(GSM_AT_SMS_Cache));
1305 }
1306 if (used != Priv->SMSCount && (error == ERR_NONE || error == ERR_EMPTY)) {
1307 smprintf(s, "WARNING: Used messages according to CPMS %d, but CMGL returned %d. Expect problems!\n", used, Priv->SMSCount);
1308 if (! GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_USE_SMSTEXTMODE)) {
1309 smprintf(s, "HINT: Your might want to use F_USE_SMSTEXTMODE flag\n");
1310 }
1311 return ERR_NONE;
1312 }
1313 return error;
1314 }
1315
ATGEN_GetNextSMS(GSM_StateMachine * s,GSM_MultiSMSMessage * sms,gboolean start)1316 GSM_Error ATGEN_GetNextSMS(GSM_StateMachine *s, GSM_MultiSMSMessage *sms, gboolean start)
1317 {
1318 GSM_Error error;
1319 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1320 int usedsms = 0, i = 0, found = -1, tmpfound = -1;
1321
1322 if (Priv->PhoneSMSMemory == 0) {
1323 error = ATGEN_SetSMSMemory(s, FALSE, FALSE, FALSE);
1324
1325 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) {
1326 return error;
1327 }
1328 }
1329 if (Priv->SIMSMSMemory == 0) {
1330 error = ATGEN_SetSMSMemory(s, TRUE, FALSE, FALSE);
1331
1332 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) {
1333 return error;
1334 }
1335 }
1336 if (Priv->SIMSMSMemory == AT_NOTAVAILABLE && Priv->PhoneSMSMemory == AT_NOTAVAILABLE) return ERR_NOTSUPPORTED;
1337
1338 /* On start we need to init everything */
1339 if (start) {
1340 /* Start from beginning */
1341 sms->SMS[0].Location = 0;
1342 Priv->LastSMSRead = 0;
1343
1344 /* Get list of messages */
1345 error = ATGEN_GetSMSList(s, TRUE);
1346 } else {
1347 error = ERR_NONE;
1348 }
1349
1350 /* Use listed locations if we have them */
1351 if (error == ERR_NONE && Priv->SMSCache != NULL) {
1352 if (start) {
1353 found = 0;
1354 } else {
1355 for (i = 0; i < Priv->SMSCount; i++) {
1356 if (Priv->SMSCache[i].Location == sms->SMS[0].Location) {
1357 found = i + 1;
1358 break;
1359 }
1360 if ((Priv->SMSCache[i].Location < sms->SMS[0].Location)
1361 && ((tmpfound == -1) ||
1362 (sms->SMS[0].Location - Priv->SMSCache[i].Location <
1363 sms->SMS[0].Location - Priv->SMSCache[tmpfound - 1].Location))
1364 ) {
1365 tmpfound = i + 1;
1366 }
1367 }
1368 }
1369
1370 if (found == -1) {
1371 smprintf(s, "Invalid location passed to %s!\n", __FUNCTION__);
1372
1373 if (tmpfound == -1) {
1374 return ERR_INVALIDLOCATION;
1375 } else {
1376 smprintf(s, "Attempting to skip to next location!\n");
1377 found = tmpfound;
1378 }
1379 }
1380 smprintf(s, "Cache status: Found: %d, count: %d\n", found, Priv->SMSCount);
1381
1382 if (found >= Priv->SMSCount) {
1383 /* Have we read all folders? */
1384 if (Priv->SMSReadFolder == Priv->NumFolders) {
1385 return ERR_EMPTY;
1386 }
1387
1388 /* Get list of messages */
1389 error = ATGEN_GetSMSList(s, FALSE);
1390
1391 /* Not supported folder? We're done then. */
1392 if (error == ERR_NOTSUPPORTED) {
1393 return ERR_EMPTY;
1394 }
1395 if (error != ERR_NONE) {
1396 return error;
1397 }
1398
1399 /* Did we read anything? */
1400 if (Priv->SMSCache != NULL && Priv->SMSCount == 0) {
1401 return ERR_EMPTY;
1402 }
1403
1404 /* Start again */
1405 found = 0;
1406 }
1407
1408 /* We might get no messages in listing above */
1409 if (Priv->SMSCache != NULL) {
1410 sms->SMS[0].Folder = 0;
1411 sms->Number = 1;
1412 sms->SMS[0].Memory = Priv->SMSMemory;
1413 sms->SMS[0].Location = Priv->SMSCache[found].Location;
1414
1415 if (Priv->SMSCache[found].State != -1) {
1416 /* Get message from cache */
1417 GSM_SetDefaultReceivedSMSData(&sms->SMS[0]);
1418 s->Phone.Data.GetSMSMessage = sms;
1419 smprintf(s, "Getting message from cache\n");
1420 smprintf(s, "%s\n", Priv->SMSCache[found].PDU);
1421 error = ATGEN_DecodePDUMessage(s,
1422 Priv->SMSCache[found].PDU,
1423 Priv->SMSCache[found].State);
1424
1425 /* Is the entry corrupted? */
1426 if (error != ERR_CORRUPTED) {
1427 return error;
1428 }
1429 /* Mark it as invalid */
1430 Priv->SMSCache[found].State = -1;
1431 /* And fall back to normal reading */
1432 }
1433
1434 /* Finally read the message */
1435 smprintf(s, "Reading next message on location %d\n", sms->SMS[0].Location);
1436 return ATGEN_GetSMS(s, sms);
1437 }
1438 }
1439
1440 /* Ensure LastSMSStatus is up to date */
1441 error = ATGEN_GetSMSStatus(s, &Priv->LastSMSStatus);
1442
1443 if (error != ERR_NONE) {
1444 return error;
1445 }
1446
1447 /* Use brute force if listing does not work */
1448 while (TRUE) {
1449 sms->SMS[0].Location++;
1450
1451 if (sms->SMS[0].Location < GSM_PHONE_MAXSMSINFOLDER) {
1452 if (Priv->SIMSMSMemory == AT_AVAILABLE) {
1453 usedsms = Priv->LastSMSStatus.SIMUsed;
1454 } else {
1455 usedsms = Priv->LastSMSStatus.PhoneUsed;
1456 }
1457
1458 if (Priv->LastSMSRead >= usedsms) {
1459 if (Priv->PhoneSMSMemory == AT_NOTAVAILABLE || Priv->LastSMSStatus.PhoneUsed == 0) {
1460 smprintf(s, "No more messages to read\n");
1461 return ERR_EMPTY;
1462 }
1463 Priv->LastSMSRead = 0;
1464
1465 /* Start on next folder */
1466 sms->SMS[0].Location = GSM_PHONE_MAXSMSINFOLDER + 1;
1467 }
1468 } else {
1469 if (Priv->PhoneSMSMemory == AT_NOTAVAILABLE) return ERR_EMPTY;
1470 if (Priv->LastSMSRead >= Priv->LastSMSStatus.PhoneUsed) return ERR_EMPTY;
1471 }
1472 sms->SMS[0].Folder = 0;
1473 error = ATGEN_GetSMS(s, sms);
1474
1475 if (error == ERR_NONE) {
1476 Priv->LastSMSRead++;
1477 break;
1478 }
1479 if (error != ERR_EMPTY && error != ERR_INVALIDLOCATION) return error;
1480 }
1481 return error;
1482 }
1483
ATGEN_ReplyGetSMSStatus(GSM_Protocol_Message * msg,GSM_StateMachine * s)1484 GSM_Error ATGEN_ReplyGetSMSStatus(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1485 {
1486 GSM_Error error;
1487 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1488 GSM_SMSMemoryStatus *SMSStatus = s->Phone.Data.SMSStatus;
1489 unsigned char buffer[50] = {'\0'};
1490 int used = 0, size = 0;
1491
1492 switch (Priv->ReplyState) {
1493 case AT_Reply_OK:
1494 smprintf(s, "SMS status received\n");
1495
1496 /* Check for +CPMS: 0,30,0,30,8,330, this is according to ETSI */
1497 error = ATGEN_ParseReply(s,
1498 GetLineString(msg->Buffer, &Priv->Lines, 2),
1499 "+CPMS: @i, @i, @0",
1500 &used, &size);
1501 if (error != ERR_NONE) {
1502 /*
1503 * Samsung formats this different way, sample response:
1504 * 1 "AT+CPMS="SM","SM""
1505 * 2 "+CPMS:"SM",3,30,"SM",3,30,"SM",3,30"
1506 * 3 "OK"
1507 */
1508 error = ATGEN_ParseReply(s,
1509 GetLineString(msg->Buffer, &Priv->Lines, 2),
1510 "+CPMS: @s, @i, @i, @0",
1511 &buffer, sizeof(buffer), &used, &size);
1512 }
1513 if (error != ERR_NONE) {
1514 /* For phones with single memory */
1515 error = ATGEN_ParseReply(s,
1516 GetLineString(msg->Buffer, &Priv->Lines, 2),
1517 "+CPMS: @i, @i",
1518 &used, &size);
1519 }
1520 if (error == ERR_NONE) {
1521 smprintf(s, "Used : %i\n", used);
1522 smprintf(s, "Size : %i\n", size);
1523 if ((strstr(msg->Buffer, "CPMS=\"ME") != NULL) ||
1524 (Priv->MotorolaSMS && strstr(msg->Buffer, "CPMS=\"MT") != NULL)) {
1525 SMSStatus->PhoneUsed = used;
1526 SMSStatus->PhoneSize = size;
1527 } else {
1528 SMSStatus->SIMUsed = used;
1529 SMSStatus->SIMSize = size;
1530 }
1531 }
1532 return error;
1533 case AT_Reply_Error:
1534 if (strstr(msg->Buffer,"SM")!=NULL) {
1535 smprintf(s, "Can't access SIM card\n");
1536 return ERR_SECURITYERROR;
1537 }
1538 return ERR_NOTSUPPORTED;
1539 case AT_Reply_CMSError:
1540 return ATGEN_HandleCMSError(s);
1541 case AT_Reply_CMEError:
1542 return ATGEN_HandleCMEError(s);
1543 default:
1544 break;
1545 }
1546 return ERR_UNKNOWNRESPONSE;
1547 }
1548
ATGEN_GetSMSStatus(GSM_StateMachine * s,GSM_SMSMemoryStatus * status)1549 GSM_Error ATGEN_GetSMSStatus(GSM_StateMachine *s, GSM_SMSMemoryStatus *status)
1550 {
1551 GSM_Error error;
1552 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1553
1554 /* No templates at all */
1555 status->TemplatesUsed = 0;
1556 status->SIMUsed = 0;
1557 status->SIMUnRead = 0;
1558 status->SIMSize = 0;
1559 s->Phone.Data.SMSStatus = status;
1560
1561 if ((Priv->SIMSMSMemory == 0) || (Priv->PhoneSMSMemory == 0)) {
1562 /* We silently ignore error here, because when this fails, we can try to setmemory anyway */
1563 ATGEN_GetSMSMemories(s);
1564 }
1565 if (Priv->PhoneSMSMemory == 0) {
1566 error = ATGEN_SetSMSMemory(s, FALSE, FALSE, FALSE);
1567
1568 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) {
1569 return error;
1570 }
1571 }
1572 if (Priv->SIMSMSMemory == 0) {
1573 error = ATGEN_SetSMSMemory(s, TRUE, FALSE, FALSE);
1574
1575 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) {
1576 return error;
1577 }
1578 }
1579 if (Priv->SIMSMSMemory == AT_AVAILABLE) {
1580 smprintf(s, "Getting SIM SMS status\n");
1581
1582 if (Priv->SIMSaveSMS == AT_AVAILABLE) {
1583 error = ATGEN_WaitForAutoLen(s, "AT+CPMS=\"SM\",\"SM\"\r", 0x00, 200, ID_GetSMSStatus);
1584 Priv->SMSMemoryWrite = TRUE;
1585 } else {
1586 error = ATGEN_WaitForAutoLen(s, "AT+CPMS=\"SM\"\r", 0x00, 200, ID_GetSMSStatus);
1587 Priv->SMSMemoryWrite = FALSE;
1588 }
1589 if (error != ERR_NONE) {
1590 return error;
1591 }
1592 Priv->SMSMemory = MEM_SM;
1593 }
1594 status->PhoneUsed = 0;
1595 status->PhoneUnRead = 0;
1596 status->PhoneSize = 0;
1597
1598 if (Priv->PhoneSMSMemory == AT_AVAILABLE) {
1599 smprintf(s, "Getting phone SMS status\n");
1600
1601 if (Priv->PhoneSaveSMS == AT_AVAILABLE) {
1602 if (Priv->MotorolaSMS) {
1603 error = ATGEN_WaitForAutoLen(s, "AT+CPMS=\"MT\"\r", 0x00, 200, ID_GetSMSStatus);
1604 Priv->SMSMemoryWrite = FALSE;
1605 } else {
1606 error = ATGEN_WaitForAutoLen(s, "AT+CPMS=\"ME\",\"ME\"\r", 0x00, 200, ID_GetSMSStatus);
1607 Priv->SMSMemoryWrite = TRUE;
1608 }
1609 } else {
1610 error = ATGEN_WaitForAutoLen(s, "AT+CPMS=\"ME\"\r", 0x00, 200, ID_GetSMSStatus);
1611 Priv->SMSMemoryWrite = FALSE;
1612 }
1613 if (error != ERR_NONE) {
1614 return error;
1615 }
1616 Priv->SMSMemory = MEM_ME;
1617 }
1618 return ERR_NONE;
1619 }
1620
ATGEN_ReplyAddSMSMessage(GSM_Protocol_Message * msg,GSM_StateMachine * s)1621 GSM_Error ATGEN_ReplyAddSMSMessage(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1622 {
1623 GSM_Error error;
1624 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1625 size_t i = 0;
1626
1627 switch (Priv->ReplyState) {
1628 case AT_Reply_SMSEdit:
1629 if (s->Protocol.Data.AT.EditMode) {
1630 s->Protocol.Data.AT.EditMode = FALSE;
1631 return ERR_NONE;
1632 }
1633 smprintf(s, "Received unexpected SMS edit prompt!\n");
1634 return ERR_UNKNOWN;
1635 case AT_Reply_OK:
1636 smprintf(s, "SMS saved OK\n");
1637
1638 /* Number of lines */
1639 i = 0;
1640
1641 while (Priv->Lines.numbers[i*2+1] != 0) {
1642 i++;
1643 }
1644 error = ATGEN_ParseReply(s,
1645 GetLineString(msg->Buffer, &Priv->Lines, i - 1),
1646 "+CMGW: @i",
1647 &s->Phone.Data.SaveSMSMessage->Location);
1648
1649 if (error != ERR_NONE) {
1650 return error;
1651 }
1652 smprintf(s, "Saved at AT location %i\n",
1653 s->Phone.Data.SaveSMSMessage->Location);
1654 /* Adjust location */
1655 ATGEN_SetSMSLocation(
1656 s,
1657 s->Phone.Data.SaveSMSMessage,
1658 /* We care only about SIM/Phone */
1659 s->Phone.Data.SaveSMSMessage->Folder <= 2 ? 1 : 2,
1660 s->Phone.Data.SaveSMSMessage->Location
1661 );
1662 return ERR_NONE;
1663 case AT_Reply_Error:
1664 smprintf(s, "Error\n");
1665 return ERR_NOTSUPPORTED;
1666 case AT_Reply_CMSError:
1667 /* This error occurs in case that phone couldn't save SMS */
1668 return ATGEN_HandleCMSError(s);
1669 case AT_Reply_CMEError:
1670 return ATGEN_HandleCMEError(s);
1671 default:
1672 break;
1673 }
1674 return ERR_UNKNOWNRESPONSE;
1675 }
1676
ATGEN_MakeSMSFrame(GSM_StateMachine * s,GSM_SMSMessage * message,unsigned char * hexreq,size_t hexlength,int * current,size_t * length2)1677 GSM_Error ATGEN_MakeSMSFrame(GSM_StateMachine *s, GSM_SMSMessage *message, unsigned char *hexreq, size_t hexlength, int *current, size_t *length2)
1678 {
1679 GSM_Error error;
1680 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1681 GSM_SMSC SMSC;
1682 unsigned char req[1000] = {'\0'}, buffer[1000] = {'\0'};
1683 int i = 0, length = 0;
1684 size_t len;
1685
1686 /* Set mode of SMS */
1687 error = ATGEN_GetSMSMode(s);
1688
1689 if (error != ERR_NONE) {
1690 return error;
1691 }
1692 length = 0;
1693 *current = 0;
1694
1695 switch (Priv->SMSMode) {
1696 case SMS_AT_PDU:
1697 if (message->PDU == SMS_Deliver) {
1698 smprintf(s, "SMS Deliver\n");
1699 error = PHONE_EncodeSMSFrame(s,message,buffer,PHONE_SMSDeliver,&length,TRUE);
1700
1701 if (error != ERR_NONE) {
1702 return error;
1703 }
1704 length = length - PHONE_SMSDeliver.Text;
1705
1706 for (i = 0;i < buffer[PHONE_SMSDeliver.SMSCNumber]+1;i++) {
1707 req[(*current)++]=buffer[PHONE_SMSDeliver.SMSCNumber+i];
1708 }
1709 req[(*current)++]=buffer[PHONE_SMSDeliver.firstbyte];
1710
1711 for (i = 0;i<((buffer[PHONE_SMSDeliver.Number]+1)/2+1)+1;i++) {
1712 req[(*current)++]=buffer[PHONE_SMSDeliver.Number+i];
1713 }
1714 req[(*current)++]=buffer[PHONE_SMSDeliver.TPPID];
1715 req[(*current)++]=buffer[PHONE_SMSDeliver.TPDCS];
1716
1717 for(i = 0;i < 7;i++) {
1718 req[(*current)++]=buffer[PHONE_SMSDeliver.DateTime+i];
1719 }
1720 req[(*current)++]=buffer[PHONE_SMSDeliver.TPUDL];
1721
1722 for(i = 0;i < length;i++) {
1723 req[(*current)++]=buffer[PHONE_SMSDeliver.Text+i];
1724 }
1725 EncodeHexBin(hexreq, req, *current);
1726 *length2 = *current * 2;
1727 *current = *current - (req[PHONE_SMSDeliver.SMSCNumber]+1);
1728 } else {
1729 smprintf(s, "SMS Submit\n");
1730 error = PHONE_EncodeSMSFrame(s,message,buffer,PHONE_SMSSubmit,&length,TRUE);
1731
1732 if (error != ERR_NONE) {
1733 return error;
1734 }
1735 length = length - PHONE_SMSSubmit.Text;
1736
1737 for (i = 0;i < buffer[PHONE_SMSSubmit.SMSCNumber]+1;i++) {
1738 req[(*current)++]=buffer[PHONE_SMSSubmit.SMSCNumber+i];
1739 }
1740 req[(*current)++]=buffer[PHONE_SMSSubmit.firstbyte];
1741 req[(*current)++]=buffer[PHONE_SMSSubmit.TPMR];
1742
1743 for (i = 0;i<((buffer[PHONE_SMSSubmit.Number]+1)/2+1)+1;i++) {
1744 req[(*current)++]=buffer[PHONE_SMSSubmit.Number+i];
1745 }
1746 req[(*current)++]=buffer[PHONE_SMSSubmit.TPPID];
1747 req[(*current)++]=buffer[PHONE_SMSSubmit.TPDCS];
1748 req[(*current)++]=buffer[PHONE_SMSSubmit.TPVP];
1749 req[(*current)++]=buffer[PHONE_SMSSubmit.TPUDL];
1750
1751 for(i = 0;i < length;i++) {
1752 req[(*current)++]=buffer[PHONE_SMSSubmit.Text+i];
1753 }
1754 req[(*current)+1]='\0';
1755 EncodeHexBin(hexreq, req, *current);
1756 *length2 = *current * 2;
1757 *current = *current - (req[PHONE_SMSSubmit.SMSCNumber]+1);
1758 }
1759 break;
1760 case SMS_AT_TXT:
1761 if (Priv->Manufacturer != AT_Nokia) {
1762 if (message->Coding != SMS_Coding_Default_No_Compression) {
1763 return ERR_NOTSUPPORTED;
1764 }
1765 }
1766 error = PHONE_EncodeSMSFrame(s,message,req,PHONE_SMSDeliver,&i,TRUE);
1767
1768 if (error != ERR_NONE) {
1769 return error;
1770 }
1771 CopyUnicodeString(SMSC.Number,message->SMSC.Number);
1772 SMSC.Location = 1;
1773 error = ATGEN_SetSMSC(s,&SMSC);
1774
1775 if (error != ERR_NONE) {
1776 return error;
1777 }
1778 len = sprintf(buffer, "AT+CSMP=%i,%i,%i,%i\r",
1779 req[PHONE_SMSDeliver.firstbyte],
1780 req[PHONE_SMSDeliver.TPVP],
1781 req[PHONE_SMSDeliver.TPPID],
1782 req[PHONE_SMSDeliver.TPDCS]);
1783 error = ATGEN_WaitFor(s, buffer, len, 0x00, 40, ID_SetSMSParameters);
1784
1785 if (error == ERR_NOTSUPPORTED) {
1786 /* Nokia Communicator 9000i doesn't support <vp> parameter */
1787 len = sprintf(buffer, "AT+CSMP=%i,,%i,%i\r",
1788 req[PHONE_SMSDeliver.firstbyte],
1789 req[PHONE_SMSDeliver.TPPID],
1790 req[PHONE_SMSDeliver.TPDCS]);
1791 error = ATGEN_WaitFor(s, buffer, len, 0x00, 40, ID_SetSMSParameters);
1792 }
1793 if (error != ERR_NONE) {
1794 smprintf(s, "WARNING: Failed to set message parameters, continuing without them!\n");
1795 }
1796 switch (message->Coding) {
1797 case SMS_Coding_Default_No_Compression:
1798 /* If not SMS with UDH, it's as normal text */
1799 if (message->UDH.Type == UDH_NoUDH) {
1800 error = ATGEN_EncodeText(
1801 s, message->Text, UnicodeLength(message->Text), hexreq, hexlength, length2
1802 );
1803 if (error != ERR_NONE) {
1804 return error;
1805 }
1806 break;
1807 }
1808 FALLTHROUGH
1809 case SMS_Coding_Unicode_No_Compression:
1810 case SMS_Coding_8bit:
1811 error = PHONE_EncodeSMSFrame(s,message,buffer,PHONE_SMSDeliver,current,TRUE);
1812
1813 if (error != ERR_NONE) {
1814 return error;
1815 }
1816 EncodeHexBin (hexreq, buffer+PHONE_SMSDeliver.Text, buffer[PHONE_SMSDeliver.TPUDL]);
1817 *length2 = buffer[PHONE_SMSDeliver.TPUDL] * 2;
1818 break;
1819 default:
1820 break;
1821 }
1822 break;
1823 }
1824 return ERR_NONE;
1825 }
1826
ATGEN_AddSMS(GSM_StateMachine * s,GSM_SMSMessage * sms)1827 GSM_Error ATGEN_AddSMS(GSM_StateMachine *s, GSM_SMSMessage *sms)
1828 {
1829 GSM_Error error, error2;
1830 GSM_Phone_Data *Phone = &s->Phone.Data;
1831 unsigned char buffer[1000] = {'\0'}, hexreq[1000] = {'\0'},folderid = 0;
1832 const char *statetxt;
1833 int state = 0, Replies = 0, reply = 0, current = 0, location = 0;
1834 size_t length = 0;
1835 size_t len;
1836
1837 /* This phone supports only sent/unsent messages on SIM */
1838 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SMSONLYSENT)) {
1839 if (sms->Folder != 2) {
1840 smprintf(s, "This phone supports only folder = 2!\n");
1841 return ERR_NOTSUPPORTED;
1842 }
1843 }
1844
1845 /* Check the lower bound (this is static, we do not support flat memory here */
1846 if (sms->Folder <= 0) {
1847 smprintf(s, "Flat memory not supported for adding!\n");
1848 return ERR_WRONGFOLDER;
1849 }
1850
1851 /* We don't actually need this, but let's initialise it. */
1852 sms->Location = 0;
1853
1854 /* Set correct memory type */
1855 error = ATGEN_GetSMSLocation(s, sms, &folderid, &location, TRUE);
1856
1857 if (error != ERR_NONE) {
1858 return error;
1859 }
1860
1861 /* Set message type based on folder */
1862 if ((sms->Folder % 2) == 1) {
1863 /* Inbox folder */
1864 sms->PDU = SMS_Deliver;
1865 } else {
1866 /* Outbox folder */
1867 sms->PDU = SMS_Submit;
1868
1869 if (sms->Memory == MEM_ME &&
1870 GSM_IsPhoneFeatureAvailable(Phone->ModelInfo, F_SUBMIT_SIM_ONLY)) {
1871 smprintf(s, "This phone probably does not support saving submit messages to ME location!\n");
1872 smprintf(s, "But trying anyway...\n");
1873 }
1874 }
1875
1876 /* Format SMS frame */
1877 error = ATGEN_MakeSMSFrame(s, sms, hexreq, sizeof(hexreq), ¤t, &length);
1878
1879 if (error != ERR_NONE) {
1880 return error;
1881 }
1882
1883 switch (Phone->Priv.ATGEN.SMSMode) {
1884 case SMS_AT_PDU:
1885 if (sms->PDU == SMS_Deliver) {
1886 state = 0;
1887 if (sms->State == SMS_Read || sms->State == SMS_Sent) state = 1;
1888 } else {
1889 state = 2;
1890 if (sms->State == SMS_Read || sms->State == SMS_Sent) state = 3;
1891 }
1892 /* Siemens M20 */
1893 if (GSM_IsPhoneFeatureAvailable(Phone->ModelInfo, F_M20SMS)) {
1894 /* No (good and 100% working) support for alphanumeric numbers */
1895 if (sms->Number[1]!='+' && (sms->Number[1]<'0' || sms->Number[1]>'9')) {
1896 EncodeUnicode(sms->Number,"123",3);
1897 error = ATGEN_MakeSMSFrame(s, sms, hexreq, sizeof(hexreq), ¤t, &length);
1898 if (error != ERR_NONE) return error;
1899 }
1900 }
1901 len = sprintf(buffer, "AT+CMGW=%i,%i\r",current,state);
1902 break;
1903 case SMS_AT_TXT:
1904 if (sms->PDU == SMS_Deliver) {
1905 statetxt = "REC UNREAD";
1906 if (sms->State == SMS_Read || sms->State == SMS_Sent) statetxt = "REC READ";
1907 } else {
1908 statetxt = "STO UNSENT";
1909 if (sms->State == SMS_Read || sms->State == SMS_Sent) statetxt = "STO SENT";
1910 }
1911 /* Siemens M20 */
1912 if (GSM_IsPhoneFeatureAvailable(Phone->ModelInfo, F_M20SMS)) {
1913 /* No (good and 100% working) support for alphanumeric numbers */
1914 /* FIXME: Try to autodetect support for <stat> (statetxt) parameter although:
1915 * Siemens M20 supports +CMGW <stat> specification but on my model it just
1916 * reports ERROR (and <stat> is not respected).
1917 * Fortunately it will write "+CMGW: <index>\n" before and the message gets written
1918 */
1919 if (sms->Number[1]!='+' && (sms->Number[1]<'0' || sms->Number[1]>'9')) {
1920 len = sprintf(buffer, "AT+CMGW=\"123\",,\"%s\"\r",statetxt);
1921 } else {
1922 len = sprintf(buffer, "AT+CMGW=\"%s\",,\"%s\"\r",DecodeUnicodeString(sms->Number),statetxt);
1923 }
1924 } else {
1925 len = sprintf(buffer, "AT+CMGW=\"%s\",,\"%s\"\r",DecodeUnicodeString(sms->Number),statetxt);
1926 }
1927 break;
1928 default:
1929 smprintf(s, "Internal error - SMS mode not set!\n");
1930 return ERR_BUG;
1931 }
1932 Phone->SaveSMSMessage = sms;
1933
1934 for (reply = 0;reply < s->ReplyNum;reply++) {
1935 if (reply != 0) {
1936 smprintf_level(s, D_ERROR, "[Retrying %i]\n", reply+1);
1937 }
1938 s->Protocol.Data.AT.EditMode = TRUE;
1939 Replies = s->ReplyNum;
1940 s->ReplyNum = 1;
1941 smprintf(s,"Waiting for modem prompt\n");
1942 error = ATGEN_WaitFor(s, buffer, len, 0x00, 20, ID_SaveSMSMessage);
1943 s->ReplyNum = Replies;
1944
1945 if (error == ERR_NONE) {
1946 Phone->DispatchError = ERR_TIMEOUT;
1947 Phone->RequestID = ID_SaveSMSMessage;
1948 usleep(100000);
1949 smprintf(s, "Saving SMS\n");
1950 error = s->Protocol.Functions->WriteMessage(s, hexreq, length, 0x00);
1951
1952 if (error != ERR_NONE) {
1953 return error;
1954 }
1955 usleep(500000);
1956
1957 /* CTRL+Z ends entering */
1958 error = s->Protocol.Functions->WriteMessage(s, "\x1A", 1, 0x00);
1959
1960 if (error != ERR_NONE) {
1961 return error;
1962 }
1963 usleep(100000);
1964 error = GSM_WaitForOnce(s, NULL, 0x00, 0x00, 40);
1965
1966 if (error != ERR_TIMEOUT) {
1967 return error;
1968 }
1969 } else {
1970 smprintf(s, "Escaping SMS mode\n");
1971 error2 = s->Protocol.Functions->WriteMessage(s, "\x1B\r", 2, 0x00);
1972
1973 if (error2 != ERR_NONE) {
1974 return error2;
1975 }
1976 return error;
1977 }
1978 }
1979
1980 return Phone->DispatchError;
1981 }
1982
ATGEN_ReplySendSMS(GSM_Protocol_Message * msg,GSM_StateMachine * s)1983 GSM_Error ATGEN_ReplySendSMS(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1984 {
1985 GSM_Error error;
1986 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1987 int i = 0,reference = 0;
1988
1989 switch (Priv->ReplyState) {
1990 case AT_Reply_SMSEdit:
1991 if (s->Protocol.Data.AT.EditMode) {
1992 s->Protocol.Data.AT.EditMode = FALSE;
1993 return ERR_NONE;
1994 }
1995 smprintf(s, "Received unexpected SMS edit prompt!\n");
1996 return ERR_UNKNOWN;
1997 case AT_Reply_OK:
1998 smprintf(s, "SMS sent OK\n");
1999
2000 /* Number of lines */
2001 i = 0;
2002 while (Priv->Lines.numbers[i*2+1] != 0) {
2003 i++;
2004 }
2005 error = ATGEN_ParseReply(s,
2006 GetLineString(msg->Buffer, &Priv->Lines, i - 1),
2007 "+CMGS: @i",
2008 &reference);
2009
2010 if (error != ERR_NONE) {
2011 reference = -1;
2012 }
2013
2014 if(s->User.SendSMSStatus != NULL) {
2015 s->User.SendSMSStatus(s, 0, reference, s->User.SendSMSStatusUserData);
2016 }
2017 return ERR_NONE;
2018
2019 case AT_Reply_CMSError:
2020 smprintf(s, "Error %i\n",Priv->ErrorCode);
2021
2022 if (s->User.SendSMSStatus != NULL) {
2023 s->User.SendSMSStatus(s, Priv->ErrorCode, -1, s->User.SendSMSStatusUserData);
2024 }
2025 return ATGEN_HandleCMSError(s);
2026 case AT_Reply_CMEError:
2027 smprintf(s, "Error %i\n",Priv->ErrorCode);
2028
2029 if (s->User.SendSMSStatus != NULL) {
2030 s->User.SendSMSStatus(s, Priv->ErrorCode, -1, s->User.SendSMSStatusUserData);
2031 }
2032 return ATGEN_HandleCMEError(s);
2033 case AT_Reply_Error:
2034 if (s->User.SendSMSStatus != NULL) {
2035 s->User.SendSMSStatus(s, -1, -1, s->User.SendSMSStatusUserData);
2036 }
2037 return ERR_UNKNOWN;
2038 default:
2039 if (s->User.SendSMSStatus != NULL) {
2040 s->User.SendSMSStatus(s, -1, -1, s->User.SendSMSStatusUserData);
2041 }
2042 return ERR_UNKNOWNRESPONSE;
2043 }
2044 }
2045
ATGEN_SendSMS(GSM_StateMachine * s,GSM_SMSMessage * sms)2046 GSM_Error ATGEN_SendSMS(GSM_StateMachine *s, GSM_SMSMessage *sms)
2047 {
2048 GSM_Error error, error2;
2049 GSM_Phone_Data *Phone = &s->Phone.Data;
2050 unsigned char buffer[1000] = {'\0'}, hexreq[1000] = {'\0'};
2051 int current = 0, Replies = 0, retries = 0;
2052 size_t length = 0;
2053 size_t len;
2054
2055 if (sms->PDU == SMS_Deliver) {
2056 sms->PDU = SMS_Submit;
2057 }
2058 error = ATGEN_MakeSMSFrame(s, sms, hexreq, sizeof(hexreq), ¤t, &length);
2059
2060 if (error != ERR_NONE) {
2061 return error;
2062 }
2063
2064 if (sms->SMSC.Number[0] == 0x00 && sms->SMSC.Number[1] == 0x00) {
2065 smprintf(s,"No SMSC in SMS to send\n");
2066 return ERR_EMPTYSMSC;
2067 }
2068
2069 switch (Phone->Priv.ATGEN.SMSMode) {
2070 case SMS_AT_PDU:
2071 len = sprintf(buffer, "AT+CMGS=%i\r",current);
2072 break;
2073 case SMS_AT_TXT:
2074 len = sprintf(buffer, "AT+CMGS=\"%s\"\r",DecodeUnicodeString(sms->Number));
2075 break;
2076 default:
2077 smprintf(s, "Internal error - SMS mode not set!\n");
2078 return ERR_BUG;
2079 }
2080
2081 /* We will be SMS edit mode */
2082 s->Protocol.Data.AT.EditMode = TRUE;
2083 /*
2084 * We handle retries on our own, because we need to escape after
2085 * failure to avoid sending message with AT commands.
2086 */
2087 Replies = s->ReplyNum;
2088 s->ReplyNum = 1;
2089
2090 while (retries < s->ReplyNum) {
2091 smprintf(s,"Waiting for modem prompt\n");
2092 error = ATGEN_WaitFor(s, buffer, len, 0x00, 30, ID_IncomingFrame);
2093
2094 /* Restore original value */
2095 s->ReplyNum = Replies;
2096
2097 if (error == ERR_NONE) {
2098 usleep(100000);
2099 smprintf(s, "Sending SMS\n");
2100 error = s->Protocol.Functions->WriteMessage(s, hexreq, length, 0x00);
2101
2102 if (error != ERR_NONE) {
2103 return error;
2104 }
2105 usleep(500000);
2106 /* CTRL+Z ends entering */
2107 error = s->Protocol.Functions->WriteMessage(s, "\x1A", 1, 0x00);
2108 usleep(100000);
2109 return error;
2110 }
2111 smprintf(s, "Escaping SMS mode\n");
2112 error2 = s->Protocol.Functions->WriteMessage(s, "\x1B\r", 2, 0x00);
2113 if (error2 != ERR_NONE) {
2114 return error2;
2115 }
2116 retries++;
2117 }
2118 return error;
2119 }
2120
ATGEN_SendSavedSMS(GSM_StateMachine * s,int Folder,int Location)2121 GSM_Error ATGEN_SendSavedSMS(GSM_StateMachine *s, int Folder, int Location)
2122 {
2123 GSM_Error error;
2124 GSM_MultiSMSMessage msms;
2125 unsigned char req[100] = {'\0'}, smsfolder = 0;
2126 int location = 0;
2127 size_t len;
2128
2129 msms.Number = 0;
2130 msms.SMS[0].Folder = Folder;
2131 msms.SMS[0].Location = Location;
2132 msms.SMS[0].Memory = 0;
2133
2134 /* By reading SMS we check if it is really inbox/outbox */
2135 error = ATGEN_GetSMS(s, &msms);
2136
2137 if (error != ERR_NONE) {
2138 return error;
2139 }
2140
2141 /* Can not send from other folder that outbox */
2142 if (msms.SMS[0].Folder != 2 && msms.SMS[0].Folder != 4) {
2143 return ERR_NOTSUPPORTED;
2144 }
2145
2146 /* Set back original position as it was probably adjusted when
2147 * reading message from phone (eg. folder was filled in). */
2148 msms.SMS[0].Folder = Folder;
2149 msms.SMS[0].Location = Location;
2150 msms.SMS[0].Memory = 0;
2151
2152 /* Adjust location to real ones */
2153 error = ATGEN_GetSMSLocation(s, &msms.SMS[0], &smsfolder, &location, FALSE);
2154
2155 if (error != ERR_NONE) {
2156 return error;
2157 }
2158 len = sprintf(req, "AT+CMSS=%i\r",location);
2159 error = s->Protocol.Functions->WriteMessage(s, req, len, 0x00);
2160 usleep(strlen(req)*1000);
2161 return error;
2162 }
2163
ATGEN_ReplyGetSMSC(GSM_Protocol_Message * msg,GSM_StateMachine * s)2164 GSM_Error ATGEN_ReplyGetSMSC(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2165 {
2166 GSM_Error error;
2167 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2168 GSM_SMSC *SMSC = s->Phone.Data.SMSC;
2169 int number_type = 0;
2170
2171 switch (Priv->ReplyState) {
2172 case AT_Reply_OK:
2173 smprintf(s, "SMSC info received\n");
2174
2175 /* Parse reply */
2176 error = ATGEN_ParseReply(s,
2177 GetLineString(msg->Buffer, &Priv->Lines, 2),
2178 "+CSCA: @p, @i",
2179 SMSC->Number, sizeof(SMSC->Number),
2180 &number_type);
2181 if (error != ERR_NONE) {
2182 error = ATGEN_ParseReply(s,
2183 GetLineString(msg->Buffer, &Priv->Lines, 2),
2184 "+CSCA: @p, @0",
2185 SMSC->Number, sizeof(SMSC->Number));
2186 }
2187 if (error != ERR_NONE) {
2188 error = ATGEN_ParseReply(s,
2189 GetLineString(msg->Buffer, &Priv->Lines, 2),
2190 "+CSCA: @p",
2191 SMSC->Number, sizeof(SMSC->Number));
2192 number_type = NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN;
2193 }
2194 if (error != ERR_NONE) {
2195 return error;
2196 }
2197 if (UnicodeLength(SMSC->Number) == 0) return ERR_EMPTY;
2198
2199 /* International number */
2200 GSM_TweakInternationalNumber(SMSC->Number, number_type);
2201
2202 /* Some things we can not find out */
2203 SMSC->Format = SMS_FORMAT_Text;
2204 SMSC->Validity.Format = SMS_Validity_RelativeFormat;
2205 SMSC->Validity.Relative = SMS_VALID_Max_Time;
2206 SMSC->Name[0] = 0;
2207 SMSC->Name[1] = 0;
2208 SMSC->DefaultNumber[0] = 0;
2209 SMSC->DefaultNumber[1] = 0;
2210 return ERR_NONE;
2211 case AT_Reply_CMSError:
2212 return ATGEN_HandleCMSError(s);
2213 case AT_Reply_CMEError:
2214 return ATGEN_HandleCMEError(s);
2215 case AT_Reply_Error:
2216 return ERR_NOTSUPPORTED;
2217 default:
2218 break;
2219 }
2220 return ERR_UNKNOWNRESPONSE;
2221 }
2222
ATGEN_GetSMSC(GSM_StateMachine * s,GSM_SMSC * smsc)2223 GSM_Error ATGEN_GetSMSC(GSM_StateMachine *s, GSM_SMSC *smsc)
2224 {
2225 GSM_Error error;
2226
2227 /* Only one location supported */
2228 if (smsc->Location != 1) {
2229 return ERR_INVALIDLOCATION;
2230 }
2231
2232 /* We prefer normal charset */
2233 error = ATGEN_SetCharset(s, AT_PREF_CHARSET_NORMAL);
2234
2235 if (error != ERR_NONE) {
2236 return error;
2237 }
2238
2239 /* Issue command */
2240 s->Phone.Data.SMSC = smsc;
2241 smprintf(s, "Getting SMSC\n");
2242 error = ATGEN_WaitForAutoLen(s, "AT+CSCA?\r", 0x00, 40, ID_GetSMSC);
2243 return error;
2244 }
2245
ATGEN_ReplyDeleteSMSMessage(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)2246 GSM_Error ATGEN_ReplyDeleteSMSMessage(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
2247 {
2248 switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
2249 case AT_Reply_OK:
2250 smprintf(s, "SMS deleted OK\n");
2251 return ERR_NONE;
2252 case AT_Reply_Error:
2253 smprintf(s, "Invalid location\n");
2254 return ERR_INVALIDLOCATION;
2255 case AT_Reply_CMSError:
2256 return ATGEN_HandleCMSError(s);
2257 case AT_Reply_CMEError:
2258 return ATGEN_HandleCMEError(s);
2259 default:
2260 break;
2261 }
2262 return ERR_UNKNOWNRESPONSE;
2263 }
2264
ATGEN_DeleteSMS(GSM_StateMachine * s,GSM_SMSMessage * sms)2265 GSM_Error ATGEN_DeleteSMS(GSM_StateMachine *s, GSM_SMSMessage *sms)
2266 {
2267 GSM_Error error;
2268 GSM_MultiSMSMessage msms;
2269 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2270 unsigned char req[20] = {'\0'}, folderid = 0;
2271 int location = 0, length = 0;
2272
2273 msms.Number = 0;
2274 msms.SMS[0] = *sms;
2275
2276 /* By reading SMS we check if it is really inbox/outbox */
2277 error = ATGEN_GetSMS(s, &msms);
2278
2279 if (error != ERR_NONE && error != ERR_CORRUPTED) {
2280 return error;
2281 }
2282
2283 error = ATGEN_GetSMSLocation(s, sms, &folderid, &location,
2284 ATGEN_IsMemoryWriteable(Priv, sms->Memory));
2285
2286 if (error != ERR_NONE) {
2287 return error;
2288 }
2289 smprintf(s, "Deleting SMS\n");
2290 length = sprintf(req, "AT+CMGD=%i\r",location);
2291 error = ATGEN_WaitFor(s, req, length, 0x00, 5, ID_DeleteSMSMessage);
2292 return error;
2293 }
2294
ATGEN_GetSMSFolders(GSM_StateMachine * s,GSM_SMSFolders * folders)2295 GSM_Error ATGEN_GetSMSFolders(GSM_StateMachine *s, GSM_SMSFolders *folders)
2296 {
2297 GSM_Error error;
2298 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2299 int used = 0;
2300
2301 if (Priv->PhoneSMSMemory == 0) {
2302 error = ATGEN_SetSMSMemory(s, FALSE, FALSE, FALSE);
2303
2304 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) {
2305 return error;
2306 }
2307 }
2308 if (Priv->SIMSMSMemory == 0) {
2309 error = ATGEN_SetSMSMemory(s, TRUE, FALSE, FALSE);
2310
2311 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) {
2312 return error;
2313 }
2314 }
2315 folders->Number = 0;
2316
2317 if (Priv->PhoneSMSMemory == AT_NOTAVAILABLE && Priv->SIMSMSMemory == AT_NOTAVAILABLE) {
2318 return ERR_NONE;
2319 }
2320 PHONE_GetSMSFolders(s,folders);
2321
2322 if (Priv->SIMSMSMemory == AT_AVAILABLE) {
2323 used = 2;
2324 }
2325 if (Priv->PhoneSMSMemory == AT_AVAILABLE) {
2326 if (used != 0) {
2327 CopyUnicodeString(folders->Folder[used ].Name,folders->Folder[0].Name);
2328 CopyUnicodeString(folders->Folder[used + 1].Name,folders->Folder[1].Name);
2329 folders->Folder[used ].InboxFolder = folders->Folder[0].InboxFolder;
2330 folders->Folder[used + 1].InboxFolder = folders->Folder[1].InboxFolder;
2331 folders->Folder[used ].OutboxFolder = folders->Folder[0].OutboxFolder;
2332 folders->Folder[used + 1].OutboxFolder = folders->Folder[1].OutboxFolder;
2333 }
2334 folders->Folder[used ].Memory = MEM_ME;
2335 folders->Folder[used + 1].Memory = MEM_ME;
2336 folders->Number += 2;
2337 used += 2;
2338 }
2339 return ERR_NONE;
2340 }
2341
ATGEN_IncomingSMSCInfo(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s UNUSED)2342 GSM_Error ATGEN_IncomingSMSCInfo(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s UNUSED)
2343 {
2344 return ERR_NONE;
2345 }
2346
ATGEN_SetFastSMSSending(GSM_StateMachine * s,gboolean enable)2347 GSM_Error ATGEN_SetFastSMSSending(GSM_StateMachine *s, gboolean enable)
2348 {
2349 GSM_Error error;
2350
2351 if (enable) {
2352 smprintf(s, "Enabling fast SMS sending\n");
2353 error = ATGEN_WaitForAutoLen(s, "AT+CMMS=2\r", 0x00, 40, ID_SetFastSMSSending);
2354 } else {
2355 smprintf(s, "Disabling fast SMS sending\n");
2356 error = ATGEN_WaitForAutoLen(s, "AT+CMMS=0\r", 0x00, 40, ID_SetFastSMSSending);
2357 }
2358 return error;
2359 }
2360
ATGEN_IncomingSMSInfo(GSM_Protocol_Message * msg,GSM_StateMachine * s)2361 GSM_Error ATGEN_IncomingSMSInfo(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2362 {
2363 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2364 char *buffer = msg->Buffer;
2365 GSM_SMSMessage sms;
2366 GSM_Error error;
2367
2368 char mem_tag[3]; // eg: "SM\0"
2369 const size_t cmd_len = 6;
2370
2371 if(!s->User.IncomingSMS || !s->Phone.Data.EnableIncomingSMS)
2372 return ERR_NONE;
2373
2374 memset(&sms, 0, sizeof(sms));
2375 sms.State = 0;
2376 sms.InboxFolder = TRUE;
2377 sms.PDU = 0;
2378
2379 if(strncmp(buffer, "+CMTI:", cmd_len) == 0) {
2380 smprintf(s, "Incoming SMS information\n");
2381 }
2382 else if(strncmp(buffer, "+CDSI:", cmd_len) == 0) {
2383 smprintf(s, "Incoming SMS status report information\n");
2384 sms.PDU = SMS_Status_Report;
2385 }
2386 else {
2387 smprintf(s, "Unrecognised response\n");
2388 return ERR_UNKNOWNRESPONSE;
2389 }
2390
2391 error = ATGEN_ParseReply(s, buffer + cmd_len, " @r, @i",
2392 &mem_tag, sizeof(mem_tag),
2393 &sms.Location);
2394 if (error != ERR_NONE)
2395 return error;
2396
2397 sms.Memory = GSM_StringToMemoryType(mem_tag);
2398 if (!ATGEN_IsMemoryAvailable(Priv, sms.Memory)) {
2399 smprintf(s, "Incoming SMS information ignored as %s memory is disabled\n", mem_tag);
2400 return ERR_NONE;
2401 }
2402
2403 switch(sms.Memory) {
2404 case MEM_ME:
2405 case MEM_MT:
2406 sms.Folder = Priv->SIMSMSMemory == AT_AVAILABLE ? 3 : 1;
2407 break;
2408 case MEM_SM:
2409 case MEM_SR:
2410 sms.Folder = 1;
2411 break;
2412 default:
2413 smprintf(s, "Unsupported memory type\n");
2414 return ERR_NOTSUPPORTED;
2415 }
2416
2417 s->User.IncomingSMS(s, &sms, s->User.IncomingSMSUserData);
2418
2419 return ERR_NONE;
2420 }
2421
ATGEN_IncomingSMSDeliver(GSM_Protocol_Message * msg,GSM_StateMachine * s)2422 GSM_Error ATGEN_IncomingSMSDeliver(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2423 {
2424 GSM_Phone_Data *Data = &s->Phone.Data;
2425 GSM_SMSMessage sms;
2426 unsigned char buffer[300] = {'\0'}, smsframe[800] = {'\0'};
2427 int current = 0, length, i = 0;
2428
2429 smprintf(s, "Incoming SMS received (Deliver)\n");
2430
2431 if (Data->EnableIncomingSMS && s->User.IncomingSMS != NULL) {
2432 sms.State = SMS_UnRead;
2433 sms.InboxFolder = TRUE;
2434 sms.PDU = SMS_Deliver;
2435
2436 /* T310 with larger SMS goes crazy and mix this incoming
2437 * frame with normal answers. PDU is always last frame
2438 * We find its' number and parse it */
2439 while (Data->Priv.ATGEN.Lines.numbers[i*2+1] != 0) {
2440 /* FIXME: handle special chars correctly */
2441 i++;
2442 }
2443 DecodeHexBin (buffer,
2444 GetLineString(msg->Buffer,&Data->Priv.ATGEN.Lines,i),
2445 GetLineLength(msg->Buffer,&Data->Priv.ATGEN.Lines,i));
2446
2447 /* We use locations from SMS layouts like in ../phone2.c(h) */
2448 for(i = 0;i < buffer[0]+1;i++) {
2449 smsframe[i]=buffer[current++];
2450 }
2451 smsframe[12]=buffer[current++];
2452 length=((buffer[current])+1)/2+1;
2453
2454 for(i = 0;i < length+1;i++) {
2455 smsframe[PHONE_SMSDeliver.Number+i]=buffer[current++];
2456 }
2457 smsframe[PHONE_SMSDeliver.TPPID] = buffer[current++];
2458 smsframe[PHONE_SMSDeliver.TPDCS] = buffer[current++];
2459
2460 for(i = 0;i < 7;i++) {
2461 smsframe[PHONE_SMSDeliver.DateTime+i]=buffer[current++];
2462 }
2463 smsframe[PHONE_SMSDeliver.TPUDL] = buffer[current++];
2464
2465 for(i = 0;i < smsframe[PHONE_SMSDeliver.TPUDL];i++) {
2466 smsframe[i+PHONE_SMSDeliver.Text]=buffer[current++];
2467 }
2468 GSM_DecodeSMSFrame(&(s->di), &sms,smsframe,PHONE_SMSDeliver);
2469 s->User.IncomingSMS(s, &sms, s->User.IncomingSMSUserData);
2470 }
2471 return ERR_NONE;
2472 }
2473
ATGEN_IncomingSMSReport(GSM_Protocol_Message * msg,GSM_StateMachine * s)2474 GSM_Error ATGEN_IncomingSMSReport(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2475 {
2476 GSM_Error error;
2477 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2478 GSM_SMSMessage sms;
2479 char buffer[300] = {'\0'};
2480 int pduSize = 0;
2481 size_t parseSize = 0;
2482
2483 assert(strncasecmp("+CDS:", msg->Buffer, 5) == 0);
2484
2485 if (!s->Phone.Data.EnableIncomingSMS || s->User.IncomingSMS == NULL)
2486 return ERR_NONE;
2487
2488 smprintf(s, "Incoming SMS received (Report)\n");
2489
2490 memset(&sms, 0, sizeof(sms));
2491 sms.State = SMS_UnRead;
2492 sms.InboxFolder = TRUE;
2493 sms.Folder = 1;
2494 pduSize = GetLineLength(msg->Buffer, &Priv->Lines, 2);
2495 assert(pduSize >= 0);
2496
2497 if(!DecodeHexBin(buffer, GetLineString(msg->Buffer, &Priv->Lines, 2), (size_t)pduSize)) {
2498 smprintf(s, "Failed to decode hex string!\n");
2499 return ERR_CORRUPTED;
2500 }
2501
2502 error = GSM_DecodePDUFrame(&(s->di), &sms, buffer, (size_t)pduSize, &parseSize, TRUE);
2503
2504 if(error == ERR_NONE)
2505 s->User.IncomingSMS(s, &sms, s->User.IncomingSMSUserData);
2506
2507 return error;
2508 }
2509
InRange(int * range,int i)2510 gboolean InRange(int *range, int i) {
2511 while (*range != -1) {
2512 if (*range == i) {
2513 return TRUE;
2514 }
2515 range++;
2516 }
2517 return FALSE;
2518 }
2519
GetRange(GSM_StateMachine * s,const char * buffer)2520 int *GetRange(GSM_StateMachine *s, const char *buffer)
2521 {
2522 int *result = NULL;
2523 size_t allocated = 0, pos = 0;
2524 const char *chr = buffer;
2525 char *endptr = NULL;
2526 gboolean in_range = FALSE;
2527 int current, diff, i;
2528
2529 smprintf(s, "Parsing range: %s\n", chr);
2530
2531 if (*chr != '(') {
2532 return NULL;
2533 }
2534 chr++;
2535
2536 while (*chr != ')' && *chr != 0) {
2537 /* Read current number */
2538 current = strtol(chr, &endptr, 10);
2539
2540 /* Detect how much numbers we have to store */
2541 if (in_range) {
2542 diff = current - result[pos - 1];
2543 } else {
2544 diff = 1;
2545 }
2546
2547 /* Did we parse anything? */
2548 if (endptr == chr) {
2549 smprintf(s, "Failed to find number in range!\n");
2550 free(result);
2551 return NULL;
2552 }
2553 /* Allocate more memory if needed */
2554 if (allocated < pos + diff + 1) {
2555 result = (int *)realloc(result, sizeof(int) * (pos + diff + 10));
2556 if (result == NULL) {
2557 smprintf(s, "Not enough memory to parse range!\n");
2558 return NULL;
2559 }
2560 allocated = pos + 10 + diff;
2561 }
2562
2563 /* Store number is memory */
2564 if (!in_range) {
2565 result[pos++] = current;
2566 } else {
2567 for (i = result[pos - 1] + 1; i <= current; i++) {
2568 result[pos++] = i;
2569 }
2570 in_range = FALSE;
2571 }
2572 /* Skip to next char after number */
2573 chr = endptr;
2574
2575 /* Check for character after number */
2576 if (*chr == '-') {
2577 in_range = TRUE;
2578 chr++;
2579 } else if (*chr == ',') {
2580 chr++;
2581 } else if (*chr == ')') {
2582 result[pos++] = -1;
2583 break;
2584 } else if (*chr != ',') {
2585 smprintf(s, "Bad character in range: %c\n", *chr);
2586 free(result);
2587 return NULL;
2588 }
2589 }
2590 if (result == NULL) {
2591 return NULL;
2592 }
2593 smprintf(s, "Returning range: ");
2594
2595 for (i = 0; result[i] != -1; i++) {
2596 smprintf(s, "%d, ", result[i]);
2597 }
2598 smprintf(s, "-1\n");
2599 return result;
2600 }
2601
ATGEN_ReplyGetCNMIMode(GSM_Protocol_Message * msg,GSM_StateMachine * s)2602 GSM_Error ATGEN_ReplyGetCNMIMode(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2603 {
2604 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2605 const char *buffer;
2606 int *range = NULL;
2607 int param = -1;
2608
2609 switch (Priv->ReplyState) {
2610 case AT_Reply_OK:
2611 break;
2612 case AT_Reply_Error:
2613 return ERR_NOTSUPPORTED;
2614 case AT_Reply_CMSError:
2615 return ATGEN_HandleCMSError(s);
2616 case AT_Reply_CMEError:
2617 return ATGEN_HandleCMEError(s);
2618 default:
2619 return ERR_UNKNOWNRESPONSE;
2620 }
2621
2622 /* Sample responses we get here:
2623 AT+CNMI=?
2624 +CNMI: (0-2),(0,1,3),(0),(0,1),(0,1)
2625
2626 Or:
2627 +CNMI:(0-3),(0-3),(0-3),(0,1),(0,1)
2628
2629 Or:
2630 +CNMI: (2),(0-1,3),(0,2),(0-1),(0)"
2631 */
2632 Priv->CNMIMode = 0;
2633 Priv->CNMIProcedure = 0;
2634 Priv->CNMIDeliverProcedure = 0;
2635 #ifdef GSM_ENABLE_CELLBROADCAST
2636 Priv->CNMIBroadcastProcedure = 0;
2637 #endif
2638 Priv->CNMIClearUnsolicitedResultCodes = 0;
2639
2640 buffer = GetLineString(msg->Buffer, &Priv->Lines, 2);
2641
2642 if (buffer == NULL) {
2643 return ERR_UNKNOWNRESPONSE;
2644 }
2645 while (isspace((int)*buffer)) {
2646 buffer++;
2647 }
2648 if (strncmp(buffer, "+CNMI:", 6) != 0) {
2649 return ERR_UNKNOWNRESPONSE;
2650 }
2651 buffer += 7;
2652 buffer = strchr(buffer, '(');
2653
2654 if (buffer == NULL) {
2655 return ERR_UNKNOWNRESPONSE;
2656 }
2657 range = GetRange(s, buffer);
2658
2659 if (range == NULL) {
2660 return ERR_UNKNOWNRESPONSE;
2661 }
2662 param = s->CurrentConfig->CNMIParams[0];
2663 if (param >= 0 && InRange(range, param)) {
2664 Priv->CNMIMode = param;
2665 }
2666 else if (InRange(range, 2)) {
2667 Priv->CNMIMode = 2; /* 2 = buffer messages and send them when link is free */
2668 }
2669 else if (InRange(range, 3)) {
2670 Priv->CNMIMode = 3; /* 3 = send messages directly */
2671 }
2672 else {
2673 free(range);
2674 range = NULL;
2675 return ERR_NONE; /* we don't want: 1 = ignore new messages, 0 = store messages and no indication */
2676 }
2677 free(range);
2678 range = NULL;
2679
2680 buffer++;
2681 buffer = strchr(buffer, '(');
2682
2683 if (buffer == NULL) {
2684 return ERR_UNKNOWNRESPONSE;
2685 }
2686 range = GetRange(s, buffer);
2687 if (range == NULL) {
2688 return ERR_UNKNOWNRESPONSE;
2689 }
2690
2691 param = s->CurrentConfig->CNMIParams[1];
2692 if (param >= 0 && InRange(range, param)) {
2693 Priv->CNMIProcedure = param;
2694 }
2695 else if (InRange(range, 1)) {
2696 Priv->CNMIProcedure = 1; /* 1 = store message and send where it is stored */
2697 }
2698 else if (InRange(range, 2)) {
2699 Priv->CNMIProcedure = 2; /* 2 = route message to TE */
2700 }
2701 else if (InRange(range, 3)) {
2702 Priv->CNMIProcedure = 3; /* 3 = 1 + route class 3 to TE */
2703 }
2704 /* we don't want: 0 = just store to memory */
2705 free(range);
2706 range = NULL;
2707
2708 buffer++;
2709 buffer = strchr(buffer, '(');
2710 #ifdef GSM_ENABLE_CELLBROADCAST
2711 if (buffer == NULL) {
2712 return ERR_UNKNOWNRESPONSE;
2713 }
2714 range = GetRange(s, buffer);
2715
2716 if (range == NULL) {
2717 return ERR_UNKNOWNRESPONSE;
2718 }
2719
2720 param = s->CurrentConfig->CNMIParams[2];
2721 if (param >= 0 && InRange(range, param)) {
2722 Priv->CNMIBroadcastProcedure = param;
2723 }
2724 else if (InRange(range, 2)) {
2725 Priv->CNMIBroadcastProcedure = 2; /* 2 = route message to TE */
2726 }
2727 else if (InRange(range, 1)) {
2728 Priv->CNMIBroadcastProcedure = 1; /* 1 = store message and send where it is stored */
2729 }
2730 else if (InRange(range, 3)) {
2731 Priv->CNMIBroadcastProcedure = 3; /* 3 = 1 + route class 3 to TE */
2732 }
2733 /* we don't want: 0 = just store to memory */
2734 free(range);
2735 range = NULL;
2736 #endif
2737
2738 buffer++;
2739 buffer = strchr(buffer, '(');
2740
2741 if (buffer == NULL) {
2742 return ERR_UNKNOWNRESPONSE;
2743 }
2744 range = GetRange(s, buffer);
2745
2746 if (range == NULL) {
2747 return ERR_UNKNOWNRESPONSE;
2748 }
2749
2750 param = s->CurrentConfig->CNMIParams[3];
2751 if (param >= 0 && InRange(range, param)) {
2752 Priv->CNMIDeliverProcedure = param;
2753 }
2754 else if (InRange(range, 2)) {
2755 Priv->CNMIDeliverProcedure = 2; /* 2 = store message and send where it is stored */
2756 }
2757 else if (InRange(range, 1)) {
2758 Priv->CNMIDeliverProcedure = 1; /* 1 = route message to TE */
2759 }
2760 /* we don't want: 0 = no routing */
2761 free(range);
2762 range = NULL;
2763
2764 buffer++;
2765 buffer = strchr(buffer, '(');
2766
2767 if (buffer == NULL) {
2768 return ERR_NONE;
2769 }
2770 range = GetRange(s, buffer);
2771
2772 if (range == NULL) {
2773 return ERR_UNKNOWNRESPONSE;
2774 }
2775
2776 param = s->CurrentConfig->CNMIParams[4];
2777 if (param >= 0 && InRange(range, param)) {
2778 Priv->CNMIClearUnsolicitedResultCodes = param;
2779 }
2780 free(range);
2781 range = NULL;
2782
2783 return ERR_NONE;
2784 }
2785
ATGEN_GetCNMIMode(GSM_StateMachine * s)2786 GSM_Error ATGEN_GetCNMIMode(GSM_StateMachine *s)
2787 {
2788 GSM_Error error;
2789
2790 error = ATGEN_WaitForAutoLen(s, "AT+CNMI=?\r", 0x00, 80, ID_GetCNMIMode);
2791 return error;
2792 }
2793
ATGEN_SetCNMI(GSM_StateMachine * s)2794 GSM_Error ATGEN_SetCNMI(GSM_StateMachine *s)
2795 {
2796 char buffer[100];
2797 int length = 0;
2798 GSM_Error error;
2799 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2800
2801 if (Priv->CNMIMode == -1) {
2802 error = ATGEN_GetCNMIMode(s);
2803
2804 if (error != ERR_NONE) {
2805 return error;
2806 }
2807 }
2808
2809 if (Priv->CNMIMode == 0) {
2810 return ERR_NOTSUPPORTED;
2811 }
2812 if (Priv->CNMIBroadcastProcedure == 0) {
2813 return ERR_NOTSUPPORTED;
2814 }
2815
2816 length = sprintf(
2817 buffer,
2818 "AT+CNMI=%d,%d,%d,%d,%d\r",
2819 Priv->CNMIMode,
2820 s->Phone.Data.EnableIncomingSMS ? Priv->CNMIProcedure : 0,
2821 #ifdef GSM_ENABLE_CELLBROADCAST
2822 s->Phone.Data.EnableIncomingCB ? Priv->CNMIBroadcastProcedure : 0,
2823 #else
2824 0,
2825 #endif
2826 Priv->CNMIDeliverProcedure,
2827 Priv->CNMIClearUnsolicitedResultCodes
2828 );
2829
2830 return ATGEN_WaitFor(s, buffer, length, 0x00, 80, ID_SetIncomingSMS);
2831 }
2832
2833
ATGEN_SetIncomingCB(GSM_StateMachine * s,gboolean enable)2834 GSM_Error ATGEN_SetIncomingCB(GSM_StateMachine *s, gboolean enable)
2835 {
2836 #ifdef GSM_ENABLE_CELLBROADCAST
2837 if (s->Phone.Data.EnableIncomingCB != enable) {
2838 s->Phone.Data.EnableIncomingCB = enable;
2839 return ATGEN_SetCNMI(s);
2840 }
2841 return ERR_NONE;
2842 #else
2843 return ERR_SOURCENOTAVAILABLE;
2844 #endif
2845 }
2846
2847
ATGEN_SetIncomingSMS(GSM_StateMachine * s,gboolean enable)2848 GSM_Error ATGEN_SetIncomingSMS(GSM_StateMachine *s, gboolean enable)
2849 {
2850 GSM_Error error = ERR_NONE;
2851 GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
2852
2853 /* We will need this when incoming message, but we can not invoke AT commands there: */
2854 if (Priv->PhoneSMSMemory == 0) {
2855 error = ATGEN_SetSMSMemory(s, FALSE, FALSE, FALSE);
2856 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) {
2857 return error;
2858 }
2859 }
2860 if (Priv->SIMSMSMemory == 0) {
2861 error = ATGEN_SetSMSMemory(s, TRUE, FALSE, FALSE);
2862
2863 if (error != ERR_NONE && error != ERR_NOTSUPPORTED) {
2864 return error;
2865 }
2866 }
2867 if (s->Phone.Data.EnableIncomingSMS != enable) {
2868 s->Phone.Data.EnableIncomingSMS = enable;
2869 return ATGEN_SetCNMI(s);
2870 }
2871 return ERR_NONE;
2872 }
2873
2874 #ifdef GSM_ENABLE_CELLBROADCAST
2875
ATGEN_ReplyIncomingCB(GSM_Protocol_Message * msg,GSM_StateMachine * s)2876 GSM_Error ATGEN_ReplyIncomingCB(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2877 {
2878 #if 0
2879 GSM_CBMessage CB;
2880 char Buffer[300] = {'\0'},Buffer2[300] = {'\0'};
2881 int i = 0;
2882 size_t j = 0;
2883
2884 DecodeHexBin (Buffer,msg->Buffer+6,msg.Length-6);
2885 DumpMessage(&di ,Buffer,msg->Length-6);
2886
2887 CB.Channel = Buffer[4];
2888
2889 for (j = 0;j < msg->Length;j++) {
2890 smprintf(s, "j=" SIZE_T_FORMAT "\n",j);
2891 i = GSM_UnpackEightBitsToSeven(0, msg->Buffer[6], msg.Buffer[6], msg.Buffer+j, Buffer2);
2892 i = msg->Buffer[6] - 1;
2893
2894 while (i != 0) {
2895 if (Buffer[i] == 13) i = i - 1; else break;
2896 }
2897 DecodeDefault(CB.Text, Buffer2, msg->Buffer[6], TRUE, NULL);
2898 smprintf(s, "Channel %i, text \"%s\"\n",CB.Channel,DecodeUnicodeString(CB.Text));
2899 }
2900 if (s->Phone.Data.EnableIncomingCB && s->User.IncomingCB != NULL) {
2901 s->User.IncomingCB(s,CB);
2902 }
2903 return ERR_NONE;
2904 #else
2905 smprintf(s, "CB received\n");
2906 return ERR_NONE;
2907 #endif
2908 }
2909
2910 #endif
2911
2912
2913 #endif
2914 /*@}*/
2915 /*@}*/
2916
2917 /* How should editor hadle tabs in this file? Add editor commands here.
2918 * vim: noexpandtab sw=8 ts=8 sts=8:
2919 */
2920