1 /* (c) 2002-2005 by Marcin Wiacek and Michal Cihar */
2 /* Checking used compiler (c) 2002 by Michal Cihar */
3 
4 #include <gammu-config.h>
5 #include <gammu-misc.h>
6 
7 #include "misc.h"
8 
9 #include "coding/coding.h"
10 #include "../debug.h"
11 
12 #include <string.h>
13 #include <time.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <ctype.h>
17 #ifdef WIN32
18 #  define WIN32_LEAN_AND_MEAN
19 #  include <windows.h>
20 #  include <locale.h>
21 #  define gmtime_r(x, y) gmtime_s(y, x)
22 #  define localtime_r(x, y) localtime_s(y, x)
23 #endif
24 #ifdef HAVE_SYS_UTSNAME_H
25 #  include <sys/utsname.h>
26 #endif
27 #ifdef __CYGWIN__
28 #include <cygwin/version.h>
29 #endif
30 
31 #ifdef WIN32
setenv(const char * name,const char * value,int overwrite)32 int setenv(const char *name, const char *value, int overwrite)
33 {
34   char env_var[_MAX_ENV];
35   char* has_value = getenv(name);
36   if(!has_value || overwrite) {
37     snprintf(env_var, _MAX_ENV, "%s=%s", name, value);
38     return _putenv(env_var);
39   }
40   return -1;
41 }
42 
unsetenv(const char * name)43 void unsetenv(const char *name)
44 {
45   _putenv(name);
46 }
47 #endif // WIN32
48 
49 /**
50  * Recalculates struct tm content. We can not use mktime directly, as it
51  * works only for dates > 1970. Day of week calculation is nased on article
52  * in Polish PC-Kurier 8/1998 page 104.
53  *
54  * @see http://www.pckurier.pl
55  */
RecalcDateTime(struct tm * st,const int year,const int month,const int day,const int hour,const int minute,const int second)56 int RecalcDateTime(struct tm *st, const int year, const int month, const int day, const int hour, const int minute, const int second)
57 {
58 	const int days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
59 	int i, p, q, r;
60 	GSM_DateTime Date;
61 
62 	Date.Year	= year;
63 	Date.Month	= month;
64 	Date.Day	= day;
65 	Date.Hour	= hour;
66 	Date.Minute	= minute;
67 	Date.Second	= second;
68 	Date.Timezone	= 0;
69 
70 	if (!CheckDate(&Date) || !CheckTime(&Date)) return 0;
71 
72 	memset(st, 0, sizeof(*st));
73 
74 	/* Calculate day of year */
75 	st->tm_yday = day;
76 	for (i = 0; i < month - 1; i++)
77 		st->tm_yday += days[i];
78 
79 	/* Calculate day of week */
80 	p = (14 - month) / 12;
81 	q = month + 12 * p - 2;
82 	r = year - p;
83 	st->tm_wday = (day + (31 * q) / 12 + r + r / 4 - r / 100 + r / 400) % 7;
84 
85 
86 	st->tm_hour = hour;
87 	st->tm_min = minute;
88 	st->tm_sec = second;
89 	st->tm_year = year - 1900;
90 	st->tm_mon = month - 1;
91 	st->tm_mday = day;
92 
93 	st->tm_isdst = -1; /* FIXME */
94 
95 	return 1;
96 }
97 
98 
99 /**
100  * Recalculates struct tm content.
101  */
RecalcDate(struct tm * st,const int year,const int month,const int day)102 int RecalcDate(struct tm *st, const int year, const int month, const int day)
103 {
104 	return RecalcDateTime(st, year, month, day, 0, 0, 0);
105 }
106 
107 
108 /**
109  * Return day of year index.
110  */
GetDayOfYear(unsigned int year,unsigned int month,unsigned int day)111 int GetDayOfYear(unsigned int year, unsigned int month, unsigned int day)
112 {
113 	struct tm st;
114 
115 	RecalcDate(&st, year, month, day);
116 
117 	return st.tm_yday;
118 }
119 
120 /**
121  * Return day of week index.
122  */
GetWeekOfMonth(unsigned int year,unsigned int month,unsigned int day)123 int GetWeekOfMonth(unsigned int year, unsigned int month, unsigned int day)
124 {
125 	struct tm st;
126 
127 	RecalcDate(&st, year, month, day);
128 
129 	return 1 + (day - st.tm_wday) / 7;
130 }
131 
132 /**
133  * Return day of week index.
134  */
GetDayOfWeek(unsigned int year,unsigned int month,unsigned int day)135 int GetDayOfWeek(unsigned int year, unsigned int month, unsigned int day)
136 {
137 	struct tm st;
138 
139 	RecalcDate(&st, year, month, day);
140 
141 	return st.tm_wday;
142 }
143 
144 /**
145  * Return textual representation of day of week;
146  */
DayOfWeek(unsigned int year,unsigned int month,unsigned int day)147 char *DayOfWeek (unsigned int year, unsigned int month, unsigned int day)
148 {
149 	static char 	DayOfWeekChar[10];
150 
151 	strcpy(DayOfWeekChar,"");
152 	switch (GetDayOfWeek(year, month, day)) {
153 		case 0: strcpy(DayOfWeekChar,"Sun"); break;
154 		case 1: strcpy(DayOfWeekChar,"Mon"); break;
155 		case 2: strcpy(DayOfWeekChar,"Tue"); break;
156 		case 3: strcpy(DayOfWeekChar,"Wed"); break;
157 		case 4: strcpy(DayOfWeekChar,"Thu"); break;
158 		case 5: strcpy(DayOfWeekChar,"Fri"); break;
159 		case 6: strcpy(DayOfWeekChar,"Sat"); break;
160 	}
161 	return DayOfWeekChar;
162 }
163 
get_local_timezone_offset(time_t posix_time)164 int get_local_timezone_offset(time_t posix_time)
165 {
166   struct tm *tm = gmtime(&posix_time);
167   tm->tm_isdst = -1;
168   return posix_time - mktime(tm);
169 }
170 
GSM_GetLocalTimezoneOffset()171 int GSM_GetLocalTimezoneOffset()
172 {
173   return get_local_timezone_offset(time(NULL));
174 }
175 
GSM_DateTimeToTimestamp(GSM_DateTime * Date,char * str)176 void GSM_DateTimeToTimestamp(GSM_DateTime *Date, char *str)
177 {
178 	time_t timet;
179 	timet = Fill_Time_T(*Date);
180 	sprintf(str, "%ld", (long)timet);
181 }
182 
GSM_DateTimeFromTimestamp(GSM_DateTime * Date,const char * str)183 void GSM_DateTimeFromTimestamp(GSM_DateTime *Date, const char *str)
184 {
185 	time_t timet;
186 
187 	timet = atof(str);
188 	Fill_GSM_DateTime(Date, timet);
189 }
190 
Fill_GSM_DateTime(GSM_DateTime * Date,time_t timet)191 void Fill_GSM_DateTime(GSM_DateTime *Date, time_t timet)
192 {
193 	struct tm *now;
194 
195 	now  		= localtime(&timet);
196 	Date->Year	= now->tm_year + 1900;
197 	Date->Month	= now->tm_mon + 1;
198 	Date->Day	= now->tm_mday;
199 	Date->Hour	= now->tm_hour;
200 	Date->Minute	= now->tm_min;
201 	Date->Second	= now->tm_sec;
202 	Date->Timezone	= GSM_GetLocalTimezoneOffset();
203 }
204 
GSM_GetCurrentDateTime(GSM_DateTime * Date)205 void GSM_GetCurrentDateTime (GSM_DateTime *Date)
206 {
207 	Fill_GSM_DateTime(Date, time(NULL));
208 }
209 
210 /*
211  * Convert GSM_DateTime to POSIX time.
212  *
213  * A GSM timestamp consists of a date and time given in UTC and
214  * an originating local time offset. If the time and date part
215  * of the GSM_DateTime argument is not in UTC the returned
216  * calculated POSIX calendar time will not be valid.
217  */
Fill_Time_T(GSM_DateTime DT)218 time_t Fill_Time_T(GSM_DateTime DT)
219 {
220   char *tz;
221 	struct tm tm;
222 	time_t posix_time;
223 
224 	dbgprintf(NULL, "StartTime: %s\n", OSDate(DT));
225 
226 	memset(&tm, 0, sizeof(tm));
227 	tm.tm_year 	= DT.Year - 1900;
228 	tm.tm_mon  	= DT.Month - 1;
229 	tm.tm_mday 	= DT.Day;
230 	tm.tm_hour 	= DT.Hour;
231 	tm.tm_min  	= DT.Minute;
232 	tm.tm_sec  	= DT.Second;
233 	tm.tm_isdst = 0;
234 
235 	tz = getenv("TZ");
236 	if(tz) {
237     tz = strdup(tz);
238     if(!tz)
239       return -1;
240   }
241 
242 	putenv((char*)"TZ=GMT+00");
243 	tzset();
244 
245 	posix_time = mktime(&tm);
246 	if(posix_time != -1)
247     posix_time += DT.Timezone > 0 ? -DT.Timezone : abs(DT.Timezone);
248 
249 	if(tz) {
250     setenv("TZ", tz, 1);
251     free(tz);
252   }
253 	else {
254 	  unsetenv("TZ");
255 	}
256 	tzset();
257 
258 	return posix_time;
259 }
260 
GSM_AddTime(GSM_DateTime DT,GSM_DeltaTime delta)261 GSM_DateTime GSM_AddTime (GSM_DateTime DT , GSM_DeltaTime delta)
262 {
263 	struct tm tm_time;
264 	time_t t_time;
265 	GSM_DateTime Date;
266 
267 	memset(&tm_time, 0, sizeof(tm_time));
268 	tm_time.tm_year 	= DT.Year - 1900;
269 	tm_time.tm_mon  	= DT.Month - 1;
270 	tm_time.tm_mday 	= DT.Day;
271 	tm_time.tm_hour 	= DT.Hour;
272 	tm_time.tm_min  	= DT.Minute;
273 	tm_time.tm_sec  	= DT.Second;
274 	tm_time.tm_isdst	= -1;
275 
276 	/* TODO: This works only for dates after 1970. But birthday dates may be before, so a more general
277 	   method than mktime /localtime should be used. */
278 	t_time = mktime (&tm_time);
279 	t_time = t_time + delta.Second + 60* (delta.Minute + 60* (delta.Hour + 24*delta.Day));
280 
281 	Fill_GSM_DateTime ( &Date, t_time);
282 	return Date;
283 }
284 
GetTimeDifference(unsigned long diff,GSM_DateTime * DT,gboolean Plus,int multi)285 void GetTimeDifference(unsigned long diff, GSM_DateTime *DT, gboolean Plus, int multi)
286 {
287 	time_t t_time;
288 
289 	t_time = Fill_Time_T(*DT);
290 
291 	if (Plus) {
292 		t_time 		+= diff*multi;
293 	} else {
294 		t_time 		-= diff*multi;
295 	}
296 
297 	Fill_GSM_DateTime(DT, t_time);
298 	dbgprintf(NULL, "EndTime: %02i-%02i-%04i %02i:%02i:%02i\n",
299 		DT->Day,DT->Month,DT->Year,DT->Hour,DT->Minute,DT->Second);
300 }
301 
OSDateTime(GSM_DateTime dt,gboolean TimeZone)302 char *OSDateTime (GSM_DateTime dt, gboolean TimeZone)
303 {
304 	struct tm 	timeptr;
305 	static char 	retval[200],retval2[200];
306 
307 	if (!RecalcDateTime(&timeptr, dt.Year, dt.Month, dt.Day,
308 				dt.Hour, dt.Minute, dt.Second)) {
309 		retval2[0] = '\0';
310 		return retval2;
311 	}
312 
313 #ifdef WIN32
314 	setlocale(LC_ALL, ".OCP");
315 #endif
316 
317 	/* This is not Y2K safe */
318 	strftime(retval2, 200, "%c", &timeptr);
319 	if (TimeZone) {
320 		snprintf(retval, sizeof(retval) - 1, " %+03i%02i",
321 			dt.Timezone / 3600, abs((dt.Timezone % 3600) / 60));
322 		strcat(retval2,retval);
323 	}
324 	/* If don't have weekday name, include it */
325 	strftime(retval, 200, "%A", &timeptr);
326 	if (strstr(retval2,retval)==NULL) {
327 		/* Check for abbreviated weekday */
328 		strftime(retval, 200, "%a", &timeptr);
329 		if (strstr(retval2,retval)==NULL) {
330 			strcat(retval2," (");
331 			strcat(retval2,retval);
332 			strcat(retval2,")");
333 		}
334 	}
335 
336 #ifdef WIN32
337 	setlocale(LC_ALL, ".ACP");
338 #endif
339 
340 	return retval2;
341 }
342 
OSDate(GSM_DateTime dt)343 char *OSDate (GSM_DateTime dt)
344 {
345 	struct tm 	timeptr;
346 	static char 	retval[200],retval2[200];
347 
348 #ifdef WIN32
349 	setlocale(LC_ALL, ".OCP");
350 #endif
351 
352 	timeptr.tm_yday 	= 0; 			/* FIXME */
353 	timeptr.tm_isdst 	= -1; 			/* FIXME */
354 	timeptr.tm_year 	= dt.Year - 1900;
355 	timeptr.tm_mon  	= dt.Month - 1;
356 	timeptr.tm_mday 	= dt.Day;
357 	timeptr.tm_hour 	= dt.Hour;
358 	timeptr.tm_min  	= dt.Minute;
359 	timeptr.tm_sec  	= dt.Second;
360 	timeptr.tm_wday 	= GetDayOfWeek(dt.Year, dt.Month, dt.Day);
361 #ifdef HAVE_STRUCT_TM_TM_ZONE
362 	timeptr.tm_zone		= NULL;
363 #endif
364 
365 	/* This is not Y2K safe */
366 	strftime(retval2, 200, "%x", &timeptr);
367 
368 	/* If don't have weekday name, include it */
369 	strftime(retval, 200, "%A", &timeptr);
370 	if (strstr(retval2,retval)==NULL) {
371 		/* Check also for short name */
372 		strftime(retval, 200, "%a", &timeptr);
373 		if (strstr(retval2,retval)==NULL) {
374             		strcat(retval2," (");
375             		strcat(retval2,retval);
376             		strcat(retval2,")");
377             	}
378 	}
379 
380 #ifdef WIN32
381 	setlocale(LC_ALL, ".ACP");
382 #endif
383 
384 	return retval2;
385 }
386 
CheckDate(GSM_DateTime * date)387 gboolean CheckDate(GSM_DateTime *date)
388 {
389 	const int days[]={31,28,31,30,31,30,31,31,30,31,30,31};
390 
391 	if (date->Year != 0 &&
392 	    ((date->Year % 4 == 0 && date->Year % 100 != 0) || date->Year % 400 == 0) &&
393 	    date->Month == 2) {
394 		return (date->Day <= 29);
395 	}
396 	return date->Year != 0 &&
397 	       date->Month >= 1 && date->Month <= 12 &&
398 	       date->Day >= 1 && date->Day <= days[date->Month-1];
399 }
400 
CheckTime(GSM_DateTime * date)401 gboolean CheckTime(GSM_DateTime *date)
402 {
403 	return date->Hour <= 23 &&
404 		date->Minute <= 59 &&
405 		date->Second <= 59;
406 }
407 
GetLine(FILE * File,char * Line,int count)408 size_t GetLine(FILE *File, char *Line, int count)
409 {
410 	int num;
411 
412 	if (fgets(Line, count, File) != NULL) {
413 		num = strlen(Line) - 1;
414 		while (num > 0) {
415 			if (Line[num] != '\n' && Line[num] != '\r') break;
416 			Line[num--] = '\0';
417 		}
418 		return strlen(Line);
419 	}
420 	return -1;
421 }
422 
InitLines(GSM_CutLines * lines)423 void InitLines(GSM_CutLines *lines)
424 {
425 	lines->numbers = NULL;
426 	lines->allocated = 0;
427 	lines->retval = NULL;
428 }
429 
FreeLines(GSM_CutLines * lines)430 void FreeLines(GSM_CutLines *lines)
431 {
432 	free(lines->numbers);
433 	lines->numbers = NULL;
434 	lines->allocated = 0;
435 	free(lines->retval);
436 	lines->retval = NULL;
437 }
438 
SplitLines(const char * message,const size_t messagesize,GSM_CutLines * lines,const char * whitespaces,const size_t spaceslen,const char * quotes,const size_t quoteslen,const gboolean eot)439 void SplitLines(const char *message, const size_t messagesize, GSM_CutLines *lines,
440 	const char *whitespaces, const size_t spaceslen,
441 	const char *quotes, const size_t quoteslen,
442 	const gboolean eot)
443 {
444 	size_t 	 i=0,number=0,j=0, lastquote = 0;
445 	gboolean whitespace = TRUE, nowwhite = FALSE, insidequotes = FALSE;
446 
447 	/* Clean current lines */
448 	for (i = 0; i < lines->allocated; i++) {
449 		lines->numbers[i] = 0;
450 	}
451 
452 	/* Go through message */
453 	for (i = 0; i < messagesize; i++) {
454 		/* Reallocate buffer if needed */
455 		if (number + 2 >= lines->allocated) {
456 			lines->allocated += 20;
457 			lines->numbers = (size_t *)realloc(lines->numbers, lines->allocated * sizeof(size_t));
458 			if (lines->numbers == NULL) {
459 				return;
460 			}
461 			for (j = lines->allocated - 20; j < lines->allocated; j++) {
462 				lines->numbers[j] = 0;
463 			}
464 		}
465 
466 		nowwhite = FALSE;
467 
468 		/* Check for quotes */
469 		for (j = 0; j < quoteslen; j++) {
470 			if (quotes[j] == message[i]) {
471 				insidequotes = !(insidequotes);
472 				lastquote = i;
473 				break;
474 			}
475 		}
476 
477 		/* Find matching quote */
478 		if (insidequotes) {
479 			continue;
480 		}
481 
482 rollback_quote:
483 		/* Check for whitespace */
484 		for (j = 0; j < spaceslen; j++) {
485 			if (whitespaces[j] == message[i]) {
486 				nowwhite = TRUE;
487 				break;
488 			}
489 		}
490 
491 		/* Split line if there is change from whitespace to non whitespace */
492 		if (whitespace) {
493 			if (!nowwhite) {
494 				lines->numbers[number] = i;
495 				number++;
496 				whitespace = FALSE;
497 			}
498 		} else {
499 			if (nowwhite) {
500 				lines->numbers[number] = i;
501 				number++;
502 				whitespace = TRUE;
503 			}
504 
505 		}
506 	}
507 
508 	/* Check for unterminated quotes and roll back to ignore them */
509 	if (number % 2 == 1 && insidequotes) {
510 		insidequotes = FALSE;
511 		i = lastquote;
512 		goto rollback_quote;
513 	}
514 
515 	/* Store possible end if there was not just whitespace */
516     	if (eot && !whitespace) {
517 		lines->numbers[number] = messagesize;
518 	}
519 }
520 
GetLineStringPos(const char * message,const GSM_CutLines * lines,int start)521 const char *GetLineStringPos(const char *message, const GSM_CutLines *lines, int start)
522 {
523 	if (message == NULL) {
524 		return NULL;
525 	}
526 
527 	return message + lines->numbers[start * 2 - 2];
528 }
529 
GetLineString(const char * message,GSM_CutLines * lines,int start)530 const char *GetLineString(const char *message, GSM_CutLines *lines, int start)
531 {
532 	int len=0;
533 	const char *pos;
534 
535 	pos = GetLineStringPos(message, lines, start);
536 	if (pos == NULL) {
537 		return NULL;
538 	}
539 
540 	len = GetLineLength(message, lines, start);
541 
542 	lines->retval = (char *)realloc(lines->retval, len + 1);
543 	if (lines->retval == NULL) {
544 		dbgprintf(NULL, "Allocation failed!\n");
545 		return NULL;
546 	}
547 
548 	memcpy(lines->retval, pos, len);
549 
550 	lines->retval[len] = '\0';
551 
552 	return lines->retval;
553 }
554 
GetLineLength(const char * message UNUSED,const GSM_CutLines * lines,int start)555 int GetLineLength(const char *message UNUSED, const GSM_CutLines *lines, int start)
556 {
557 	return lines->numbers[start*2-2+1] - lines->numbers[start*2-2];
558 }
559 
CopyLineString(char * dest,const char * src,const GSM_CutLines * lines,int start)560 void CopyLineString(char *dest, const char *src, const GSM_CutLines *lines, int start)
561 {
562 	int len;
563 	const char *pos;
564 
565 	len = GetLineLength(src, lines, start);
566 	pos = GetLineStringPos(src, lines, start);
567 	if (pos == NULL) {
568 		dest[0] = '\0';
569 		return;
570 	}
571 	memcpy(dest, pos, len);
572 	dest[len] = '\0';
573 }
574 
GetOS(void)575 const char *GetOS(void)
576 {
577 #ifdef WIN32
578 	OSVERSIONINFOEX Ver;
579 	gboolean		Extended = TRUE;
580 #else
581 #  ifdef HAVE_SYS_UTSNAME_H
582 	struct utsname	Ver;
583 #  endif
584 #endif
585 	static char 	Buffer[240] = {0x00};
586 
587 	/* Value was already calculated */
588 	if (Buffer[0] != 0) return Buffer;
589 
590 #ifdef WIN32
591 	memset(&Ver,0,sizeof(OSVERSIONINFOEX));
592 	Ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
593 
594    	if (!GetVersionEx((OSVERSIONINFO *)&Ver)) {
595 		Extended 		= FALSE;
596 	      	Ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
597 	        if (!GetVersionEx((OSVERSIONINFO *)&Ver)) {
598 			snprintf(Buffer, sizeof(Buffer) - 1, "Windows");
599 			return Buffer;
600 		}
601 	}
602 
603 	/* ----------------- 9x family ------------------ */
604 
605 	/* no info about Win95 SP1, Win95 OSR2.1, Win95 OSR2.5.... */
606 	if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 0 && Ver.dwBuildNumber == 950) {
607 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows 95");
608 	} else if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 0 && Ver.dwBuildNumber == 1111) {
609 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows 95 OSR2.x");
610 
611 	/* no info about Win98 SP1.... */
612 	} else if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 10 && Ver.dwBuildNumber == 1998) {
613 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows 98");
614 	} else if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 10 && Ver.dwBuildNumber == 2222) {
615 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows 98 SE");
616 
617 	} else if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 90 && Ver.dwBuildNumber == 3000) {
618 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows ME");
619 
620 	/* ---------------- NT family ------------------- */
621 
622 	} else if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 0 && Ver.dwBuildNumber == 1381) {
623 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows NT 4.0");
624 
625 	} else if (Ver.dwMajorVersion == 5 && Ver.dwMinorVersion == 0 && Ver.dwBuildNumber == 2195) {
626 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows 2000");
627 
628 	} else if (Ver.dwMajorVersion == 5 && Ver.dwMinorVersion == 1 && Ver.dwBuildNumber == 2600) {
629 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows XP");
630 #if _MSC_VER > 1200 /* 6.0 has it undeclared */
631 		if (Extended) {
632 			if (Ver.wSuiteMask & VER_SUITE_PERSONAL) {
633 				snprintf(Buffer+strlen(Buffer), sizeof(Buffer) - 1 - strlen(Buffer)," Home");
634 			} else {
635 				snprintf(Buffer+strlen(Buffer), sizeof(Buffer) - 1 - strlen(Buffer)," Pro");
636 			}
637 		}
638 #endif
639 
640 	} else if (Ver.dwMajorVersion == 5 && Ver.dwMinorVersion == 2) {
641 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows 2003");
642 
643 	} else if (Ver.dwMajorVersion == 6 && Ver.dwMinorVersion == 0) {
644 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows Vista");
645 
646 	} else if (Ver.dwMajorVersion == 6 && Ver.dwMinorVersion > 0) {
647 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows Server 2007");
648 
649 	} else {
650 		snprintf(Buffer, sizeof(Buffer) - 1, "Windows %i.%i.%i",(int)Ver.dwMajorVersion,(int)Ver.dwMinorVersion,(int)Ver.dwBuildNumber);
651 	}
652 
653 	if (Extended && Ver.wServicePackMajor != 0) {
654 		snprintf(Buffer+strlen(Buffer), sizeof(Buffer) - 1 - strlen(Buffer)," SP%i",Ver.wServicePackMajor);
655 	}
656 #elif defined(HAVE_SYS_UTSNAME_H)
657 	uname(&Ver);
658 	snprintf(Buffer, sizeof(Buffer) - 1, "%s, kernel %s (%s)", Ver.sysname, Ver.release, Ver.version);
659 #elif defined(__FreeBSD__)
660 	snprintf(Buffer, sizeof(Buffer) - 1, "FreeBSD");
661 #elif defined(__NetBSD__)
662 	snprintf(Buffer, sizeof(Buffer) - 1, "NetBSD");
663 #elif defined(__OpenBSD__)
664 	snprintf(Buffer, sizeof(Buffer) - 1, "OpenBSD");
665 #elif defined(__GNU__)
666 	snprintf(Buffer, sizeof(Buffer) - 1, "GNU/Hurd");
667 #elif defined(sun) || defined(__sun) || defined(__sun__)
668 #  ifdef __SVR4
669 	snprintf(Buffer, sizeof(Buffer) - 1, "Sun Solaris");
670 #  else
671 	snprintf(Buffer, sizeof(Buffer) - 1, "SunOS");
672 #  endif
673 #elif defined(hpux) || defined(__hpux) || defined(__hpux__)
674 	snprintf(Buffer, sizeof(Buffer) - 1, "HP-UX");
675 #elif defined(ultrix) || defined(__ultrix) || defined(__ultrix__)
676 	snprintf(Buffer, sizeof(Buffer) - 1, "DEC Ultrix");
677 #elif defined(sgi) || defined(__sgi)
678 	snprintf(Buffer, sizeof(Buffer) - 1, "SGI Irix");
679 #elif defined(__osf__)
680 	snprintf(Buffer, sizeof(Buffer) - 1, "OSF Unix");
681 #elif defined(bsdi) || defined(__bsdi__)
682 	snprintf(Buffer, sizeof(Buffer) - 1, "BSDI Unix");
683 #elif defined(_AIX)
684 	snprintf(Buffer, sizeof(Buffer) - 1, "AIX Unix");
685 #elif defined(_UNIXWARE)
686 	snprintf(Buffer, sizeof(Buffer) - 1, "SCO Unixware");
687 #elif defined(DGUX)
688 	snprintf(Buffer, sizeof(Buffer) - 1, "DG Unix");
689 #elif defined(__QNX__)
690 	snprintf(Buffer, sizeof(Buffer) - 1, "QNX");
691 #else
692 	snprintf(Buffer, sizeof(Buffer) - 1, "unknown OS");
693 #endif
694 	return Buffer;
695 }
696 
GetCompiler(void)697 const char *GetCompiler(void)
698 {
699 	static char Buffer[100] = {0x00};
700 
701 	/* Value was already calculated */
702 	if (Buffer[0] != 0) return Buffer;
703 
704 #ifdef _MSC_VER
705 	if (_MSC_VER == 1200) { /* ? */
706 		snprintf(Buffer, sizeof(Buffer) - 1, "MS VC 6.0");
707 	} else if (_MSC_VER == 1300) {
708 		snprintf(Buffer, sizeof(Buffer) - 1, "MS VC .NET 2002");
709 	} else if (_MSC_VER == 1310) {
710 		snprintf(Buffer, sizeof(Buffer) - 1, "MS VC .NET 2003");
711 	} else if (_MSC_VER == 1400) {
712 		snprintf(Buffer, sizeof(Buffer) - 1, "MS VC .NET 2005");
713 	} else {
714 		snprintf(Buffer, sizeof(Buffer) - 1, "MS VC %i",_MSC_VER);
715 	}
716 #elif defined(__BORLANDC__)
717 	snprintf(Buffer, sizeof(Buffer) - 1, "Borland C++ %i",__BORLANDC__);
718 #elif defined(__MINGW32__)
719 	snprintf(Buffer, sizeof(Buffer) - 1, "GCC %i.%i, MinGW %i.%i", __GNUC__, __GNUC_MINOR__, __MINGW32_MAJOR_VERSION, __MINGW32_MINOR_VERSION);
720 #elif defined(__CYGWIN__)
721 	snprintf(Buffer, sizeof(Buffer) - 1, "GCC %i.%i, Cygwin %i.%i", __GNUC__, __GNUC_MINOR__, CYGWIN_VERSION_DLL_MAJOR, CYGWIN_VERSION_DLL_MINOR);
722 #elif defined(__GNUC__)
723 	snprintf(Buffer, sizeof(Buffer) - 1, "GCC %i.%i", __GNUC__, __GNUC_MINOR__);
724 #elif defined(DJGPP)
725 	snprintf(Buffer, sizeof(Buffer) - 1, "djgpp %d.%d", __DJGPP, __DJGPP_MINOR);
726 #elif defined(__SUNPRO_CC)
727 	snprintf(Buffer, sizeof(Buffer) - 1, "Sun C++ %x", __SUNPRO_CC);
728 #elif defined(__INTEL_COMPILER)
729 	snprintf(Buffer, sizeof(Buffer) - 1, "Intel Compiler %ld", __INTEL_COMPILER);
730 #else
731 	snprintf(Buffer, sizeof(Buffer) - 1, "unknown compiler");
732 #endif
733 
734 	return Buffer;
735 }
736 
GSM_IsNewerVersion(const char * latest_version,const char * current_version)737 gboolean GSM_IsNewerVersion(const char *latest_version, const char *current_version)
738 {
739 	size_t i;
740 	size_t len = strlen(latest_version);
741 
742 	for (i = 0; i < len ; i++) {
743 		if (latest_version[i] > current_version[i]) {
744 			return TRUE;
745 		}
746 	}
747 
748 	return FALSE;
749 }
750 
StripSpaces(char * buff)751 void StripSpaces(char *buff)
752 {
753 	ssize_t i = 0;
754 
755 	while(isspace(buff[i])) {
756 		i++;
757 	}
758 	if (i > 0) {
759 		memmove(buff, buff + i, strlen(buff + i));
760 	}
761 	i = strlen(buff) - 1;
762 	while(isspace(buff[i]) && i >= 0) {
763 		buff[i] = 0;
764 		i--;
765 	}
766 
767 }
768 
769 /* How should editor hadle tabs in this file? Add editor commands here.
770  * vim: noexpandtab sw=8 ts=8 sts=8:
771  */
772