diff options
Diffstat (limited to 'rbutil/rbutilqt/base/detect.cpp')
-rw-r--r-- | rbutil/rbutilqt/base/detect.cpp | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/rbutil/rbutilqt/base/detect.cpp b/rbutil/rbutilqt/base/detect.cpp new file mode 100644 index 0000000000..d2a65ee72f --- /dev/null +++ b/rbutil/rbutilqt/base/detect.cpp | |||
@@ -0,0 +1,441 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2007 by Dominik Wenger | ||
10 | * $Id$ | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | |||
21 | #include "detect.h" | ||
22 | |||
23 | #include <QtCore> | ||
24 | #include <QDebug> | ||
25 | |||
26 | #include <cstdlib> | ||
27 | #include <stdio.h> | ||
28 | |||
29 | // Windows Includes | ||
30 | #if defined(Q_OS_WIN32) | ||
31 | #if defined(UNICODE) | ||
32 | #define _UNICODE | ||
33 | #endif | ||
34 | #include <windows.h> | ||
35 | #include <tchar.h> | ||
36 | #include <lm.h> | ||
37 | #include <windows.h> | ||
38 | #include <setupapi.h> | ||
39 | #endif | ||
40 | |||
41 | // Linux and Mac includes | ||
42 | #if defined(Q_OS_LINUX) || defined(Q_OS_MACX) | ||
43 | #include <usb.h> | ||
44 | #include <sys/utsname.h> | ||
45 | #include <unistd.h> | ||
46 | #include <pwd.h> | ||
47 | #endif | ||
48 | |||
49 | // Linux includes | ||
50 | #if defined(Q_OS_LINUX) | ||
51 | #include <mntent.h> | ||
52 | #endif | ||
53 | |||
54 | // Mac includes | ||
55 | #if defined(Q_OS_MACX) | ||
56 | #include <sys/param.h> | ||
57 | #include <sys/ucred.h> | ||
58 | #include <sys/mount.h> | ||
59 | #endif | ||
60 | |||
61 | |||
62 | /** @brief detect permission of user (only Windows at moment). | ||
63 | * @return enum userlevel. | ||
64 | */ | ||
65 | #if defined(Q_OS_WIN32) | ||
66 | enum Detect::userlevel Detect::userPermissions(void) | ||
67 | { | ||
68 | LPUSER_INFO_1 buf; | ||
69 | NET_API_STATUS napistatus; | ||
70 | wchar_t userbuf[UNLEN]; | ||
71 | DWORD usersize = UNLEN; | ||
72 | BOOL status; | ||
73 | enum userlevel result; | ||
74 | |||
75 | status = GetUserNameW(userbuf, &usersize); | ||
76 | if(!status) | ||
77 | return ERR; | ||
78 | |||
79 | napistatus = NetUserGetInfo(NULL, userbuf, (DWORD)1, (LPBYTE*)&buf); | ||
80 | |||
81 | switch(buf->usri1_priv) { | ||
82 | case USER_PRIV_GUEST: | ||
83 | result = GUEST; | ||
84 | break; | ||
85 | case USER_PRIV_USER: | ||
86 | result = USER; | ||
87 | break; | ||
88 | case USER_PRIV_ADMIN: | ||
89 | result = ADMIN; | ||
90 | break; | ||
91 | default: | ||
92 | result = ERR; | ||
93 | break; | ||
94 | } | ||
95 | NetApiBufferFree(buf); | ||
96 | |||
97 | return result; | ||
98 | } | ||
99 | |||
100 | /** @brief detects user permissions (only Windows at moment). | ||
101 | * @return a user readable string with the permission. | ||
102 | */ | ||
103 | QString Detect::userPermissionsString(void) | ||
104 | { | ||
105 | QString result; | ||
106 | int perm = userPermissions(); | ||
107 | switch(perm) { | ||
108 | case GUEST: | ||
109 | result = QObject::tr("Guest"); | ||
110 | break; | ||
111 | case ADMIN: | ||
112 | result = QObject::tr("Admin"); | ||
113 | break; | ||
114 | case USER: | ||
115 | result = QObject::tr("User"); | ||
116 | break; | ||
117 | default: | ||
118 | result = QObject::tr("Error"); | ||
119 | break; | ||
120 | } | ||
121 | return result; | ||
122 | } | ||
123 | #endif | ||
124 | |||
125 | |||
126 | /** @brief detects current Username. | ||
127 | * @return string with Username. | ||
128 | */ | ||
129 | QString Detect::userName(void) | ||
130 | { | ||
131 | #if defined(Q_OS_WIN32) | ||
132 | wchar_t userbuf[UNLEN]; | ||
133 | DWORD usersize = UNLEN; | ||
134 | BOOL status; | ||
135 | |||
136 | status = GetUserNameW(userbuf, &usersize); | ||
137 | |||
138 | return QString::fromWCharArray(userbuf); | ||
139 | #endif | ||
140 | #if defined(Q_OS_LINUX) || defined(Q_OS_MACX) | ||
141 | struct passwd *user; | ||
142 | user = getpwuid(geteuid()); | ||
143 | return QString(user->pw_name); | ||
144 | #endif | ||
145 | } | ||
146 | |||
147 | |||
148 | /** @brief detects the OS Version | ||
149 | * @return String with OS Version. | ||
150 | */ | ||
151 | QString Detect::osVersionString(void) | ||
152 | { | ||
153 | QString result; | ||
154 | #if defined(Q_OS_WIN32) | ||
155 | OSVERSIONINFO osvi; | ||
156 | ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); | ||
157 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | ||
158 | GetVersionEx(&osvi); | ||
159 | |||
160 | result = QString("Windows version %1.%2, ").arg(osvi.dwMajorVersion).arg(osvi.dwMinorVersion); | ||
161 | if(osvi.szCSDVersion) | ||
162 | result += QString("build %1 (%2)").arg(osvi.dwBuildNumber) | ||
163 | .arg(QString::fromWCharArray(osvi.szCSDVersion)); | ||
164 | else | ||
165 | result += QString("build %1").arg(osvi.dwBuildNumber); | ||
166 | #endif | ||
167 | #if defined(Q_OS_LINUX) || defined(Q_OS_MACX) | ||
168 | struct utsname u; | ||
169 | int ret; | ||
170 | ret = uname(&u); | ||
171 | |||
172 | result = QString("CPU: %1<br/>System: %2<br/>Release: %3<br/>Version: %4") | ||
173 | .arg(u.machine).arg(u.sysname).arg(u.release).arg(u.version); | ||
174 | #endif | ||
175 | return result; | ||
176 | } | ||
177 | |||
178 | QList<uint32_t> Detect::listUsbIds(void) | ||
179 | { | ||
180 | return listUsbDevices().keys(); | ||
181 | } | ||
182 | |||
183 | /** @brief detect devices based on usb pid / vid. | ||
184 | * @return list with usb VID / PID values. | ||
185 | */ | ||
186 | QMap<uint32_t, QString> Detect::listUsbDevices(void) | ||
187 | { | ||
188 | QMap<uint32_t, QString> usbids; | ||
189 | // usb pid detection | ||
190 | #if defined(Q_OS_LINUX) || defined(Q_OS_MACX) | ||
191 | usb_init(); | ||
192 | usb_find_busses(); | ||
193 | usb_find_devices(); | ||
194 | struct usb_bus *b; | ||
195 | b = usb_busses; | ||
196 | |||
197 | while(b) { | ||
198 | qDebug() << "bus:" << b->dirname << b->devices; | ||
199 | if(b->devices) { | ||
200 | qDebug() << "devices present."; | ||
201 | struct usb_device *u; | ||
202 | u = b->devices; | ||
203 | while(u) { | ||
204 | uint32_t id; | ||
205 | id = u->descriptor.idVendor << 16 | u->descriptor.idProduct; | ||
206 | // get identification strings | ||
207 | usb_dev_handle *dev; | ||
208 | QString name; | ||
209 | char string[256]; | ||
210 | int res; | ||
211 | dev = usb_open(u); | ||
212 | if(dev) { | ||
213 | if(u->descriptor.iManufacturer) { | ||
214 | res = usb_get_string_simple(dev, u->descriptor.iManufacturer, string, sizeof(string)); | ||
215 | if(res > 0) | ||
216 | name += QString::fromAscii(string) + " "; | ||
217 | } | ||
218 | if(u->descriptor.iProduct) { | ||
219 | res = usb_get_string_simple(dev, u->descriptor.iProduct, string, sizeof(string)); | ||
220 | if(res > 0) | ||
221 | name += QString::fromAscii(string); | ||
222 | } | ||
223 | } | ||
224 | usb_close(dev); | ||
225 | if(name.isEmpty()) name = QObject::tr("(no description available)"); | ||
226 | |||
227 | if(id) usbids.insert(id, name); | ||
228 | u = u->next; | ||
229 | } | ||
230 | } | ||
231 | b = b->next; | ||
232 | } | ||
233 | #endif | ||
234 | |||
235 | #if defined(Q_OS_WIN32) | ||
236 | HDEVINFO deviceInfo; | ||
237 | SP_DEVINFO_DATA infoData; | ||
238 | DWORD i; | ||
239 | |||
240 | // Iterate over all devices | ||
241 | // by doing it this way it's unneccessary to use GUIDs which might be not | ||
242 | // present in current MinGW. It also seemed to be more reliably than using | ||
243 | // a GUID. | ||
244 | // See KB259695 for an example. | ||
245 | deviceInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); | ||
246 | |||
247 | infoData.cbSize = sizeof(SP_DEVINFO_DATA); | ||
248 | |||
249 | for(i = 0; SetupDiEnumDeviceInfo(deviceInfo, i, &infoData); i++) { | ||
250 | DWORD data; | ||
251 | LPTSTR buffer = NULL; | ||
252 | DWORD buffersize = 0; | ||
253 | QString description; | ||
254 | |||
255 | // get device desriptor first | ||
256 | // for some reason not doing so results in bad things (tm) | ||
257 | while(!SetupDiGetDeviceRegistryProperty(deviceInfo, &infoData, | ||
258 | SPDRP_DEVICEDESC,&data, (PBYTE)buffer, buffersize, &buffersize)) { | ||
259 | if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { | ||
260 | if(buffer) free(buffer); | ||
261 | // double buffer size to avoid problems as per KB888609 | ||
262 | buffer = (LPTSTR)malloc(buffersize * 2); | ||
263 | } | ||
264 | else { | ||
265 | break; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | // now get the hardware id, which contains PID and VID. | ||
270 | while(!SetupDiGetDeviceRegistryProperty(deviceInfo, &infoData, | ||
271 | SPDRP_LOCATION_INFORMATION,&data, (PBYTE)buffer, buffersize, &buffersize)) { | ||
272 | if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { | ||
273 | if(buffer) free(buffer); | ||
274 | // double buffer size to avoid problems as per KB888609 | ||
275 | buffer = (LPTSTR)malloc(buffersize * 2); | ||
276 | } | ||
277 | else { | ||
278 | break; | ||
279 | } | ||
280 | } | ||
281 | description = QString::fromWCharArray(buffer); | ||
282 | |||
283 | while(!SetupDiGetDeviceRegistryProperty(deviceInfo, &infoData, | ||
284 | SPDRP_HARDWAREID,&data, (PBYTE)buffer, buffersize, &buffersize)) { | ||
285 | if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { | ||
286 | if(buffer) free(buffer); | ||
287 | // double buffer size to avoid problems as per KB888609 | ||
288 | buffer = (LPTSTR)malloc(buffersize * 2); | ||
289 | } | ||
290 | else { | ||
291 | break; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | unsigned int vid, pid, rev; | ||
296 | if(_stscanf(buffer, _TEXT("USB\\Vid_%x&Pid_%x&Rev_%x"), &vid, &pid, &rev) == 3) { | ||
297 | uint32_t id; | ||
298 | id = vid << 16 | pid; | ||
299 | usbids.insert(id, description); | ||
300 | qDebug("VID: %04x, PID: %04x", vid, pid); | ||
301 | } | ||
302 | if(buffer) free(buffer); | ||
303 | } | ||
304 | SetupDiDestroyDeviceInfoList(deviceInfo); | ||
305 | |||
306 | #endif | ||
307 | return usbids; | ||
308 | } | ||
309 | |||
310 | |||
311 | /** @brief detects current system proxy | ||
312 | * @return QUrl with proxy or empty | ||
313 | */ | ||
314 | QUrl Detect::systemProxy(void) | ||
315 | { | ||
316 | #if defined(Q_OS_LINUX) | ||
317 | return QUrl(getenv("http_proxy")); | ||
318 | #elif defined(Q_OS_WIN32) | ||
319 | HKEY hk; | ||
320 | wchar_t proxyval[80]; | ||
321 | DWORD buflen = 80; | ||
322 | long ret; | ||
323 | DWORD enable; | ||
324 | DWORD enalen = sizeof(DWORD); | ||
325 | |||
326 | ret = RegOpenKeyEx(HKEY_CURRENT_USER, | ||
327 | _TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"), | ||
328 | 0, KEY_QUERY_VALUE, &hk); | ||
329 | if(ret != ERROR_SUCCESS) return QUrl(""); | ||
330 | |||
331 | ret = RegQueryValueEx(hk, _TEXT("ProxyServer"), NULL, NULL, (LPBYTE)proxyval, &buflen); | ||
332 | if(ret != ERROR_SUCCESS) return QUrl(""); | ||
333 | |||
334 | ret = RegQueryValueEx(hk, _TEXT("ProxyEnable"), NULL, NULL, (LPBYTE)&enable, &enalen); | ||
335 | if(ret != ERROR_SUCCESS) return QUrl(""); | ||
336 | |||
337 | RegCloseKey(hk); | ||
338 | |||
339 | //qDebug() << QString::fromWCharArray(proxyval) << QString("%1").arg(enable); | ||
340 | if(enable != 0) | ||
341 | return QUrl("http://" + QString::fromWCharArray(proxyval)); | ||
342 | else | ||
343 | return QUrl(""); | ||
344 | #else | ||
345 | return QUrl(""); | ||
346 | #endif | ||
347 | } | ||
348 | |||
349 | |||
350 | /** @brief detects the installed Rockbox version | ||
351 | * @return QString with version. Empty if not aviable | ||
352 | */ | ||
353 | QString Detect::installedVersion(QString mountpoint) | ||
354 | { | ||
355 | // read rockbox-info.txt | ||
356 | QFile info(mountpoint +"/.rockbox/rockbox-info.txt"); | ||
357 | if(!info.open(QIODevice::ReadOnly)) | ||
358 | { | ||
359 | return ""; | ||
360 | } | ||
361 | |||
362 | while (!info.atEnd()) { | ||
363 | QString line = info.readLine(); | ||
364 | |||
365 | if(line.contains("Version:")) | ||
366 | { | ||
367 | return line.remove("Version:").trimmed(); | ||
368 | } | ||
369 | } | ||
370 | info.close(); | ||
371 | return ""; | ||
372 | } | ||
373 | |||
374 | |||
375 | /** @brief detects installed rockbox target id | ||
376 | * @return TargetId of installed rockbox, or -1 if not available | ||
377 | */ | ||
378 | int Detect::installedTargetId(QString mountpoint) | ||
379 | { | ||
380 | // read rockbox-info.txt | ||
381 | QFile info(mountpoint +"/.rockbox/rockbox-info.txt"); | ||
382 | if(!info.open(QIODevice::ReadOnly)) | ||
383 | { | ||
384 | return -1; | ||
385 | } | ||
386 | |||
387 | while (!info.atEnd()) | ||
388 | { | ||
389 | QString line = info.readLine(); | ||
390 | if(line.contains("Target id:")) | ||
391 | { | ||
392 | qDebug() << line; | ||
393 | return line.remove("Target id:").trimmed().toInt(); | ||
394 | } | ||
395 | } | ||
396 | info.close(); | ||
397 | return -1; | ||
398 | } | ||
399 | |||
400 | |||
401 | /** @brief checks different Enviroment things. Ask if user wants to continue. | ||
402 | * @param settings A pointer to rbutils settings class | ||
403 | * @param permission if it should check for permission | ||
404 | * @param targetId the targetID to check for. if it is -1 no check is done. | ||
405 | * @return string with error messages if problems occurred, empty strings if none. | ||
406 | */ | ||
407 | QString Detect::check(RbSettings* settings, bool permission, int targetId) | ||
408 | { | ||
409 | QString text = ""; | ||
410 | |||
411 | // check permission | ||
412 | if(permission) | ||
413 | { | ||
414 | #if defined(Q_OS_WIN32) | ||
415 | if(Detect::userPermissions() != Detect::ADMIN) | ||
416 | { | ||
417 | text += QObject::tr("<li>Permissions insufficient for bootloader " | ||
418 | "installation.\nAdministrator priviledges are necessary.</li>"); | ||
419 | } | ||
420 | #endif | ||
421 | } | ||
422 | |||
423 | // Check TargetId | ||
424 | if(targetId > 0) | ||
425 | { | ||
426 | int installedID = Detect::installedTargetId(settings->mountpoint()); | ||
427 | if( installedID != -1 && installedID != targetId) | ||
428 | { | ||
429 | text += QObject::tr("<li>Target mismatch detected.\n" | ||
430 | "Installed target: %1, selected target: %2.</li>") | ||
431 | .arg(settings->nameOfTargetId(installedID),settings->curName()); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | if(!text.isEmpty()) | ||
436 | return QObject::tr("Problem detected:") + "<ul>" + text + "</ul>"; | ||
437 | else | ||
438 | return text; | ||
439 | } | ||
440 | |||
441 | |||