1 /* (c) 2002-2005 by Marcin Wiacek and Michal Cihar */
2
3 #include <gammu-config.h>
4
5 #include <string.h>
6 #include <stdlib.h>
7 #include <sys/stat.h>
8 #include <sys/socket.h>
9
10 #include <gammu-keys.h>
11 #include <gammu-debug.h>
12
13 #include "../misc/coding/coding.h"
14 #include "../debug.h"
15 #include "gsmmisc.h"
16
17 #include "../../libgammu/misc/string.h"
18
19 struct keys_table_position {
20 char whatchar;
21 int whatcode;
22 };
23
24 static struct keys_table_position Keys[] = {
25 {'m',GSM_KEY_MENU}, {'M',GSM_KEY_MENU},
26 {'n',GSM_KEY_NAMES}, {'N',GSM_KEY_NAMES},
27 {'p',GSM_KEY_POWER}, {'P',GSM_KEY_POWER},
28 {'u',GSM_KEY_UP}, {'U',GSM_KEY_UP},
29 {'d',GSM_KEY_DOWN}, {'D',GSM_KEY_DOWN},
30 {'+',GSM_KEY_INCREASEVOLUME}, {'-',GSM_KEY_DECREASEVOLUME},
31 {'1',GSM_KEY_1}, {'2',GSM_KEY_2}, {'3',GSM_KEY_3},
32 {'4',GSM_KEY_4}, {'5',GSM_KEY_5}, {'6',GSM_KEY_6},
33 {'7',GSM_KEY_7}, {'8',GSM_KEY_8}, {'9',GSM_KEY_9},
34 {'*',GSM_KEY_ASTERISK}, {'0',GSM_KEY_0}, {'#',GSM_KEY_HASH},
35 {'g',GSM_KEY_GREEN}, {'G',GSM_KEY_GREEN},
36 {'r',GSM_KEY_RED}, {'R',GSM_KEY_RED},
37 {'<',GSM_KEY_LEFT}, {'>',GSM_KEY_RIGHT},
38 {'[',GSM_KEY_SOFT1}, {']',GSM_KEY_SOFT2},
39 {'h',GSM_KEY_HEADSET}, {'H',GSM_KEY_HEADSET},
40 {'c',GSM_KEY_CLEAR}, {'C',GSM_KEY_CLEAR},
41 {'j',GSM_KEY_JOYSTICK}, {'J',GSM_KEY_JOYSTICK},
42 {'f',GSM_KEY_CAMERA}, {'F',GSM_KEY_CAMERA},
43 {'o',GSM_KEY_OPERATOR}, {'O',GSM_KEY_OPERATOR},
44 {'m',GSM_KEY_MEDIA}, {'M',GSM_KEY_MEDIA},
45 {'d',GSM_KEY_DESKTOP}, {'D',GSM_KEY_DESKTOP},
46 {'@',GSM_KEY_RETURN},
47 {' ',0}
48 };
49
MakeKeySequence(char * text,GSM_KeyCode * KeyCode,size_t * Length)50 GSM_Error MakeKeySequence(char *text, GSM_KeyCode *KeyCode, size_t *Length)
51 {
52 int i,j;
53 char key;
54
55 for (i=0;i<(int)(strlen(text));i++) {
56 key = text[i];
57 KeyCode[i] = GSM_KEY_NONE;
58 j = 0;
59 while (Keys[j].whatchar!=' ') {
60 if (Keys[j].whatchar==key) {
61 KeyCode[i]=Keys[j].whatcode;
62 break;
63 }
64 j++;
65 }
66 if (KeyCode[i] == GSM_KEY_NONE) {
67 *Length = i;
68 return ERR_NOTSUPPORTED;
69 }
70 }
71 *Length = i;
72 return ERR_NONE;
73 }
74
GSM_ReadFile(const char * FileName,GSM_File * File)75 GSM_Error GSM_ReadFile(const char *FileName, GSM_File *File)
76 {
77 int i = 1000;
78 FILE *file;
79 struct stat fileinfo;
80
81 if (FileName[0] == 0x00) return ERR_UNKNOWN;
82 file = fopen(FileName,"rb");
83 if (file == NULL) return ERR_CANTOPENFILE;
84
85 free(File->Buffer);
86 File->Buffer = NULL;
87 File->Used = 0;
88 while (i == 1000) {
89 File->Buffer = (unsigned char *)realloc(File->Buffer,File->Used + 1000);
90 i = fread(File->Buffer+File->Used,1,1000,file);
91 File->Used = File->Used + i;
92 }
93 File->Buffer = (unsigned char *)realloc(File->Buffer,File->Used + 1);
94 /* Make it 0 terminated, in case it is needed somewhere (we don't count this to length) */
95 File->Buffer[File->Used] = 0;
96 fclose(file);
97
98 File->Level = 0;
99 GSM_IdentifyFileFormat(File);
100 File->Protected = FALSE;
101 File->Hidden = FALSE;
102 File->System = FALSE;
103 File->ReadOnly = FALSE; /* @todo TODO get this from permissions? */
104 File->Folder = FALSE;
105
106 File->ModifiedEmpty = TRUE;
107 if (stat(FileName,&fileinfo) == 0) {
108 File->ModifiedEmpty = FALSE;
109 dbgprintf(NULL, "File info read correctly\n");
110 /* st_mtime is time of last modification of file */
111 Fill_GSM_DateTime(&File->Modified, fileinfo.st_mtime);
112 dbgprintf(NULL, "FillTime: %s\n", OSDate(File->Modified));
113 }
114
115 return ERR_NONE;
116 }
117
GSM_JADFindLine(GSM_File * File,const char * Name,char * Value)118 static void GSM_JADFindLine(GSM_File *File, const char *Name, char *Value)
119 {
120 unsigned char Line[2000];
121 size_t Pos = 0;
122
123 Value[0] = 0;
124
125 while (1) {
126 if (MyGetLine(File->Buffer, &Pos, Line, File->Used, sizeof(Line), FALSE) != ERR_NONE) break;
127 if (strlen(Line) == 0) break;
128 if (!strncmp(Line,Name,strlen(Name))) {
129 Pos = strlen(Name);
130 while (Line[Pos] == 0x20) Pos++;
131 strcpy(Value,Line+Pos);
132 return;
133 }
134 }
135 }
136
GSM_JADFindData(GSM_File * File,char * Vendor,char * Name,char * JAR,char * Version,int * Size)137 GSM_Error GSM_JADFindData(GSM_File *File, char *Vendor, char *Name, char *JAR, char *Version, int *Size)
138 {
139 char Size2[200];
140
141 GSM_JADFindLine(File, "MIDlet-Vendor:", Vendor);
142 if (Vendor[0] == 0x00) return ERR_FILENOTSUPPORTED;
143 dbgprintf(NULL, "Vendor: \"%s\"\n",Vendor);
144
145 GSM_JADFindLine(File, "MIDlet-Name:", Name);
146 if (Name[0] == 0x00) return ERR_FILENOTSUPPORTED;
147 dbgprintf(NULL, "Name: \"%s\"\n",Name);
148
149 GSM_JADFindLine(File, "MIDlet-Jar-URL:", JAR);
150 if (JAR[0] == 0x00) return ERR_FILENOTSUPPORTED;
151 dbgprintf(NULL, "JAR file URL: \"%s\"\n",JAR);
152
153 GSM_JADFindLine(File, "MIDlet-Jar-Size:", Size2);
154 *Size = -1;
155 if (Size2[0] == 0x00) return ERR_FILENOTSUPPORTED;
156 dbgprintf(NULL, "JAR size: \"%s\"\n",Size2);
157 (*Size) = atoi(Size2);
158
159 GSM_JADFindLine(File, "MIDlet-Version:", Version);
160 dbgprintf(NULL, "Version: \"%s\"\n",Version);
161
162 return ERR_NONE;
163 }
164
GSM_IdentifyFileFormat(GSM_File * File)165 void GSM_IdentifyFileFormat(GSM_File *File)
166 {
167 File->Type = GSM_File_Other;
168 if (File->Used > 2) {
169 if (memcmp(File->Buffer, "BM",2)==0) {
170 File->Type = GSM_File_Image_BMP;
171 } else if (memcmp(File->Buffer, "GIF",3)==0) {
172 File->Type = GSM_File_Image_GIF;
173 } else if (File->Buffer[0] == 0x00 && File->Buffer[1] == 0x00) {
174 File->Type = GSM_File_Image_WBMP;
175 } else if (memcmp(File->Buffer+1, "PNG",3)==0) {
176 File->Type = GSM_File_Image_PNG;
177 } else if (File->Buffer[0] == 0xFF && File->Buffer[1] == 0xD8) {
178 File->Type = GSM_File_Image_JPG;
179 } else if (memcmp(File->Buffer, "MThd",4)==0) {
180 File->Type = GSM_File_Sound_MIDI;
181 } else if (File->Buffer[0] == 0x00 && File->Buffer[1] == 0x02) {
182 File->Type = GSM_File_Sound_NRT;
183 }
184 }
185 }
186
187 PRINTF_STYLE(4, 5)
VC_StoreLine(char * Buffer,const size_t buff_len,size_t * Pos,const char * format,...)188 GSM_Error VC_StoreLine(char *Buffer, const size_t buff_len, size_t *Pos, const char *format, ...)
189 {
190 va_list argp;
191 int result;
192
193 va_start(argp, format);
194 result = vsnprintf(Buffer + (*Pos), buff_len - *Pos - 1, format, argp);
195 va_end(argp);
196
197 *Pos += result;
198 if (*Pos >= buff_len - 1) return ERR_MOREMEMORY;
199
200 result = snprintf(Buffer + (*Pos), buff_len - *Pos - 1, "%c%c", 13, 10);
201
202 *Pos += result;
203 if (*Pos >= buff_len - 1) return ERR_MOREMEMORY;
204
205 return ERR_NONE;
206 }
207
208 PRINTF_STYLE(4, 5)
VC_Store(char * Buffer,const size_t buff_len,size_t * Pos,const char * format,...)209 GSM_Error VC_Store(char *Buffer, const size_t buff_len, size_t *Pos, const char *format, ...)
210 {
211 va_list argp;
212 int result;
213
214 va_start(argp, format);
215 result = vsnprintf(Buffer + (*Pos), buff_len - *Pos - 1, format, argp);
216 va_end(argp);
217
218 *Pos += result;
219 if (*Pos >= buff_len - 1) return ERR_MOREMEMORY;
220
221 return ERR_NONE;
222 }
223
224
VC_StoreDateTime(char * Buffer,const size_t buff_len,size_t * Pos,const GSM_DateTime * Date,const char * Start)225 GSM_Error VC_StoreDateTime(char *Buffer, const size_t buff_len, size_t *Pos, const GSM_DateTime *Date, const char *Start)
226 {
227 GSM_Error error;
228
229 if (Start != NULL) {
230 error = VC_Store(Buffer, buff_len, Pos, "%s:", Start);
231 if (error != ERR_NONE) return error;
232 }
233 error = VC_StoreLine(Buffer, buff_len, Pos,
234 "%04d%02d%02dT%02d%02d%02d%s",
235 Date->Year, Date->Month, Date->Day,
236 Date->Hour, Date->Minute, Date->Second,
237 Date->Timezone == 0 ? "Z" : "");
238 return error;
239 }
240
VC_StoreDate(char * Buffer,const size_t buff_len,size_t * Pos,const GSM_DateTime * Date,const char * Start)241 GSM_Error VC_StoreDate(char *Buffer, const size_t buff_len, size_t *Pos, const GSM_DateTime *Date, const char *Start)
242 {
243 GSM_Error error;
244
245 if (Start != NULL) {
246 error = VC_Store(Buffer, buff_len, Pos, "%s:", Start);
247 if (error != ERR_NONE) return error;
248 }
249 error = VC_StoreLine(Buffer, buff_len, Pos,
250 "%04d%02d%02d",
251 Date->Year, Date->Month, Date->Day);
252 return error;
253 }
254
ReadVCALDateTime(const char * Buffer,GSM_DateTime * dt)255 gboolean ReadVCALDateTime(const char *Buffer, GSM_DateTime *dt)
256 {
257 time_t timestamp;
258 char year[5]="", month[3]="", day[3]="", hour[3]="", minute[3]="", second[3]="";
259
260 memset(dt,0,sizeof(GSM_DateTime));
261
262 /* YYYY-MM-DD is invalid, though used */
263 if (sscanf(Buffer, "%d-%d-%d", &dt->Year, &dt->Month, &dt->Day) == 3) {
264 goto checkdt;
265 }
266
267 if (strlen(Buffer) < 8) {
268 return FALSE;
269 }
270
271 strncpy(year, Buffer, 4);
272 strncpy(month, Buffer+4, 2);
273 strncpy(day, Buffer+6, 2);
274 dt->Year = atoi(year);
275 dt->Month = atoi(month);
276 dt->Day = atoi(day);
277
278 if (Buffer[8] == 'T') {
279 if (strlen(Buffer + 9) < 6) return FALSE;
280
281 strncpy(hour, Buffer+9, 2);
282 strncpy(minute, Buffer+11, 2);
283 strncpy(second, Buffer+13, 2);
284 dt->Hour = atoi(hour);
285 dt->Minute = atoi(minute);
286 dt->Second = atoi(second);
287
288 /**
289 * @todo Handle properly timezone information
290 */
291 if (Buffer[15] == 'Z') dt->Timezone = 0; /* Z = ZULU = GMT */
292 }
293 checkdt:
294
295 if (!CheckTime(dt)) {
296 dbgprintf(NULL, "incorrect date %d-%d-%d %d:%d:%d\n",dt->Day,dt->Month,dt->Year,dt->Hour,dt->Minute,dt->Second);
297 return FALSE;
298 }
299 if (dt->Year!=0) {
300 if (!CheckDate(dt)) {
301 dbgprintf(NULL, "incorrect date %d-%d-%d %d:%d:%d\n",dt->Day,dt->Month,dt->Year,dt->Hour,dt->Minute,dt->Second);
302 return FALSE;
303 }
304 }
305
306 if (dt->Timezone != 0) {
307 timestamp = Fill_Time_T(*dt) + dt->Timezone;
308 Fill_GSM_DateTime(dt, timestamp);
309 }
310
311 return TRUE;
312 }
313
ReadVCALInt(char * Buffer,const char * Start,int * Value)314 gboolean ReadVCALInt(char *Buffer, const char *Start, int *Value)
315 {
316 unsigned char buff[200];
317
318 *Value = 0;
319
320 strcpy(buff,Start);
321 strcat(buff,":");
322 if (!strncmp(Buffer,buff,strlen(buff))) {
323 int lstart = strlen(Start);
324 int lvalue = strlen(Buffer)-(lstart+1);
325 strncpy(buff,Buffer+lstart+1,lvalue);
326 strncpy(buff+lvalue,"\0",1);
327 if (sscanf(buff,"%i",Value)) {
328 dbgprintf(NULL, "ReadVCalInt is \"%i\"\n",*Value);
329 return TRUE;
330 }
331 }
332 return FALSE;
333 }
334
335
ReadVCALDate(char * Buffer,const char * Start,GSM_DateTime * Date,gboolean * is_date_only)336 gboolean ReadVCALDate(char *Buffer, const char *Start, GSM_DateTime *Date, gboolean *is_date_only)
337 {
338 char fullstart[200];
339 unsigned char datestring[200];
340
341 if (!ReadVCALText(Buffer, Start, datestring, FALSE, NULL)) {
342 fullstart[0] = 0;
343 strcat(fullstart, Start);
344 strcat(fullstart, ";VALUE=DATE");
345 if (ReadVCALText(Buffer, fullstart, datestring, FALSE, NULL)) {
346 *is_date_only = TRUE;
347 } else {
348 fullstart[0] = 0;
349 strcat(fullstart, Start);
350 strcat(fullstart, ";VALUE=DATE-TIME");
351 if (! ReadVCALText(Buffer, fullstart, datestring, FALSE, NULL)) {
352 return FALSE;
353 }
354 }
355 }
356
357 if (ReadVCALDateTime(DecodeUnicodeString(datestring), Date)) {
358 dbgprintf(NULL, "ReadVCALDateTime is %s\n", OSDate(*Date));
359 *is_date_only = FALSE;
360 return TRUE;
361 }
362
363 return FALSE;
364 }
365
366
VC_StoreText(char * Buffer,const size_t buff_len,size_t * Pos,const unsigned char * Text,const char * Start,const gboolean UTF8)367 GSM_Error VC_StoreText(char *Buffer, const size_t buff_len, size_t *Pos, const unsigned char *Text, const char *Start, const gboolean UTF8)
368 {
369 char *buffer=NULL;
370 size_t len=0;
371 GSM_Error error;
372
373 len = UnicodeLength(Text);
374
375 if (len == 0) return ERR_NONE;
376
377 /* Need to be big enough to store quoted printable */
378 buffer = (char *)malloc(len * 8);
379 if (buffer == NULL) return ERR_MOREMEMORY;
380
381 if (UTF8) {
382 EncodeUTF8QuotedPrintable(buffer, Text);
383 error = VC_StoreLine(Buffer, buff_len, Pos, "%s:%s", Start, buffer);
384 } else {
385 EncodeUTF8QuotedPrintable(buffer, Text);
386 if (UnicodeLength(Text) == strlen(buffer)) {
387 /* Text is plain ASCII */
388 error = VC_StoreLine(Buffer, buff_len, Pos, "%s:%s", Start, buffer);
389 } else {
390 error = VC_StoreLine(Buffer, buff_len, Pos, "%s;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:%s", Start, buffer);
391 }
392 }
393
394 free(buffer);
395 buffer=NULL;
396 return error;
397 }
398
VC_StoreBase64(char * Buffer,const size_t buff_len,size_t * Pos,const unsigned char * data,const size_t length)399 GSM_Error VC_StoreBase64(char *Buffer, const size_t buff_len, size_t *Pos, const unsigned char *data, const size_t length)
400 {
401 char *buffer=NULL, *pos=NULL, linebuffer[80]={0};
402 size_t len=0, current=0;
403 char spacer[2]={0};
404 GSM_Error error;
405
406 /*
407 * Need to be big enough to store base64 (what is *4/3, but *2 is safer
408 * and we don't have to care about rounding and padding).
409 */
410 buffer = (char *)malloc(length * 2);
411 if (buffer == NULL) return ERR_MOREMEMORY;
412
413 spacer[0] = 0;
414 spacer[1] = 0;
415
416
417 EncodeBASE64(data, buffer, length);
418
419 len = strlen(buffer);
420 pos = buffer;
421
422 /* Write at most 76 chars per line */
423 while (len > 0) {
424 current = MIN(len, 76);
425 strncpy(linebuffer, pos, current);
426 linebuffer[current] = 0;
427 error = VC_StoreLine(Buffer, buff_len, Pos, "%s%s", spacer, linebuffer);
428 if (error != ERR_NONE) {
429 free(buffer);
430 buffer=NULL;
431 return error;
432 }
433 spacer[0] = ' ';
434 len -= current;
435 pos += current;
436 }
437
438 free(buffer);
439 buffer=NULL;
440 return ERR_NONE;
441 }
442
VCALGetTextPart(unsigned char * Buff,int * pos)443 unsigned char *VCALGetTextPart(unsigned char *Buff, int *pos)
444 {
445 static unsigned char tmp[1000];
446 unsigned char *start;
447
448 start = Buff + *pos;
449 while (Buff[*pos] != 0 || Buff[*pos + 1] != 0) {
450 if (Buff[*pos] == 0 && Buff[*pos + 1] == ';') {
451 Buff[*pos + 1] = 0;
452 CopyUnicodeString(tmp, start);
453 Buff[*pos + 1] = ';';
454 *pos += 2;
455 return tmp;
456 }
457 *pos += 2;
458 }
459 if (start == Buff || (start[0] == 0 && start[1] == 0)) return NULL;
460 CopyUnicodeString(tmp, start);
461 return tmp;
462 }
463
464 /**
465 * We separate matching text (Start) to tokens and then try to find all
466 * tokens in Buffer. We also accept tokens like PREF, CHARSET or ENCODING.
467 *
468 * Also it parses TYPE=* tokens, matching it to text types passed in Start
469 * parameter. For example Start "TEL;FAX;VOICE" matches "TEL;TYPE=FAX,VOICE"
470 * or "TEL;FAX;TYPE=VOICE" or "TEL;TYPE=FAX;TYPE=VOICE" and of course
471 * "TEL;FAX;VOICE".
472 *
473 * When all tokens are matched we found matching line.
474 */
ReadVCALText(char * Buffer,const char * Start,unsigned char * Value,const gboolean UTF8,GSM_EntryLocation * location)475 gboolean ReadVCALText(char *Buffer, const char *Start, unsigned char *Value, const gboolean UTF8, GSM_EntryLocation *location)
476 {
477 char *line = NULL;
478 char **tokens = NULL;
479 char *charset = NULL;
480 char *begin, *pos, *end, *end2;
481 gboolean quoted_printable = FALSE;
482 size_t numtokens, token;
483 size_t i, j, len;
484 gboolean found;
485 gboolean ret = FALSE;
486
487 /* Initialize output */
488 Value[0] = 0x00;
489 Value[1] = 0x00;
490
491 /* Count number of tokens */
492 len = strlen(Start);
493 numtokens = 1;
494 for (i = 0; i < len; i++) {
495 if (Start[i] == ';') {
496 numtokens++;
497 }
498 }
499
500 /* Allocate memory */
501 line = strdup(Start);
502 if (line == NULL) {
503 dbgprintf(NULL, "Could not alloc!\n");
504 goto fail;
505 }
506 tokens = (char **)malloc(sizeof(char *) * numtokens);
507 if (tokens == NULL) {
508 dbgprintf(NULL, "Could not alloc!\n");
509 goto fail;
510 }
511
512 /* Parse Start to vCard tokens (separated by ;) */
513 token = 0;
514 begin = line;
515 for (i = 0; i < len; i++) {
516 if (line[i] == ';') {
517 tokens[token++] = begin;
518 begin = line + i + 1;
519 line[i] = 0;
520 }
521 }
522 /* Store last token */
523 tokens[token] = begin;
524
525 /* Compare first token, it must be in place */
526 pos = Buffer;
527 len = strlen(tokens[0]);
528 if (strncasecmp(pos, tokens[0], len) != 0) {
529 goto fail;
530 }
531 /* Advance position */
532 pos += len;
533 /* No need to check this token anymore */
534 tokens[0][0] = 0;
535 /* Initialize location */
536 if (location != NULL) {
537 *location = PBK_Location_Unknown;
538 }
539
540 /* Check remaining tokens */
541 while (*pos != ':') {
542 if (*pos == ';') {
543 pos++;
544 } else {
545 dbgprintf(NULL, "Could not parse! (stopped at string: %s)\n", pos);
546 goto fail;
547 }
548 found = FALSE;
549 for (token = 0; token < numtokens; token++) {
550 len = strlen(tokens[token]);
551 /* Skip already matched tokens */
552 if (len == 0) {
553 continue;
554 }
555 if (strncasecmp(pos, tokens[token], len) == 0) {
556 dbgprintf(NULL, "Found %s\n", tokens[token]);
557 /* Advance position */
558 pos += len;
559 /* We need to check one token less */
560 tokens[token][0] = 0;
561 found = TRUE;
562 break;
563 }
564 }
565 if (!found) {
566 if (strncasecmp(pos, "ENCODING=QUOTED-PRINTABLE", 25) == 0) {
567 quoted_printable = TRUE;
568 /* Advance position */
569 pos += 25;
570 found = TRUE;
571 } else if (strncasecmp(pos, "CHARSET=", 8) == 0) {
572 /* Advance position */
573 pos += 8;
574 /* Grab charset */
575 end = strchr(pos, ':');
576 end2 = strchr(pos, ';');
577 if (end == NULL && end2 == NULL) {
578 dbgprintf(NULL, "Could not read charset!\n");
579 goto fail;
580 } else if (end == NULL) {
581 end = end2;
582 } else if (end2 != NULL && end2 < end) {
583 end = end2;
584 }
585 /* We basically want strndup, but it is not portable */
586 charset = strdup(pos);
587 if (charset == NULL) {
588 dbgprintf(NULL, "Could not alloc!\n");
589 goto fail;
590 }
591 charset[end - pos] = 0;
592
593 pos = end;
594 found = TRUE;
595 } else if (strncasecmp(pos, "TZID=", 5) == 0) {
596 /* @todo: We ignore time zone for now */
597 /* Advance position */
598 pos += 5;
599 /* Go behind value */
600 end = strchr(pos, ':');
601 end2 = strchr(pos, ';');
602 if (end == NULL && end2 == NULL) {
603 dbgprintf(NULL, "Could not read timezone!\n");
604 goto fail;
605 } else if (end == NULL) {
606 end = end2;
607 } else if (end2 != NULL && end2 < end) {
608 end = end2;
609 }
610 pos = end;
611 found = TRUE;
612 } else if (strncasecmp(pos, "TYPE=", 5) == 0) {
613 /* We ignore TYPE= prefix */
614 pos += 5;
615
616 /* Now process types, which should be comma separated */
617 while (*pos != ':' && *pos != ';') {
618 found = FALSE;
619
620 /* Go through tokens to match */
621 for (token = 0; token < numtokens; token++) {
622 len = strlen(tokens[token]);
623 /* Skip already matched tokens */
624 if (len == 0) {
625 continue;
626 }
627 if (strncasecmp(pos, tokens[token], len) == 0) {
628 dbgprintf(NULL, "Found %s\n", tokens[token]);
629 /* Advance position */
630 pos += len;
631 /* We need to check one token less */
632 tokens[token][0] = 0;
633 found = TRUE;
634 break;
635 }
636 }
637
638 if (!found) {
639 if (strncasecmp(pos, "PREF", 4) == 0) {
640 /* We ignore pref token */
641 pos += 4;
642 found = TRUE;
643 } else if (strncasecmp(pos, "WORK", 4) == 0) {
644 /* We ignore work token */
645 pos += 4;
646 found = TRUE;
647 if (location != NULL) {
648 *location = PBK_Location_Work;
649 }
650 } else if (strncasecmp(pos, "HOME", 4) == 0) {
651 /* We ignore home token */
652 pos += 4;
653 found = TRUE;
654 if (location != NULL) {
655 *location = PBK_Location_Home;
656 }
657 } else {
658 dbgprintf(NULL, "%s not found! (%s)\n", Start, pos);
659 goto fail;
660 }
661 }
662
663 if (*pos == ';' || *pos == ':') {
664 dbgprintf(NULL, "End of TYPE= string\n");
665 break;
666 } else if (*pos == ',') {
667 /* Advance past separator */
668 pos++;
669 } else {
670 dbgprintf(NULL, "Could not parse TYPE=! (stopped at string: %s)\n", pos);
671 goto fail;
672 }
673
674 }
675 } else if (strncasecmp(pos, "PREF", 4) == 0) {
676 /* We ignore pref token */
677 pos += 4;
678 found = TRUE;
679 } else if (location && strncasecmp(pos, "WORK", 4) == 0) {
680 /* We ignore pref token */
681 pos += 4;
682 found = TRUE;
683 *location = PBK_Location_Work;
684 } else if (location && strncasecmp(pos, "HOME", 4) == 0) {
685 /* We ignore pref token */
686 pos += 4;
687 found = TRUE;
688 *location = PBK_Location_Home;
689 }
690 if (!found) {
691 dbgprintf(NULL, "%s not found!\n", Start);
692 goto fail;
693 }
694 }
695 }
696 /* Skip : */
697 pos++;
698 /* Length of rest */
699 len = strlen(pos);
700
701 /* Did we match all our tokens? */
702 for (token = 0; token < numtokens; token++) {
703 if (strlen(tokens[token]) > 0) {
704 dbgprintf(NULL, "All tokens did not match!\n");
705 goto fail;
706 }
707 }
708
709 /* Decode the text */
710 if (charset == NULL) {
711 if (quoted_printable) {
712 if (UTF8) {
713 DecodeUTF8QuotedPrintable(Value, pos, len);
714 } else {
715 DecodeISO88591QuotedPrintable(Value, pos, len);
716 }
717 } else {
718 if (UTF8) {
719 DecodeUTF8(Value, pos, len);
720 } else {
721 DecodeISO88591(Value, pos, len);
722 }
723 }
724 } else {
725 if (strcasecmp(charset, "UTF-8") == 0||
726 strcasecmp(charset, "\"UTF-8\"") == 0
727 ) {
728 if (quoted_printable) {
729 DecodeUTF8QuotedPrintable(Value, pos, len);
730 } else {
731 DecodeUTF8(Value, pos, len);
732 }
733 } else if (strcasecmp(charset, "UTF-7") == 0||
734 strcasecmp(charset, "\"UTF-7\"") == 0
735 ) {
736 if (quoted_printable) {
737 dbgprintf(NULL, "Unsupported charset: %s\n", charset);
738 goto fail;
739 } else {
740 DecodeUTF7(Value, pos, len);
741 }
742 } else {
743 dbgprintf(NULL, "Unsupported charset: %s\n", charset);
744 goto fail;
745 }
746 }
747
748 /* Postprocess escaped chars */
749 len = UnicodeLength(Value);
750 for (i = 0; i < len; i++) {
751 if (Value[(2 * i)] == 0 && Value[(2 * i) + 1] == '\\') {
752 j = i + 1;
753 if (Value[(2 * j)] == 0 && (
754 Value[(2 * j) + 1] == 'n' ||
755 Value[(2 * j) + 1] == 'N')
756 ) {
757 Value[(2 * i) + 1] = '\n';
758 } else if (Value[(2 * j)] == 0 && (
759 Value[(2 * j) + 1] == 'r' ||
760 Value[(2 * j) + 1] == 'R')
761 ) {
762 Value[(2 * i) + 1] = '\r';
763 } else if (Value[(2 * j)] == 0 && Value[(2 * j) + 1] == '\\') {
764 Value[(2 * i) + 1] = '\\';
765 } else if (Value[(2 * j)] == 0 && Value[(2 * j) + 1] == ';') {
766 Value[(2 * i) + 1] = ';';
767 } else if (Value[(2 * j)] == 0 && Value[(2 * j) + 1] == ',') {
768 Value[(2 * i) + 1] = ',';
769 } else {
770 /* We ignore unknown for now */
771 continue;
772 }
773 /* Shift the string */
774 memmove(Value + (2 * j), Value + (2 * j) + 2, 2 * (len + 1 - j));
775 len--;
776 }
777 }
778
779 ret = TRUE;
780 dbgprintf(NULL, "ReadVCalText(%s) is \"%s\"\n", Start, DecodeUnicodeConsole(Value));
781 fail:
782 free(line);
783 line=NULL;
784 free(tokens);
785 tokens=NULL;
786 free(charset);
787 charset=NULL;
788 return ret;
789 }
790
GSM_ClearBatteryCharge(GSM_BatteryCharge * bat)791 void GSM_ClearBatteryCharge(GSM_BatteryCharge *bat)
792 {
793 bat->BatteryPercent = -1;
794 bat->ChargeState = 0;
795 bat->BatteryType = 0;
796 bat->BatteryVoltage = -1;
797 bat->ChargeVoltage = -1;
798 bat->ChargeCurrent = -1;
799 bat->PhoneCurrent = -1;
800 bat->BatteryTemperature = -1;
801 bat->PhoneTemperature = -1;
802 bat->BatteryCapacity = -1;
803 }
804
805 /* How should editor hadle tabs in this file? Add editor commands here.
806 * vim: noexpandtab sw=8 ts=8 sts=8:
807 */
808