From 4d8e7bd24edc6377ccbc2e5a94b999e6975c3482 Mon Sep 17 00:00:00 2001 From: cold-brewed <47337035+cold-brewed@users.noreply.github.com> Date: Fri, 29 Mar 2024 08:23:55 -0400 Subject: [PATCH] qt: Add UUID features, MAC address configuration, machine move detection --- src/86box.c | 1 + src/config.c | 11 ++++++++ src/device.c | 3 +-- src/include/86box/86box.h | 12 ++++++--- src/qt/qt_deviceconfig.cpp | 39 ++++++++++++++++++++++++++++ src/qt/qt_main.cpp | 21 +++++++++++++++ src/qt/qt_util.cpp | 53 ++++++++++++++++++++++++++++++++++++++ src/qt/qt_util.hpp | 5 ++++ 8 files changed, 139 insertions(+), 6 deletions(-) diff --git a/src/86box.c b/src/86box.c index 88229a820..67d0bb165 100644 --- a/src/86box.c +++ b/src/86box.c @@ -206,6 +206,7 @@ int video_fullscreen_scale_maximized = 0; /* (C) Whether also apply when maximized. */ int do_auto_pause = 0; /* (C) Auto-pause the emulator on focus loss */ +char uuid[MAX_UUID_LEN] = { '\0' }; /* (C) UUID or machine identifier */ /* Statistics. */ extern int mmuflush; diff --git a/src/config.c b/src/config.c index da02a93b0..95d23cea3 100644 --- a/src/config.c +++ b/src/config.c @@ -209,6 +209,12 @@ load_general(void) ini_section_delete_var(cat, "window_coordinates"); do_auto_pause = ini_section_get_int(cat, "do_auto_pause", 0); + + p = ini_section_get_string(cat, "uuid", NULL); + if (p != NULL) + strncpy(uuid, p, sizeof(uuid) - 1); + else + strncpy(uuid, "", sizeof(uuid) - 1); } /* Load monitor section. */ @@ -1878,6 +1884,11 @@ save_general(void) else ini_section_delete_var(cat, "do_auto_pause"); + if (strnlen(uuid, sizeof(uuid) - 1) > 0) + ini_section_set_string(cat, "uuid", uuid); + else + ini_section_delete_var(cat, "uuid"); + ini_delete_section_if_empty(config, cat); } diff --git a/src/device.c b/src/device.c index b934e7246..321f105e5 100644 --- a/src/device.c +++ b/src/device.c @@ -467,8 +467,7 @@ device_has_config(const device_t *dev) config = dev->config; while (config->type != -1) { - if (config->type != CONFIG_MAC) - c++; + c++; config++; } diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index b34b95621..3f5f3f2ab 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -35,6 +35,9 @@ #define MAX_PREV_IMAGES 4 #define MAX_IMAGE_PATH_LEN 2048 +/* Max UUID Length */ +#define MAX_UUID_LEN 64 + /* Default language 0xFFFF = from system, 0x409 = en-US */ #define DEFAULT_LANGUAGE 0x0409 @@ -167,10 +170,11 @@ extern uint16_t key_prefix_2_2; extern uint16_t key_uncapture_1; extern uint16_t key_uncapture_2; -extern char exe_path[2048]; /* path (dir) of executable */ -extern char usr_path[1024]; /* path (dir) of user data */ -extern char cfg_path[1024]; /* full path of config file */ -extern int open_dir_usr_path; /* default file open dialog directory of usr_path */ +extern char exe_path[2048]; /* path (dir) of executable */ +extern char usr_path[1024]; /* path (dir) of user data */ +extern char cfg_path[1024]; /* full path of config file */ +extern int open_dir_usr_path; /* default file open dialog directory of usr_path */ +extern char uuid[MAX_UUID_LEN]; /* UUID or machine identifier */ #ifndef USE_NEW_DYNAREC extern FILE *stdlog; /* file to log output to */ #endif diff --git a/src/qt/qt_deviceconfig.cpp b/src/qt/qt_deviceconfig.cpp index 6c7db0f3d..d2ae70245 100644 --- a/src/qt/qt_deviceconfig.cpp +++ b/src/qt/qt_deviceconfig.cpp @@ -29,7 +29,9 @@ #include #include #include +#include #include +#include extern "C" { #include <86box/86box.h> @@ -38,6 +40,7 @@ extern "C" { #include <86box/device.h> #include <86box/midi_rtmidi.h> #include <86box/mem.h> +#include <86box/random.h> #include <86box/rom.h> } @@ -116,6 +119,7 @@ DeviceConfig::ConfigureDevice(const _device_ *device, int instance, Settings *se device_set_context(&device_context, device, instance); auto device_label = new QLabel(device->name); + device_label->setAlignment(Qt::AlignCenter); dc.ui->formLayout->addRow(device_label); auto line = new QFrame; line->setFrameShape(QFrame::HLine); @@ -291,6 +295,33 @@ DeviceConfig::ConfigureDevice(const _device_ *device, int instance, Settings *se cbox->setCurrentIndex(currentIndex); break; } + case CONFIG_MAC: + { + // QHBoxLayout for the line edit widget and the generate button + auto hboxLayout = new QHBoxLayout(); + auto generateButton = new QPushButton(tr("Generate")); + auto lineEdit = new QLineEdit; + // Allow the line edit to expand and fill available space + lineEdit->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Preferred); + lineEdit->setInputMask("HH:HH:HH;0"); + lineEdit->setObjectName(config->name); + // Display the current or generated MAC in uppercase + // When stored it will be converted to lowercase + if (config_get_mac(device_context.name, config->name, config->default_int) & 0xFF000000) { + lineEdit->setText(QString::asprintf("%02X:%02X:%02X", random_generate(), random_generate(), random_generate())); + } else { + auto current_mac = QString(config_get_string(device_context.name, config->name, const_cast(config->default_string))); + lineEdit->setText(current_mac.toUpper()); + } + // Action for the generate button + connect(generateButton, &QPushButton::clicked, [lineEdit] { + lineEdit->setText(QString::asprintf("%02X:%02X:%02X", random_generate(), random_generate(), random_generate())); + }); + hboxLayout->addWidget(lineEdit); + hboxLayout->addWidget(generateButton); + dc.ui->formLayout->addRow(config->description, hboxLayout); + break; + } } ++config; } @@ -362,6 +393,14 @@ DeviceConfig::ConfigureDevice(const _device_ *device, int instance, Settings *se config_set_int(device_context.name, const_cast(config->name), spinBox->value()); break; } + case CONFIG_MAC: + { + const auto *lineEdit = dc.findChild(config->name); + // Store the mac address as lowercase + auto macText = lineEdit->displayText().toLower(); + config_set_string(device_context.name, config->name, macText.toUtf8().constData()); + break; + } } config++; } diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index a621d1441..78eaff5e9 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef QT_STATIC /* Static builds need plugin imports */ @@ -71,6 +72,7 @@ extern "C" { #include "cocoa_mouse.hpp" #include "qt_styleoverride.hpp" #include "qt_unixmanagerfilter.hpp" +#include "qt_util.hpp" // Void Cast #define VC(x) const_cast(x) @@ -220,6 +222,25 @@ main(int argc, char *argv[]) return 6; } + // UUID / copy / move detection + if(!util::compareUuid()) { + QMessageBox movewarnbox; + movewarnbox.setIcon(QMessageBox::Icon::Warning); + movewarnbox.setText("This machine might have been moved or copied."); + movewarnbox.setInformativeText("In order to ensure proper networking functionality, 86Box needs to know if this machine was moved or copied.\n\nSelect \"I Copied It\" if you are not sure."); + const QPushButton *movedButton = movewarnbox.addButton(QObject::tr("I Moved It"), QMessageBox::AcceptRole); + const QPushButton *copiedButton = movewarnbox.addButton(QObject::tr("I Copied It"), QMessageBox::DestructiveRole); + QPushButton *cancelButton = movewarnbox.addButton(QObject::tr("Cancel"), QMessageBox::RejectRole); + movewarnbox.setDefaultButton(cancelButton); + movewarnbox.exec(); + if (movewarnbox.clickedButton() == copiedButton) { + util::storeCurrentUuid(); + util::generateNewMacAdresses(); + } else if (movewarnbox.clickedButton() == movedButton) { + util::storeCurrentUuid(); + } + } + #ifdef Q_OS_WINDOWS # if !defined(EMU_BUILD_NUM) || (EMU_BUILD_NUM != 5624) HWND winbox = FindWindow("TWinBoxMain", NULL); diff --git a/src/qt/qt_util.cpp b/src/qt/qt_util.cpp index b05b656bb..0a59cdf5d 100644 --- a/src/qt/qt_util.cpp +++ b/src/qt/qt_util.cpp @@ -21,8 +21,20 @@ #if QT_VERSION <= QT_VERSION_CHECK(5, 14, 0) # include #endif +#include #include "qt_util.hpp" +extern "C" { +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/device.h> +#include <86box/ini.h> +#include <86box/random.h> +#include <86box/thread.h> +#include <86box/timer.h> +#include <86box/network.h> +} + namespace util { QScreen * screenOfWidget(QWidget *widget) @@ -56,4 +68,45 @@ DlgFilter(std::initializer_list extensions, bool last) return " (" % temp.join(' ') % ")" % (!last ? ";;" : ""); } +QString currentUuid() +{ + return QUuid::createUuidV5(QUuid{}, QString(usr_path)).toString(QUuid::WithoutBraces); +} + +bool compareUuid() +{ + // A uuid not set in the config file will have a zero length. + // Any uuid that is lower than the minimum length will be considered invalid + // and a new one will be generated + if (const auto currentUuidLength = QString(uuid).length(); currentUuidLength < UUID_MIN_LENGTH) { + storeCurrentUuid(); + return true; + } + // The uuid appears to be a valid, at least by length. + // Compare with a simple string match + return uuid == currentUuid(); +} + +void +storeCurrentUuid() +{ + strncpy(uuid, currentUuid().toUtf8().constData(), sizeof(uuid) - 1); +} + +void +generateNewMacAdresses() +{ + for (int i = 0; i < NET_CARD_MAX; ++i) { + auto net_card = net_cards_conf[i]; + if (net_card.device_num != 0) { + const auto network_device = network_card_getdevice(net_card.device_num); + device_context_t device_context; + + device_set_context(&device_context, network_device, i+1); + auto generatedMac = QString::asprintf("%02X:%02X:%02X", random_generate(), random_generate(), random_generate()).toLower(); + config_set_string(device_context.name, "mac", generatedMac.toUtf8().constData()); + } + } +} + } diff --git a/src/qt/qt_util.hpp b/src/qt/qt_util.hpp index 6ecd904b3..07e44b621 100644 --- a/src/qt/qt_util.hpp +++ b/src/qt/qt_util.hpp @@ -8,10 +8,15 @@ class QScreen; namespace util { +static constexpr auto UUID_MIN_LENGTH = 36; /* Creates extension list for qt filedialog */ QString DlgFilter(std::initializer_list extensions, bool last = false); /* Returns screen the widget is on */ QScreen *screenOfWidget(QWidget *widget); +QString currentUuid(); +void storeCurrentUuid(); +bool compareUuid(); +void generateNewMacAdresses(); }; #endif