diff options
Diffstat (limited to 'utils/rbutilqt/base/system.cpp')
-rw-r--r-- | utils/rbutilqt/base/system.cpp | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/utils/rbutilqt/base/system.cpp b/utils/rbutilqt/base/system.cpp new file mode 100644 index 0000000000..dafab971ec --- /dev/null +++ b/utils/rbutilqt/base/system.cpp | |||
@@ -0,0 +1,519 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2007 by Dominik Wenger | ||
10 | * | ||
11 | * All files in this archive are subject to the GNU General Public License. | ||
12 | * See the file COPYING in the source tree root for full license agreement. | ||
13 | * | ||
14 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
15 | * KIND, either express or implied. | ||
16 | * | ||
17 | ****************************************************************************/ | ||
18 | |||
19 | |||
20 | #include "system.h" | ||
21 | |||
22 | #include <QtCore> | ||
23 | #include <QDebug> | ||
24 | |||
25 | #include <cstdlib> | ||
26 | #include <stdio.h> | ||
27 | |||
28 | // Windows Includes | ||
29 | #if defined(Q_OS_WIN32) | ||
30 | #if defined(UNICODE) | ||
31 | #define _UNICODE | ||
32 | #endif | ||
33 | #include <windows.h> | ||
34 | #include <tchar.h> | ||
35 | #include <lm.h> | ||
36 | #include <windows.h> | ||
37 | #include <setupapi.h> | ||
38 | #endif | ||
39 | |||
40 | // Linux and Mac includes | ||
41 | #if defined(Q_OS_LINUX) || defined(Q_OS_MACX) | ||
42 | #include <sys/utsname.h> | ||
43 | #include <unistd.h> | ||
44 | #include <pwd.h> | ||
45 | #endif | ||
46 | |||
47 | // Linux includes | ||
48 | #if defined(Q_OS_LINUX) | ||
49 | #include <libusb-1.0/libusb.h> | ||
50 | #include <mntent.h> | ||
51 | #endif | ||
52 | |||
53 | // Mac includes | ||
54 | #if defined(Q_OS_MACX) | ||
55 | #include <sys/param.h> | ||
56 | #include <sys/ucred.h> | ||
57 | #include <sys/mount.h> | ||
58 | |||
59 | #include <CoreFoundation/CoreFoundation.h> | ||
60 | #include <SystemConfiguration/SystemConfiguration.h> | ||
61 | #include <CoreServices/CoreServices.h> | ||
62 | #include <IOKit/IOKitLib.h> | ||
63 | #include <IOKit/usb/IOUSBLib.h> | ||
64 | #endif | ||
65 | |||
66 | #include "utils.h" | ||
67 | #include "rbsettings.h" | ||
68 | #include "Logger.h" | ||
69 | |||
70 | /** @brief detect permission of user (only Windows at moment). | ||
71 | * @return enum userlevel. | ||
72 | */ | ||
73 | #if defined(Q_OS_WIN32) | ||
74 | enum System::userlevel System::userPermissions(void) | ||
75 | { | ||
76 | LPUSER_INFO_1 buf = NULL; | ||
77 | wchar_t userbuf[UNLEN]; | ||
78 | DWORD usersize = UNLEN; | ||
79 | BOOL status; | ||
80 | enum userlevel result = ERR; | ||
81 | |||
82 | status = GetUserNameW(userbuf, &usersize); | ||
83 | if(!status) | ||
84 | return ERR; | ||
85 | |||
86 | if(NetUserGetInfo(NULL, userbuf, (DWORD)1, (LPBYTE*)&buf) == NERR_Success) { | ||
87 | switch(buf->usri1_priv) { | ||
88 | case USER_PRIV_GUEST: | ||
89 | result = GUEST; | ||
90 | break; | ||
91 | case USER_PRIV_USER: | ||
92 | result = USER; | ||
93 | break; | ||
94 | case USER_PRIV_ADMIN: | ||
95 | result = ADMIN; | ||
96 | break; | ||
97 | default: | ||
98 | result = ERR; | ||
99 | break; | ||
100 | } | ||
101 | } | ||
102 | if(buf != NULL) | ||
103 | NetApiBufferFree(buf); | ||
104 | |||
105 | return result; | ||
106 | } | ||
107 | |||
108 | /** @brief detects user permissions (only Windows at moment). | ||
109 | * @return a user readable string with the permission. | ||
110 | */ | ||
111 | QString System::userPermissionsString(void) | ||
112 | { | ||
113 | QString result; | ||
114 | int perm = userPermissions(); | ||
115 | switch(perm) { | ||
116 | case GUEST: | ||
117 | result = tr("Guest"); | ||
118 | break; | ||
119 | case ADMIN: | ||
120 | result = tr("Admin"); | ||
121 | break; | ||
122 | case USER: | ||
123 | result = tr("User"); | ||
124 | break; | ||
125 | default: | ||
126 | result = tr("Error"); | ||
127 | break; | ||
128 | } | ||
129 | return result; | ||
130 | } | ||
131 | #endif | ||
132 | |||
133 | |||
134 | /** @brief detects current Username. | ||
135 | * @return string with Username. | ||
136 | */ | ||
137 | QString System::userName(void) | ||
138 | { | ||
139 | #if defined(Q_OS_WIN32) | ||
140 | wchar_t userbuf[UNLEN]; | ||
141 | DWORD usersize = UNLEN; | ||
142 | |||
143 | if(GetUserNameW(userbuf, &usersize) == 0) | ||
144 | return QString(); | ||
145 | |||
146 | return QString::fromWCharArray(userbuf); | ||
147 | #endif | ||
148 | #if defined(Q_OS_LINUX) || defined(Q_OS_MACX) | ||
149 | struct passwd *user; | ||
150 | user = getpwuid(geteuid()); | ||
151 | return QString(user->pw_name); | ||
152 | #endif | ||
153 | } | ||
154 | |||
155 | |||
156 | /** @brief detects the OS Version | ||
157 | * @return String with OS Version. | ||
158 | */ | ||
159 | QString System::osVersionString(void) | ||
160 | { | ||
161 | QString result; | ||
162 | #if defined(Q_OS_WIN32) | ||
163 | SYSTEM_INFO sysinfo; | ||
164 | OSVERSIONINFO osvi; | ||
165 | ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); | ||
166 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | ||
167 | GetVersionEx(&osvi); | ||
168 | GetSystemInfo(&sysinfo); | ||
169 | |||
170 | result = QString("Windows version %1.%2, ").arg(osvi.dwMajorVersion).arg(osvi.dwMinorVersion); | ||
171 | if(osvi.szCSDVersion) | ||
172 | result += QString("build %1 (%2)").arg(osvi.dwBuildNumber) | ||
173 | .arg(QString::fromWCharArray(osvi.szCSDVersion)); | ||
174 | else | ||
175 | result += QString("build %1").arg(osvi.dwBuildNumber); | ||
176 | result += QString("<br/>CPU: %1, %2 processor(s)").arg(sysinfo.dwProcessorType) | ||
177 | .arg(sysinfo.dwNumberOfProcessors); | ||
178 | #endif | ||
179 | #if defined(Q_OS_LINUX) || defined(Q_OS_MACX) | ||
180 | struct utsname u; | ||
181 | int ret; | ||
182 | ret = uname(&u); | ||
183 | |||
184 | #if defined(Q_OS_MACX) | ||
185 | SInt32 cores; | ||
186 | Gestalt(gestaltCountOfCPUs, &cores); | ||
187 | #else | ||
188 | long cores = sysconf(_SC_NPROCESSORS_ONLN); | ||
189 | #endif | ||
190 | if(ret != -1) { | ||
191 | result = QString("CPU: %1, %2 processor(s)").arg(u.machine).arg(cores); | ||
192 | result += QString("<br/>System: %2<br/>Release: %3<br/>Version: %4") | ||
193 | .arg(u.sysname).arg(u.release).arg(u.version); | ||
194 | } | ||
195 | else { | ||
196 | result = QString("(Error when retrieving system information)"); | ||
197 | } | ||
198 | #if defined(Q_OS_MACX) | ||
199 | SInt32 major; | ||
200 | SInt32 minor; | ||
201 | SInt32 bugfix; | ||
202 | Gestalt(gestaltSystemVersionMajor, &major); | ||
203 | Gestalt(gestaltSystemVersionMinor, &minor); | ||
204 | Gestalt(gestaltSystemVersionBugFix, &bugfix); | ||
205 | |||
206 | result += QString("<br/>OS X %1.%2.%3 ").arg(major).arg(minor).arg(bugfix); | ||
207 | // 1: 86k, 2: ppc, 10: i386 | ||
208 | SInt32 arch; | ||
209 | Gestalt(gestaltSysArchitecture, &arch); | ||
210 | switch(arch) { | ||
211 | case 1: | ||
212 | result.append("(86k)"); | ||
213 | break; | ||
214 | case 2: | ||
215 | result.append("(ppc)"); | ||
216 | break; | ||
217 | case 10: | ||
218 | result.append("(x86)"); | ||
219 | break; | ||
220 | default: | ||
221 | result.append("(unknown)"); | ||
222 | break; | ||
223 | } | ||
224 | #endif | ||
225 | #endif | ||
226 | result += QString("<br/>Qt version %1").arg(qVersion()); | ||
227 | return result; | ||
228 | } | ||
229 | |||
230 | QList<uint32_t> System::listUsbIds(void) | ||
231 | { | ||
232 | return listUsbDevices().keys(); | ||
233 | } | ||
234 | |||
235 | /** @brief detect devices based on usb pid / vid. | ||
236 | * @return list with usb VID / PID values. | ||
237 | */ | ||
238 | QMultiMap<uint32_t, QString> System::listUsbDevices(void) | ||
239 | { | ||
240 | QMultiMap<uint32_t, QString> usbids; | ||
241 | // usb pid detection | ||
242 | LOG_INFO() << "Searching for USB devices"; | ||
243 | #if defined(Q_OS_LINUX) | ||
244 | libusb_device **devs; | ||
245 | if(libusb_init(nullptr) != 0) { | ||
246 | LOG_ERROR() << "Initializing libusb-1 failed."; | ||
247 | return usbids; | ||
248 | } | ||
249 | |||
250 | if(libusb_get_device_list(nullptr, &devs) < 1) { | ||
251 | LOG_ERROR() << "Error getting device list."; | ||
252 | return usbids; | ||
253 | } | ||
254 | libusb_device *dev; | ||
255 | int i = 0; | ||
256 | while((dev = devs[i++]) != nullptr) { | ||
257 | QString name; | ||
258 | unsigned char buf[256]; | ||
259 | uint32_t id; | ||
260 | struct libusb_device_descriptor descriptor; | ||
261 | if(libusb_get_device_descriptor(dev, &descriptor) == 0) { | ||
262 | id = descriptor.idVendor << 16 | descriptor.idProduct; | ||
263 | |||
264 | libusb_device_handle *dh; | ||
265 | if(libusb_open(dev, &dh) == 0) { | ||
266 | libusb_get_string_descriptor_ascii(dh, descriptor.iManufacturer, buf, 256); | ||
267 | name += QString::fromLatin1((char*)buf) + " "; | ||
268 | libusb_get_string_descriptor_ascii(dh, descriptor.iProduct, buf, 256); | ||
269 | name += QString::fromLatin1((char*)buf); | ||
270 | libusb_close(dh); | ||
271 | } | ||
272 | if(name.isEmpty()) | ||
273 | name = tr("(no description available)"); | ||
274 | if(id) { | ||
275 | usbids.insert(id, name); | ||
276 | LOG_INFO("USB: 0x%08x, %s", id, name.toLocal8Bit().data()); | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | libusb_free_device_list(devs, 1); | ||
282 | libusb_exit(nullptr); | ||
283 | #endif | ||
284 | |||
285 | #if defined(Q_OS_MACX) | ||
286 | kern_return_t result = KERN_FAILURE; | ||
287 | CFMutableDictionaryRef usb_matching_dictionary; | ||
288 | io_iterator_t usb_iterator = IO_OBJECT_NULL; | ||
289 | usb_matching_dictionary = IOServiceMatching(kIOUSBDeviceClassName); | ||
290 | result = IOServiceGetMatchingServices(kIOMasterPortDefault, usb_matching_dictionary, | ||
291 | &usb_iterator); | ||
292 | if(result) { | ||
293 | LOG_ERROR() << "USB: IOKit: Could not get matching services."; | ||
294 | return usbids; | ||
295 | } | ||
296 | |||
297 | io_object_t usbCurrentObj; | ||
298 | while((usbCurrentObj = IOIteratorNext(usb_iterator))) { | ||
299 | uint32_t id; | ||
300 | QString name; | ||
301 | /* get vendor ID */ | ||
302 | CFTypeRef vidref = NULL; | ||
303 | int vid = 0; | ||
304 | vidref = IORegistryEntryCreateCFProperty(usbCurrentObj, CFSTR("idVendor"), | ||
305 | kCFAllocatorDefault, 0); | ||
306 | CFNumberGetValue((CFNumberRef)vidref, kCFNumberIntType, &vid); | ||
307 | CFRelease(vidref); | ||
308 | |||
309 | /* get product ID */ | ||
310 | CFTypeRef pidref = NULL; | ||
311 | int pid = 0; | ||
312 | pidref = IORegistryEntryCreateCFProperty(usbCurrentObj, CFSTR("idProduct"), | ||
313 | kCFAllocatorDefault, 0); | ||
314 | CFNumberGetValue((CFNumberRef)pidref, kCFNumberIntType, &pid); | ||
315 | CFRelease(pidref); | ||
316 | id = vid << 16 | pid; | ||
317 | |||
318 | /* get product vendor */ | ||
319 | char vendor_buf[256]; | ||
320 | CFIndex vendor_buflen = 256; | ||
321 | CFTypeRef vendor_name_ref = NULL; | ||
322 | |||
323 | vendor_name_ref = IORegistryEntrySearchCFProperty(usbCurrentObj, | ||
324 | kIOServicePlane, CFSTR("USB Vendor Name"), | ||
325 | kCFAllocatorDefault, 0); | ||
326 | if(vendor_name_ref != NULL) { | ||
327 | CFStringGetCString((CFStringRef)vendor_name_ref, vendor_buf, vendor_buflen, | ||
328 | kCFStringEncodingUTF8); | ||
329 | name += QString::fromUtf8(vendor_buf) + " "; | ||
330 | CFRelease(vendor_name_ref); | ||
331 | } | ||
332 | else { | ||
333 | name += QObject::tr("(unknown vendor name) "); | ||
334 | } | ||
335 | |||
336 | /* get product name */ | ||
337 | char product_buf[256]; | ||
338 | CFIndex product_buflen = 256; | ||
339 | CFTypeRef product_name_ref = NULL; | ||
340 | |||
341 | product_name_ref = IORegistryEntrySearchCFProperty(usbCurrentObj, | ||
342 | kIOServicePlane, CFSTR("USB Product Name"), | ||
343 | kCFAllocatorDefault, 0); | ||
344 | if(product_name_ref != NULL) { | ||
345 | CFStringGetCString((CFStringRef)product_name_ref, product_buf, product_buflen, | ||
346 | kCFStringEncodingUTF8); | ||
347 | name += QString::fromUtf8(product_buf); | ||
348 | CFRelease(product_name_ref); | ||
349 | } | ||
350 | else { | ||
351 | name += QObject::tr("(unknown product name)"); | ||
352 | } | ||
353 | |||
354 | if(id) { | ||
355 | usbids.insertMulti(id, name); | ||
356 | LOG_INFO() << "USB:" << QString("0x%1").arg(id, 8, 16) << name; | ||
357 | } | ||
358 | |||
359 | } | ||
360 | IOObjectRelease(usb_iterator); | ||
361 | #endif | ||
362 | |||
363 | #if defined(Q_OS_WIN32) | ||
364 | HDEVINFO deviceInfo; | ||
365 | SP_DEVINFO_DATA infoData; | ||
366 | DWORD i; | ||
367 | |||
368 | // Iterate over all devices | ||
369 | // by doing it this way it's unneccessary to use GUIDs which might be not | ||
370 | // present in current MinGW. It also seemed to be more reliably than using | ||
371 | // a GUID. | ||
372 | // See KB259695 for an example. | ||
373 | deviceInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); | ||
374 | |||
375 | infoData.cbSize = sizeof(SP_DEVINFO_DATA); | ||
376 | |||
377 | for(i = 0; SetupDiEnumDeviceInfo(deviceInfo, i, &infoData); i++) { | ||
378 | DWORD data; | ||
379 | LPTSTR buffer = NULL; | ||
380 | DWORD buffersize = 0; | ||
381 | QString description; | ||
382 | |||
383 | // get device descriptor first | ||
384 | // for some reason not doing so results in bad things (tm) | ||
385 | while(!SetupDiGetDeviceRegistryProperty(deviceInfo, &infoData, | ||
386 | SPDRP_DEVICEDESC, &data, (PBYTE)buffer, buffersize, &buffersize)) { | ||
387 | if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { | ||
388 | if(buffer) free(buffer); | ||
389 | // double buffer size to avoid problems as per KB888609 | ||
390 | buffer = (LPTSTR)malloc(buffersize * 2); | ||
391 | } | ||
392 | else { | ||
393 | break; | ||
394 | } | ||
395 | } | ||
396 | if(!buffer) { | ||
397 | LOG_WARNING() << "Got no device description" | ||
398 | << "(SetupDiGetDeviceRegistryProperty), item" << i; | ||
399 | continue; | ||
400 | } | ||
401 | description = QString::fromWCharArray(buffer); | ||
402 | |||
403 | // now get the hardware id, which contains PID and VID. | ||
404 | while(!SetupDiGetDeviceRegistryProperty(deviceInfo, &infoData, | ||
405 | SPDRP_HARDWAREID, &data, (PBYTE)buffer, buffersize, &buffersize)) { | ||
406 | if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { | ||
407 | if(buffer) free(buffer); | ||
408 | // double buffer size to avoid problems as per KB888609 | ||
409 | buffer = (LPTSTR)malloc(buffersize * 2); | ||
410 | } | ||
411 | else { | ||
412 | break; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | if(buffer) { | ||
417 | // convert buffer text to upper case to avoid depending on the case of | ||
418 | // the keys (W7 uses different casing than XP at least), in addition | ||
419 | // XP may use "Vid_" and "Pid_". | ||
420 | QString data = QString::fromWCharArray(buffer).toUpper(); | ||
421 | QRegExp rex("USB\\\\VID_([0-9A-F]{4})&PID_([0-9A-F]{4}).*"); | ||
422 | if(rex.indexIn(data) >= 0) { | ||
423 | uint32_t id; | ||
424 | id = rex.cap(1).toUInt(0, 16) << 16 | rex.cap(2).toUInt(0, 16); | ||
425 | usbids.insert(id, description); | ||
426 | LOG_INFO() << "USB:" << QString("0x%1").arg(id, 8, 16); | ||
427 | } | ||
428 | free(buffer); | ||
429 | } | ||
430 | } | ||
431 | SetupDiDestroyDeviceInfoList(deviceInfo); | ||
432 | |||
433 | #endif | ||
434 | return usbids; | ||
435 | } | ||
436 | |||
437 | |||
438 | /** @brief detects current system proxy | ||
439 | * @return QUrl with proxy or empty | ||
440 | */ | ||
441 | QUrl System::systemProxy(void) | ||
442 | { | ||
443 | #if defined(Q_OS_LINUX) | ||
444 | return QUrl(getenv("http_proxy")); | ||
445 | #elif defined(Q_OS_WIN32) | ||
446 | HKEY hk; | ||
447 | wchar_t proxyval[80]; | ||
448 | DWORD buflen = 80; | ||
449 | long ret; | ||
450 | DWORD enable; | ||
451 | DWORD enalen = sizeof(DWORD); | ||
452 | |||
453 | ret = RegOpenKeyEx(HKEY_CURRENT_USER, | ||
454 | _TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"), | ||
455 | 0, KEY_QUERY_VALUE, &hk); | ||
456 | if(ret != ERROR_SUCCESS) return QUrl(""); | ||
457 | |||
458 | ret = RegQueryValueEx(hk, _TEXT("ProxyServer"), NULL, NULL, (LPBYTE)proxyval, &buflen); | ||
459 | if(ret != ERROR_SUCCESS) return QUrl(""); | ||
460 | |||
461 | ret = RegQueryValueEx(hk, _TEXT("ProxyEnable"), NULL, NULL, (LPBYTE)&enable, &enalen); | ||
462 | if(ret != ERROR_SUCCESS) return QUrl(""); | ||
463 | |||
464 | RegCloseKey(hk); | ||
465 | |||
466 | //LOG_INFO() << QString::fromWCharArray(proxyval) << QString("%1").arg(enable); | ||
467 | if(enable != 0) | ||
468 | return QUrl("http://" + QString::fromWCharArray(proxyval)); | ||
469 | else | ||
470 | return QUrl(""); | ||
471 | #elif defined(Q_OS_MACX) | ||
472 | |||
473 | CFDictionaryRef dictref; | ||
474 | CFStringRef stringref; | ||
475 | CFNumberRef numberref; | ||
476 | int enable = 0; | ||
477 | int port = 0; | ||
478 | unsigned int bufsize = 0; | ||
479 | char *buf; | ||
480 | QUrl proxy; | ||
481 | |||
482 | dictref = SCDynamicStoreCopyProxies(NULL); | ||
483 | if(dictref == NULL) | ||
484 | return proxy; | ||
485 | numberref = (CFNumberRef)CFDictionaryGetValue(dictref, kSCPropNetProxiesHTTPEnable); | ||
486 | if(numberref != NULL) | ||
487 | CFNumberGetValue(numberref, kCFNumberIntType, &enable); | ||
488 | if(enable == 1) { | ||
489 | // get proxy string | ||
490 | stringref = (CFStringRef)CFDictionaryGetValue(dictref, kSCPropNetProxiesHTTPProxy); | ||
491 | if(stringref != NULL) { | ||
492 | // get number of characters. CFStringGetLength uses UTF-16 code pairs | ||
493 | bufsize = CFStringGetLength(stringref) * 2 + 1; | ||
494 | buf = (char*)malloc(sizeof(char) * bufsize); | ||
495 | if(buf == NULL) { | ||
496 | LOG_ERROR() << "can't allocate memory for proxy string!"; | ||
497 | CFRelease(dictref); | ||
498 | return QUrl(""); | ||
499 | } | ||
500 | CFStringGetCString(stringref, buf, bufsize, kCFStringEncodingUTF16); | ||
501 | numberref = (CFNumberRef)CFDictionaryGetValue(dictref, kSCPropNetProxiesHTTPPort); | ||
502 | if(numberref != NULL) | ||
503 | CFNumberGetValue(numberref, kCFNumberIntType, &port); | ||
504 | proxy.setScheme("http"); | ||
505 | proxy.setHost(QString::fromUtf16((unsigned short*)buf)); | ||
506 | proxy.setPort(port); | ||
507 | |||
508 | free(buf); | ||
509 | } | ||
510 | } | ||
511 | CFRelease(dictref); | ||
512 | |||
513 | return proxy; | ||
514 | #else | ||
515 | return QUrl(""); | ||
516 | #endif | ||
517 | } | ||
518 | |||
519 | |||