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