[WIN32] cosmetics: removed some XP only code.
[vuplus_xbmc] / xbmc / utils / SystemInfo.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <limits.h>
22
23 #include "threads/SystemClock.h"
24 #include "system.h"
25 #include "SystemInfo.h"
26 #ifndef TARGET_POSIX
27 #include <conio.h>
28 #else
29 #include <sys/utsname.h>
30 #endif
31 #include "GUIInfoManager.h"
32 #include "filesystem/CurlFile.h"
33 #include "network/Network.h"
34 #include "Application.h"
35 #include "windowing/WindowingFactory.h"
36 #include "guilib/LocalizeStrings.h"
37 #include "CPUInfo.h"
38 #include "utils/TimeUtils.h"
39 #include "utils/log.h"
40 #ifdef TARGET_WINDOWS
41 #include "dwmapi.h"
42 #endif
43 #if defined(TARGET_DARWIN)
44 #include "osx/DarwinUtils.h"
45 #include "osx/CocoaInterface.h"
46 #endif
47 #include "powermanagement/PowerManager.h"
48 #include "utils/StringUtils.h"
49 #include "utils/XMLUtils.h"
50
51 /* Target identification */
52 #if defined(TARGET_DARWIN)
53 #include <Availability.h>
54 #elif defined(TARGET_ANDROID)
55 #include <android/api-level.h>
56 #elif defined(TARGET_FREEBSD)
57 #include <sys/param.h>
58 #elif defined(TARGET_LINUX)
59 #include <linux/version.h>
60 #endif
61
62 CSysInfo g_sysinfo;
63
64 CSysInfoJob::CSysInfoJob()
65 {
66 }
67
68 bool CSysInfoJob::DoWork()
69 {
70   m_info.systemUptime      = GetSystemUpTime(false);
71   m_info.systemTotalUptime = GetSystemUpTime(true);
72   m_info.internetState     = GetInternetState();
73   m_info.videoEncoder      = GetVideoEncoder();
74   m_info.cpuFrequency      = GetCPUFreqInfo();
75   m_info.kernelVersion     = CSysInfo::GetKernelVersion();
76   m_info.macAddress        = GetMACAddress();
77   m_info.batteryLevel      = GetBatteryLevel();
78   return true;
79 }
80
81 const CSysData &CSysInfoJob::GetData() const
82 {
83   return m_info;
84 }
85
86 CStdString CSysInfoJob::GetCPUFreqInfo()
87 {
88   CStdString strCPUFreq;
89   double CPUFreq = GetCPUFrequency();
90   strCPUFreq.Format("%4.2fMHz", CPUFreq);
91   return strCPUFreq;
92 }
93
94 CSysData::INTERNET_STATE CSysInfoJob::GetInternetState()
95 {
96   // Internet connection state!
97   XFILE::CCurlFile http;
98   if (http.IsInternet())
99     return CSysData::CONNECTED;
100   if (http.IsInternet(false))
101     return CSysData::NO_DNS;
102   return CSysData::DISCONNECTED;
103 }
104
105 CStdString CSysInfoJob::GetMACAddress()
106 {
107 #if defined(HAS_LINUX_NETWORK) || defined(HAS_WIN32_NETWORK)
108   CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
109   if (iface)
110     return iface->GetMacAddress();
111 #endif
112   return "";
113 }
114
115 CStdString CSysInfoJob::GetVideoEncoder()
116 {
117   return "GPU: " + g_Windowing.GetRenderRenderer();
118 }
119
120 CStdString CSysInfoJob::GetBatteryLevel()
121 {
122   CStdString strVal;
123   strVal.Format("%d%%", g_powerManager.BatteryLevel());
124   return strVal;
125 }
126
127 double CSysInfoJob::GetCPUFrequency()
128 {
129 #if defined (TARGET_POSIX) || defined(TARGET_WINDOWS)
130   return double (g_cpuInfo.getCPUFrequency());
131 #else
132   return 0;
133 #endif
134 }
135
136 bool CSysInfoJob::SystemUpTime(int iInputMinutes, int &iMinutes, int &iHours, int &iDays)
137 {
138   iMinutes=0;iHours=0;iDays=0;
139   iMinutes = iInputMinutes;
140   if (iMinutes >= 60) // Hour's
141   {
142     iHours = iMinutes / 60;
143     iMinutes = iMinutes - (iHours *60);
144   }
145   if (iHours >= 24) // Days
146   {
147     iDays = iHours / 24;
148     iHours = iHours - (iDays * 24);
149   }
150   return true;
151 }
152
153 CStdString CSysInfoJob::GetSystemUpTime(bool bTotalUptime)
154 {
155   CStdString strSystemUptime;
156   int iInputMinutes, iMinutes,iHours,iDays;
157
158   if(bTotalUptime)
159   {
160     //Total Uptime
161     iInputMinutes = g_sysinfo.GetTotalUptime() + ((int)(XbmcThreads::SystemClockMillis() / 60000));
162   }
163   else
164   {
165     //Current UpTime
166     iInputMinutes = (int)(XbmcThreads::SystemClockMillis() / 60000);
167   }
168
169   SystemUpTime(iInputMinutes,iMinutes, iHours, iDays);
170   if (iDays > 0)
171   {
172     strSystemUptime.Format("%i %s, %i %s, %i %s",
173       iDays,g_localizeStrings.Get(12393),
174       iHours,g_localizeStrings.Get(12392),
175       iMinutes, g_localizeStrings.Get(12391));
176   }
177   else if (iDays == 0 && iHours >= 1 )
178   {
179     strSystemUptime.Format("%i %s, %i %s",
180       iHours,g_localizeStrings.Get(12392),
181       iMinutes, g_localizeStrings.Get(12391));
182   }
183   else if (iDays == 0 && iHours == 0 &&  iMinutes >= 0)
184   {
185     strSystemUptime.Format("%i %s",
186       iMinutes, g_localizeStrings.Get(12391));
187   }
188   return strSystemUptime;
189 }
190
191 CStdString CSysInfo::TranslateInfo(int info) const
192 {
193   switch(info)
194   {
195   case SYSTEM_VIDEO_ENCODER_INFO:
196     return m_info.videoEncoder;
197   case NETWORK_MAC_ADDRESS:
198     return m_info.macAddress;
199   case SYSTEM_KERNEL_VERSION:
200     return m_info.kernelVersion;
201   case SYSTEM_CPUFREQUENCY:
202     return m_info.cpuFrequency;
203   case SYSTEM_UPTIME:
204     return m_info.systemUptime;
205   case SYSTEM_TOTALUPTIME:
206     return m_info.systemTotalUptime;
207   case SYSTEM_INTERNET_STATE:
208     if (m_info.internetState == CSysData::CONNECTED)
209       return g_localizeStrings.Get(13296);
210     else if (m_info.internetState == CSysData::NO_DNS)
211       return g_localizeStrings.Get(13274);
212     else
213       return g_localizeStrings.Get(13297);
214   case SYSTEM_BATTERY_LEVEL:
215     return m_info.batteryLevel;
216   default:
217     return "";
218   }
219 }
220
221 void CSysInfo::Reset()
222 {
223   m_info.Reset();
224 }
225
226 CSysInfo::CSysInfo(void) : CInfoLoader(15 * 1000)
227 {
228   memset(MD5_Sign, 0, sizeof(MD5_Sign));
229   m_iSystemTimeTotalUp = 0;
230 }
231
232 CSysInfo::~CSysInfo()
233 {
234 }
235
236 bool CSysInfo::Load(const TiXmlNode *settings)
237 {
238   if (settings == NULL)
239     return false;
240   
241   const TiXmlElement *pElement = settings->FirstChildElement("general");
242   if (pElement)
243     XMLUtils::GetInt(pElement, "systemtotaluptime", m_iSystemTimeTotalUp, 0, INT_MAX);
244
245   return true;
246 }
247
248 bool CSysInfo::Save(TiXmlNode *settings) const
249 {
250   if (settings == NULL)
251     return false;
252
253   TiXmlNode *generalNode = settings->FirstChild("general");
254   if (generalNode == NULL)
255   {
256     TiXmlElement generalNodeNew("general");
257     generalNode = settings->InsertEndChild(generalNodeNew);
258     if (generalNode == NULL)
259       return false;
260   }
261   XMLUtils::SetInt(generalNode, "systemtotaluptime", m_iSystemTimeTotalUp);
262
263   return true;
264 }
265
266 bool CSysInfo::GetDiskSpace(const CStdString drive,int& iTotal, int& iTotalFree, int& iTotalUsed, int& iPercentFree, int& iPercentUsed)
267 {
268   bool bRet= false;
269   ULARGE_INTEGER ULTotal= { { 0 } };
270   ULARGE_INTEGER ULTotalFree= { { 0 } };
271
272   if( !drive.IsEmpty() && !drive.Equals("*") )
273   {
274 #ifdef TARGET_WINDOWS
275     UINT uidriveType = GetDriveType(( drive + ":\\" ));
276     if(uidriveType != DRIVE_UNKNOWN && uidriveType != DRIVE_NO_ROOT_DIR)
277 #endif
278       bRet= ( 0 != GetDiskFreeSpaceEx( ( drive + ":\\" ), NULL, &ULTotal, &ULTotalFree) );
279   }
280   else
281   {
282     ULARGE_INTEGER ULTotalTmp= { { 0 } };
283     ULARGE_INTEGER ULTotalFreeTmp= { { 0 } };
284 #ifdef TARGET_WINDOWS
285     char* pcBuffer= NULL;
286     DWORD dwStrLength= GetLogicalDriveStrings( 0, pcBuffer );
287     if( dwStrLength != 0 )
288     {
289       dwStrLength+= 1;
290       pcBuffer= new char [dwStrLength];
291       GetLogicalDriveStrings( dwStrLength, pcBuffer );
292       int iPos= 0;
293       do {
294         if( DRIVE_FIXED == GetDriveType( pcBuffer + iPos  ) &&
295             GetDiskFreeSpaceEx( ( pcBuffer + iPos ), NULL, &ULTotal, &ULTotalFree ) )
296         {
297           ULTotalTmp.QuadPart+= ULTotal.QuadPart;
298           ULTotalFreeTmp.QuadPart+= ULTotalFree.QuadPart;
299         }
300         iPos += (strlen( pcBuffer + iPos) + 1 );
301       }while( strlen( pcBuffer + iPos ) > 0 );
302     }
303     delete[] pcBuffer;
304 #else // for linux and osx
305     static const char *drv_letter[] = { "C:\\", "E:\\", "F:\\", "G:\\", "X:\\", "Y:\\", "Z:\\", NULL };
306     for( int i = 0; drv_letter[i]; i++)
307     {
308       if( GetDiskFreeSpaceEx( drv_letter[i], NULL, &ULTotal, &ULTotalFree ) )
309       {
310         ULTotalTmp.QuadPart+= ULTotal.QuadPart;
311         ULTotalFreeTmp.QuadPart+= ULTotalFree.QuadPart;
312       }
313     }
314 #endif
315     if( ULTotalTmp.QuadPart || ULTotalFreeTmp.QuadPart )
316     {
317       ULTotal.QuadPart= ULTotalTmp.QuadPart;
318       ULTotalFree.QuadPart= ULTotalFreeTmp.QuadPart;
319       bRet= true;
320     }
321   }
322
323   if( bRet )
324   {
325     iTotal = (int)( ULTotal.QuadPart / MB );
326     iTotalFree = (int)( ULTotalFree.QuadPart / MB );
327     iTotalUsed = iTotal - iTotalFree;
328     if( ULTotal.QuadPart > 0 )
329     {
330       iPercentUsed = (int)( 100.0f * ( ULTotal.QuadPart - ULTotalFree.QuadPart ) / ULTotal.QuadPart + 0.5f );
331     }
332     else
333     {
334       iPercentUsed = 0;
335     }
336     iPercentFree = 100 - iPercentUsed;
337   }
338
339   return bRet;
340 }
341
342 CStdString CSysInfo::GetCPUModel()
343 {
344   return "CPU: " + g_cpuInfo.getCPUModel();
345 }
346
347 CStdString CSysInfo::GetCPUBogoMips()
348 {
349   return "BogoMips: " + g_cpuInfo.getCPUBogoMips();
350 }
351
352 CStdString CSysInfo::GetCPUHardware()
353 {
354   return "Hardware: " + g_cpuInfo.getCPUHardware();
355 }
356
357 CStdString CSysInfo::GetCPURevision()
358 {
359   return "Revision: " + g_cpuInfo.getCPURevision();
360 }
361
362 CStdString CSysInfo::GetCPUSerial()
363 {
364   return "Serial: " + g_cpuInfo.getCPUSerial();
365 }
366
367 bool CSysInfo::IsAeroDisabled()
368 {
369 #ifdef TARGET_WINDOWS
370   BOOL aeroEnabled = FALSE;
371   HRESULT res = DwmIsCompositionEnabled(&aeroEnabled);
372   if (SUCCEEDED(res))
373     return !aeroEnabled;
374 #endif
375   return false;
376 }
377
378 CSysInfo::WindowsVersion CSysInfo::m_WinVer = WindowsVersionUnknown;
379
380 bool CSysInfo::IsWindowsVersion(WindowsVersion ver)
381 {
382   if (ver == WindowsVersionUnknown)
383     return false;
384   return GetWindowsVersion() == ver;
385 }
386
387 bool CSysInfo::IsWindowsVersionAtLeast(WindowsVersion ver)
388 {
389   if (ver == WindowsVersionUnknown)
390     return false;
391   return GetWindowsVersion() >= ver;
392 }
393
394 CSysInfo::WindowsVersion CSysInfo::GetWindowsVersion()
395 {
396 #ifdef TARGET_WINDOWS
397   if (m_WinVer == WindowsVersionUnknown)
398   {
399     OSVERSIONINFOEX osvi;
400     ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
401     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
402     if (GetVersionEx((OSVERSIONINFO *)&osvi))
403     {
404       if (osvi.dwMajorVersion == 5 && (osvi.dwMinorVersion == 1 || osvi.dwMinorVersion == 2 ))
405         m_WinVer = WindowsVersionWinXP;
406       else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
407         m_WinVer = WindowsVersionVista;
408       else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)
409         m_WinVer = WindowsVersionWin7;
410       else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2)
411         m_WinVer = WindowsVersionWin8;
412       /* Insert checks for new Windows versions here */
413       else if ( (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion > 2) || osvi.dwMajorVersion > 6)
414         m_WinVer = WindowsVersionFuture;
415     }
416   }
417 #endif // TARGET_WINDOWS
418   return m_WinVer;
419 }
420
421 bool CSysInfo::IsOS64bit()
422 {
423 #ifdef TARGET_WINDOWS
424   SYSTEM_INFO si;
425   GetSystemInfo(&si);
426   if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
427     return true;
428   
429   BOOL (WINAPI *ptrIsWow64) (HANDLE, PBOOL);
430   HMODULE hKernel32 = GetModuleHandleA("kernel32");
431   if (hKernel32 == NULL)
432     return false; // Can't detect OS
433   ptrIsWow64 = (BOOL (WINAPI *) (HANDLE, PBOOL)) GetProcAddress(hKernel32, "IsWow64Process");
434   BOOL wow64proc = FALSE;
435   if (ptrIsWow64 == NULL || ptrIsWow64(GetCurrentProcess(), &wow64proc) == FALSE)
436     return false; // Can't detect OS
437   return wow64proc != FALSE;
438 #else // TARGET_WINDOWS
439   // TODO: Implement Linux, FreeBSD, Android, OSX
440   return false;
441 #endif // TARGET_WINDOWS
442 }
443
444 CStdString CSysInfo::GetKernelVersion()
445 {
446 #if defined(TARGET_DARWIN)
447   return g_sysinfo.GetUnameVersion();
448 #elif defined (TARGET_POSIX)
449   struct utsname un;
450   if (uname(&un)==0)
451   {
452     CStdString strKernel;
453     strKernel.Format("%s %s %s %s", un.sysname, un.release, un.version, un.machine);
454     return strKernel;
455   }
456
457   return "";
458 #else
459   OSVERSIONINFOEX osvi;
460   ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
461   osvi.dwOSVersionInfoSize = sizeof(osvi);
462
463   std::string strKernel = "Windows";
464   if (GetVersionEx((OSVERSIONINFO *)&osvi))
465   {
466     switch (GetWindowsVersion())
467     {
468     case WindowsVersionWinXP:
469       if (GetSystemMetrics(SM_SERVERR2))
470         strKernel.append(" Server 2003 R2");
471       else if (osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER)
472         strKernel.append(" Storage Server 2003");
473       else if (osvi.wSuiteMask & VER_SUITE_WH_SERVER)
474         strKernel.append(" Home Server");
475       else if (osvi.wProductType == VER_NT_WORKSTATION && IsOS64bit())
476         strKernel.append(" XP Professional");
477       else if (osvi.wProductType != VER_NT_WORKSTATION)
478         strKernel.append(" Server 2003");
479       else if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
480         strKernel.append("XP Home Edition" );
481       else
482         strKernel.append("XP Professional" );
483       break;
484     case WindowsVersionVista:
485       if (osvi.wProductType == VER_NT_WORKSTATION)
486         strKernel.append(" Vista");
487       else
488         strKernel.append(" Server 2008");
489       break;
490     case WindowsVersionWin7:
491       if (osvi.wProductType == VER_NT_WORKSTATION)
492         strKernel.append(" 7");
493       else
494         strKernel.append(" Server 2008 R2");
495       break;
496     case WindowsVersionWin8:
497       if (osvi.wProductType == VER_NT_WORKSTATION)
498         strKernel.append(" 8");
499       else
500         strKernel.append(" Server 2012");
501       break;
502     case WindowsVersionFuture:
503       strKernel.append(" Unknown Future Version");
504       break;
505     default:
506       strKernel.append(" Unknown version");
507       break;
508     }
509
510     // Append Service Pack version if any
511     if (osvi.wServicePackMajor > 0)
512     {
513       strKernel.append(StringUtils::Format(" SP%d", osvi.wServicePackMajor));
514       if (osvi.wServicePackMinor > 0)
515       {
516         strKernel.append(StringUtils::Format(".%d", osvi.wServicePackMinor));
517       }
518     }
519
520     if (IsOS64bit())
521       strKernel.append(" 64-bit");
522     else
523       strKernel.append(" 32-bit");
524
525     strKernel.append(StringUtils::Format(", build %d", osvi.dwBuildNumber));
526   }
527   else
528   {
529     strKernel.append(" unknown");
530     if (IsOS64bit())
531       strKernel.append(" 64-bit");
532     else
533       strKernel.append(" 32-bit");
534   }
535
536   return strKernel;
537 #endif
538 }
539
540 bool CSysInfo::HasInternet()
541 {
542   if (m_info.internetState != CSysData::UNKNOWN)
543     return m_info.internetState == CSysData::CONNECTED;
544   return (m_info.internetState = CSysInfoJob::GetInternetState()) == CSysData::CONNECTED;
545 }
546
547 CStdString CSysInfo::GetHddSpaceInfo(int drive, bool shortText)
548 {
549  int percent;
550  return GetHddSpaceInfo( percent, drive, shortText);
551 }
552
553 CStdString CSysInfo::GetHddSpaceInfo(int& percent, int drive, bool shortText)
554 {
555   int total, totalFree, totalUsed, percentFree, percentused;
556   CStdString strRet;
557   percent = 0;
558   if (g_sysinfo.GetDiskSpace("", total, totalFree, totalUsed, percentFree, percentused))
559   {
560     if (shortText)
561     {
562       switch(drive)
563       {
564         case SYSTEM_FREE_SPACE:
565           percent = percentFree;
566           break;
567         case SYSTEM_USED_SPACE:
568           percent = percentused;
569           break;
570       }
571     }
572     else
573     {
574       switch(drive)
575       {
576       case SYSTEM_FREE_SPACE:
577         strRet.Format("%i MB %s", totalFree, g_localizeStrings.Get(160));
578         break;
579       case SYSTEM_USED_SPACE:
580         strRet.Format("%i MB %s", totalUsed, g_localizeStrings.Get(20162));
581         break;
582       case SYSTEM_TOTAL_SPACE:
583         strRet.Format("%i MB %s", total, g_localizeStrings.Get(20161));
584         break;
585       case SYSTEM_FREE_SPACE_PERCENT:
586         strRet.Format("%i %% %s", percentFree, g_localizeStrings.Get(160));
587         break;
588       case SYSTEM_USED_SPACE_PERCENT:
589         strRet.Format("%i %% %s", percentused, g_localizeStrings.Get(20162));
590         break;
591       }
592     }
593   }
594   else
595   {
596     if (shortText)
597       strRet = "N/A";
598     else
599       strRet = g_localizeStrings.Get(161);
600   }
601   return strRet;
602 }
603
604 #if defined(TARGET_LINUX)
605 CStdString CSysInfo::GetLinuxDistro()
606 {
607 #if defined(TARGET_ANDROID)
608   return "Android";
609 #endif
610   static const char* release_file[] = { "/etc/debian_version",
611                                         "/etc/SuSE-release",
612                                         "/etc/mandrake-release",
613                                         "/etc/fedora-release",
614                                         "/etc/redhat-release",
615                                         "/etc/gentoo-release",
616                                         "/etc/slackware-version",
617                                         "/etc/arch-release",
618                                         "/etc/buildroot-release",
619                                         NULL };
620   CStdString result("");
621   char buffer[256] = {'\0'};
622
623   /* Try reading PRETTY_NAME from /etc/os-release first.
624    * If this fails, fall back to lsb_release or distro-specific release-file. */
625
626   FILE *os_release = fopen("/etc/os-release", "r");
627
628   if (os_release)
629   {
630     char *key = NULL;
631     char *val = NULL;
632
633     while (fgets(buffer, sizeof(buffer), os_release))
634     {
635       key = val = buffer;
636       strsep(&val, "=");
637
638       if (strcmp(key, "PRETTY_NAME") == 0)
639       {
640         char *pretty_name = val;
641
642         // remove newline and enclosing quotes
643         if (pretty_name[strlen(pretty_name) - 1] == '\n')
644           pretty_name[strlen(pretty_name) - 1] = '\0';
645
646         if (pretty_name[0] == '\'' || pretty_name[0] == '\"')
647         {
648           pretty_name++;
649           pretty_name[strlen(pretty_name) - 1] = '\0';
650         }
651
652         result = pretty_name;
653         break;
654       }
655     }
656
657     fclose(os_release);
658
659     if (!result.IsEmpty())
660       return result;
661   }
662
663   FILE* pipe = popen("unset PYTHONHOME; unset PYTHONPATH; lsb_release -d  2>/dev/null | cut -f2", "r");
664   if (pipe)
665   {
666     if (fread(buffer, sizeof(char), sizeof(buffer), pipe) > 0 && !ferror(pipe))
667       result = buffer;
668     pclose(pipe);
669     if (!result.IsEmpty())
670       return result.Trim();
671   }
672
673   FILE* file = NULL;
674   for (int i = 0; result.IsEmpty() && release_file[i]; i++)
675   {
676     file = fopen(release_file[i], "r");
677     if (file)
678     {
679       if (fgets(buffer, sizeof(buffer), file))
680       {
681         result = buffer;
682         if (!result.IsEmpty())
683           return result.Trim();
684       }
685       fclose(file);
686     }
687   }
688
689   CLog::Log(LOGWARNING, "Unable to determine Linux distribution");
690   return "Unknown";
691 }
692 #endif
693
694 #ifdef TARGET_POSIX
695 CStdString CSysInfo::GetUnameVersion()
696 {
697   CStdString result = "";
698
699 #if defined(TARGET_ANDROID)
700   struct utsname name;
701   if (uname(&name) == -1)
702     result = "Android";
703   result += name.release;
704   result += " ";
705   result += name.machine;
706 #elif defined(TARGET_DARWIN_IOS)
707   result = GetDarwinOSReleaseString();
708   result += ", ";
709   result += GetDarwinVersionString();
710 #else
711   FILE* pipe = popen("uname -rm", "r");
712   if (pipe)
713   {
714     char buffer[256];
715     if (fgets(buffer, sizeof(buffer), pipe))
716     {
717       result = buffer;
718 #if defined(TARGET_DARWIN)
719       result.Trim();
720       result += ", "; 
721       result += GetDarwinVersionString();
722 #endif
723     }
724     else
725       CLog::Log(LOGWARNING, "Unable to determine Uname version");
726     pclose(pipe);
727   }
728 #endif//else !TARGET_ANDROID
729
730   return result.Trim();
731 }
732 #endif
733
734 #if defined(TARGET_WINDOWS)
735 CStdString CSysInfo::GetUAWindowsVersion()
736 {
737   OSVERSIONINFOEX osvi = {};
738
739   osvi.dwOSVersionInfoSize = sizeof(osvi);
740   CStdString strVersion = "Windows NT";
741
742   if (GetVersionEx((OSVERSIONINFO *)&osvi))
743   {
744     strVersion.AppendFormat(" %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion);
745   }
746
747   SYSTEM_INFO si = {};
748   GetSystemInfo(&si);
749
750   BOOL bIsWow = FALSE;
751   if (IsWow64Process(GetCurrentProcess(), &bIsWow))
752   {
753     if (bIsWow)
754     {
755       strVersion.append(";WOW64");
756       GetNativeSystemInfo(&si);     // different function to read the info under Wow
757     }
758   }
759
760   if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
761     strVersion.append(";Win64;x64");
762   else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64)
763     strVersion.append(";Win64;IA64");
764
765   return strVersion;
766 }
767 #endif
768
769
770 CStdString CSysInfo::GetUserAgent()
771 {
772   CStdString result;
773   result = "XBMC/" + g_infoManager.GetLabel(SYSTEM_BUILD_VERSION) + " (";
774 #if defined(TARGET_WINDOWS)
775   result += GetUAWindowsVersion();
776 #elif defined(TARGET_DARWIN)
777 #if defined(TARGET_DARWIN_IOS)
778   result += "iOS; ";
779 #else
780   result += "Mac OS X; ";
781 #endif
782   result += GetUnameVersion();
783 #elif defined(TARGET_FREEBSD)
784   result += "FreeBSD; ";
785   result += GetUnameVersion();
786 #elif defined(TARGET_POSIX)
787   result += "Linux; ";
788   result += GetLinuxDistro();
789   result += "; ";
790   result += GetUnameVersion();
791 #endif
792   result += "; http://xbmc.org)";
793
794   return result;
795 }
796
797 bool CSysInfo::IsAppleTV2()
798 {
799 #if defined(TARGET_DARWIN)
800   return DarwinIsAppleTV2();
801 #else
802   return false;
803 #endif
804 }
805
806 bool CSysInfo::HasVideoToolBoxDecoder()
807 {
808   bool        result = false;
809
810 #if defined(HAVE_VIDEOTOOLBOXDECODER)
811   result = DarwinHasVideoToolboxDecoder();
812 #endif
813   return result;
814 }
815
816 std::string CSysInfo::GetBuildTargetPlatformName(void)
817 {
818 #if defined(TARGET_DARWIN_OSX)
819   return "Darwin OSX";
820 #elif defined(TARGET_DARWIN_IOS_ATV2)
821   return "Darwin iOS ATV2";
822 #elif defined(TARGET_DARWIN_IOS)
823   return "Darwin iOS";
824 #elif defined(TARGET_FREEBSD)
825   return "FreeBSD";
826 #elif defined(TARGET_ANDROID)
827   return "Android";
828 #elif defined(TARGET_LINUX)
829   return "Linux";
830 #elif defined(TARGET_WINDOWS)
831   return "Win32";
832 #else
833   return "unknown platform";
834 #endif
835 }
836
837 std::string CSysInfo::GetBuildTargetPlatformVersion(void)
838 {
839 /* Expand macro before stringify */
840 #define STR_MACRO(x) #x
841 #define XSTR_MACRO(x) STR_MACRO(x)
842
843 #if defined(TARGET_DARWIN_OSX)
844   return "version " XSTR_MACRO(__MAC_OS_X_VERSION_MIN_REQUIRED);
845 #elif defined(TARGET_DARWIN_IOS)
846   return "version " XSTR_MACRO(__IPHONE_OS_VERSION_MIN_REQUIRED);
847 #elif defined(TARGET_FREEBSD)
848   return "version " XSTR_MACRO(__FreeBSD_version);
849 #elif defined(TARGET_ANDROID)
850   return "API level " XSTR_MACRO(__ANDROID_API__);
851 #elif defined(TARGET_LINUX)
852   std::string ver = StringUtils::Format("%i.%i.%i", LINUX_VERSION_CODE >> 16, (LINUX_VERSION_CODE >> 8) & 0xff, LINUX_VERSION_CODE & 0xff);
853   return ver;
854 #elif defined(TARGET_WINDOWS)
855   return "version " XSTR_MACRO(NTDDI_VERSION);
856 #else
857   return "(unknown platform)";
858 #endif
859 }
860
861
862 CJob *CSysInfo::GetJob() const
863 {
864   return new CSysInfoJob();
865 }
866
867 void CSysInfo::OnJobComplete(unsigned int jobID, bool success, CJob *job)
868 {
869   m_info = ((CSysInfoJob *)job)->GetData();
870   CInfoLoader::OnJobComplete(jobID, success, job);
871 }