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), &current, &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), &current, &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), &current, &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