mirror of
http://180.163.74.83:13000/zhangzhenghao/write_mac_qt.git
synced 2025-12-12 13:44:29 +00:00
338 lines
12 KiB
C++
338 lines
12 KiB
C++
#include "MainWindow.h"
|
||
#include "NetworkManager.h"
|
||
#include "SshClient.h"
|
||
#include "Logger.h"
|
||
|
||
#include <QVBoxLayout>
|
||
#include <QHBoxLayout>
|
||
#include <QFormLayout>
|
||
#include <QMessageBox>
|
||
#include <QFile>
|
||
#include <QRegularExpression>
|
||
#include <QDateTime>
|
||
#include <QCoreApplication>
|
||
#include <QScreen>
|
||
#include <QGuiApplication>
|
||
|
||
static const char *kInterfacesPath = "/etc/network/interfaces";
|
||
// 尝试在存在参考文件时使用其前缀以保持格式一致
|
||
|
||
MainWindow::MainWindow(QWidget *parent)
|
||
: QMainWindow(parent),
|
||
ipInput(new QLineEdit(this)),
|
||
macInput(new QLineEdit(this)),
|
||
currentMacLabel(new QLabel("当前MAC: 未读取", this)),
|
||
modifyButton(new QPushButton("修改MAC", this)),
|
||
backupButton(new QPushButton("备份文件", this)),
|
||
logView(new QTextEdit(this)),
|
||
useSshCheck(new QCheckBox("使用SSH远程执行", this)),
|
||
sshUserInput(new QLineEdit(this)),
|
||
sshPassInput(new QLineEdit(this)),
|
||
presetPassCombo(new QComboBox(this)),
|
||
connectButton(new QPushButton("连接", this)),
|
||
refreshButton(new QPushButton("刷新", this)),
|
||
netMgr(new NetworkManager(this)),
|
||
sshClient(new SshClient(this)),
|
||
logger(new Logger(this))
|
||
{
|
||
setWindowTitle("MAC修改工具");
|
||
logView->setReadOnly(true);
|
||
|
||
// 根据屏幕分辨率自适应调整日志框大小
|
||
QScreen *screen = QGuiApplication::primaryScreen();
|
||
if (screen) {
|
||
QRect screenGeometry = screen->availableGeometry();
|
||
int screenWidth = screenGeometry.width();
|
||
int screenHeight = screenGeometry.height();
|
||
|
||
// 日志框宽度为屏幕宽度的 25-30%,最小 390px
|
||
int logWidth = qMax(390, static_cast<int>(screenWidth * 0.25));
|
||
// 日志框高度为屏幕高度的 40-50%,最小 410px
|
||
int logHeight = qMax(410, static_cast<int>(screenHeight * 0.4));
|
||
|
||
logView->setMinimumWidth(logWidth);
|
||
logView->setMinimumHeight(logHeight);
|
||
} else {
|
||
// 如果无法获取屏幕信息,使用默认值
|
||
logView->setMinimumWidth(390);
|
||
logView->setMinimumHeight(410);
|
||
}
|
||
|
||
sshPassInput->setEchoMode(QLineEdit::Password);
|
||
|
||
auto *central = new QWidget(this);
|
||
auto *layout = new QVBoxLayout(central);
|
||
|
||
auto *form = new QFormLayout();
|
||
form->addRow("SSH主机/IP", ipInput);
|
||
presetIpCombo = new QComboBox(this);
|
||
presetIpCombo->addItem("自定义");
|
||
presetIpCombo->addItem("圆通");
|
||
presetIpCombo->addItem("拼多多");
|
||
form->addRow("内置IP", presetIpCombo);
|
||
form->addRow("SSH用户", sshUserInput);
|
||
presetPassCombo->addItem("自定义");
|
||
presetPassCombo->addItem("圆通");
|
||
presetPassCombo->addItem("拼多多");
|
||
presetPassCombo->addItem("兔喜");
|
||
form->addRow("内置密码", presetPassCombo);
|
||
form->addRow("登录密码", sshPassInput);
|
||
form->addRow("修改MAC地址", macInput);
|
||
// 在“当前MAC”行右侧添加 连接/刷新 按钮
|
||
QWidget *macButtonsWidget = new QWidget(this);
|
||
auto *macBtnsLayout = new QHBoxLayout(macButtonsWidget);
|
||
macBtnsLayout->setContentsMargins(0,0,0,0);
|
||
macBtnsLayout->addWidget(connectButton);
|
||
macBtnsLayout->addWidget(refreshButton);
|
||
form->addRow(currentMacLabel, macButtonsWidget);
|
||
layout->addLayout(form);
|
||
|
||
auto *btns = new QHBoxLayout();
|
||
btns->addWidget(backupButton);
|
||
btns->addWidget(modifyButton);
|
||
layout->addLayout(btns);
|
||
|
||
layout->addWidget(useSshCheck);
|
||
useSshCheck->setChecked(true);
|
||
useSshCheck->hide();
|
||
connect(useSshCheck, &QCheckBox::toggled, this, &MainWindow::onSshModeToggled);
|
||
|
||
layout->addWidget(new QLabel("日志", this));
|
||
layout->addWidget(logView);
|
||
setCentralWidget(central);
|
||
|
||
connect(modifyButton, &QPushButton::clicked, this, &MainWindow::onModifyClicked);
|
||
connect(backupButton, &QPushButton::clicked, this, &MainWindow::onBackupClicked);
|
||
connect(connectButton, &QPushButton::clicked, this, &MainWindow::onConnectClicked);
|
||
connect(refreshButton, &QPushButton::clicked, this, &MainWindow::onRefreshClicked);
|
||
connect(presetPassCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::onPresetPassChanged);
|
||
connect(presetIpCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::onPresetIpChanged);
|
||
|
||
// 默认使用SSH远程执行,提供占位提示
|
||
useSshCheck->setChecked(true);
|
||
ipInput->setPlaceholderText("例: 10.10.12.12/hostname");
|
||
macInput->setText("90:A9:F7:30:00:00");
|
||
sshUserInput->setText("root");
|
||
sshPassInput->setPlaceholderText("登录密码");
|
||
|
||
updateCurrentMac();
|
||
}
|
||
|
||
MainWindow::~MainWindow() {}
|
||
|
||
void MainWindow::log(const QString &msg) {
|
||
QString ts = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
|
||
QString line = ts + " - " + msg;
|
||
logger->append(msg);
|
||
logView->append(line);
|
||
logView->append("");
|
||
}
|
||
|
||
QString MainWindow::generateMacFromIp(const QString &ip) {
|
||
// 简单示例:固定前缀90:A9:F7:30,根据IP最后两段计算两个字节,末尾固定00
|
||
QRegularExpression re("^(?:\\d{1,3}\\.){3}\\d{1,3}$");
|
||
if (!re.match(ip).hasMatch()) return {};
|
||
auto parts = ip.split('.');
|
||
if (parts.size() != 4) return {};
|
||
bool ok1=false, ok2=false;
|
||
int p2 = parts[2].toInt(&ok1);
|
||
int p3 = parts[3].toInt(&ok2);
|
||
if (!ok1 || !ok2) return {};
|
||
auto toHexByte = [](int v){ v = qBound(0, v, 255); return QString("%1").arg(v,2,16,QChar('0')).toUpper(); };
|
||
QString mac = QString("90:A9:F7:30:%1:%2").arg(toHexByte(p2))
|
||
.arg(toHexByte(p3));
|
||
return mac;
|
||
}
|
||
|
||
bool MainWindow::isValidMac(const QString &mac) const {
|
||
QRegularExpression mre("^[0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2}){5}$");
|
||
return mre.match(mac).hasMatch();
|
||
}
|
||
|
||
void MainWindow::updateCurrentMac() {
|
||
if (useSshCheck->isChecked() && !sshConnected) {
|
||
setCurrentMacStatus("当前MAC: 未连接主机", false);
|
||
return;
|
||
}
|
||
auto mac = netMgr->readCurrentMac(kInterfacesPath);
|
||
if (mac.isEmpty()) {
|
||
setCurrentMacStatus("当前MAC: 未找到或读取失败", false);
|
||
} else {
|
||
setCurrentMacStatus("当前MAC: " + mac, true);
|
||
}
|
||
}
|
||
|
||
void MainWindow::onBackupClicked() {
|
||
QString err;
|
||
|
||
// 检查是否使用 SSH 远程模式
|
||
if (useSshCheck->isChecked()) {
|
||
QString host = ipInput->text().trimmed();
|
||
QString user = sshUserInput->text().trimmed();
|
||
QString password = sshPassInput->text().trimmed();
|
||
|
||
if (host.isEmpty() || user.isEmpty()) {
|
||
QMessageBox::warning(this, "参数错误", "请先填写IP地址和SSH用户名");
|
||
return;
|
||
}
|
||
|
||
// 使用 SshClient 执行远程备份
|
||
SshClient ssh;
|
||
if (!ssh.backupRemoteFile(host, user, password, kInterfacesPath, &err)) {
|
||
QMessageBox::critical(this, "备份失败", err);
|
||
log("备份失败: " + err);
|
||
return;
|
||
}
|
||
|
||
QMessageBox::information(this, "备份完成", "已在远程服务器备份到 " + QString(kInterfacesPath) + ".bak");
|
||
log("已备份远程 interfaces 文件");
|
||
return;
|
||
}
|
||
|
||
// 本地模式
|
||
if (!netMgr->backupFile(kInterfacesPath, &err)) {
|
||
QMessageBox::critical(this, "备份失败", err);
|
||
log("备份失败: " + err);
|
||
return;
|
||
}
|
||
QMessageBox::information(this, "备份完成", "已备份到同目录 .bak 文件");
|
||
log("已备份 interfaces 文件");
|
||
}
|
||
|
||
void MainWindow::onModifyClicked() {
|
||
QString ip = ipInput->text().trimmed();
|
||
QString mac = macInput->text().trimmed();
|
||
if (mac.isEmpty()) mac = generateMacFromIp(ip);
|
||
if (!isValidMac(mac)) {
|
||
QMessageBox::warning(this, "输入错误", "MAC地址格式错误,需形如AA:BB:CC:DD:EE:FF");
|
||
return;
|
||
}
|
||
|
||
if (useSshCheck->isChecked()) {
|
||
// 通过SSH远程执行修改
|
||
QString host = ipInput->text().trimmed();
|
||
QString user = sshUserInput->text().trimmed();
|
||
QString auth = QString("密码");
|
||
QString secret = sshPassInput->text();
|
||
QString err;
|
||
QString refPath = QCoreApplication::applicationDirPath() + "/interfaces";
|
||
QString useRef = QFile::exists(refPath) ? refPath : QString();
|
||
bool ok = sshClient->applyMacRemote(host, user, auth, secret, mac, kInterfacesPath, useRef, &err);
|
||
if (!ok) {
|
||
QMessageBox::critical(this, "远程修改失败", err);
|
||
log("远程修改失败: " + err);
|
||
return;
|
||
}
|
||
QMessageBox::information(this, "远程修改完成", "已通过SSH修改MAC");
|
||
log("远程修改完成");
|
||
if (!err.isEmpty()) log(err);
|
||
onRefreshClicked();
|
||
} else {
|
||
// 本地修改
|
||
QString err;
|
||
if (!netMgr->ensureRootPermission(&err)) {
|
||
QMessageBox::critical(this, "权限不足", err);
|
||
log("权限不足: " + err);
|
||
return;
|
||
}
|
||
QString refPath = QCoreApplication::applicationDirPath() + "/interfaces";
|
||
QString useRef = QFile::exists(refPath) ? refPath : QString();
|
||
if (!netMgr->applyMacLocal(kInterfacesPath, useRef, mac, &err)) {
|
||
QMessageBox::critical(this, "修改失败", err);
|
||
log("修改失败: " + err);
|
||
return;
|
||
}
|
||
QMessageBox::information(this, "修改完成", "MAC地址已更新");
|
||
log("本地修改完成,更新MAC为: " + mac);
|
||
updateCurrentMac();
|
||
}
|
||
}
|
||
|
||
void MainWindow::onConnectClicked() {
|
||
// 连接:尝试读取远程当前MAC
|
||
QString host = ipInput->text().trimmed();
|
||
QString user = sshUserInput->text().trimmed();
|
||
QString secret = sshPassInput->text();
|
||
QString err;
|
||
// 远端读取:复用 applyMacRemote 的读取函数(将实现)
|
||
QString remoteMac;
|
||
if (sshClient->readRemoteCurrentMac(host, user, secret, kInterfacesPath, &remoteMac, &err)) {
|
||
setCurrentMacStatus("当前MAC: " + remoteMac, true);
|
||
log("已连接并读取远程MAC: " + remoteMac);
|
||
sshConnected = true;
|
||
} else {
|
||
QMessageBox::critical(this, "连接失败", err);
|
||
log("连接失败: " + err);
|
||
sshConnected = false;
|
||
setCurrentMacStatus("当前MAC: 未连接主机", false);
|
||
}
|
||
}
|
||
|
||
void MainWindow::onRefreshClicked() {
|
||
// 刷新当前MAC(根据是否使用SSH选择本地或远程)
|
||
if (useSshCheck->isChecked()) {
|
||
QString host = ipInput->text().trimmed();
|
||
QString user = sshUserInput->text().trimmed();
|
||
QString secret = sshPassInput->text();
|
||
QString err;
|
||
QString remoteMac;
|
||
if (sshClient->readRemoteCurrentMac(host, user, secret, kInterfacesPath, &remoteMac, &err)) {
|
||
setCurrentMacStatus("当前MAC: " + remoteMac, true);
|
||
log("已刷新远程MAC: " + remoteMac);
|
||
sshConnected = true;
|
||
} else {
|
||
QMessageBox::warning(this, "刷新失败", err);
|
||
log("刷新失败: " + err);
|
||
sshConnected = false;
|
||
setCurrentMacStatus("当前MAC: 未连接主机", false);
|
||
}
|
||
} else {
|
||
updateCurrentMac();
|
||
log("已刷新本地MAC");
|
||
}
|
||
}
|
||
|
||
void MainWindow::onPresetPassChanged(int idx) {
|
||
switch (idx) {
|
||
case 1:
|
||
sshPassInput->setText("&Over#B0Ost!");
|
||
break;
|
||
case 2:
|
||
sshPassInput->setText("PddloTSecPwdOnly!");
|
||
break;
|
||
case 3:
|
||
sshPassInput->setText("TxApPwd#2025!");
|
||
break;
|
||
default:
|
||
// 自定义:不覆盖用户输入,可选择清空
|
||
// sshPassInput->clear();
|
||
break;
|
||
}
|
||
}
|
||
|
||
void MainWindow::onPresetIpChanged(int idx) {
|
||
switch (idx) {
|
||
case 1:
|
||
ipInput->setText("192.168.172.173");
|
||
break;
|
||
case 2:
|
||
ipInput->setText("10.10.12.12");
|
||
break;
|
||
default:
|
||
// 自定义:不强制覆盖,保留用户当前输入
|
||
break;
|
||
}
|
||
}
|
||
|
||
void MainWindow::onSshModeToggled(bool checked) {
|
||
sshConnected = false;
|
||
updateCurrentMac();
|
||
}
|
||
|
||
void MainWindow::setCurrentMacStatus(const QString &text, bool ok) {
|
||
currentMacLabel->setText(text);
|
||
QPalette pal = currentMacLabel->palette();
|
||
pal.setColor(QPalette::WindowText, ok ? QColor(0, 128, 0) : QColor(200, 0, 0));
|
||
currentMacLabel->setPalette(pal);
|
||
}
|