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