1 /****************************************************************************
2 **
3 ** Copyright (C) 2008-2010 Andrey Rijov <ANDron142@yandex.ru>
4 ** Copyright (C) 2016 Tobias Gläßer
5 **
6 ** This file is part of AQEMU.
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License as published by
10 ** the Free Software Foundation; either version 2 of the License.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 ** Boston, MA  02110-1301, USA.
21 **
22 ****************************************************************************/
23 
24 #include <QDir>
25 #include <QFile>
26 #include <QFileInfo>
27 #include <QFileInfoList>
28 #include <QDateTime>
29 #include <QMessageBox>
30 #include <QApplication>
31 #include <QSettings>
32 #include <QRegExp>
33 #include <QProcess>
34 #include <QStringList>
35 #include <QTextStream>
36 
37 #ifdef Q_OS_WIN32
38 #include <iostream>
39 #include <windows.h>
40 HANDLE Console_HANDLE = GetStdHandle( STD_OUTPUT_HANDLE );
41 #else
42 #include <QDebug>
43 #include <iostream>
44 #endif
45 
46 #include "Utils.h"
47 #include "System_Info.h"
48 
49 static uint Messages_Index = 0;
50 
51 static bool Save_Messages_To_Log = true;
52 static QString Log_Path = "";
53 
54 static bool Use_Stdout;
55 static bool Stdout_Debug;
56 static bool Stdout_Warning;
57 static bool Stdout_Error;
58 
59 static bool Show_User_Graphic_Warning = true;
60 
61 static QStringList Recent_CD_Images;
62 static QStringList Recent_FDD_Images;
63 
Disable_User_Graphic_Warning()64 Disable_User_Graphic_Warning::Disable_User_Graphic_Warning()
65 {
66     Show_User_Graphic_Warning = false;
67 }
~Disable_User_Graphic_Warning()68 Disable_User_Graphic_Warning::~Disable_User_Graphic_Warning()
69 {
70     Show_User_Graphic_Warning = true;
71 }
72 
AQDebugStdCout(const QString & s)73 void AQDebugStdCout(const QString& s)
74 {
75     std::cout << s.toLatin1().constData() << std::endl;
76 }
77 
78 
AQDebug(const QString & sender,const QString & mes)79 void AQDebug( const QString &sender, const QString &mes )
80 {
81 	if( Use_Stdout && Stdout_Debug )
82 	{
83 	#ifdef Q_OS_WIN32
84 		SetConsoleTextAttribute( Console_HANDLE, 10 );
85 		std::cout << QString( "\nAQEMU Debug [%1] >>>\nSender: %2\nMessage: %3" )
86 							  .arg(Messages_Index).arg(sender).arg(mes).toStdString();
87 	#else
88 		AQDebugStdCout( QString(
89 			"\n\33[32mAQEMU Debug\33[0m [%1] >>>\n\33[32mSender:\33[0m %2\n\33[32mMessage:\33[0m %3")
90 			.arg(Messages_Index).arg(sender).arg(mes));
91 	#endif
92 	}
93 
94 	if( Save_Messages_To_Log && Stdout_Debug )
95 		AQSave_To_Log( "Debug", sender, mes );
96 
97 	Messages_Index++;
98 }
99 
AQWarning(const QString & sender,const QString & mes)100 void AQWarning( const QString &sender, const QString &mes )
101 {
102 	if( Use_Stdout && Stdout_Warning )
103 	{
104 	#ifdef Q_OS_WIN32
105 		SetConsoleTextAttribute( Console_HANDLE, 14 );
106 		std::cout << QString( "\nAQEMU Warning [%1] >>>\nSender: %2\nMessage: %3" )
107 							  .arg(Messages_Index).arg(sender).arg(mes).toStdString();
108 	#else
109 		AQDebugStdCout( QString(
110 			"\n\33[34mAQEMU Warning\33[0m [%1] >>>\n\33[34mSender:\33[0m %2\n\33[34mMessage:\33[0m %3")
111 			.arg(Messages_Index).arg(sender).arg(mes));
112 	#endif
113 	}
114 
115 	if( Save_Messages_To_Log && Stdout_Warning )
116 		AQSave_To_Log( "Warning", sender, mes );
117 
118 	Messages_Index++;
119 }
120 
AQError(const QString & sender,const QString & mes)121 void AQError( const QString &sender, const QString &mes )
122 {
123 	if( Use_Stdout && Stdout_Error )
124 	{
125 	#ifdef Q_OS_WIN32
126 		SetConsoleTextAttribute( Console_HANDLE, 12 );
127 		std::cout << QString( "\nAQEMU Error [%1] >>>\nSender: %2\nMessage: %3" )
128 							  .arg(Messages_Index).arg(sender).arg(mes).toStdString();
129 	#else
130 		AQDebugStdCout( QString(
131 			"\n\33[31mAQEMU Error\33[0m [%1] >>>\n\33[31mSender:\33[0m %2\n\33[31mMessage:\33[0m %3")
132 			.arg(Messages_Index).arg(sender).arg(mes));
133 	#endif
134 	}
135 
136 	if( Save_Messages_To_Log && Stdout_Error )
137 		AQSave_To_Log( "Error", sender, mes );
138 
139 	Messages_Index++;
140 }
141 
AQGraphic_Warning(const QString & caption,const QString & mes)142 void AQGraphic_Warning( const QString &caption, const QString &mes )
143 {
144     if ( Show_User_Graphic_Warning == false )
145         return;
146 
147 	QMessageBox::warning( NULL, caption, mes, QMessageBox::Ok );
148 }
149 
AQGraphic_Warning(const QString & sender,const QString & caption,const QString & mes,bool fatal)150 void AQGraphic_Warning( const QString &sender, const QString &caption, const QString &mes, bool fatal )
151 {
152     if ( Show_User_Graphic_Warning == false )
153         return;
154 
155 	if( fatal )
156 	{
157 		QMessageBox::warning( NULL, caption,
158 					QString("Sender: %1\nMessage: %2\n").arg(sender).arg(mes) +
159 					QObject::tr("This Fatal Error. Recomend Close AQEMU."),
160 					QMessageBox::Ok );
161 	}
162 	else
163 	{
164 		QMessageBox::warning( NULL, caption,
165 					QString("Sender: %1\nMessage: %2").arg(sender).arg(mes),
166 					QMessageBox::Ok );
167 	}
168 
169 	if( Save_Messages_To_Log )
170 		AQSave_To_Log( "Warning", sender, mes );
171 }
172 
AQGraphic_Error(const QString & sender,const QString & caption,const QString & mes,bool fatal)173 void AQGraphic_Error( const QString &sender, const QString &caption, const QString &mes, bool fatal )
174 {
175 	if( fatal )
176 	{
177 		QMessageBox::critical( NULL, caption,
178 					QString("Sender: %1\nMessage: %2\n").arg(sender).arg(mes) +
179 					QObject::tr("Fatal error. It's recommended to close AQEMU"),
180 					QMessageBox::Ok );
181 	}
182 	else
183 	{
184 		QMessageBox::critical( NULL, caption,
185 					QString("Sender: %1\nMessage: %2").arg(sender).arg(mes),
186 					QMessageBox::Ok );
187 	}
188 
189 	if( Save_Messages_To_Log )
190 		AQSave_To_Log( "Error", sender, mes );
191 }
192 
AQUse_Log(bool use)193 void AQUse_Log( bool use )
194 {
195 	Save_Messages_To_Log = use;
196 }
197 
AQUse_Debug_Output(bool use,bool d,bool w,bool e)198 void AQUse_Debug_Output( bool use, bool d, bool w, bool e )
199 {
200 	Use_Stdout = use;
201 	Stdout_Debug = d;
202 	Stdout_Warning = w;
203 	Stdout_Error = e;
204 }
205 
AQLog_Path(const QString & path)206 void AQLog_Path( const QString& path )
207 {
208 	Log_Path = path;
209 }
210 
AQSave_To_Log(const QString & mes_type,const QString & sender,const QString & mes)211 void AQSave_To_Log( const QString &mes_type, const QString &sender, const QString &mes )
212 {
213 	if( Log_Path.isEmpty() ) return;
214 
215 	QFile log_file( Log_Path );
216 
217 	if( ! log_file.open(QIODevice::Append | QIODevice::Text) )
218 	{
219 		AQUse_Log( false ); // off loging
220 		AQError( "void AQSave_To_Log( const QString& mes_type, const QString& sender, const QString& mes )",
221 				 "Cannot Open Log file to Write! Log Path: \"" + Log_Path + "\"" );
222 	}
223 	else
224 	{
225 		QTextStream out( &log_file );
226 		out << "Type: " << mes_type << " Num: " << Messages_Index << "\nDate: "
227 			<< QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss zzz")
228 			<< "\nSender: " << sender << "\nMessage: " << mes << "\n\n";
229 	}
230 }
231 
Create_New_HDD_Image(bool encrypted,const QString & base_image,const QString & file_name,const QString & format,VM::Device_Size size,bool verbose)232 bool Create_New_HDD_Image( bool encrypted, const QString &base_image,
233 						   const QString &file_name, const QString &format, VM::Device_Size size, bool verbose )
234 {
235 	// Create command line
236 	QStringList args;
237 	args << "create";
238 
239 	if( encrypted )
240 		args << "-e";
241 
242 	if( ! base_image.isEmpty() )
243 		args << "-b" << base_image;
244 
245 	args << "-f" << format;
246 
247 	args << file_name;
248 
249 	switch( size.Suffix )
250 	{
251 		case VM::Size_Suf_Mb: // MB
252 			args << QString::number( size.Size ) + "M";
253 			break;
254 
255 		case VM::Size_Suf_Gb: // GB
256 			args << QString::number( size.Size ) + "G";
257 			break;
258 
259 		default: // KG
260 			args << QString::number( size.Size );
261 			break;
262 	}
263 
264 	// Start qemu-img process
265 	QProcess qemu_img;
266 	QSettings settings;
267 	qemu_img.start( settings.value("QEMU-IMG_Path", "qemu-img").toString(), args );
268 
269 	if( ! qemu_img.waitForStarted(2000) )
270 	{
271 		AQGraphic_Error( "bool Create_New_HDD_Image( bool encrypted, const QString &base_image,"
272 						 "const QString &file_name, const QString &format, VM::Device_Size size, bool verbose )",
273 						 QObject::tr("Error!"), QObject::tr("Cannot Start qemu-img! Image isn't Created!") );
274 		return false;
275 	}
276 
277 	if( ! qemu_img.waitForFinished(10000) )
278 	{
279 		AQGraphic_Error( "bool Create_New_HDD_Image( bool encrypted, const QString &base_image,"
280 						 "const QString &file_name, const QString &format, VM::Device_Size size, bool verbose )",
281 						 QObject::tr("Error!"), QObject::tr("qemu-img Cannot Finish! Image isn't Created!") );
282 		return false;
283 	}
284 	else
285 	{
286 		QByteArray err = qemu_img.readAllStandardError();
287 		QByteArray out = qemu_img.readAllStandardOutput();
288 
289 		if( err.count() > 0 )
290 		{
291 			AQGraphic_Error( "bool Create_New_HDD_Image( bool encrypted, const QString &base_image,"
292 							 "const QString &file_name, const QString &format, VM::Device_Size size, bool verbose )",
293 							 QObject::tr("Error!"), QObject::tr("Cannot Create Image!\nInformation: ") + err );
294 		}
295 
296 		QRegExp rx( "Format*ing*fmt*size*" );
297 		rx.setPatternSyntax( QRegExp::Wildcard );
298 
299 		if( verbose )
300 		{
301 			if( rx.exactMatch( out ) )
302 			{
303 				QMessageBox::information( NULL, QObject::tr("Complete!"),
304 						QObject::tr("QEMU-IMG is Creates HDD Image.\nAdditional Information:\n") + out );
305 			}
306 			else
307 			{
308 				QMessageBox::information( NULL, QObject::tr("Warning!"),
309 						 QObject::tr("QEMU-IMG is Returned non Standard Message!.\nAdditional Information:\n") + out );
310 			}
311 		}
312 
313 		return true;
314 	}
315 }
316 
Create_New_HDD_Image(const QString & file_name,VM::Device_Size size)317 bool Create_New_HDD_Image( const QString &file_name, VM::Device_Size size )
318 {
319 	QSettings settings;
320 	QString format = settings.value( "Default_HDD_Image_Format", "qcow2" ).toString();
321 
322 	return Create_New_HDD_Image( false, "", file_name, format, size, false );
323 }
324 
Format_HDD_Image(const QString & file_name,VM::Disk_Info info)325 bool Format_HDD_Image( const QString &file_name, VM::Disk_Info info )
326 {
327 	if( file_name.isEmpty() )
328 	{
329 		AQError( "bool Format_HDD_Image( const QString &file_name )",
330 				 "File Name is Empty!" );
331 
332 		return false;
333 	}
334 
335 	VM_HDD tmp_hd = VM_HDD( true, file_name );
336 	tmp_hd.Set_Disk_Info( info );
337 	QString hd_format = tmp_hd.Get_Image_Format();
338 
339 	if( hd_format.isEmpty() )
340 	{
341 		AQError( "bool Format_HDD_Image( const QString &file_name )",
342 				 "Format is Empty!" );
343 
344 		return false;
345 	}
346 
347 	return Create_New_HDD_Image( false, "", file_name, hd_format, tmp_hd.Get_Virtual_Size(), false );
348 }
349 
Get_Templates_List()350 QList<QString> Get_Templates_List()
351 {
352 	QList<QString> all_templates;
353 	QSettings settings;
354 
355 	// VM Templates
356 	QDir sys_templates_dir( QDir::toNativeSeparators(settings.value("AQEMU_Data_Folder", "").toString() + "/os_templates/") );
357 
358 	QFileInfoList sys_templates_list = sys_templates_dir.entryInfoList(
359 			QStringList("*.aqvmt"), QDir::Files, QDir::Unsorted );
360 
361 	QDir user_templates_dir( QDir::toNativeSeparators(settings.value("VM_Directory", "").toString() + "/os_templates/") );
362 
363 	QFileInfoList user_templates_list = user_templates_dir.entryInfoList(
364 			QStringList("*.aqvmt"), QDir::Files, QDir::Unsorted );
365 
366 	for( int tx = 0; tx < sys_templates_list.count(); ++tx )
367 	{
368 		for( int ux = 0; ux < user_templates_list.count(); ++ux )
369 		{
370 			if( sys_templates_list[tx].completeBaseName() ==
371 						 user_templates_list[ux].completeBaseName() )
372 			{
373 				sys_templates_list.takeAt( tx ); // delete system template
374 				tx -= 1;
375 				ux = user_templates_list.count();
376 			}
377 		}
378 	}
379 
380 	// OK. In Template Lists Only Unique Values
381 	for( int ix = 0; ix < sys_templates_list.count(); ++ix )
382 		all_templates.append( sys_templates_list[ix].absoluteFilePath() );
383 
384 	for( int ix = 0; ix < user_templates_list.count(); ++ix )
385 		all_templates.append( user_templates_list[ix].absoluteFilePath() );
386 
387 	// sort
388 	qSort( all_templates );
389 
390 	return all_templates;
391 }
392 
393 
Get_FS_Compatible_VM_Name(const QString & name)394 QString Get_FS_Compatible_VM_Name( const QString &name )
395 {
396 	//QRegExp vm_name_val = QRegExp( "[^a-zA-Z0-9_]" ); // old style
397 	QRegExp vm_name_val = QRegExp( "[^\\w\\.]" );
398 
399 	QString tmp = name;
400 	tmp = tmp.replace( vm_name_val, "_" );
401 
402 	return tmp.replace( "__", "_" );
403 }
404 
Get_Complete_VM_File_Path(const QString & vm_name)405 QString Get_Complete_VM_File_Path( const QString &vm_name )
406 {
407 	//QRegExp vm_name_val = QRegExp( "[^a-zA-Z0-9_]" ); // old style
408 	QRegExp vm_name_val = QRegExp( "[^\\w]" );
409 
410 	QString tmp = vm_name;
411 	tmp = tmp.replace( vm_name_val, "_" );
412 
413 	QString new_name = tmp.replace( "__", "_" );
414 	QString tmp_str = new_name;
415 
416 	QSettings settings;
417 
418 	QString ret_str = settings.value("VM_Directory", "").toString() + tmp_str;
419 
420 	if( ! ret_str.endsWith(".aqemu") )
421 		ret_str += ".aqemu";
422 
423 	for( int ix = 0; QFile::exists(ret_str); ++ix )
424 		tmp_str = new_name + QString::number( ix );
425 
426 	return ret_str;
427 }
428 
Get_TR_Size_Suffix(VM::Device_Size suf)429 QString Get_TR_Size_Suffix( VM::Device_Size suf )
430 {
431 	switch( suf.Suffix )
432 	{
433 		case VM::Size_Suf_Kb:
434 			return QObject::tr("Kb");
435 
436 		case VM::Size_Suf_Mb:
437 			return QObject::tr("Mb");
438 
439 		case VM::Size_Suf_Gb:
440 			return QObject::tr("Gb");
441 
442 		default:
443 			AQError( "QString Get_TR_Size_Suffix( VM::Device_Size suf )",
444 					 "Virtual Size Suffix Default Section!" );
445 			return "";
446 	}
447 }
448 
Get_Last_Dir_Path(const QString & path)449 QString Get_Last_Dir_Path( const QString &path )
450 {
451 	QFileInfo info( path );
452 	QString dir = info.path();
453 
454 	if( dir.isEmpty() ) return "/";
455 	else return dir;
456 }
457 
It_Host_Device(const QString & path)458 bool It_Host_Device( const QString &path )
459 {
460 	#ifdef Q_OS_WIN32
461 	// FIXME
462 	return false;
463 	#else
464 	if( path.startsWith("/dev/") ) return true;
465 	else return false;
466 	#endif
467 }
468 
Check_AQEMU_Permissions()469 void Check_AQEMU_Permissions()
470 {
471 	QSettings settings;
472 	QFileInfo test_perm;
473 
474 	#ifndef Q_OS_WIN32
475 	// This Section For Unix Like OS.
476 	test_perm = QFileInfo( settings.fileName() );
477 
478 	if( test_perm.exists() )
479 	{
480 		if( ! test_perm.isWritable() )
481 		{
482 			AQGraphic_Error( "void Check_AQEMU_Permissions()", QObject::tr("Error!"),
483 							 QObject::tr("AQEMU Config File is Read Only!\nCheck Permissions For File: ") +
484 							 settings.fileName(), true );
485 		}
486 	}
487 	#endif
488 
489 	// Check VM Dir Permissions
490 	test_perm = QFileInfo( settings.value("VM_Directory", "~").toString() );
491 
492 	if( test_perm.exists() )
493 	{
494 		if( ! test_perm.isWritable() )
495 		{
496 			AQGraphic_Error( "void Check_AQEMU_Permissions()", QObject::tr("Error!"),
497 							 QObject::tr("AQEMU VM Directory is Read Only!\nCheck Permissions For: ") +
498 							 settings.value("VM_Directory", "~").toString(), true );
499 		}
500 	}
501 
502 	// Check VM Templates Dir Permissions
503 	test_perm = QFileInfo( settings.value("VM_Directory", "~").toString() + "os_templates" );
504 
505 	if( test_perm.exists() )
506 	{
507 		if( ! test_perm.isWritable() )
508 		{
509 			AQGraphic_Error( "void Check_AQEMU_Permissions()", QObject::tr("Error!"),
510 							 QObject::tr("AQEMU VM Template Directory is Read Only!\nCheck Permissions For: ") +
511 							 settings.value("VM_Directory", "~").toString() + "os_templates", true );
512 		}
513 	}
514 
515 	// Check AQEMU Log File Permissions
516 	if( ! settings.value("Log/Log_Path", "").toString().isEmpty() )
517 	{
518 		test_perm = QFileInfo( settings.value("Log/Log_Path", "").toString() );
519 
520 		if( test_perm.exists() )
521 		{
522 			if( ! test_perm.isWritable() )
523 			{
524 				AQGraphic_Error( "void Check_AQEMU_Permissions()", QObject::tr("Error!"),
525 								 QObject::tr("AQEMU Log File is Read Only!\nCheck Permissions For File: ") +
526 								 settings.value("Log/Log_Path", "").toString(), false );
527 			}
528 		}
529 	}
530 }
531 
String_To_Emulator_Version(const QString & str)532 VM::Emulator_Version String_To_Emulator_Version( const QString &str )
533 {
534 	if( str == "QEMU 0.9.0" ) return VM::QEMU_2_0;
535 	else if( str == "QEMU 0.9.1" ) return VM::QEMU_2_0;
536 	else if( str == "QEMU 0.10.X" ) return VM::QEMU_2_0;
537 	else if( str == "QEMU 0.11.X" ) return VM::QEMU_2_0;
538 	else if( str == "QEMU 0.12.X" ) return VM::QEMU_2_0;
539 	else if( str == "QEMU 0.13.X" ) return VM::QEMU_2_0;
540 	else if( str == "QEMU 0.14.X" ) return VM::QEMU_2_0;
541 	else if( str == "QEMU 0.15.X" ) return VM::QEMU_2_0;
542 	else if( str == "QEMU 1.0" ) return VM::QEMU_2_0;
543 	else if( str == "QEMU 2.0" ) return VM::QEMU_2_0;
544 	else if( str == "KVM 7X" ) return VM::QEMU_2_0;
545 	else if( str == "KVM 8X" ) return VM::QEMU_2_0;
546 	else if( str == "KVM 0.11.X" ) return VM::QEMU_2_0;
547 	else if( str == "KVM 0.12.X" ) return VM::QEMU_2_0;
548 	else if( str == "KVM 0.13.X" ) return VM::QEMU_2_0;
549 	else if( str == "KVM 0.14.X" ) return VM::QEMU_2_0;
550 	else if( str == "KVM 0.15.X" ) return VM::QEMU_2_0;
551 	else if( str == "KVM 1.0" ) return VM::QEMU_2_0;
552 	else if( str == "Obsolete" ) return VM::Obsolete;
553 	else
554 	{
555 		AQError( "VM::Emulator_Version String_To_Emulator_Version( const QString &str )",
556 				 QString("Emulator version \"%1\" not valid!").arg(str) );
557 		return VM::Obsolete;
558 	}
559 }
560 
Emulator_Version_To_String(VM::Emulator_Version ver)561 QString Emulator_Version_To_String( VM::Emulator_Version ver )
562 {
563 	switch( ver )
564 	{
565 		case VM::QEMU_2_0:
566 			return "QEMU 2.0";
567 
568 		case VM::Obsolete:
569 			return "Obsolete";
570 
571 		default:
572 			AQError( "QString Emulator_Version_To_String( VM::Emulator_Version ver )",
573 					 QString("Emulator version \"%1\" not valid!").arg((int)ver) );
574 			return "";
575 	}
576 }
577 
578 static QList<Emulator> Emulators_List;
579 static QList<Emulator> Empty_Emul_List;
580 static Emulator Empty_Emul;
581 
Update_Emulators_List()582 bool Update_Emulators_List()
583 {
584 	// Clear old emulator list
585 	Emulators_List.clear();
586 
587 	// Get dir path
588 	QSettings settings;
589 	QFileInfo info( settings.fileName() );
590 	QString aqemuSettingsFolder = info.absoluteDir().absolutePath();
591 	if( ! (aqemuSettingsFolder.endsWith("/") || aqemuSettingsFolder.endsWith("\\")) )
592 		aqemuSettingsFolder = QDir::toNativeSeparators( aqemuSettingsFolder + "/" );
593 
594 	if( ! QFile::exists(aqemuSettingsFolder) )
595 	{
596 		AQError( "bool Update_Emulators_List()",
597 				 QString("Cannot get path for save emulator! Folder \"%1\" not exists!").arg(aqemuSettingsFolder) );
598 		return false;
599 	}
600 
601 	// Get all *.emulators files
602 	QDir emulDir( aqemuSettingsFolder );
603 	QStringList emulFiles = emulDir.entryList( QStringList("*.emulator"), QDir::Files, QDir::Name );
604 
605 	if( emulFiles.isEmpty() )
606 	{
607 		AQWarning( "bool Update_Emulators_List()",
608 				   QString("No emulators found in \"%1\"").arg(aqemuSettingsFolder) );
609 		return false;
610 	}
611 
612 	// Check default emulators
613 	bool qDef = false;
614 
615 	// Load emulators
616 	for( int ex = 0; ex < emulFiles.count(); ++ex )
617 	{
618 		Emulator tmp;
619 
620 		if( ! tmp.Load(aqemuSettingsFolder + emulFiles[ex]) )
621 		{
622 			AQError( "bool Update_Emulators_List()",
623 					 QString("Cannot load emulator from file: \"%1\"").arg(emulFiles[ex]) );
624 			continue;
625 		}
626 
627 		// Default?
628 		if( tmp.Get_Default() )
629 		{
630 			if( qDef )
631 			{
632 				AQWarning( "bool Update_Emulators_List()",
633 						   "Default QEMU emulator already loaded." );
634 				tmp.Set_Default( false );
635 			}
636 			else qDef = true;
637 		}
638 
639 		// Update available options?
640 		if( tmp.Get_Check_Available_Options() )
641 		{
642 			QMap<QString, QString> tmpBinFiles = tmp.Get_Binary_Files();
643 			QMap<QString, Available_Devices> tmpDevMap; // result
644 
645 			for( QMap<QString, QString>::const_iterator it = tmpBinFiles.constBegin(); it != tmpBinFiles.constEnd(); ++it )
646 			{
647 				if( ! it.value().isEmpty() )
648 				{
649 					bool ok = false;
650 					Available_Devices tmpDev = System_Info::Get_Emulator_Info( it.value(), &ok, tmp.Get_Version(), it.key() );
651 
652 					if( ! ok )
653 					{
654 						AQError( "bool Update_Emulators_List()",
655 								 "Cannot set new emulator available options!" );
656 						continue;
657 					}
658 
659 					// Adding device
660 					tmpDevMap[ it.key() ] = tmpDev;
661 				}
662 			}
663 
664 			// Set all devices
665 			tmp.Set_Devices( tmpDevMap );
666 		}
667 
668 		// Check version?
669 		if( tmp.Get_Check_Version() )
670 		{
671 			// Get bin file path
672 			QString binFilePath = "";
673 			QMap<QString, QString> tmpBinFiles = tmp.Get_Binary_Files();
674 			for( QMap<QString, QString>::const_iterator it = tmpBinFiles.constBegin(); it != tmpBinFiles.constEnd(); ++it )
675 			{
676 				if( QFile::exists(it.value()) )
677 				{
678 					binFilePath = it.value();
679 					break;
680 				}
681 			}
682 
683 			if( binFilePath.isEmpty() )
684 			{
685 				AQError( "bool Update_Emulators_List()",
686 						 QString("Cannot find exists emulator binary file for emulator \"%1\"!").arg(tmp.Get_Name()) );
687 			}
688 
689 			// All OK, check version
690 			tmp.Set_Version( System_Info::Get_Emulator_Version(binFilePath) );
691 		}
692 
693 		// Adding emulator
694 		Emulators_List << tmp;
695 	}
696 
697 	// Emulator loaded?
698 	if( Emulators_List.isEmpty() )
699 	{
700 		AQWarning( "bool Update_Emulators_List()",
701 				   "No emulators loaded!" );
702 		return false;
703 	}
704 
705 	// Check defaults
706 	if( qDef == false )
707 	{
708 		for( int ex = 0; ex < Emulators_List.count(); ++ex )
709 	    {
710 		    Emulators_List[ex].Set_Default( true );
711 		    break;
712 		}
713 	}
714 
715 	// All OK
716 	return true;
717 }
718 
Get_Emulators_List()719 const QList<Emulator> &Get_Emulators_List()
720 {
721 	if( Update_Emulators_List() ) return Emulators_List; // FIXME Update
722 	else
723 	{
724 		AQError( "QList<Emulator> Get_Emulators_List()",
725 				 "Cannot Update Emulators List" );
726 		return Empty_Emul_List;
727 	}
728 }
729 
Remove_All_Emulators_Files()730 bool Remove_All_Emulators_Files()
731 {
732 	// Get emulators dir path
733 	QSettings settings;
734 	QFileInfo info( settings.fileName() );
735 	QString aqemuSettingsFolder = info.absoluteDir().absolutePath();
736 	aqemuSettingsFolder += aqemuSettingsFolder.endsWith( QDir::toNativeSeparators("/") )
737 						   ? ""
738 						   : QDir::toNativeSeparators( "/" );
739 
740 	if( ! QFile::exists(aqemuSettingsFolder) )
741 	{
742 		AQError( "bool Remove_All_Emulators_Files()",
743 				 QString("Cannot get path for save emulator! Folder \"%1\" not exists!").arg(aqemuSettingsFolder) );
744 		return false;
745 	}
746 	else
747 	{
748 		// Get all *.emulators files
749 		QDir emulDir( aqemuSettingsFolder );
750 		QStringList emulFiles = emulDir.entryList( QStringList("*.emulator"), QDir::Files, QDir::Name );
751 
752 		bool allFilesRemoved = true;
753 		for( int dx = 0; dx < emulFiles.count(); ++dx )
754 		{
755 			if( ! QFile::remove(aqemuSettingsFolder + emulFiles[dx]) )
756 			{
757 				AQError( "bool Remove_All_Emulators_Files()",
758 						 QString("Cannot delete file \"%1\"!").arg(emulFiles[dx]) );
759 				allFilesRemoved = false;
760 			}
761 		}
762 
763 		return allFilesRemoved;
764 	}
765 }
766 
Get_Default_Emulator()767 const Emulator &Get_Default_Emulator()
768 {
769 	if( Emulators_List.count() <= 0 )
770 		AQError( "const Emulator &Get_Default_Emulator()",
771 				 "Emulator Count == 0" );
772 	else
773 	{
774 		for( int ix = 0; ix < Emulators_List.count(); ix++ )
775 		{
776 			if( Emulators_List[ix].Get_Default() )
777 		    {
778 				return Emulators_List[ ix ];
779 		    }
780 		}
781 	}
782 
783 	AQWarning( "const Emulator &Get_Default_Emulator()",
784 			   "Cannot Find!" );
785 	return Empty_Emul;
786 }
787 
Get_Emulator_By_Name(const QString & name)788 const Emulator &Get_Emulator_By_Name( const QString &name )
789 {
790 	if( Emulators_List.count() <= 0 )
791 		AQError( "const Emulator Get_Emulator_By_Name( const QString &name )",
792 				 "Emulator Count == 0" );
793 	else
794 	{
795 		for( int ix = 0; ix < Emulators_List.count(); ix++ )
796 		{
797 			if( Emulators_List[ix].Get_Name() == name )
798 				return Emulators_List[ ix ];
799 		}
800 	}
801 
802 	AQWarning( "const Emulator Get_Emulator_By_Name( const QString &name )",
803 			   "Cannot Find!" );
804 	return Empty_Emul;
805 }
806 
Get_Random(int min,int max)807 int Get_Random( int min, int max )
808 {
809 	if( min < 0 || max > RAND_MAX || min > max )
810 	{
811 		return -1;
812 	}
813 
814 	qsrand( QTime::currentTime().msec() );
815 
816 	return int( qrand() / (RAND_MAX + 1.0) * (max + 1 - min) + min );
817 }
818 
Load_Recent_Images_List()819 void Load_Recent_Images_List()
820 {
821 	QSettings settings;
822 
823 	// CD
824 	int max_cd = settings.value( "CD_ROM_Existing_Images/Max", "5" ).toString().toInt();
825 
826 	Recent_CD_Images.clear();
827 
828 	for( int ix = 0; ix < max_cd; ++ix )
829 	{
830 		QString tmp = settings.value( "CD_ROM_Existing_Images/item" + QString::number(ix), "" ).toString();
831 
832 		if( ! tmp.isEmpty() ) Recent_CD_Images << tmp;
833 	}
834 
835 	// FDD
836 	int max_fdd = settings.value( "Floppy_Existing_Images/Max", "5" ).toString().toInt();
837 
838 	Recent_FDD_Images.clear();
839 
840 	for( int ix = 0; ix < max_fdd; ++ix )
841 	{
842 		QString tmp = settings.value( "Floppy_Existing_Images/item" + QString::number(ix), "" ).toString();
843 
844 		if( ! tmp.isEmpty() ) Recent_FDD_Images << tmp;
845 	}
846 }
847 
Get_CD_Recent_Images_List()848 const QStringList &Get_CD_Recent_Images_List()
849 {
850 	return Recent_CD_Images;
851 }
852 
Add_To_Recent_CD_Files(const QString & path)853 void Add_To_Recent_CD_Files( const QString &path )
854 {
855 	QSettings settings;
856 	int max = settings.value( "CD_ROM_Existing_Images/Max", "5" ).toString().toInt();
857 
858 	// This Unique Path?
859 	for( int fx = 0; fx < Recent_CD_Images.count() && fx < max; ++fx )
860 	{
861 		if( Recent_CD_Images[fx] == path )
862 		{
863 			AQDebug( "void Add_To_Recent_CD_Files( const QString &path )",
864 					 "CD-ROM Path Not Unique." );
865 
866 			// Up it path in list
867 			if( fx < Recent_CD_Images.count()-1 )
868 			{
869 				// swap items
870 				QString tmp = Recent_CD_Images[ fx+1 ];
871 				Recent_CD_Images[ fx+1 ] = Recent_CD_Images[ fx ];
872 				Recent_CD_Images[ fx ] = tmp;
873 			}
874 			else return;
875 		}
876 	}
877 
878 	// Add to List
879 	if( Recent_CD_Images.count() < max )
880 	{
881 		Recent_CD_Images << path;
882 		settings.setValue( "CD_ROM_Existing_Images/item" + QString::number(Recent_CD_Images.count()-1), path );
883 	}
884 	else
885 	{
886 		// Delete first element and add new to end
887 		for( int ix = 0; ix < Recent_CD_Images.count() -1 && ix < max -1; ++ix )
888 		{
889 			Recent_CD_Images[ ix ] = Recent_CD_Images[ ix +1 ];
890 		}
891 
892 		Recent_CD_Images[ max -1 ] = path;
893 
894 		// Save Items
895 		for( int ix = 0; ix < Recent_CD_Images.count(); ix++ )
896 		{
897 			settings.setValue( "CD_ROM_Existing_Images/item" + QString::number(ix), Recent_CD_Images[ix] );
898 		}
899 	}
900 }
901 
Get_FDD_Recent_Images_List()902 const QStringList &Get_FDD_Recent_Images_List()
903 {
904 	return Recent_FDD_Images;
905 }
906 
Add_To_Recent_FDD_Files(const QString & path)907 void Add_To_Recent_FDD_Files( const QString &path )
908 {
909 	QSettings settings;
910 	int max = settings.value( "Floppy_Existing_Images/Max", "5" ).toString().toInt();
911 
912 	// This Unique Path?
913 	for( int fx = 0; fx < Recent_FDD_Images.count() && fx < max; ++fx )
914 	{
915 		if( Recent_FDD_Images[fx] == path )
916 		{
917 			AQDebug( "void Add_To_Recent_FDD_Files( const QString &path )",
918 					 "Floppy Path Not Unique." );
919 
920 			// Up it path in list
921 			if( fx < Recent_FDD_Images.count()-1 )
922 			{
923 				// swap items
924 				QString tmp = Recent_FDD_Images[ fx+1 ];
925 				Recent_FDD_Images[ fx+1 ] = Recent_FDD_Images[ fx ];
926 				Recent_FDD_Images[ fx ] = tmp;
927 			}
928 			else return;
929 		}
930 	}
931 
932 	// Add to List
933 	if( Recent_FDD_Images.count() < max )
934 	{
935 		Recent_FDD_Images << path;
936 		settings.setValue( "Floppy_Existing_Images/item" + QString::number(Recent_FDD_Images.count()-1), path );
937 	}
938 	else
939 	{
940 		// Delete first element and add new to end
941 		for( int ix = 0; ix < Recent_FDD_Images.count() -1 && ix < max -1; ++ix )
942 		{
943 			Recent_FDD_Images[ ix ] = Recent_FDD_Images[ ix +1 ];
944 		}
945 
946 		Recent_FDD_Images[ max -1 ] = path;
947 
948 		// Save Items
949 		for( int ix = 0; ix < Recent_FDD_Images.count(); ix++ )
950 		{
951 			settings.setValue( "Floppy_Existing_Images/item" + QString::number(ix), Recent_FDD_Images[ix] );
952 		}
953 	}
954 }
955 
956 static bool Show_Error_Window;
957 
Get_Show_Error_Window()958 bool Get_Show_Error_Window()
959 {
960 	return Show_Error_Window;
961 }
962 
Set_Show_Error_Window(bool show)963 void Set_Show_Error_Window( bool show )
964 {
965 	Show_Error_Window = show;
966 }
967 
968 #include <QCheckBox>
969 
Checkbox_Dependend_Set_Enabled(QList<QWidget * > & children_to_enable,QCheckBox * checkbox,bool enabled)970 void Checkbox_Dependend_Set_Enabled(QList<QWidget*>& children_to_enable, QCheckBox* checkbox, bool enabled)
971 {
972     checkbox->setEnabled(enabled);
973 
974     if ( ! checkbox->isChecked() )
975         enabled = false;
976 
977     for( int i = 0; i < children_to_enable.count(); i++)
978         children_to_enable[i]->setEnabled(enabled);
979 }
980 
981 
982