1 /* Samsung-specific functions
2  * Copyright (C) 2004 Claudio Matsuoka <cmatsuoka@gmail.com>
3  * Copyright (c) 2009 Michal Cihar <michal@cihar.com>
4  */
5 
6 #include <gammu-config.h>
7 
8 #ifdef GSM_ENABLE_ATGEN
9 
10 #include <string.h>
11 #include <time.h>
12 #include <ctype.h>
13 
14 #include "../../misc/coding/coding.h"
15 #include "../../gsmcomon.h"
16 #include "../pfunc.h"
17 
18 #include "atgen.h"
19 #include "samsung.h"
20 
21 /* Binary frame size */
22 #define BLKSZ 1024
23 
24 struct ModelRes {
25 	const char *model;
26 	const size_t width;
27 	const size_t height;
28 };
29 
30 static struct ModelRes modres[] = {
31 	{ "S100", 128, 128 },
32 	{ "S200", 128, 113 },
33 	{ "S300", 128,  97 },
34 	{ "S500", 128, 128 },
35 	{ "T100", 128, 128 },
36 	{ "E700", 128, 128 },
37 	{ NULL, 0, 0 }
38 };
39 
40 /*
41  * CRC functions from the Granch SBNI12 Linux driver by
42  * Denis I. Timofeev <timofeev@granch.ru>
43  */
44 static unsigned int crc32tab[] = {
45 	0xD202EF8D,  0xA505DF1B,  0x3C0C8EA1,  0x4B0BBE37,
46 	0xD56F2B94,  0xA2681B02,  0x3B614AB8,  0x4C667A2E,
47 	0xDCD967BF,  0xABDE5729,  0x32D70693,  0x45D03605,
48 	0xDBB4A3A6,  0xACB39330,  0x35BAC28A,  0x42BDF21C,
49 	0xCFB5FFE9,  0xB8B2CF7F,  0x21BB9EC5,  0x56BCAE53,
50 	0xC8D83BF0,  0xBFDF0B66,  0x26D65ADC,  0x51D16A4A,
51 	0xC16E77DB,  0xB669474D,  0x2F6016F7,  0x58672661,
52 	0xC603B3C2,  0xB1048354,  0x280DD2EE,  0x5F0AE278,
53 	0xE96CCF45,  0x9E6BFFD3,  0x0762AE69,  0x70659EFF,
54 	0xEE010B5C,  0x99063BCA,  0x000F6A70,  0x77085AE6,
55 	0xE7B74777,  0x90B077E1,  0x09B9265B,  0x7EBE16CD,
56 	0xE0DA836E,  0x97DDB3F8,  0x0ED4E242,  0x79D3D2D4,
57 	0xF4DBDF21,  0x83DCEFB7,  0x1AD5BE0D,  0x6DD28E9B,
58 	0xF3B61B38,  0x84B12BAE,  0x1DB87A14,  0x6ABF4A82,
59 	0xFA005713,  0x8D076785,  0x140E363F,  0x630906A9,
60 	0xFD6D930A,  0x8A6AA39C,  0x1363F226,  0x6464C2B0,
61 	0xA4DEAE1D,  0xD3D99E8B,  0x4AD0CF31,  0x3DD7FFA7,
62 	0xA3B36A04,  0xD4B45A92,  0x4DBD0B28,  0x3ABA3BBE,
63 	0xAA05262F,  0xDD0216B9,  0x440B4703,  0x330C7795,
64 	0xAD68E236,  0xDA6FD2A0,  0x4366831A,  0x3461B38C,
65 	0xB969BE79,  0xCE6E8EEF,  0x5767DF55,  0x2060EFC3,
66 	0xBE047A60,  0xC9034AF6,  0x500A1B4C,  0x270D2BDA,
67 	0xB7B2364B,  0xC0B506DD,  0x59BC5767,  0x2EBB67F1,
68 	0xB0DFF252,  0xC7D8C2C4,  0x5ED1937E,  0x29D6A3E8,
69 	0x9FB08ED5,  0xE8B7BE43,  0x71BEEFF9,  0x06B9DF6F,
70 	0x98DD4ACC,  0xEFDA7A5A,  0x76D32BE0,  0x01D41B76,
71 	0x916B06E7,  0xE66C3671,  0x7F6567CB,  0x0862575D,
72 	0x9606C2FE,  0xE101F268,  0x7808A3D2,  0x0F0F9344,
73 	0x82079EB1,  0xF500AE27,  0x6C09FF9D,  0x1B0ECF0B,
74 	0x856A5AA8,  0xF26D6A3E,  0x6B643B84,  0x1C630B12,
75 	0x8CDC1683,  0xFBDB2615,  0x62D277AF,  0x15D54739,
76 	0x8BB1D29A,  0xFCB6E20C,  0x65BFB3B6,  0x12B88320,
77 	0x3FBA6CAD,  0x48BD5C3B,  0xD1B40D81,  0xA6B33D17,
78 	0x38D7A8B4,  0x4FD09822,  0xD6D9C998,  0xA1DEF90E,
79 	0x3161E49F,  0x4666D409,  0xDF6F85B3,  0xA868B525,
80 	0x360C2086,  0x410B1010,  0xD80241AA,  0xAF05713C,
81 	0x220D7CC9,  0x550A4C5F,  0xCC031DE5,  0xBB042D73,
82 	0x2560B8D0,  0x52678846,  0xCB6ED9FC,  0xBC69E96A,
83 	0x2CD6F4FB,  0x5BD1C46D,  0xC2D895D7,  0xB5DFA541,
84 	0x2BBB30E2,  0x5CBC0074,  0xC5B551CE,  0xB2B26158,
85 	0x04D44C65,  0x73D37CF3,  0xEADA2D49,  0x9DDD1DDF,
86 	0x03B9887C,  0x74BEB8EA,  0xEDB7E950,  0x9AB0D9C6,
87 	0x0A0FC457,  0x7D08F4C1,  0xE401A57B,  0x930695ED,
88 	0x0D62004E,  0x7A6530D8,  0xE36C6162,  0x946B51F4,
89 	0x19635C01,  0x6E646C97,  0xF76D3D2D,  0x806A0DBB,
90 	0x1E0E9818,  0x6909A88E,  0xF000F934,  0x8707C9A2,
91 	0x17B8D433,  0x60BFE4A5,  0xF9B6B51F,  0x8EB18589,
92 	0x10D5102A,  0x67D220BC,  0xFEDB7106,  0x89DC4190,
93 	0x49662D3D,  0x3E611DAB,  0xA7684C11,  0xD06F7C87,
94 	0x4E0BE924,  0x390CD9B2,  0xA0058808,  0xD702B89E,
95 	0x47BDA50F,  0x30BA9599,  0xA9B3C423,  0xDEB4F4B5,
96 	0x40D06116,  0x37D75180,  0xAEDE003A,  0xD9D930AC,
97 	0x54D13D59,  0x23D60DCF,  0xBADF5C75,  0xCDD86CE3,
98 	0x53BCF940,  0x24BBC9D6,  0xBDB2986C,  0xCAB5A8FA,
99 	0x5A0AB56B,  0x2D0D85FD,  0xB404D447,  0xC303E4D1,
100 	0x5D677172,  0x2A6041E4,  0xB369105E,  0xC46E20C8,
101 	0x72080DF5,  0x050F3D63,  0x9C066CD9,  0xEB015C4F,
102 	0x7565C9EC,  0x0262F97A,  0x9B6BA8C0,  0xEC6C9856,
103 	0x7CD385C7,  0x0BD4B551,  0x92DDE4EB,  0xE5DAD47D,
104 	0x7BBE41DE,  0x0CB97148,  0x95B020F2,  0xE2B71064,
105 	0x6FBF1D91,  0x18B82D07,  0x81B17CBD,  0xF6B64C2B,
106 	0x68D2D988,  0x1FD5E91E,  0x86DCB8A4,  0xF1DB8832,
107 	0x616495A3,  0x1663A535,  0x8F6AF48F,  0xF86DC419,
108 	0x660951BA,  0x110E612C,  0x88073096,  0xFF000000
109 };
110 
GetCRC(char * data,int size)111 static unsigned int GetCRC(char *data, int size)
112 {
113 	unsigned int crc = 0;
114 
115 	while (size--)
116 		crc = crc32tab[(crc ^ *data++) & 0xff] ^ ((crc >> 8) & 0x00FFFFFF);
117 
118 	return crc;
119 }
120 
121 /*
122  * Frame transfer
123  */
124 
WaitFor(GSM_StateMachine * s,const char * t,int ttl)125 static GSM_Error WaitFor(GSM_StateMachine *s, const char *t, int ttl)
126 {
127 	char 		readbuf[100]={0};
128 	int 		n=0,sec=0;
129         GSM_DateTime    Date;
130 
131         GSM_GetCurrentDateTime (&Date);
132         sec = Date.Second;
133 
134 	n = s->Device.Functions->ReadDevice(s, readbuf, sizeof(readbuf) - 1);
135 	readbuf[n] = '\0';
136 
137 	while (strstr(readbuf, t) == NULL && (sec + ttl) >= Date.Second) {
138 		usleep(500000);
139 		n = s->Device.Functions->ReadDevice(s, readbuf, sizeof(readbuf) - 1);
140 		readbuf[n] = '\0';
141         	GSM_GetCurrentDateTime (&Date);
142 	}
143 
144 	return (sec + ttl) >= Date.Second ? ERR_NONE : ERR_TIMEOUT;
145 }
146 
SetSamsungFrame(GSM_StateMachine * s,unsigned char * buff,int size,GSM_Phone_RequestID id)147 static GSM_Error SetSamsungFrame(GSM_StateMachine *s, unsigned char *buff, int size, GSM_Phone_RequestID id)
148 {
149 	GSM_Phone_Data		*Phone = &s->Phone.Data;
150 	GSM_Error		error;
151 	int			i, count;
152 
153 	count = size / BLKSZ;
154 
155 	for (i = 0; i < count; i++) {
156 		error = WaitFor(s, ">", 4);
157  		if (error!=ERR_NONE) return error;
158 
159  		error = s->Protocol.Functions->WriteMessage(s,
160 			buff + i * BLKSZ, BLKSZ, 0x00);
161  		if (error!=ERR_NONE) return error;
162 	}
163 
164 	error = WaitFor(s, ">", 4);
165  	if (error!=ERR_NONE) return error;
166 	error = s->Protocol.Functions->WriteMessage(s,
167 		buff + i * BLKSZ, size%BLKSZ, 0x00);
168 	if (error!=ERR_NONE) return error;
169 
170 	error = GSM_WaitFor(s, "", 0, 0x00, 4, id);
171 	if (error!=ERR_NONE) return error;
172 
173 	return Phone->DispatchError;
174 }
175 
176 /* Answer format for binary data transfer
177  *
178  * SDNDCRC = 0xa : RECEIVECRC = 0xcbf53a1c : BINSIZE = 5
179  * CRCERR
180  */
ReplySetSamsungFrame(GSM_Protocol_Message * msg,GSM_StateMachine * s)181 static GSM_Error ReplySetSamsungFrame(GSM_Protocol_Message *msg, GSM_StateMachine *s)
182 {
183 	unsigned long 		txcrc, rxcrc;
184 	int 			binsize;
185 	char 			*pos;
186 
187 	/* Parse SDNDCRC */
188 	pos = strchr(msg->Buffer, '=');
189 	if (!pos) return ERR_UNKNOWN;
190 	pos++;
191 	txcrc = strtoul(pos, NULL, 0);
192 	smprintf(s, "Sent CRC     : 0x%lx\n", txcrc);
193 
194 	/* Parse RECEIVECRC */
195 	pos = strchr(pos, '=');
196 	if (!pos) return ERR_UNKNOWN;
197 	pos++;
198 	rxcrc = strtoul(pos, NULL, 0);
199 	smprintf(s, "Reveived CRC : 0x%lx\n", rxcrc);
200 
201 	/* Parse BINSIZE */
202 	pos = strchr(pos, '=');
203 	if (!pos) return ERR_UNKNOWN;
204 	pos++;
205 	binsize = strtoul(pos, NULL, 0);
206 	smprintf(s, "Binary size  : %d\n", binsize);
207 
208 	return txcrc == rxcrc ? ERR_NONE : ERR_WRONGCRC;
209 }
210 
211 /*
212  * Bitmaps
213  */
214 
SAMSUNG_ReplyGetBitmap(GSM_Protocol_Message * msg,GSM_StateMachine * s)215 GSM_Error SAMSUNG_ReplyGetBitmap(GSM_Protocol_Message *msg, GSM_StateMachine *s)
216 {
217  	GSM_Phone_ATGENData 	*Priv = &s->Phone.Data.Priv.ATGEN;
218 	char 		buffer[32];
219 	char 			*pos;
220 	int			location, count;
221 
222  	switch (Priv->ReplyState) {
223  	case AT_Reply_OK:
224 		smprintf(s, "Bitmap info received\n");
225 		/* Parse +IMGR:location,name,0,0,0,0 */
226 
227 		/* Parse location */
228 		pos = strchr(msg->Buffer, ':');
229 		if (!pos) return ERR_UNKNOWN;
230 		pos++;
231 		location = atoi(pos);
232 		smprintf(s, "Location : %d\n", location);
233 
234 		/* Parse name */
235 		pos = strchr(pos, '"');
236 		if (!pos) return ERR_UNKNOWN;
237 		pos++;
238 		for (count = 0; count < 31; count++) {
239 			if (pos[count] == '"')
240 				break;
241 			buffer[count] = pos[count];
242 		}
243 		buffer[count] = 0;
244 		smprintf(s, "Name     : %s\n", buffer);
245 		EncodeUnicode(s->Phone.Data.Bitmap->Name, buffer, strlen(buffer));
246 
247 		s->Phone.Data.Bitmap->Location = location;
248 
249 		return ERR_NONE;
250 	case AT_Reply_Error:
251 		return ERR_NOTSUPPORTED;
252 	case AT_Reply_CMSError:
253 	        return ATGEN_HandleCMSError(s);
254 	case AT_Reply_CMEError:
255 	        return ATGEN_HandleCMEError(s);
256  	default:
257 		return ERR_UNKNOWNRESPONSE;
258 	}
259 }
260 
SAMSUNG_ReplySetBitmap(GSM_Protocol_Message * msg,GSM_StateMachine * s)261 GSM_Error SAMSUNG_ReplySetBitmap(GSM_Protocol_Message *msg, GSM_StateMachine *s)
262 {
263 	smprintf(s, "Bitmap sent\n");
264 	return ReplySetSamsungFrame(msg, s);
265 }
266 
SAMSUNG_GetBitmap(GSM_StateMachine * s,GSM_Bitmap * Bitmap)267 GSM_Error SAMSUNG_GetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap)
268 {
269 	unsigned char req[100];
270 	size_t len;
271 
272 	s->Phone.Data.Bitmap=Bitmap;
273 	smprintf(s, "Getting bitmap\n");
274 	len = sprintf(req, "AT+IMGR=%d\r", Bitmap->Location-1);
275 	return GSM_WaitFor (s, req, len, 0x00, 4, ID_GetBitmap);
276 }
277 
SAMSUNG_SetBitmap(GSM_StateMachine * s,GSM_Bitmap * Bitmap)278 GSM_Error SAMSUNG_SetBitmap(GSM_StateMachine *s, GSM_Bitmap *Bitmap)
279 {
280 	unsigned char	req[100];
281 	unsigned long	crc;
282 	GSM_Error	error;
283 	char		name[50], *dot;
284     const char *model;
285 	GSM_Phone_Data  *Data = &s->Phone.Data;
286 	int 		i;
287 	size_t len;
288 
289 	s->Phone.Data.Bitmap = Bitmap;
290 	smprintf(s, "Setting bitmap\n");
291 
292 	if (Bitmap->Type != GSM_PictureBinary) {
293 		smprintf(s, "Invalid picture type\n");
294 		return ERR_INVALIDDATA;
295 	}
296 
297 	if (Bitmap->BinaryPic.Type != PICTURE_GIF) {
298 		smprintf(s, "Invalid binary picture type\n");
299 		return ERR_INVALIDDATA;
300 	}
301 
302 	/* Check if picture size matches phone model */
303 	model = Data->ModelInfo->model;
304 	smprintf(s, "Checking picture size for %s\n", model);
305 	for (i = 0; modres[i].model; i++) {
306 		if (!strcmp(model, modres[i].model)) {
307 			if (Bitmap->BitmapWidth != modres[i].width ||
308 			    Bitmap->BitmapHeight != modres[i].height) {
309 				smprintf(s, "Model %s must use %ld x %ld picture size\n",
310 					modres[i].model,
311 					(long)modres[i].width,
312 					(long)modres[i].height);
313 				return ERR_INVALIDDATA;
314 			}
315 			break;
316 		}
317 	}
318 	if (modres[i].model == NULL) {
319 		smprintf(s, "Model \"%s\" is not supported.\n", Data->Model);
320 		return ERR_NOTSUPPORTED;
321 	}
322 
323 	crc = GetCRC(Bitmap->BinaryPic.Buffer, Bitmap->BinaryPic.Length);
324 
325 	/* Remove extension from file name */
326 	strncpy(name, DecodeUnicodeString(Bitmap->Name), 50);
327 	name[49] = '\0';
328 	if ((dot = strrchr(name, '.')) != NULL)
329 		*dot = 0;
330 
331 	len = sprintf(req, "AT+IMGW=0,\"%s\",2,0,0,0,0,100,%ld,%u\r", name,
332 		(long int)Bitmap->BinaryPic.Length, (unsigned int)crc);
333 
334 	error = s->Protocol.Functions->WriteMessage(s, req, len, 0x00);
335 	if (error!=ERR_NONE) return error;
336 
337 	return SetSamsungFrame(s, Bitmap->BinaryPic.Buffer,
338 		Bitmap->BinaryPic.Length, ID_SetBitmap);
339 }
340 
341 /*
342  * Ringtones
343  */
344 
SAMSUNG_ReplyGetRingtone(GSM_Protocol_Message * msg,GSM_StateMachine * s)345 GSM_Error SAMSUNG_ReplyGetRingtone(GSM_Protocol_Message *msg, GSM_StateMachine *s)
346 {
347  	GSM_Phone_ATGENData 	*Priv = &s->Phone.Data.Priv.ATGEN;
348 	unsigned char 		buffer[32];
349 	char 			*pos;
350 	int			location, length, count;
351 
352  	switch (Priv->ReplyState) {
353  	case AT_Reply_OK:
354 		smprintf(s, "Ringtone info received\n");
355 		/* Parse +MELR:location,name,size */
356 
357 		/* Parse location */
358 		pos = strchr(msg->Buffer, ':');
359 		if (!pos) return ERR_UNKNOWN;
360 		pos++;
361 		location = atoi(pos);
362 		smprintf(s, "Location : %d\n", location);
363 
364 		/* Parse name */
365 		pos = strchr(pos, '"');
366 		if (!pos) return ERR_UNKNOWN;
367 		pos++;
368 		/* Ringtone.Name size is 20 chars */
369 		for (count = 0; count < 19; count++) {
370 			if (pos[count] == '"')
371 				break;
372 			buffer[count] = pos[count];
373 		}
374 		buffer[count] = 0;
375 		smprintf(s, "Name     : %s\n", buffer);
376 		EncodeUnicode(s->Phone.Data.Ringtone->Name,buffer,strlen(buffer));
377 
378 		/* Parse ringtone length */
379 		pos = strchr(pos, ',');
380 		if (!pos) return ERR_UNKNOWN;
381 		pos++;
382 		length = atoi(pos);
383 		smprintf(s, "Length   : %d\n", length);
384 
385 		/* S300 ringtones are always MMF */
386 		s->Phone.Data.Ringtone->Format = RING_MMF;
387 		s->Phone.Data.Ringtone->Location = location;
388 		s->Phone.Data.Ringtone->BinaryTone.Length = length;
389 
390 		return ERR_NONE;
391 	case AT_Reply_Error:
392 		return ERR_UNKNOWN;
393 	case AT_Reply_CMSError:
394 	        return ATGEN_HandleCMSError(s);
395 	case AT_Reply_CMEError:
396 	        return ATGEN_HandleCMEError(s);
397  	default:
398 		return ERR_UNKNOWNRESPONSE;
399 	}
400 }
401 
SAMSUNG_GetRingtone(GSM_StateMachine * s,GSM_Ringtone * Ringtone,gboolean PhoneRingtone UNUSED)402 GSM_Error SAMSUNG_GetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, gboolean PhoneRingtone UNUSED)
403 {
404 	unsigned char req[100];
405 	size_t len;
406 
407 	s->Phone.Data.Ringtone = Ringtone;
408 	smprintf(s, "Getting ringtone\n");
409 	len = sprintf(req, "AT+MELR=%d\r", Ringtone->Location-1);
410 	return GSM_WaitFor (s, req, len, 0x00, 4, ID_GetRingtone);
411 }
412 
SAMSUNG_ReplySetRingtone(GSM_Protocol_Message * msg,GSM_StateMachine * s)413 GSM_Error SAMSUNG_ReplySetRingtone(GSM_Protocol_Message *msg, GSM_StateMachine *s)
414 {
415 	smprintf(s, "Ringtone sent\n");
416 	return ReplySetSamsungFrame(msg, s);
417 }
418 
SAMSUNG_SetRingtone(GSM_StateMachine * s,GSM_Ringtone * Ringtone,int * maxlength UNUSED)419 GSM_Error SAMSUNG_SetRingtone(GSM_StateMachine *s, GSM_Ringtone *Ringtone, int *maxlength UNUSED)
420 {
421 	unsigned char	req[100];
422 	unsigned long	crc;
423 	GSM_Error	error;
424 	char		name[50], *dot;
425 	size_t len;
426 
427 	s->Phone.Data.Ringtone = Ringtone;
428 	smprintf(s, "Setting ringtone\n");
429 
430 	if (Ringtone->Format != RING_MMF) {
431 		smprintf(s, "Not MMF ringtone\n");
432 		return ERR_INVALIDDATA;
433 	}
434 
435 	/* Remove extension from file name */
436 	strncpy(name, DecodeUnicodeString(Ringtone->Name), 50);
437 	name[49] = '\0';
438 	if ((dot = strrchr(name, '.')) != NULL) *dot = 0;
439 
440 	crc = GetCRC(Ringtone->BinaryTone.Buffer, Ringtone->BinaryTone.Length);
441 	len = sprintf(req, "AT+MELW=0,\"%s\",4,%ld,%u\r", name,
442 		(long)Ringtone->BinaryTone.Length, (unsigned int)crc);
443 
444 	error = s->Protocol.Functions->WriteMessage(s, req, len, 0x00);
445 	if (error!=ERR_NONE) return error;
446 
447 	return SetSamsungFrame(s, Ringtone->BinaryTone.Buffer,
448 		Ringtone->BinaryTone.Length, ID_SetRingtone);
449 }
450 
451 /**
452  * Check what variant of calendar protocol for Samsung is supported.
453  */
SAMSUNG_CheckCalendar(GSM_StateMachine * s)454 GSM_Error SAMSUNG_CheckCalendar(GSM_StateMachine *s)
455 {
456  	GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
457 	GSM_Error error;
458 
459 	if (Priv->SamsungCalendar != 0) {
460 		return ERR_NONE;
461 	}
462 
463 	smprintf(s, "Checking for supported calendar commands\n");
464 
465 	error = ATGEN_WaitForAutoLen(s, "AT+SSHT?\r", 0x00, 10, ID_GetProtocol);
466 	if (error == ERR_NONE) {
467 		Priv->SamsungCalendar = SAMSUNG_SSH;
468 		return ERR_NONE;
469 	}
470 
471 	error = ATGEN_WaitForAutoLen(s, "AT+ORGI?\r", 0x00, 10, ID_GetProtocol);
472 	if (error == ERR_NONE) {
473 		Priv->SamsungCalendar = SAMSUNG_ORG;
474 		return ERR_NONE;
475 	}
476 
477 	Priv->SamsungCalendar = SAMSUNG_NONE;
478 	return ERR_NONE;
479 
480 }
481 
SAMSUNG_ReplyGetMemoryInfo(GSM_Protocol_Message * msg,GSM_StateMachine * s)482 GSM_Error SAMSUNG_ReplyGetMemoryInfo(GSM_Protocol_Message *msg, GSM_StateMachine *s)
483 {
484  	GSM_Phone_ATGENData 	*Priv = &s->Phone.Data.Priv.ATGEN;
485 
486 	Priv->PBK_SPBR = AT_NOTAVAILABLE;
487 
488  	switch (Priv->ReplyState) {
489  	case AT_Reply_OK:
490 		/* FIXME: does phone give also some useful infromation here? */
491 		Priv->PBK_SPBR = AT_AVAILABLE;
492 
493 		return ERR_NONE;
494 	case AT_Reply_Error:
495 		return ERR_UNKNOWN;
496 	case AT_Reply_CMSError:
497 	        return ATGEN_HandleCMSError(s);
498 	case AT_Reply_CMEError:
499 	        return ATGEN_HandleCMEError(s);
500  	default:
501 		return ERR_UNKNOWNRESPONSE;
502 	}
503 }
504 
SAMSUNG_ReplyGetMemory(GSM_Protocol_Message * msg,GSM_StateMachine * s)505 GSM_Error SAMSUNG_ReplyGetMemory(GSM_Protocol_Message *msg, GSM_StateMachine *s)
506 {
507  	GSM_Phone_ATGENData 	*Priv = &s->Phone.Data.Priv.ATGEN;
508  	GSM_MemoryEntry		*Memory = s->Phone.Data.Memory;
509 	GSM_Error error;
510 	const char *str;
511 	int i, j, year = 1900, month = 0, day = 0;
512 
513 	switch (Priv->ReplyState) {
514 	case AT_Reply_OK:
515  		smprintf(s, "Phonebook entry received\n");
516 		Memory->EntriesNum = 12;
517 		Memory->Entries[0].EntryType = PBK_Number_Mobile;
518 		Memory->Entries[0].Location = PBK_Location_Unknown;
519 		Memory->Entries[0].AddError = ERR_NONE;
520 		Memory->Entries[0].VoiceTag = 0;
521 		Memory->Entries[0].SMSList[0] = 0;
522 		Memory->Entries[1].EntryType = PBK_Number_General;
523 		Memory->Entries[1].Location = PBK_Location_Home;
524 		Memory->Entries[1].AddError = ERR_NONE;
525 		Memory->Entries[1].VoiceTag = 0;
526 		Memory->Entries[1].SMSList[0] = 0;
527 		Memory->Entries[2].EntryType = PBK_Number_General;
528 		Memory->Entries[2].Location = PBK_Location_Work;
529 		Memory->Entries[2].AddError = ERR_NONE;
530 		Memory->Entries[2].VoiceTag = 0;
531 		Memory->Entries[2].SMSList[0] = 0;
532 		Memory->Entries[3].EntryType = PBK_Number_Fax;
533 		Memory->Entries[3].Location = PBK_Location_Unknown;
534 		Memory->Entries[3].AddError = ERR_NONE;
535 		Memory->Entries[3].VoiceTag = 0;
536 		Memory->Entries[3].SMSList[0] = 0;
537 		Memory->Entries[4].EntryType = PBK_Number_General;
538 		Memory->Entries[4].Location = PBK_Location_Unknown;
539 		Memory->Entries[4].AddError = ERR_NONE;
540 		Memory->Entries[4].VoiceTag = 0;
541 		Memory->Entries[4].SMSList[0] = 0;
542 		Memory->Entries[5].EntryType = PBK_Text_Email;
543 		Memory->Entries[5].Location = PBK_Location_Unknown;
544 		Memory->Entries[5].AddError = ERR_NONE;
545 		Memory->Entries[5].VoiceTag = 0;
546 		Memory->Entries[5].SMSList[0] = 0;
547 		Memory->Entries[6].EntryType = PBK_Text_FirstName;
548 		Memory->Entries[6].Location = PBK_Location_Unknown;
549 		Memory->Entries[6].AddError = ERR_NONE;
550 		Memory->Entries[6].VoiceTag = 0;
551 		Memory->Entries[6].SMSList[0] = 0;
552 		Memory->Entries[7].EntryType = PBK_Text_LastName;
553 		Memory->Entries[7].Location = PBK_Location_Unknown;
554 		Memory->Entries[7].AddError = ERR_NONE;
555 		Memory->Entries[7].VoiceTag = 0;
556 		Memory->Entries[7].SMSList[0] = 0;
557 		Memory->Entries[8].EntryType = PBK_Text_Note;
558 		Memory->Entries[8].Location = PBK_Location_Unknown;
559 		Memory->Entries[8].AddError = ERR_NONE;
560 		Memory->Entries[8].VoiceTag = 0;
561 		Memory->Entries[8].SMSList[0] = 0;
562 		Memory->Entries[9].EntryType = PBK_Text_Note;
563 		Memory->Entries[9].Location = PBK_Location_Unknown;
564 		Memory->Entries[9].AddError = ERR_NONE;
565 		Memory->Entries[9].VoiceTag = 0;
566 		Memory->Entries[9].SMSList[0] = 0;
567 		EncodeUnicode(Memory->Entries[9].Text, "", 0);
568 		Memory->Entries[10].EntryType = PBK_Text_Note;
569 		Memory->Entries[10].Location = PBK_Location_Unknown;
570 		Memory->Entries[10].AddError = ERR_NONE;
571 		Memory->Entries[10].VoiceTag = 0;
572 		Memory->Entries[10].SMSList[0] = 0;
573 		EncodeUnicode(Memory->Entries[10].Text, "", 0);
574 		Memory->Entries[11].EntryType = PBK_Text_Note;
575 		Memory->Entries[11].Location = PBK_Location_Unknown;
576 		Memory->Entries[11].AddError = ERR_NONE;
577 		Memory->Entries[11].VoiceTag = 0;
578 		Memory->Entries[11].SMSList[0] = 0;
579 		EncodeUnicode(Memory->Entries[11].Text, "", 0);
580 
581 		/* Get line from reply */
582 		str = GetLineString(msg->Buffer, &Priv->Lines, 2);
583 
584 		/* Empty entry */
585 		if (strcmp(str, "OK") == 0) return ERR_EMPTY;
586 
587 		/* Philips has it's SPBR as well, but different reply */
588 		if ( Priv->Manufacturer == AT_Philips) {
589 			error = ATGEN_ParseReply(s,
590 						GetLineString(msg->Buffer, &Priv->Lines, 2),
591 						"+SPBR: @n, @u, @p",
592 						&Memory->Location,
593 						Memory->Entries[0].Text, sizeof(Memory->Entries[0].Text),
594 						Memory->Entries[1].Text, sizeof(Memory->Entries[1].Text));
595 			if (error == ERR_NONE) {
596 				/* Set name type */
597 				Memory->Entries[0].EntryType = PBK_Text_Name;
598 				Memory->Entries[0].Location = PBK_Location_Unknown;
599 
600 				/* Set number type */
601 				Memory->Entries[1].EntryType = PBK_Number_General;
602 				Memory->Entries[1].Location = PBK_Location_Unknown;
603 				Memory->Entries[1].VoiceTag = 0;
604 				Memory->Entries[1].SMSList[0] = 0;
605 
606 				return ERR_NONE;
607 			}
608 		}
609 
610 		/*
611 		 * Parse reply string
612 		 *
613 		 * The last string seems to be always empty, so it is
614 		 * not handled in rest of the code.
615 		 */
616 		error = ATGEN_ParseReply(s, str,
617 					"+SPBR: @i, @p, @p, @p, @p, @p, @s, @T, @T, @T, @T",
618 					&Memory->Location,
619 					Memory->Entries[0].Text, sizeof(Memory->Entries[0].Text),
620 					Memory->Entries[1].Text, sizeof(Memory->Entries[1].Text),
621 					Memory->Entries[2].Text, sizeof(Memory->Entries[2].Text),
622 					Memory->Entries[3].Text, sizeof(Memory->Entries[3].Text),
623 					Memory->Entries[4].Text, sizeof(Memory->Entries[4].Text),
624 					Memory->Entries[5].Text, sizeof(Memory->Entries[5].Text),
625 					Memory->Entries[6].Text, sizeof(Memory->Entries[6].Text),
626 					Memory->Entries[7].Text, sizeof(Memory->Entries[7].Text),
627 					Memory->Entries[8].Text, sizeof(Memory->Entries[8].Text),
628 					Memory->Entries[9].Text, sizeof(Memory->Entries[9].Text));
629 		if (error != ERR_NONE) {
630 			/*
631 			 * Some phones have different string:
632 			 * +SPBR: 1,"+999999999999","","","","","aaaaaaaaaa@gmail.com","6,Aaaaaa","8,Ssssssss",1999,1,31,"2,Me","0,"
633 			 */
634 			error = ATGEN_ParseReply(s, str,
635 						"+SPBR: @i, @p, @p, @p, @p, @p, @s, @T, @T, @i, @i, @i, @T, @T",
636 						&Memory->Location,
637 						Memory->Entries[0].Text, sizeof(Memory->Entries[0].Text),
638 						Memory->Entries[1].Text, sizeof(Memory->Entries[1].Text),
639 						Memory->Entries[2].Text, sizeof(Memory->Entries[2].Text),
640 						Memory->Entries[3].Text, sizeof(Memory->Entries[3].Text),
641 						Memory->Entries[4].Text, sizeof(Memory->Entries[4].Text),
642 						Memory->Entries[5].Text, sizeof(Memory->Entries[5].Text),
643 						Memory->Entries[6].Text, sizeof(Memory->Entries[6].Text),
644 						Memory->Entries[7].Text, sizeof(Memory->Entries[7].Text),
645 						&year, &month, &day,
646 						Memory->Entries[8].Text, sizeof(Memory->Entries[8].Text),
647 						Memory->Entries[9].Text, sizeof(Memory->Entries[9].Text));
648 		}
649 		if (error != ERR_NONE) {
650 			/*
651 			 * Some phones have different string:
652 			 * +SPBR:1,"5,37217201","0,","0,","0,","0,","14,admrede@inf.ufsc.br","0,","11,Admrede Inf","4,Ufsc","0,","0,",1900,1,1,"0,"
653 			 */
654 			error = ATGEN_ParseReply(s, str,
655 						"+SPBR: @i, @T, @T, @T, @T, @T, @T, @T, @T, @T, @T, @T, @i, @i, @i, @T",
656 						&Memory->Location,
657 						Memory->Entries[0].Text, sizeof(Memory->Entries[0].Text),
658 						Memory->Entries[1].Text, sizeof(Memory->Entries[1].Text),
659 						Memory->Entries[2].Text, sizeof(Memory->Entries[2].Text),
660 						Memory->Entries[3].Text, sizeof(Memory->Entries[3].Text),
661 						Memory->Entries[4].Text, sizeof(Memory->Entries[4].Text),
662 						Memory->Entries[5].Text, sizeof(Memory->Entries[5].Text),
663 						Memory->Entries[6].Text, sizeof(Memory->Entries[6].Text),
664 						Memory->Entries[7].Text, sizeof(Memory->Entries[7].Text),
665 						Memory->Entries[9].Text, sizeof(Memory->Entries[9].Text),
666 						Memory->Entries[10].Text, sizeof(Memory->Entries[10].Text),
667 						Memory->Entries[11].Text, sizeof(Memory->Entries[11].Text),
668 						&year, &month, &day,
669 						Memory->Entries[8].Text, sizeof(Memory->Entries[8].Text));
670 		}
671 		if (error != ERR_NONE) {
672 			return error;
673 		}
674 		/* Remove empty entries */
675 		for (i = 0; i < Memory->EntriesNum; i++) {
676 			if (UnicodeLength(Memory->Entries[i].Text) == 0) {
677 				for (j = i + 1; j < Memory->EntriesNum; j++) {
678 					CopyUnicodeString(Memory->Entries[j - 1].Text, Memory->Entries[j].Text);
679 					Memory->Entries[j - 1].EntryType = Memory->Entries[j].EntryType;
680 					Memory->Entries[j - 1].Location = Memory->Entries[j].Location;
681 				}
682 				Memory->EntriesNum--;
683 			}
684 		}
685 		/* Was there stored birthday? */
686 		if (year > 1900) {
687 			Memory->Entries[Memory->EntriesNum].EntryType = PBK_Date;
688 			Memory->Entries[Memory->EntriesNum].Location = PBK_Location_Unknown;
689 			Memory->Entries[Memory->EntriesNum].Date.Year = year;
690 			Memory->Entries[Memory->EntriesNum].Date.Month = month;
691 			Memory->Entries[Memory->EntriesNum].Date.Day = day;
692 			Memory->Entries[Memory->EntriesNum].Date.Hour = 0;
693 			Memory->Entries[Memory->EntriesNum].Date.Minute = 0;
694 			Memory->Entries[Memory->EntriesNum].Date.Second = 0;
695 			Memory->Entries[Memory->EntriesNum].Date.Timezone = 0;
696 			Memory->EntriesNum++;
697 		}
698 		if (Memory->EntriesNum == 0) {
699 			return ERR_EMPTY;
700 		}
701 		return ERR_NONE;
702 	case AT_Reply_Error:
703                 return ERR_UNKNOWN;
704 	case AT_Reply_CMSError:
705  	        return ATGEN_HandleCMSError(s);
706 	case AT_Reply_CMEError:
707 		/* Empty location */
708 		if (Priv->ErrorCode == 28) {
709 			return ERR_EMPTY;
710 		}
711 	        return ATGEN_HandleCMEError(s);
712 	default:
713 		break;
714 	}
715 	return ERR_UNKNOWNRESPONSE;
716 }
717 
SAMSUNG_SetMemory(GSM_StateMachine * s,GSM_MemoryEntry * entry)718 GSM_Error SAMSUNG_SetMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
719 {
720  	GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
721 
722 	SAMSUNG_CheckCalendar(s);
723 
724 	if (Priv->SamsungCalendar == SAMSUNG_NONE) {
725 		return ERR_NOTSUPPORTED;
726 	} else if (Priv->SamsungCalendar == SAMSUNG_SSH) {
727 		return ERR_NOTIMPLEMENTED;
728 	}
729 
730 	/* FIXME: Here you have to implement conversion of GSM_MemoryEntry to AT command */
731 	smprintf(s, "Setting memory for Samsung not implemented yet!\n");
732 	return ERR_NOTIMPLEMENTED;
733 }
734 
SAMSUNG_ORG_ReplyGetCalendarStatus(GSM_Protocol_Message * msg,GSM_StateMachine * s)735 GSM_Error SAMSUNG_ORG_ReplyGetCalendarStatus(GSM_Protocol_Message *msg, GSM_StateMachine *s)
736 {
737 	GSM_Phone_ATGENData	*Priv = &s->Phone.Data.Priv.ATGEN;
738 	GSM_Error error;
739 	int ignore;
740 
741 	if (Priv->ReplyState != AT_Reply_OK) {
742 		switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
743 		case AT_Reply_Error:
744 			return ERR_NOTSUPPORTED;
745 		case AT_Reply_CMSError:
746 			return ATGEN_HandleCMSError(s);
747 		case AT_Reply_CMEError:
748 			return ATGEN_HandleCMEError(s);
749 		default:
750 			return ERR_UNKNOWNRESPONSE;
751 		}
752 	}
753 
754 	if (strcmp(GetLineString(msg->Buffer, &Priv->Lines, 2), "OK") == 0) {
755 		return ERR_NOTSUPPORTED;
756 	}
757 
758 	error = ATGEN_ParseReply(s,
759 		GetLineString(msg->Buffer, &Priv->Lines, 2),
760 		"+ORGI: @i, @i, @i, @i, @i",
761 		&s->Phone.Data.CalStatus->Used,
762 		&s->Phone.Data.CalStatus->Free,
763 		&ignore,
764 		&ignore,
765 		&ignore);
766 	if (error != ERR_NONE) return error;
767 	s->Phone.Data.CalStatus->Free -= s->Phone.Data.CalStatus->Used;
768 	return ERR_NONE;
769 }
770 
SAMSUNG_SSH_ReplyGetCalendarStatus(GSM_Protocol_Message * msg,GSM_StateMachine * s)771 GSM_Error SAMSUNG_SSH_ReplyGetCalendarStatus(GSM_Protocol_Message *msg, GSM_StateMachine *s)
772 {
773 	GSM_Phone_ATGENData	*Priv = &s->Phone.Data.Priv.ATGEN;
774 	GSM_Error error;
775 	int ignore;
776 
777 	if (Priv->ReplyState != AT_Reply_OK) {
778 		switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
779 		case AT_Reply_Error:
780 			return ERR_NOTSUPPORTED;
781 		case AT_Reply_CMSError:
782 			return ATGEN_HandleCMSError(s);
783 		case AT_Reply_CMEError:
784 			return ATGEN_HandleCMEError(s);
785 		default:
786 			return ERR_UNKNOWNRESPONSE;
787 		}
788 	}
789 
790 	error = ATGEN_ParseReply(s,
791 		GetLineString(msg->Buffer, &Priv->Lines, 2),
792 		"+SSHI: @i, @i, @i",
793 		&s->Phone.Data.CalStatus->Used,
794 		&s->Phone.Data.CalStatus->Free,
795 		&ignore);
796 	if (error != ERR_NONE) return error;
797 	s->Phone.Data.CalStatus->Free -= s->Phone.Data.CalStatus->Used;
798 	return ERR_NONE;
799 }
800 
SAMSUNG_GetCalendarStatus(GSM_StateMachine * s,GSM_CalendarStatus * Status)801 GSM_Error SAMSUNG_GetCalendarStatus(GSM_StateMachine *s, GSM_CalendarStatus *Status)
802 {
803 	GSM_Error error;
804  	GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
805 
806 	s->Phone.Data.CalStatus = Status;
807 
808 	SAMSUNG_CheckCalendar(s);
809 
810 	if (Priv->SamsungCalendar == SAMSUNG_NONE) {
811 		return ERR_NOTSUPPORTED;
812 	} else if (Priv->SamsungCalendar == SAMSUNG_SSH) {
813 		error = ATGEN_WaitForAutoLen(s, "AT+SSHI?\r", 0x00, 10, ID_GetCalendarNotesInfo);
814 		return error;
815 	} else if (Priv->SamsungCalendar == SAMSUNG_ORG) {
816 		error = ATGEN_WaitForAutoLen(s, "AT+ORGI?\r", 0x00, 10, ID_GetCalendarNotesInfo);
817 		return error;
818 	}
819 
820 	return ERR_BUG;
821 }
822 
SAMSUNG_ParseAppointment(GSM_StateMachine * s,const char * line)823 GSM_Error SAMSUNG_ParseAppointment(GSM_StateMachine *s, const char *line)
824 {
825 	GSM_Error error;
826 	int ignore, alarm_flag, alarm_time, alarm_quantity, alarm_repeat;
827 	char ignorestring[10];
828 	GSM_CalendarEntry *Note = s->Phone.Data.Cal;
829 	/*
830 par03: Organizer entry short name
831 par04: Organizer entry detailed description
832 par05: Start day
833 par06: Start month
834 par07: Start year
835 par08: Start hour
836 par09: Start minute
837 par10: End day
838 par11: End month
839 par12: End year
840 par13: End hour
841 par14: End minute
842 par15: Location
843 par16: Alarm flag (0=no, 1=yes)
844 par17: Alarm time unit (1=minutes, 2=hours, days, 4=weeks)
845 par18: Alarm items quantity
846 par19: Alarm repeat flag (0 or empty=no, 2=yes)
847 par20: Empty
848 par21: Empty
849 par22: Repeat until day
850 par23: Repeat until month
851 par24: Repeat until year
852 */
853 	Note->Entries[0].EntryType = CAL_TEXT;
854 	Note->Entries[1].EntryType = CAL_DESCRIPTION;
855 	Note->Entries[2].EntryType = CAL_START_DATETIME;
856 	Note->Entries[2].Date.Timezone = 0;
857 	Note->Entries[2].Date.Second = 0;
858 	Note->Entries[3].EntryType = CAL_END_DATETIME;
859 	Note->Entries[3].Date.Timezone = 0;
860 	Note->Entries[3].Date.Second = 0;
861 	Note->Entries[4].EntryType = CAL_LOCATION;
862 	Note->EntriesNum = 4;
863 	error = ATGEN_ParseReply(s,
864 		line,
865 		"+ORGR: @i, @i, @S, @S, @i, @i, @i, @i, @i, @i, @i, @i, @i, @i, @s, @I, @I, @I, @I, @s, @s, @I, @I, @I",
866 		&ignore,
867 		&ignore,
868 		Note->Entries[0].Text, sizeof(Note->Entries[0].Text),
869 		Note->Entries[1].Text, sizeof(Note->Entries[1].Text),
870 		&(Note->Entries[2].Date.Day),
871 		&(Note->Entries[2].Date.Month),
872 		&(Note->Entries[2].Date.Year),
873 		&(Note->Entries[2].Date.Hour),
874 		&(Note->Entries[2].Date.Minute),
875 		&(Note->Entries[3].Date.Day),
876 		&(Note->Entries[3].Date.Month),
877 		&(Note->Entries[3].Date.Year),
878 		&(Note->Entries[3].Date.Hour),
879 		&(Note->Entries[3].Date.Minute),
880 		Note->Entries[4].Text, sizeof(Note->Entries[4].Text),
881 		&alarm_flag,
882 		&alarm_time,
883 		&alarm_quantity,
884 		&alarm_repeat,
885 		ignorestring, sizeof(ignorestring),
886 		ignorestring, sizeof(ignorestring),
887 		&(Note->Entries[5].Date.Day),
888 		&(Note->Entries[5].Date.Month),
889 		&(Note->Entries[5].Date.Year)
890 		);
891 	if (error != ERR_NONE) return error;
892 	return ERR_NONE;
893 }
894 
SAMSUNG_ParseAniversary(GSM_StateMachine * s,const char * line)895 GSM_Error SAMSUNG_ParseAniversary(GSM_StateMachine *s, const char *line)
896 {
897 	GSM_Error error;
898 	int ignore, alarm_flag, alarm_time, alarm_quantity, alarm_repeat;
899 	char ignorestring[10];
900 	GSM_CalendarEntry *Note = s->Phone.Data.Cal;
901 	/*
902 par03: Empty
903 par04: Ocassion name
904 par05: Alarm day
905 par06: Alarm month
906 par07: Alarm year
907 par08: Alarm hour
908 par09: Alarm minutes
909 par10: Empty
910 par11: Empty
911 par12: Empty
912 par13: Empty
913 par14: Empty
914 par15: Empty
915 par16: Alarm flag (0=no, 1=yes)
916 par17: Alarm time unit (1=minutes, 2=hours, days, 4=weeks)
917 par18: Alarm items quantity
918 par19: Repeat each year (0=no, 4=yes)
919 par20: Empty
920 par21: Empty
921 par22: Empty
922 par23: Empty
923 par24: Empty
924 */
925 	Note->Entries[0].EntryType = CAL_TEXT;
926 	Note->Entries[1].EntryType = CAL_TONE_ALARM_DATETIME;
927 	Note->Entries[1].Date.Timezone = 0;
928 	Note->Entries[1].Date.Second = 0;
929 	Note->EntriesNum = 2;
930 	error = ATGEN_ParseReply(s,
931 		line,
932 		"+ORGR: @i, @i, @S, @S, @i, @i, @i, @i, @i, @s, @s, @s, @s, @s, @s, @i, @i, @i, @i, @0",
933 		&ignore,
934 		&ignore,
935 		ignorestring, sizeof(ignorestring),
936 		Note->Entries[0].Text, sizeof(Note->Entries[0].Text),
937 		&(Note->Entries[1].Date.Day),
938 		&(Note->Entries[1].Date.Month),
939 		&(Note->Entries[1].Date.Year),
940 		&(Note->Entries[1].Date.Hour),
941 		&(Note->Entries[1].Date.Minute),
942 		ignorestring, sizeof(ignorestring),
943 		ignorestring, sizeof(ignorestring),
944 		ignorestring, sizeof(ignorestring),
945 		ignorestring, sizeof(ignorestring),
946 		ignorestring, sizeof(ignorestring),
947 		ignorestring, sizeof(ignorestring),
948 		&alarm_flag,
949 		&alarm_time,
950 		&alarm_quantity,
951 		&alarm_repeat
952 		);
953 	if (error != ERR_NONE) return error;
954 	return ERR_NONE;
955 }
956 
SAMSUNG_ParseTask(GSM_StateMachine * s,const char * line)957 GSM_Error SAMSUNG_ParseTask(GSM_StateMachine *s, const char *line)
958 {
959 	GSM_Error error;
960 	int ignore, alarm_flag, alarm_time, alarm_quantity, priority, status;
961 	char ignorestring[10];
962 	GSM_CalendarEntry *Note = s->Phone.Data.Cal;
963 	/*
964 par03: Empty
965 par04: Task name
966 par05: Start day
967 par06: Start month
968 par07: Start year
969 par08: Alarm hour
970 par09: Alarm minute
971 par10: Due day
972 par11: Due month
973 par12: Due year
974 par13: Empty
975 par14: Empty
976 par15: Empty
977 par16: Alarm flag (0=no, 1=yes)
978 par17: Alarm time unit (1=minutes, 2=hours, days, 4=weeks)
979 par18: Alarm items quantity
980 par19: Empty
981 par20: Task priority (1=high, 2=normal, 3=low)
982 par21: Task status (0=undone, 1=done)
983 par22: Empty
984 par23: Empty
985 par24: Empty
986 */
987 	Note->Entries[0].EntryType = CAL_TEXT;
988 	Note->Entries[1].EntryType = CAL_TONE_ALARM_DATETIME;
989 	Note->Entries[1].Date.Timezone = 0;
990 	Note->Entries[1].Date.Second = 0;
991 	Note->Entries[2].EntryType = CAL_END_DATETIME;
992 	Note->Entries[2].Date.Timezone = 0;
993 	Note->Entries[2].Date.Second = 0;
994 	Note->Entries[2].Date.Hour = 0;
995 	Note->Entries[2].Date.Minute = 0;
996 	Note->EntriesNum = 3;
997 	error = ATGEN_ParseReply(s,
998 		line,
999 		"+ORGR: @i, @i, @S, @S, @i, @i, @i, @i, @i, @i, @i, @i, @s, @s, @s, @i, @i, @i, @s, @i, @i, @0",
1000 		&ignore,
1001 		&ignore,
1002 		ignorestring, sizeof(ignorestring),
1003 		Note->Entries[0].Text, sizeof(Note->Entries[0].Text),
1004 		&(Note->Entries[1].Date.Day),
1005 		&(Note->Entries[1].Date.Month),
1006 		&(Note->Entries[1].Date.Year),
1007 		&(Note->Entries[1].Date.Hour),
1008 		&(Note->Entries[1].Date.Minute),
1009 		&(Note->Entries[2].Date.Day),
1010 		&(Note->Entries[2].Date.Month),
1011 		&(Note->Entries[2].Date.Year),
1012 		ignorestring, sizeof(ignorestring),
1013 		ignorestring, sizeof(ignorestring),
1014 		ignorestring, sizeof(ignorestring),
1015 		&alarm_flag,
1016 		&alarm_time,
1017 		&alarm_quantity,
1018 		ignorestring, sizeof(ignorestring),
1019 		&priority,
1020 		&status
1021 		);
1022 	if (error != ERR_NONE) return error;
1023 	return ERR_NONE;
1024 }
1025 
SAMSUNG_ORG_ReplyGetCalendar(GSM_Protocol_Message * msg,GSM_StateMachine * s)1026 GSM_Error SAMSUNG_ORG_ReplyGetCalendar(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1027 {
1028 	GSM_Phone_ATGENData	*Priv = &s->Phone.Data.Priv.ATGEN;
1029 	GSM_Error error;
1030 	int ignore, type;
1031 	const char *line;
1032 
1033 	if (Priv->ReplyState != AT_Reply_OK) {
1034 		switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
1035 		case AT_Reply_Error:
1036 			return ERR_NOTSUPPORTED;
1037 		case AT_Reply_CMSError:
1038 			return ATGEN_HandleCMSError(s);
1039 		case AT_Reply_CMEError:
1040 			return ATGEN_HandleCMEError(s);
1041 		default:
1042 			return ERR_UNKNOWNRESPONSE;
1043 		}
1044 	}
1045 
1046 	line = GetLineString(msg->Buffer, &Priv->Lines, 2);
1047 
1048 	if (strcmp("OK", line) == 0) {
1049 		return ERR_EMPTY;
1050 	}
1051 
1052 	error = ATGEN_ParseReply(s,
1053 		line,
1054 		"+ORGR: @i, @i, @0",
1055 		&ignore,
1056 		&type);
1057 	if (error != ERR_NONE) return error;
1058 
1059 	switch (type) {
1060 		case 1:
1061 			s->Phone.Data.Cal->Type = GSM_CAL_MEETING;
1062 			return SAMSUNG_ParseAppointment(s, line);
1063 		case 2:
1064 			s->Phone.Data.Cal->Type = GSM_CAL_BIRTHDAY;
1065 			return SAMSUNG_ParseAniversary(s, line);
1066 		case 3:
1067 			/* TODO: This should be rather turned into todo entry */
1068 			s->Phone.Data.Cal->Type = GSM_CAL_REMINDER;
1069 			return SAMSUNG_ParseTask(s, line);
1070 		case 4:
1071 			s->Phone.Data.Cal->Type = GSM_CAL_MEMO;
1072 			return SAMSUNG_ParseAppointment(s, line);
1073 		default:
1074 			smprintf(s, "WARNING: Unknown entry type %d, treating as memo!\n", type);
1075 			s->Phone.Data.Cal->Type = GSM_CAL_MEMO;
1076 			return SAMSUNG_ParseAppointment(s, line);
1077 	}
1078 }
1079 
SAMSUNG_SSH_ReplyGetCalendar(GSM_Protocol_Message * msg,GSM_StateMachine * s)1080 GSM_Error SAMSUNG_SSH_ReplyGetCalendar(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1081 {
1082 	return ERR_NOTIMPLEMENTED;
1083 }
1084 
SAMSUNG_GetNextCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Note,gboolean start)1085 GSM_Error SAMSUNG_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note, gboolean start)
1086 {
1087 	GSM_Error error;
1088  	GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1089 
1090 	SAMSUNG_CheckCalendar(s);
1091 
1092 	if (Priv->SamsungCalendar == SAMSUNG_NONE) {
1093 		return ERR_NOTSUPPORTED;
1094 	}
1095 
1096 	if (start) {
1097 		/* One below actual first position */
1098 		Note->Location = 0;
1099 		error = SAMSUNG_GetCalendarStatus(s, &Priv->CalendarStatus);
1100 		if (error != ERR_NONE) {
1101 			return error;
1102 		}
1103 		Priv->CalendarRead = 0;
1104 	}
1105 	s->Phone.Data.Cal 	= Note;
1106 	Note->EntriesNum 	= 0;
1107 	smprintf(s, "Getting calendar entry\n");
1108 	error = ERR_EMPTY;
1109 	while (error == ERR_EMPTY) {
1110 		Note->Location++;
1111 		if (Note->Location >= Priv->CalendarStatus.Used + Priv->CalendarStatus.Free) {
1112 			/* We're at the end */
1113 			return ERR_EMPTY;
1114 		}
1115 		if (Priv->CalendarRead >= Priv->CalendarStatus.Used) {
1116 			/* We've read all entries */
1117 			return ERR_EMPTY;
1118 		}
1119 		error = SAMSUNG_GetCalendar(s, Note);
1120 		if (error == ERR_NONE) {
1121 			Priv->CalendarRead++;
1122 		}
1123 	}
1124 	return error;
1125 }
1126 
SAMSUNG_GetCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Note)1127 GSM_Error SAMSUNG_GetCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
1128 {
1129 	char req[50];
1130 	GSM_Error error;
1131 	size_t len;
1132  	GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1133 
1134 	s->Phone.Data.Cal = Note;
1135 
1136 	SAMSUNG_CheckCalendar(s);
1137 
1138 	if (Priv->SamsungCalendar == SAMSUNG_NONE) {
1139 		return ERR_NOTSUPPORTED;
1140 	} else if (Priv->SamsungCalendar == SAMSUNG_ORG) {
1141 		len = sprintf(req, "AT+ORGR=%d\r", Note->Location - 1);
1142 	} else if (Priv->SamsungCalendar == SAMSUNG_SSH) {
1143 		len = sprintf(req, "AT+SSHR=%d\r", Note->Location);
1144 	} else {
1145 		return ERR_BUG;
1146 	}
1147 
1148 	error = ATGEN_WaitFor(s, req, len, 0x00, 10, ID_GetCalendarNote);
1149 	return error;
1150 }
1151 
SAMSUNG_ORG_ReplySetCalendar(GSM_Protocol_Message * msg,GSM_StateMachine * s)1152 GSM_Error SAMSUNG_ORG_ReplySetCalendar(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1153 {
1154 	return ERR_NOTIMPLEMENTED;
1155 }
1156 
SAMSUNG_DelCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Note)1157 GSM_Error SAMSUNG_DelCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
1158 {
1159 	char req[50];
1160 	GSM_Error error;
1161 	size_t len;
1162  	GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1163 
1164 	SAMSUNG_CheckCalendar(s);
1165 
1166 	if (Priv->SamsungCalendar == SAMSUNG_NONE) {
1167 		return ERR_NOTSUPPORTED;
1168 	} else if (Priv->SamsungCalendar == SAMSUNG_ORG) {
1169 		len = sprintf(req, "AT+ORGD=%d\r", Note->Location - 1);
1170 	} else if (Priv->SamsungCalendar == SAMSUNG_SSH) {
1171 		len = sprintf(req, "AT+SSHD=%d\r", Note->Location);
1172 	} else {
1173 		return ERR_BUG;
1174 	}
1175 
1176 	error = ATGEN_WaitFor(s, req, len, 0x00, 10, ID_DeleteCalendarNote);
1177 	return error;
1178 }
1179 
SAMSUNG_SetCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Note)1180 GSM_Error SAMSUNG_SetCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
1181 {
1182  	GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1183 
1184 	SAMSUNG_CheckCalendar(s);
1185 
1186 	if (Priv->SamsungCalendar == SAMSUNG_NONE) {
1187 		return ERR_NOTSUPPORTED;
1188 	} else if (Priv->SamsungCalendar == SAMSUNG_ORG) {
1189 		return ERR_NOTIMPLEMENTED;
1190 	} else {
1191 		return ERR_NOTIMPLEMENTED;
1192 	}
1193 }
1194 
SAMSUNG_AddCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Note)1195 GSM_Error SAMSUNG_AddCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
1196 {
1197  	GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
1198 
1199 	SAMSUNG_CheckCalendar(s);
1200 
1201 	if (Priv->SamsungCalendar == SAMSUNG_NONE) {
1202 		return ERR_NOTSUPPORTED;
1203 	} else if (Priv->SamsungCalendar == SAMSUNG_ORG) {
1204 		return ERR_NOTIMPLEMENTED;
1205 	} else {
1206 		return ERR_NOTIMPLEMENTED;
1207 	}
1208 }
1209 #endif
1210 
1211 /* How should editor hadle tabs in this file? Add editor commands here.
1212  * vim: noexpandtab sw=8 ts=8 sts=8:
1213  */
1214