mirror of
https://github.com/palera1n/palera1n.git
synced 2026-10-21 09:47:01 +02:00
467 lines
11 KiB
C++
467 lines
11 KiB
C++
#ifdef WITH_GUI
|
|
|
|
#include "DfuPanel.hpp"
|
|
|
|
#include "AppFrame.hpp"
|
|
#include "DevicePanel.hpp"
|
|
|
|
#include "../state.hpp"
|
|
#include "../sequence.hpp"
|
|
#include "../utils.h"
|
|
#include "../globals.h"
|
|
#include "../paleinfo.h"
|
|
|
|
#include <thread>
|
|
|
|
#include <wx/wx.h>
|
|
#include <wx/mstream.h>
|
|
#include <wx/image.h>
|
|
#include <wx/bitmap.h>
|
|
|
|
#include "../gen/images/atv_std_brd.h"
|
|
#include "../gen/images/ipad.h"
|
|
#include "../gen/images/ipadmini.h"
|
|
#include "../gen/images/iphone6s.h"
|
|
#include "../gen/images/iphone7.h"
|
|
#include "../gen/images/iphone8.h"
|
|
#include "../gen/images/iphonese.h"
|
|
#include "../gen/images/iphonex.h"
|
|
#include "../gen/images/ipodtouch.h"
|
|
#include "../gen/images/siriremote.h"
|
|
|
|
#include <libirecovery.h>
|
|
|
|
DfuPanel::DfuPanel(MainFrame* frame, wxWindow* parent)
|
|
: DevicePanel(frame, parent)
|
|
{
|
|
Bind(wxEVT_SHOW, &DfuPanel::OnShow, this);
|
|
auto* root = new wxBoxSizer(wxVERTICAL);
|
|
|
|
m_headerText = new wxStaticText(this, wxID_ANY, "Time to put the device into DFU mode. Locate the buttons as marked below\non your device and check the instructions on the right.");
|
|
root->Add(m_headerText, 0, wxALL, 10);
|
|
|
|
auto* contentRow = new wxBoxSizer(wxHORIZONTAL);
|
|
|
|
m_devicePanel = new wxPanel(this);
|
|
m_devicePanel->SetMinSize(wxSize(310, 260));
|
|
|
|
m_deviceImage = new wxStaticBitmap(
|
|
m_devicePanel,
|
|
wxID_ANY,
|
|
wxBitmap()
|
|
);
|
|
|
|
contentRow->Add(m_devicePanel, 1, wxTOP, 10);
|
|
m_stepsSizer = new wxBoxSizer(wxVERTICAL);
|
|
contentRow->Add(m_stepsSizer, 2, wxEXPAND | wxALL, 0);
|
|
|
|
root->Add(contentRow, 1, wxEXPAND);
|
|
|
|
m_backButton = new wxButton(this, wxID_ANY, "Back");
|
|
m_startButton = new wxButton(this, wxID_ANY, "Start");
|
|
|
|
m_backButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
|
|
{
|
|
frame->ShowMain();
|
|
});
|
|
|
|
m_startButton->Bind(wxEVT_BUTTON, [this](wxCommandEvent&)
|
|
{
|
|
m_isEnteringDfu = true;
|
|
m_backButton->Disable();
|
|
m_startButton->Disable();
|
|
|
|
StartSequence(m_sequence);
|
|
});
|
|
|
|
m_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent&)
|
|
{
|
|
RunStep();
|
|
});
|
|
|
|
m_stagnentTimer.Bind(wxEVT_TIMER, [this](wxTimerEvent&)
|
|
{
|
|
m_headerText->SetLabel("Time to put the device into DFU mode. Locate the buttons as marked below\non your device and check the instructions on the right.");
|
|
m_backButton->Enable();
|
|
m_startButton->Enable();
|
|
GetMainFrame()->ShowExploit();
|
|
});
|
|
|
|
auto* bottomRow = new wxBoxSizer(wxHORIZONTAL);
|
|
bottomRow->AddStretchSpacer();
|
|
bottomRow->Add(m_backButton, 0, wxRIGHT | wxLEFT | wxBOTTOM, 12);
|
|
bottomRow->Add(m_startButton, 0, wxRIGHT | wxLEFT | wxBOTTOM, 12);
|
|
|
|
root->Add(bottomRow, 0, wxEXPAND);
|
|
|
|
SetSizer(root);
|
|
}
|
|
|
|
void DfuPanel::SetDeviceState(const DeviceState& state)
|
|
{
|
|
DevicePanel::SetDeviceState(state);
|
|
|
|
if (!(this->IsShown()))
|
|
return;
|
|
|
|
if (m_isEnteringDfu && state.mode == DeviceMode::DFU)
|
|
{
|
|
m_isEnteringDfu = false;
|
|
m_headerText->SetLabel("Device entered DFU mode successfully.\n");
|
|
|
|
m_index = m_sequence.steps.size();
|
|
m_stepRemaining = -1;
|
|
m_actionExecutedIndex = -1;
|
|
|
|
const wxColour kInactive =
|
|
wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
|
|
|
|
for (auto* lbl : m_stepLabels)
|
|
lbl->SetForegroundColour(kInactive);
|
|
|
|
for (auto* lbl : m_buttonLabels)
|
|
lbl->SetForegroundColour(kInactive);
|
|
|
|
if (!m_stagnentTimer.IsRunning())
|
|
m_stagnentTimer.StartOnce(3000);
|
|
}
|
|
|
|
if (m_isEnteringDfu && state.mode == DeviceMode::Normal)
|
|
{
|
|
m_isEnteringDfu = false;
|
|
m_backButton->Enable();
|
|
m_startButton->Enable();
|
|
GetMainFrame()->ShowRecovery();
|
|
GetMainFrame()->GetRecoveryPanel()->SetStatusText("Hmm... It seems like the device didn't enter DFU mode.");
|
|
}
|
|
|
|
if (m_isEnteringDfu && state.mode == DeviceMode::Recovery)
|
|
{
|
|
m_isEnteringDfu = false;
|
|
m_backButton->Enable();
|
|
m_startButton->Enable();
|
|
GetMainFrame()->ShowMain();
|
|
}
|
|
}
|
|
|
|
void DfuPanel::OnShow(wxShowEvent& event)
|
|
{
|
|
if (event.IsShown())
|
|
{
|
|
if (palerain_flags & palerain_option_quick) {
|
|
m_isEnteringDfu = true;
|
|
m_backButton->Disable();
|
|
m_startButton->Disable();
|
|
|
|
StartSequence(m_sequence);
|
|
}
|
|
}
|
|
|
|
DevicePanel::OnShow(event);
|
|
}
|
|
|
|
void DfuPanel::LoadDevice(const std::string& productType)
|
|
{
|
|
const wxColour kActive =
|
|
wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
|
|
|
|
const wxColour kInactive =
|
|
wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
|
|
|
|
m_sequence = ParseSequence(productType);
|
|
m_index = 0;
|
|
|
|
m_deviceImage->SetBitmap(wxBitmap());
|
|
|
|
for (auto* lbl : m_stepLabels)
|
|
lbl->Destroy();
|
|
|
|
m_stepLabels.clear();
|
|
m_stepsSizer->Clear(false);
|
|
|
|
for (auto* lbl : m_buttonLabels)
|
|
lbl->Destroy();
|
|
|
|
m_buttonLabels.clear();
|
|
|
|
const unsigned char* imageData = nullptr;
|
|
size_t imageSize = 0;
|
|
|
|
if (m_sequence.imageName == "ipadmini")
|
|
{
|
|
imageData = images_ipadmini_png;
|
|
imageSize = images_ipadmini_png_len;
|
|
}
|
|
else if (m_sequence.imageName == "ipad")
|
|
{
|
|
imageData = images_ipad_png;
|
|
imageSize = images_ipad_png_len;
|
|
}
|
|
else if (m_sequence.imageName == "iphonese")
|
|
{
|
|
imageData = images_iphonese_png;
|
|
imageSize = images_iphonese_png_len;
|
|
}
|
|
else if (m_sequence.imageName == "iphone6s")
|
|
{
|
|
imageData = images_iphone6s_png;
|
|
imageSize = images_iphone6s_png_len;
|
|
}
|
|
else if (m_sequence.imageName == "iphone7")
|
|
{
|
|
imageData = images_iphone7_png;
|
|
imageSize = images_iphone7_png_len;
|
|
}
|
|
else if (m_sequence.imageName == "iphone8")
|
|
{
|
|
imageData = images_iphone8_png;
|
|
imageSize = images_iphone8_png_len;
|
|
}
|
|
else if (m_sequence.imageName == "iphonex")
|
|
{
|
|
imageData = images_iphonex_png;
|
|
imageSize = images_iphonex_png_len;
|
|
}
|
|
else if (m_sequence.imageName == "ipodtouch")
|
|
{
|
|
imageData = images_ipodtouch_png;
|
|
imageSize = images_ipodtouch_png_len;
|
|
}
|
|
else if (m_sequence.imageName == "siriremote")
|
|
{
|
|
imageData = images_siriremote_png;
|
|
imageSize = images_siriremote_png_len;
|
|
}
|
|
else if (m_sequence.imageName == "atv_std_brd")
|
|
{
|
|
imageData = images_atv_std_brd_png;
|
|
imageSize = images_atv_std_brd_png_len;
|
|
}
|
|
|
|
if (imageData)
|
|
{
|
|
wxMemoryInputStream stream(imageData, imageSize);
|
|
|
|
wxImage img(stream, wxBITMAP_TYPE_PNG);
|
|
|
|
if (img.IsOk())
|
|
{
|
|
img = img.Scale(
|
|
m_sequence.imageWidth,
|
|
m_sequence.imageHeight,
|
|
wxIMAGE_QUALITY_HIGH
|
|
);
|
|
|
|
m_deviceImage->SetBitmap(wxBitmap(img));
|
|
m_deviceImage->SetPosition(wxPoint(m_sequence.imageOffsetX, 0));
|
|
}
|
|
}
|
|
|
|
for (const auto& button : m_sequence.buttons)
|
|
{
|
|
auto* lbl = new wxStaticText(
|
|
m_devicePanel,
|
|
wxID_ANY,
|
|
button.name
|
|
);
|
|
|
|
lbl->SetPosition(wxPoint(button.x, button.y));
|
|
|
|
m_buttonLabels.push_back(lbl);
|
|
}
|
|
|
|
for (size_t i = 0; i < m_sequence.steps.size(); i++)
|
|
{
|
|
const auto& step = m_sequence.steps[i];
|
|
|
|
wxString label = wxString::Format(
|
|
"%zu. %s (%d)",
|
|
i + 1,
|
|
step.description,
|
|
step.duration
|
|
);
|
|
|
|
auto* lbl = new wxStaticText(
|
|
this,
|
|
wxID_ANY,
|
|
label
|
|
);
|
|
|
|
lbl->SetForegroundColour(i == 0 ? kActive : kInactive);
|
|
|
|
m_stepsSizer->Add(lbl, 0, wxBOTTOM, 5);
|
|
m_stepLabels.push_back(lbl);
|
|
}
|
|
|
|
m_devicePanel->Layout();
|
|
m_stepsSizer->Layout();
|
|
|
|
Layout();
|
|
Fit();
|
|
Refresh();
|
|
}
|
|
|
|
void DfuPanel::StartSequence(const DfuSequence& seq)
|
|
{
|
|
m_sequence = seq;
|
|
m_index = 0;
|
|
m_stepRemaining = -1;
|
|
m_actionExecutedIndex = -1;
|
|
|
|
RunStep();
|
|
m_timer.StartOnce(1000);
|
|
}
|
|
|
|
void DfuPanel::RunStep()
|
|
{
|
|
if (m_sequence.steps.empty())
|
|
return;
|
|
|
|
const wxColour kActive =
|
|
wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
|
|
|
|
const wxColour kInactive =
|
|
wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
|
|
|
|
if (m_index >= m_sequence.steps.size())
|
|
{
|
|
for (auto* lbl : m_stepLabels)
|
|
lbl->SetForegroundColour(kInactive);
|
|
|
|
Layout();
|
|
Refresh();
|
|
|
|
m_timer.Stop();
|
|
return;
|
|
}
|
|
|
|
const auto& step = m_sequence.steps[m_index];
|
|
|
|
if (m_stepRemaining < 0)
|
|
m_stepRemaining = step.duration;
|
|
|
|
if (m_stepRemaining > 0)
|
|
--m_stepRemaining;
|
|
|
|
bool finished = (m_stepRemaining == 0);
|
|
size_t completedIndex = m_index;
|
|
|
|
if (finished)
|
|
{
|
|
++m_index;
|
|
m_stepRemaining = -1;
|
|
}
|
|
|
|
for (size_t i = 0; i < m_stepLabels.size(); i++)
|
|
{
|
|
auto* lbl = m_stepLabels[i];
|
|
|
|
if (i == m_index)
|
|
{
|
|
lbl->SetForegroundColour(kActive);
|
|
|
|
lbl->SetLabel(wxString::Format(
|
|
"%zu. %s (%d)",
|
|
i + 1,
|
|
m_sequence.steps[i].description,
|
|
m_stepRemaining < 0 ? m_sequence.steps[i].duration : m_stepRemaining
|
|
));
|
|
}
|
|
else if (finished && i == completedIndex)
|
|
{
|
|
lbl->SetForegroundColour(kInactive);
|
|
|
|
lbl->SetLabel(wxString::Format(
|
|
"%zu. %s (0)",
|
|
i + 1,
|
|
m_sequence.steps[i].description
|
|
));
|
|
}
|
|
else
|
|
{
|
|
lbl->SetForegroundColour(kInactive);
|
|
}
|
|
}
|
|
|
|
for (auto* lbl : m_buttonLabels)
|
|
lbl->SetForegroundColour(kInactive);
|
|
|
|
const auto& activeStep =
|
|
(m_index < m_sequence.steps.size())
|
|
? m_sequence.steps[m_index]
|
|
: m_sequence.steps.back();
|
|
|
|
for (const auto& buttonId : activeStep.activeButtons)
|
|
{
|
|
for (const auto& btn : m_sequence.buttons)
|
|
{
|
|
if (btn.id == buttonId)
|
|
{
|
|
for (auto* lbl : m_buttonLabels)
|
|
{
|
|
if (lbl->GetLabel() == btn.name)
|
|
lbl->SetForegroundColour(kActive);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_index < m_sequence.steps.size())
|
|
{
|
|
const auto& activeStep = m_sequence.steps[m_index];
|
|
|
|
if (!activeStep.action.empty() && m_actionExecutedIndex != m_index)
|
|
{
|
|
m_actionExecutedIndex = m_index;
|
|
|
|
if (activeStep.action == "reboot")
|
|
{
|
|
Reboot();
|
|
}
|
|
}
|
|
}
|
|
|
|
Layout();
|
|
Refresh();
|
|
Update();
|
|
|
|
m_timer.StartOnce(1000);
|
|
}
|
|
|
|
void DfuPanel::Reboot()
|
|
{
|
|
std::thread([this]()
|
|
{
|
|
const auto state = GetDeviceState();
|
|
|
|
if (!state.connected || state.mode != DeviceMode::Recovery)
|
|
return;
|
|
|
|
irecv_client_t client = nullptr;
|
|
|
|
int attempts = 0;
|
|
const int max_attempts = 8;
|
|
|
|
while (attempts < max_attempts)
|
|
{
|
|
if (irecv_open_with_ecid(&client, state.ecid) == IRECV_E_SUCCESS)
|
|
break;
|
|
|
|
attempts++;
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
|
}
|
|
|
|
if (!client)
|
|
{
|
|
return;
|
|
}
|
|
irecv_setenv(client, "auto-boot", "true");
|
|
irecv_saveenv(client);
|
|
irecv_reboot(client);
|
|
|
|
irecv_close(client);
|
|
}).detach();
|
|
}
|
|
|
|
#endif // WITH_GUI
|