Merged from linuxport rev21200:21590. Updated.
[xbmc:xbmc-antiquated.git] / XBMC / xbmc / utils / SystemInfo.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.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, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "stdafx.h"
23 #include "SystemInfo.h"
24 #ifndef _LINUX
25 #include <conio.h>
26 #else
27 #include <sys/utsname.h>
28 #endif
29 #include "utils/GUIInfoManager.h"
30 #include "FileSystem/FileCurl.h"
31 #include "Network.h"
32 #include "Application.h"
33 #include "GraphicContext.h"
34 #include "Surface.h"
35 CSysInfo g_sysinfo;
36
37 void CBackgroundSystemInfoLoader::GetInformation()
38 {
39   CSysInfo *callback = (CSysInfo *)m_callback;
40   //Request always
41   callback->m_systemuptime = callback->GetSystemUpTime(false);
42   callback->m_systemtotaluptime = callback->GetSystemUpTime(true);
43   callback->m_InternetState = callback->GetInternetState();
44 #if defined (_LINUX) || defined(_WIN32PC)
45   callback->m_videoencoder    = callback->GetVideoEncoder();
46   callback->m_xboxversion     = callback->GetXBVerInfo();
47   callback->m_cpufrequency    = callback->GetCPUFreqInfo();
48   callback->m_kernelversion   = callback->GetKernelVersion();
49   callback->m_macadress       = callback->GetMACAddress();
50   callback->m_bRequestDone = true;
51 #endif
52 }
53
54 const char *CSysInfo::TranslateInfo(DWORD dwInfo)
55 {
56   switch(dwInfo)
57   {
58   case SYSTEM_VIDEO_ENCODER_INFO:
59     if (m_bRequestDone) return m_videoencoder;
60     else return CInfoLoader::BusyInfo(dwInfo);
61     break;
62   case NETWORK_MAC_ADDRESS:
63     if (m_bRequestDone) return m_macadress;
64     else return CInfoLoader::BusyInfo(dwInfo);
65     break;
66   case SYSTEM_KERNEL_VERSION:
67     if (m_bRequestDone) return m_kernelversion;
68     else return CInfoLoader::BusyInfo(dwInfo);
69     break;
70   case SYSTEM_CPUFREQUENCY:
71     if (m_bRequestDone) return m_cpufrequency;
72     else return CInfoLoader::BusyInfo(dwInfo);
73     break;
74   case SYSTEM_UPTIME:
75     if (!m_systemuptime.IsEmpty()) return m_systemuptime;
76     else return CInfoLoader::BusyInfo(dwInfo);
77   case SYSTEM_TOTALUPTIME:
78      if (!m_systemtotaluptime.IsEmpty()) return m_systemtotaluptime;
79     else return CInfoLoader::BusyInfo(dwInfo);
80   case SYSTEM_INTERNET_STATE:
81     if (!m_InternetState.IsEmpty())return m_InternetState;
82     else return g_localizeStrings.Get(503); //Busy text
83
84   default:
85     return g_localizeStrings.Get(503); //Busy text
86   }
87 }
88 DWORD CSysInfo::TimeToNextRefreshInMs()
89 {
90   // request every 15 seconds
91   return 15000;
92 }
93 void CSysInfo::Reset()
94 {
95   m_bInternetState = false;
96   m_InternetState = "";
97 }
98
99 CSysInfo::CSysInfo(void) : CInfoLoader("sysinfo")
100 {
101 }
102
103 CSysInfo::~CSysInfo()
104 {
105 }
106
107 bool CSysInfo::GetDiskSpace(const CStdString drive,int& iTotal, int& iTotalFree, int& iTotalUsed, int& iPercentFree, int& iPercentUsed)
108 {
109   bool bRet= false;
110   ULARGE_INTEGER ULTotal= { { 0 } };
111   ULARGE_INTEGER ULTotalFree= { { 0 } };
112
113   if( !drive.IsEmpty() && !drive.Equals("*") ) 
114   { 
115 #ifdef _WIN32PC
116     UINT uidriveType = GetDriveType(( drive + ":\\" ));
117     if(uidriveType != DRIVE_UNKNOWN && uidriveType != DRIVE_NO_ROOT_DIR)
118 #endif
119       bRet= ( 0 != GetDiskFreeSpaceEx( ( drive + ":\\" ), NULL, &ULTotal, &ULTotalFree) );
120   }
121   else 
122   {
123     ULARGE_INTEGER ULTotalTmp= { { 0 } };
124     ULARGE_INTEGER ULTotalFreeTmp= { { 0 } };
125 #ifdef _WIN32PC 
126     char* pcBuffer= NULL;
127     DWORD dwStrLength= GetLogicalDriveStrings( 0, pcBuffer );
128     if( dwStrLength != 0 )
129     {
130       dwStrLength+= 1;
131       pcBuffer= new char [dwStrLength];
132       GetLogicalDriveStrings( dwStrLength, pcBuffer );
133       int iPos= 0;
134       do {
135         if( DRIVE_FIXED == GetDriveType( pcBuffer + iPos  ) &&
136             GetDiskFreeSpaceEx( ( pcBuffer + iPos ), NULL, &ULTotal, &ULTotalFree ) )
137         {
138           ULTotalTmp.QuadPart+= ULTotal.QuadPart;
139           ULTotalFreeTmp.QuadPart+= ULTotalFree.QuadPart;
140         }
141         iPos += (strlen( pcBuffer + iPos) + 1 );
142       }while( strlen( pcBuffer + iPos ) > 0 );
143     }
144     delete[] pcBuffer;
145 #else // for linux and osx
146     static const char *drv_letter[] = { "C:\\", "E:\\", "F:\\", "G:\\", "X:\\", "Y:\\", "Z:\\", NULL };
147     for( int i = 0; drv_letter[i]; i++)
148     {
149       if( GetDiskFreeSpaceEx( drv_letter[i], NULL, &ULTotal, &ULTotalFree ) )
150       {
151         ULTotalTmp.QuadPart+= ULTotal.QuadPart;
152         ULTotalFreeTmp.QuadPart+= ULTotalFree.QuadPart;
153       }
154     }
155 #endif
156     if( ULTotalTmp.QuadPart || ULTotalFreeTmp.QuadPart )
157     {
158       ULTotal.QuadPart= ULTotalTmp.QuadPart;
159       ULTotalFree.QuadPart= ULTotalFreeTmp.QuadPart;
160       bRet= true;
161     }
162   }
163
164   if( bRet )
165   {
166     iTotal = (int)( ULTotal.QuadPart / MB );
167     iTotalFree = (int)( ULTotalFree.QuadPart / MB );
168     iTotalUsed = iTotal - iTotalFree;
169     iPercentUsed = (int)( 100.0f * ( ULTotal.QuadPart - ULTotalFree.QuadPart ) / ULTotal.QuadPart + 0.5f );
170     iPercentFree = 100 - iPercentUsed;
171   }
172
173   return bRet;
174 }
175
176 double CSysInfo::GetCPUFrequency()
177 {
178 #if defined (_LINUX) || defined(_WIN32PC)
179   return double (g_cpuInfo.getCPUFrequency());
180 #else
181   return 0;
182 #endif
183 }
184
185 CStdString CSysInfo::GetMACAddress()
186 {
187 #if defined(HAS_LINUX_NETWORK)
188   CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
189   if (iface)
190     return iface->GetMacAddress();
191 #endif
192   return "";
193 }
194
195 CStdString CSysInfo::GetVideoEncoder()
196 {
197 #ifdef HAS_SDL_OPENGL
198   return "GPU: " + g_graphicsContext.getScreenSurface()->GetGLRenderer();
199 #else // TODO:DIRECTX
200   return "GPU: DIRECTX";
201 #endif
202 }
203
204 CStdString CSysInfo::GetXBVerInfo()
205 {
206   return "CPU: " + g_cpuInfo.getCPUModel();
207 }
208
209 CStdString CSysInfo::GetKernelVersion()
210 {
211 #if defined (_LINUX)
212   struct utsname un;
213   if (uname(&un)==0)
214   {
215     CStdString strKernel;
216     strKernel.Format("%s %s %s %s", un.sysname, un.release, un.version, un.machine);
217     return strKernel;
218   }
219
220   return "";
221 #else
222   OSVERSIONINFOEX osvi;
223   SYSTEM_INFO si;
224
225   ZeroMemory(&si, sizeof(SYSTEM_INFO));
226   ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
227
228   GetSystemInfo(&si);
229
230   osvi.dwOSVersionInfoSize = sizeof(osvi);
231   CStdString strKernel = "Windows ";
232
233   if (GetVersionEx((OSVERSIONINFO *)&osvi))
234   {
235     if ( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0 )
236     {
237       if( osvi.wProductType == VER_NT_WORKSTATION )
238         strKernel.append("Vista");
239       else
240         strKernel.append("Server 2008");
241
242       if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 || si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64)
243         strKernel.append(", 64-bit Native");
244       else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
245       {
246         BOOL bIsWow = FALSE;;
247         if(IsWow64Process(GetCurrentProcess(), &bIsWow))
248         {
249           if (bIsWow)
250           {
251             GetNativeSystemInfo(&si);
252             if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
253              strKernel.append(", 64-bit (WoW)");
254           }
255           else 
256           {
257             strKernel.append(", 32-bit");
258           }
259         }
260         else
261           strKernel.append(", 32-bit");
262       }
263     }
264     else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
265     {
266       if( osvi.wProductType == VER_NT_WORKSTATION && si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
267       {
268         strKernel.append("XP Professional x64 Edition");
269       }
270     }
271     else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
272     {
273       strKernel.append("XP ");
274       if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
275         strKernel.append("Home Edition" );
276       else 
277         strKernel.append("Professional" );
278     }
279     else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
280     {
281       strKernel.append("2000");
282     }
283
284     if( _tcslen(osvi.szCSDVersion) > 0 )
285     {
286       strKernel.append(" ");
287       strKernel.append(osvi.szCSDVersion);
288     }
289     CStdString strBuild;
290     strBuild.Format(" build %d",osvi.dwBuildNumber);
291     strKernel += strBuild;
292   }
293   return strKernel;
294 #endif
295 }
296
297 CStdString CSysInfo::GetCPUFreqInfo()
298 {
299   CStdString strCPUFreq;
300   double CPUFreq = GetCPUFrequency();
301   strCPUFreq.Format("%4.2fMHz", CPUFreq);
302   return strCPUFreq;
303 }
304
305 CStdString CSysInfo::GetHddSpaceInfo(int drive, bool shortText)
306 {
307  int percent;
308  return GetHddSpaceInfo( percent, drive, shortText);
309 }
310
311 CStdString CSysInfo::GetHddSpaceInfo(int& percent, int drive, bool shortText)
312 {
313   int total, totalFree, totalUsed, percentFree, percentused;
314   CStdString strDrive;
315   bool bRet=false;
316   percent = 0;
317   CStdString strRet;
318   switch (drive)
319   {
320     case SYSTEM_FREE_SPACE:
321     case SYSTEM_USED_SPACE:
322     case SYSTEM_TOTAL_SPACE:
323     case SYSTEM_FREE_SPACE_PERCENT:
324     case SYSTEM_USED_SPACE_PERCENT:
325       bRet = g_sysinfo.GetDiskSpace("",total, totalFree, totalUsed, percentFree, percentused);
326       break;
327     case LCD_FREE_SPACE_C:
328     case SYSTEM_FREE_SPACE_C:
329     case SYSTEM_USED_SPACE_C:
330     case SYSTEM_TOTAL_SPACE_C:
331     case SYSTEM_FREE_SPACE_PERCENT_C:
332     case SYSTEM_USED_SPACE_PERCENT_C:
333       strDrive = "C";
334       bRet = g_sysinfo.GetDiskSpace("C",total, totalFree, totalUsed, percentFree, percentused);
335       break;
336     case LCD_FREE_SPACE_E:
337     case SYSTEM_FREE_SPACE_E:
338     case SYSTEM_USED_SPACE_E:
339     case SYSTEM_TOTAL_SPACE_E:
340     case SYSTEM_FREE_SPACE_PERCENT_E:
341     case SYSTEM_USED_SPACE_PERCENT_E:
342       strDrive = "E";
343       bRet = g_sysinfo.GetDiskSpace("E",total, totalFree, totalUsed, percentFree, percentused);
344       break;
345     case LCD_FREE_SPACE_F:
346     case SYSTEM_FREE_SPACE_F:
347     case SYSTEM_USED_SPACE_F:
348     case SYSTEM_TOTAL_SPACE_F:
349     case SYSTEM_FREE_SPACE_PERCENT_F:
350     case SYSTEM_USED_SPACE_PERCENT_F:
351       strDrive = "F";
352       bRet = g_sysinfo.GetDiskSpace("F",total, totalFree, totalUsed, percentFree, percentused);
353       break;
354     case LCD_FREE_SPACE_G:
355     case SYSTEM_FREE_SPACE_G:
356     case SYSTEM_USED_SPACE_G:
357     case SYSTEM_TOTAL_SPACE_G:
358     case SYSTEM_FREE_SPACE_PERCENT_G:
359     case SYSTEM_USED_SPACE_PERCENT_G:
360       strDrive = "G";
361       bRet = g_sysinfo.GetDiskSpace("G",total, totalFree, totalUsed, percentFree, percentused);
362       break;
363     case SYSTEM_USED_SPACE_X:
364     case SYSTEM_FREE_SPACE_X:
365     case SYSTEM_TOTAL_SPACE_X:
366       strDrive = "X";
367       bRet = g_sysinfo.GetDiskSpace("X",total, totalFree, totalUsed, percentFree, percentused);
368       break;
369     case SYSTEM_USED_SPACE_Y:
370     case SYSTEM_FREE_SPACE_Y:
371     case SYSTEM_TOTAL_SPACE_Y:
372       strDrive = "Y";
373       bRet = g_sysinfo.GetDiskSpace("Y",total, totalFree, totalUsed, percentFree, percentused);
374       break;
375     case SYSTEM_USED_SPACE_Z:
376     case SYSTEM_FREE_SPACE_Z:
377     case SYSTEM_TOTAL_SPACE_Z:
378       strDrive = "Z";
379       bRet = g_sysinfo.GetDiskSpace("Z",total, totalFree, totalUsed, percentFree, percentused);
380       break;
381   }
382   if (bRet)
383   {
384     if (shortText)
385     {
386       switch(drive)
387       {
388         case LCD_FREE_SPACE_C:
389         case LCD_FREE_SPACE_E:
390         case LCD_FREE_SPACE_F:
391         case LCD_FREE_SPACE_G:
392           strRet.Format("%iMB", totalFree);
393           break;
394         case SYSTEM_FREE_SPACE:
395         case SYSTEM_FREE_SPACE_C:
396         case SYSTEM_FREE_SPACE_E:
397         case SYSTEM_FREE_SPACE_F:
398         case SYSTEM_FREE_SPACE_G:
399         case SYSTEM_FREE_SPACE_X:
400         case SYSTEM_FREE_SPACE_Y:
401         case SYSTEM_FREE_SPACE_Z:
402           percent = percentFree;
403           break;
404         case SYSTEM_USED_SPACE:
405         case SYSTEM_USED_SPACE_C:
406         case SYSTEM_USED_SPACE_E:
407         case SYSTEM_USED_SPACE_F:
408         case SYSTEM_USED_SPACE_G:
409         case SYSTEM_USED_SPACE_X:
410         case SYSTEM_USED_SPACE_Y:
411         case SYSTEM_USED_SPACE_Z:
412           percent = percentused;
413           break;
414       }
415     }
416     else
417     {
418       switch(drive)
419       {
420       case SYSTEM_FREE_SPACE:
421       case SYSTEM_FREE_SPACE_C:
422       case SYSTEM_FREE_SPACE_E:
423       case SYSTEM_FREE_SPACE_F:
424       case SYSTEM_FREE_SPACE_G:
425       case SYSTEM_FREE_SPACE_X:
426       case SYSTEM_FREE_SPACE_Y:
427       case SYSTEM_FREE_SPACE_Z:
428         if (strDrive.IsEmpty())
429           strRet.Format("%i MB %s", totalFree, g_localizeStrings.Get(160));
430         else
431           strRet.Format("%s: %i MB %s", strDrive, totalFree, g_localizeStrings.Get(160));
432         break;
433       case SYSTEM_USED_SPACE:
434       case SYSTEM_USED_SPACE_C:
435       case SYSTEM_USED_SPACE_E:
436       case SYSTEM_USED_SPACE_F:
437       case SYSTEM_USED_SPACE_G:
438       case SYSTEM_USED_SPACE_X:
439       case SYSTEM_USED_SPACE_Y:
440       case SYSTEM_USED_SPACE_Z:
441         if (strDrive.IsEmpty())
442           strRet.Format("%i MB %s", totalUsed, g_localizeStrings.Get(20162));
443         else
444           strRet.Format("%s: %i MB %s", strDrive, totalUsed, g_localizeStrings.Get(20162));
445         break;
446       case SYSTEM_TOTAL_SPACE:
447       case SYSTEM_TOTAL_SPACE_C:
448       case SYSTEM_TOTAL_SPACE_E:
449       case SYSTEM_TOTAL_SPACE_F:
450       case SYSTEM_TOTAL_SPACE_G:
451         if (strDrive.IsEmpty())
452           strRet.Format("%i MB %s", total, g_localizeStrings.Get(20161));
453         else
454           strRet.Format("%s: %i MB %s", strDrive, total, g_localizeStrings.Get(20161));
455         break;
456       case SYSTEM_FREE_SPACE_PERCENT:
457       case SYSTEM_FREE_SPACE_PERCENT_C:
458       case SYSTEM_FREE_SPACE_PERCENT_E:
459       case SYSTEM_FREE_SPACE_PERCENT_F:
460       case SYSTEM_FREE_SPACE_PERCENT_G:
461         if (strDrive.IsEmpty())
462           strRet.Format("%i MB %s", percentFree, g_localizeStrings.Get(160));
463         else
464           strRet.Format("%s: %i MB %s", strDrive, percentFree, g_localizeStrings.Get(160));
465         break;
466       case SYSTEM_USED_SPACE_PERCENT:
467       case SYSTEM_USED_SPACE_PERCENT_C:
468       case SYSTEM_USED_SPACE_PERCENT_E:
469       case SYSTEM_USED_SPACE_PERCENT_F:
470       case SYSTEM_USED_SPACE_PERCENT_G:
471         if (strDrive.IsEmpty())
472           strRet.Format("%i MB %s", percentused, g_localizeStrings.Get(20162));
473         else
474           strRet.Format("%s: %i MB %s", strDrive, percentused, g_localizeStrings.Get(20162));
475         break;
476       }
477     }
478   }
479   else
480   {
481     if (shortText)
482       strRet = "N/A";
483     else if (strDrive.IsEmpty())
484       strRet = g_localizeStrings.Get(161);
485     else
486       strRet.Format("%s: %s", strDrive, g_localizeStrings.Get(161));
487   }
488   return strRet;
489 }
490
491 bool CSysInfo::SystemUpTime(int iInputMinutes, int &iMinutes, int &iHours, int &iDays)
492 {
493   iMinutes=0;iHours=0;iDays=0;
494   iMinutes = iInputMinutes;
495   if (iMinutes >= 60) // Hour's
496   {
497     iHours = iMinutes / 60;
498     iMinutes = iMinutes - (iHours *60);
499   }
500   if (iHours >= 24) // Days
501   {
502     iDays = iHours / 24;
503     iHours = iHours - (iDays * 24);
504   }
505   return true;
506 }
507
508 CStdString CSysInfo::GetSystemUpTime(bool bTotalUptime)
509 {
510   CStdString strSystemUptime;
511   int iInputMinutes, iMinutes,iHours,iDays;
512
513   if(bTotalUptime)
514   {
515     //Total Uptime
516     iInputMinutes = g_stSettings.m_iSystemTimeTotalUp + ((int)(timeGetTime() / 60000));
517   }
518   else
519   {
520     //Current UpTime
521     iInputMinutes = (int)(timeGetTime() / 60000);
522   }
523
524   SystemUpTime(iInputMinutes,iMinutes, iHours, iDays);
525   if (iDays > 0)
526   {
527     strSystemUptime.Format("%i %s, %i %s, %i %s",
528       iDays,g_localizeStrings.Get(12393),
529       iHours,g_localizeStrings.Get(12392),
530       iMinutes, g_localizeStrings.Get(12391));
531   }
532   else if (iDays == 0 && iHours >= 1 )
533   {
534     strSystemUptime.Format("%i %s, %i %s",
535       iHours,g_localizeStrings.Get(12392),
536       iMinutes, g_localizeStrings.Get(12391));
537   }
538   else if (iDays == 0 && iHours == 0 &&  iMinutes >= 0)
539   {
540     strSystemUptime.Format("%i %s",
541       iMinutes, g_localizeStrings.Get(12391));
542   }
543   return strSystemUptime;
544 }
545
546 CStdString CSysInfo::GetInternetState()
547 {
548   // Internet connection state!
549   XFILE::CFileCurl http;
550   m_bInternetState = http.IsInternet();
551   if (m_bInternetState)
552     return g_localizeStrings.Get(13296);
553   else if (http.IsInternet(false))
554     return g_localizeStrings.Get(13274);
555   else // NOT Connected to the Internet!
556     return g_localizeStrings.Get(13297);
557 }
558
559 #if defined(_LINUX) && !defined(__APPLE__)
560 CStdString CSysInfo::GetLinuxDistro()
561 {
562   CStdString result = "";
563   
564   FILE* pipe = popen("unset PYTHONHOME; unset PYTHONPATH; /usr/bin/lsb_release -d | cut -f2", "r");
565   if (pipe)
566   {
567     char buffer[256];
568     memset(buffer, 0, sizeof(buffer)*sizeof(char));
569     if (fread(buffer, sizeof(buffer)*sizeof(char), 1, pipe) == 1)
570       result = buffer;
571     else
572       CLog::Log(LOGWARNING, "Unable to determine Linux distribution");
573     pclose(pipe);
574   }
575   
576   return result.Trim();
577 }
578 #endif
579
580 #ifdef _LINUX
581 CStdString CSysInfo::GetUnameVersion()
582 {
583   CStdString result = "";
584   
585   FILE* pipe = popen("uname -rs", "r");
586   if (pipe)
587   {
588     char buffer[256];
589     memset(buffer, 0, sizeof(buffer)*sizeof(char));
590     if (fread(buffer, sizeof(buffer)*sizeof(char), 1, pipe) == 1)
591       result = buffer;
592     else
593       CLog::Log(LOGWARNING, "Unable to determine Uname version");
594     pclose(pipe);
595   }
596   
597   return result.Trim();
598 }
599 #endif
600
601 CStdString CSysInfo::GetUserAgent()
602 {
603   CStdString result;
604   result = "XBMC/" + g_infoManager.GetLabel(SYSTEM_BUILD_VERSION) + " (";
605 #if defined(_WIN32PC)
606   result += "Windows; ";
607   result += GetKernelVersion();
608 #elif defined(__APPLE__)
609   result += "Mac OS X; ";
610   result += GetUnameVersion();
611 #elif defined(_LINUX)
612   result += "Linux; ";
613   CStdString distro = GetLinuxDistro();
614   if (distro != "")
615   {
616     result += distro;
617     result += "; ";
618   }
619   result += GetUnameVersion();
620 #endif
621   result += "; http://www.xbmc.org)";
622   
623   return result;
624 }
625
626 #if defined(__APPLE__)
627 bool CSysInfo::IsAppleTV()
628 {
629   bool        result = false;
630   char        buffer[512];
631   size_t      len = 512;
632   std::string hw_model = "unknown";
633   
634   if (sysctlbyname("hw.model", &buffer, &len, NULL, 0) == 0)
635     hw_model = buffer;
636   
637   if (hw_model.find("AppleTV") != std::string::npos)
638     result = true;
639
640   return result;
641 }
642 #endif
643