mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 09:05:59 +08:00
wifi for printer config dialog
Enumerating wifi ssid and psk for win, apple and linux. Win automatically loads password if possible. Apple retrieves password from keychain on button. Apple lists only connected network in some cases (ARM or latest OS wdk). Cmake linking CoreWLAN lib on apple. Result is written on usb drive.
This commit is contained in:
parent
12f735652b
commit
0638b3057f
@ -201,6 +201,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/FirmwareDialog.hpp
|
||||
GUI/PrintHostDialogs.cpp
|
||||
GUI/PrintHostDialogs.hpp
|
||||
GUI/WifiConfigDialog.cpp
|
||||
GUI/WifiConfigDialog.hpp
|
||||
GUI/Jobs/Job.hpp
|
||||
GUI/Jobs/Worker.hpp
|
||||
GUI/Jobs/BoostThreadWorker.hpp
|
||||
@ -304,6 +306,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
Utils/WinRegistry.hpp
|
||||
Utils/WxFontUtils.cpp
|
||||
Utils/WxFontUtils.hpp
|
||||
Utils/WifiScanner.hpp
|
||||
Utils/WifiScanner.cpp
|
||||
)
|
||||
|
||||
find_package(NanoSVG REQUIRED)
|
||||
@ -313,6 +317,8 @@ if (APPLE)
|
||||
Utils/RetinaHelperImpl.mm
|
||||
Utils/MacDarkMode.mm
|
||||
Utils/MacUtils.mm
|
||||
Utils/WifiScannerMac.h
|
||||
Utils/WifiScannerMac.mm
|
||||
GUI/RemovableDriveManagerMM.mm
|
||||
GUI/RemovableDriveManagerMM.h
|
||||
GUI/Mouse3DHandlerMac.mm
|
||||
@ -320,6 +326,7 @@ if (APPLE)
|
||||
GUI/InstanceCheckMac.h
|
||||
)
|
||||
FIND_LIBRARY(DISKARBITRATION_LIBRARY DiskArbitration)
|
||||
FIND_LIBRARY(COREWLAN_LIBRARY CoreWLAN)
|
||||
endif ()
|
||||
|
||||
add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
|
||||
@ -339,7 +346,7 @@ if (MSVC)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES})
|
||||
elseif (APPLE)
|
||||
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
|
||||
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY} ${COREWLAN_LIBRARY})
|
||||
endif()
|
||||
|
||||
if (SLIC3R_STATIC)
|
||||
|
@ -95,6 +95,8 @@
|
||||
#include "DesktopIntegrationDialog.hpp"
|
||||
#include "SendSystemInfoDialog.hpp"
|
||||
#include "Downloader.hpp"
|
||||
#include "PhysicalPrinterDialog.hpp"
|
||||
#include "WifiConfigDialog.hpp"
|
||||
|
||||
#include "BitmapCache.hpp"
|
||||
#include "Notebook.hpp"
|
||||
@ -2446,6 +2448,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
||||
// TODO: for when we're able to flash dictionaries
|
||||
// local_menu->Append(config_id_base + FirmwareMenuDict, _L("Flash Language File"), _L("Upload a language dictionary file into a Prusa printer"));
|
||||
}
|
||||
local_menu->Append(config_id_base + ConfigMenuWifiConfigFile, _L("Wi-Fi Configuration File"), _L("Generate a file to be loaded by a Prusa printer to configure a Wi-Fi connection."));
|
||||
|
||||
local_menu->Bind(wxEVT_MENU, [this, config_id_base](wxEvent &event) {
|
||||
switch (event.GetId() - config_id_base) {
|
||||
@ -2544,6 +2547,16 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
||||
case ConfigMenuFlashFirmware:
|
||||
FirmwareDialog::run(mainframe);
|
||||
break;
|
||||
case ConfigMenuWifiConfigFile:
|
||||
{
|
||||
std::string file_path;
|
||||
WifiConfigDialog dialog(mainframe, file_path, removable_drive_manager());
|
||||
if (dialog.ShowModal() == wxID_OK)
|
||||
{
|
||||
plater_->get_notification_manager()->push_exporting_finished_notification(file_path, boost::filesystem::path(file_path).parent_path().string(), true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ enum ConfigMenuIDs {
|
||||
ConfigMenuLanguage,
|
||||
ConfigMenuFlashFirmware,
|
||||
ConfigMenuCnt,
|
||||
ConfigMenuWifiConfigFile
|
||||
};
|
||||
|
||||
class Tab;
|
||||
|
@ -838,5 +838,4 @@ void PhysicalPrinterDialog::DeletePreset(PresetForPrinter* preset_for_printer)
|
||||
|
||||
update_host_type(true);
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
@ -105,7 +105,6 @@ protected:
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -1095,4 +1095,11 @@ void RemovableDriveManager::eject_thread_finish()
|
||||
}
|
||||
#endif // __APPLE__
|
||||
|
||||
std::vector<DriveData> RemovableDriveManager::get_drive_list()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_drives_mutex);
|
||||
return m_current_drives;
|
||||
}
|
||||
}
|
||||
}} // namespace Slic3r::GUI
|
||||
|
@ -92,7 +92,8 @@ public:
|
||||
// Called by Win32 Volume arrived / detached callback.
|
||||
void volumes_changed();
|
||||
#endif // _WIN32
|
||||
|
||||
// returns copy of m_current_drives (protected by mutex)
|
||||
std::vector<DriveData> get_drive_list();
|
||||
private:
|
||||
bool m_initialized { false };
|
||||
wxEvtHandler* m_callback_evt_handler { nullptr };
|
||||
|
249
src/slic3r/GUI/WifiConfigDialog.cpp
Normal file
249
src/slic3r/GUI/WifiConfigDialog.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
#include "WifiConfigDialog.hpp"
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "format.hpp"
|
||||
#include "RemovableDriveManager.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/button.h>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
WifiConfigDialog::WifiConfigDialog(wxWindow* parent, std::string& file_path, RemovableDriveManager* removable_manager)
|
||||
: DPIDialog(parent, wxID_ANY, _L("Physical Printer Instalation"), wxDefaultPosition, wxDefaultSize/*wxSize(25 * wxGetApp().em_unit(), 20 * wxGetApp().em_unit())*/, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
, m_wifi_scanner(new WifiScanner())
|
||||
, out_file_path(file_path)
|
||||
, m_removable_manager(removable_manager)
|
||||
{
|
||||
const int em = GUI::wxGetApp().em_unit();
|
||||
|
||||
wxPanel* panel = new wxPanel(this);
|
||||
wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL);
|
||||
panel->SetSizer(vsizer);
|
||||
|
||||
auto* ssid_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
// TRN SSID of WiFi network.
|
||||
wxStaticText* ssid_label = new wxStaticText(panel, wxID_ANY, GUI::format_wxstr("%1%:", _L("SSID")));
|
||||
m_ssid_combo = new wxComboBox(panel, wxID_ANY);
|
||||
#if __APPLE__
|
||||
m_ssid_combo->SetToolTip(_L("On some versions of MacOS, this only loads SSID of connencted network."));
|
||||
#endif // __APPLE__
|
||||
rescan_networks(false);
|
||||
wxButton* ssid_button = new wxButton(panel, wxID_ANY, _(L("Rescan")));
|
||||
ssid_sizer->Add(m_ssid_combo, 1, wxALIGN_CENTER_VERTICAL, 10);
|
||||
ssid_sizer->Add(ssid_button, 0);
|
||||
|
||||
auto* pass_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
// TRN Password of WiFi network.
|
||||
wxStaticText* password_label = new wxStaticText(panel, wxID_ANY, GUI::format_wxstr("%1%:", _L("Password")));
|
||||
m_pass_textctrl = new wxTextCtrl(panel, wxID_ANY, "", wxDefaultPosition, wxDefaultSize);
|
||||
pass_sizer->Add(m_pass_textctrl, 1, wxALIGN_CENTER_VERTICAL, 10);
|
||||
#if __APPLE__
|
||||
wxButton* pass_button = new wxButton(panel, wxID_ANY, _(L("Retrieve")));
|
||||
pass_sizer->Add(pass_button, 0);
|
||||
pass_button->Bind(wxEVT_BUTTON, &WifiConfigDialog::on_retrieve_password, this);
|
||||
#endif // __APPLE__
|
||||
// show password if current ssid was selected already
|
||||
fill_password();
|
||||
|
||||
auto* drive_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
// TRN description of Combo Box with path to USB drive.
|
||||
wxStaticText* drive_label = new wxStaticText(panel, wxID_ANY, GUI::format_wxstr("%1%:", _L("Drive")));
|
||||
m_drive_combo = new wxComboBox(panel, wxID_ANY);
|
||||
rescan_drives();
|
||||
wxButton* drive_button = new wxButton(panel, wxID_ANY, _(L("Rescan")));
|
||||
drive_sizer->Add(m_drive_combo, 1, wxALIGN_CENTER_VERTICAL, 10);
|
||||
drive_sizer->Add(drive_button, 0);
|
||||
|
||||
wxButton* ok_button = new wxButton(panel, wxID_OK, _L("Write"));
|
||||
wxButton* cancel_button = new wxButton(panel, wxID_CANCEL);
|
||||
|
||||
auto* grid = new wxFlexGridSizer(2, 15, 15);
|
||||
grid->AddGrowableCol(1);
|
||||
|
||||
grid->Add(ssid_label, 0, wxALIGN_CENTER_VERTICAL);
|
||||
grid->Add(ssid_sizer, 0, wxEXPAND);
|
||||
|
||||
grid->Add(password_label, 0, wxALIGN_CENTER_VERTICAL);
|
||||
grid->Add(pass_sizer, 0, wxEXPAND);
|
||||
|
||||
grid->Add(drive_label, 0, wxALIGN_CENTER_VERTICAL);
|
||||
grid->Add(drive_sizer, 0, wxEXPAND);
|
||||
|
||||
vsizer->Add(grid, 0, wxEXPAND | wxTOP | wxBOTTOM, 15);
|
||||
|
||||
wxBoxSizer* buttons_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
buttons_sizer->Add(ok_button, 1, wxLEFT);
|
||||
buttons_sizer->AddStretchSpacer();
|
||||
buttons_sizer->Add(cancel_button, 1, wxRIGHT);
|
||||
|
||||
vsizer->Add(buttons_sizer, 0, wxEXPAND);
|
||||
|
||||
wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
|
||||
topsizer->Add(panel, 1, wxEXPAND | wxALL, 15);
|
||||
SetSizerAndFit(topsizer);
|
||||
|
||||
ok_button->Bind(wxEVT_BUTTON, &WifiConfigDialog::on_ok, this);
|
||||
m_ssid_combo->Bind(wxEVT_TEXT, &WifiConfigDialog::on_combo, this);
|
||||
drive_button->Bind(wxEVT_BUTTON, &WifiConfigDialog::on_rescan_drives, this);
|
||||
ssid_button->Bind(wxEVT_BUTTON, &WifiConfigDialog::on_rescan_networks, this);
|
||||
}
|
||||
|
||||
WifiConfigDialog::~WifiConfigDialog()
|
||||
{
|
||||
if (m_wifi_scanner)
|
||||
delete m_wifi_scanner;
|
||||
}
|
||||
|
||||
void WifiConfigDialog::on_combo(wxCommandEvent& e)
|
||||
{
|
||||
fill_password();
|
||||
}
|
||||
|
||||
void WifiConfigDialog::fill_password()
|
||||
{
|
||||
assert(m_ssid_combo && m_pass_textctrl && m_wifi_scanner);
|
||||
if (auto it = m_wifi_scanner->get_map().find(m_ssid_combo->GetValue()); it != m_wifi_scanner->get_map().end())
|
||||
m_pass_textctrl->SetValue(boost::nowide::widen(it->second));
|
||||
}
|
||||
|
||||
void WifiConfigDialog::on_retrieve_password(wxCommandEvent& e)
|
||||
{
|
||||
if (m_ssid_combo->GetValue().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string psk = m_wifi_scanner->get_psk(boost::nowide::narrow(m_ssid_combo->GetValue()));
|
||||
if (psk.empty()) {
|
||||
// TRN Alert message when retrieving password for wifi from keychain. Probably will display only on Apple so keychain is MacOS term.
|
||||
wxString msg = _L("No password in the keychain for given SSID.");
|
||||
show_info(nullptr, msg);
|
||||
return;
|
||||
}
|
||||
m_pass_textctrl->SetValue(boost::nowide::widen(psk));
|
||||
}
|
||||
|
||||
void WifiConfigDialog::on_rescan_drives(wxCommandEvent& e)
|
||||
{
|
||||
rescan_drives();
|
||||
}
|
||||
|
||||
void WifiConfigDialog::rescan_drives()
|
||||
{
|
||||
assert(m_drive_combo && m_removable_manager);
|
||||
m_drive_combo->Clear();
|
||||
std::vector<DriveData> ddata = m_removable_manager->get_drive_list();
|
||||
for (const auto& data : ddata) {
|
||||
m_drive_combo->Append(boost::nowide::widen(data.path));
|
||||
}
|
||||
if (m_drive_combo->GetCount() > 0) {
|
||||
m_drive_combo->Select(0);
|
||||
}
|
||||
}
|
||||
|
||||
void WifiConfigDialog::on_rescan_networks(wxCommandEvent& e)
|
||||
{
|
||||
rescan_networks(true);
|
||||
}
|
||||
|
||||
void WifiConfigDialog::rescan_networks(bool select)
|
||||
{
|
||||
assert(m_ssid_combo && m_wifi_scanner);
|
||||
m_wifi_scanner->scan();
|
||||
std::string current = m_wifi_scanner->get_current_ssid();
|
||||
const auto& map = m_wifi_scanner->get_map();
|
||||
m_ssid_combo->Clear();
|
||||
for (const auto pair : map) {
|
||||
m_ssid_combo->Append(pair.first);
|
||||
// select ssid of current network (if connected)
|
||||
if (current == pair.first)
|
||||
m_ssid_combo->Select(m_ssid_combo->GetCount() - 1);
|
||||
}
|
||||
if (m_ssid_combo->GetSelection() == -1 && m_ssid_combo->GetCount() > 0)
|
||||
m_ssid_combo->Select(0);
|
||||
if (select && m_ssid_combo->GetSelection() != -1)
|
||||
fill_password();
|
||||
}
|
||||
|
||||
void WifiConfigDialog::on_ok(wxCommandEvent& e)
|
||||
{
|
||||
assert(m_ssid_combo && m_pass_textctrl);
|
||||
if (m_ssid_combo->GetValue().empty()) {
|
||||
// TRN Alert message when writing WiFi configuration file to usb drive.
|
||||
wxString msg = _L("SSID field is empty.");
|
||||
show_info(nullptr, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string selected_path = boost::nowide::narrow(m_drive_combo->GetValue());
|
||||
|
||||
if (selected_path.empty()) {
|
||||
// TRN Alert message when writing WiFi configuration file to usb drive.
|
||||
wxString msg = _L("Drive field is empty.");
|
||||
show_info(nullptr, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
boost::filesystem::path file_path = boost::filesystem::path(selected_path) / "prusa_printer_settings.ini";
|
||||
|
||||
bool path_on_removable_media = m_removable_manager->set_and_verify_last_save_path(file_path.string());
|
||||
if (!path_on_removable_media) {
|
||||
// TRN Alert message when writing WiFi configuration file to usb drive.
|
||||
wxString msg = _L("Selected path is not on removable media.");
|
||||
show_info(nullptr, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (boost::filesystem::exists(file_path))
|
||||
{
|
||||
wxString msg_text = GUI::format_wxstr("%1% already exists. Do you want to rewrite it?", file_path.string());
|
||||
WarningDialog dialog(m_parent, msg_text, _L("Warning"), wxYES | wxNO);
|
||||
if (dialog.ShowModal() == wxID_NO)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wxString ssid = m_ssid_combo->GetValue();
|
||||
wxString pass = m_pass_textctrl->GetValue();
|
||||
wxString data = GUI::format(
|
||||
"[wifi]\n"
|
||||
"ssid=%1%\n"
|
||||
"psk=%2%\n"
|
||||
, ssid
|
||||
, pass
|
||||
);
|
||||
|
||||
FILE* file;
|
||||
file = fopen(file_path.string().c_str(), "w");
|
||||
if (file == NULL) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to write to file " << file_path;
|
||||
// TODO show error
|
||||
show_error(nullptr, _L("Failed to open file for writing."));
|
||||
return;
|
||||
}
|
||||
fwrite(data.c_str(), 1, data.size(), file);
|
||||
fclose(file);
|
||||
out_file_path = file_path.string();
|
||||
this->EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
void WifiConfigDialog::on_dpi_changed(const wxRect& suggested_rect)
|
||||
{
|
||||
SetFont(wxGetApp().normal_font());
|
||||
|
||||
const int em = em_unit();
|
||||
|
||||
//msw_buttons_rescale(this, em, { wxID_OK, wxID_CANCEL });
|
||||
|
||||
Fit();
|
||||
Refresh();
|
||||
}
|
||||
}}// Slicer::GUI
|
45
src/slic3r/GUI/WifiConfigDialog.hpp
Normal file
45
src/slic3r/GUI/WifiConfigDialog.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef slic3r_WifiConfigDialog_hpp_
|
||||
#define slic3r_WifiConfigDialog_hpp_
|
||||
|
||||
#include "GUI_Utils.hpp"
|
||||
|
||||
#include "../Utils/WifiScanner.hpp"
|
||||
|
||||
#include <wx/event.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/combobox.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
class RemovableDriveManager;
|
||||
class WifiConfigDialog : public DPIDialog
|
||||
{
|
||||
public:
|
||||
WifiConfigDialog(wxWindow* parent, std::string& file_path, RemovableDriveManager* removable_manager);
|
||||
~WifiConfigDialog();
|
||||
private:
|
||||
wxComboBox* m_ssid_combo {nullptr};
|
||||
wxTextCtrl* m_pass_textctrl {nullptr};
|
||||
wxComboBox* m_drive_combo {nullptr};
|
||||
|
||||
void on_ok(wxCommandEvent& e);
|
||||
void on_combo(wxCommandEvent& e);
|
||||
void on_rescan_drives(wxCommandEvent& e);
|
||||
void on_rescan_networks(wxCommandEvent& e);
|
||||
void on_retrieve_password(wxCommandEvent& e);
|
||||
void rescan_drives();
|
||||
void rescan_networks(bool select);
|
||||
void fill_password();
|
||||
// reference to string that is filled after ShowModal is called from owner
|
||||
std::string& out_file_path;
|
||||
WifiScanner* m_wifi_scanner;
|
||||
RemovableDriveManager* m_removable_manager;
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
void on_sys_color_changed() override {}
|
||||
};
|
||||
|
||||
}} // Slicer::GUI
|
||||
#endif
|
459
src/slic3r/Utils/WifiScanner.cpp
Normal file
459
src/slic3r/Utils/WifiScanner.cpp
Normal file
@ -0,0 +1,459 @@
|
||||
#include "WifiScanner.hpp"
|
||||
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/nowide/system.hpp>
|
||||
#include <boost/property_tree/xml_parser.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <wlanapi.h>
|
||||
#include <objbase.h>
|
||||
#include <wtypes.h>
|
||||
|
||||
// Need to link with Wlanapi.lib and Ole32.lib
|
||||
#pragma comment(lib, "wlanapi.lib")
|
||||
#pragma comment(lib, "ole32.lib")
|
||||
#elif __APPLE_
|
||||
#include "WifiScannerMac.h"
|
||||
#endif
|
||||
|
||||
#if __linux__
|
||||
#include <dbus/dbus.h> /* Pull in all of D-Bus headers. */
|
||||
#endif //__linux__
|
||||
|
||||
namespace {
|
||||
bool ptree_get_value(const boost::property_tree::ptree& pt, const std::string& target, std::string& result)
|
||||
{
|
||||
// Check if the current node has the target element
|
||||
if (pt.find(target) != pt.not_found()) {
|
||||
result = pt.get<std::string>(target);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Recursively search child nodes
|
||||
for (const auto& child : pt) {
|
||||
if (ptree_get_value(child.second, target, result)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // Element not found in this subtree
|
||||
}
|
||||
#ifdef _WIN32
|
||||
// Fill SSID map. Implementation from Raspberry Pi imager and Win32 Api examples.
|
||||
// https://github.com/raspberrypi/rpi-imager/blob/qml/src/windows/winwlancredentials.cpp
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlangetavailablenetworklist
|
||||
void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid)
|
||||
{
|
||||
HANDLE handle;
|
||||
DWORD supported_version = 0;
|
||||
DWORD client_version = 2;
|
||||
PWLAN_INTERFACE_INFO_LIST interface_list = NULL;
|
||||
|
||||
|
||||
if (WlanOpenHandle(client_version, NULL, &supported_version, &handle) != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
if (WlanEnumInterfaces(handle, NULL, &interface_list) != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
for (DWORD i = 0; i < interface_list->dwNumberOfItems; i++)
|
||||
{
|
||||
if (interface_list->InterfaceInfo[i].isState == wlan_interface_state_connected)
|
||||
{
|
||||
PWLAN_CONNECTION_ATTRIBUTES pConnectInfo = NULL;
|
||||
DWORD connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES);
|
||||
WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid;
|
||||
|
||||
if (WlanQueryInterface(handle, &interface_list->InterfaceInfo[i].InterfaceGuid,
|
||||
wlan_intf_opcode_current_connection, NULL,
|
||||
&connectInfoSize, (PVOID*)&pConnectInfo, &opCode) == ERROR_SUCCESS && pConnectInfo && pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength)
|
||||
{
|
||||
connected_ssid = std::string((const char*)pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID,
|
||||
pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength);
|
||||
}
|
||||
|
||||
WlanFreeMemory(pConnectInfo);
|
||||
}
|
||||
|
||||
PWLAN_PROFILE_INFO_LIST profile_list = NULL;
|
||||
PWLAN_INTERFACE_INFO interface_info_entry = NULL;
|
||||
PWLAN_AVAILABLE_NETWORK_LIST available_network_list = NULL;
|
||||
WCHAR guid[39] = { 0 };
|
||||
|
||||
// Get all available networks.
|
||||
interface_info_entry = (WLAN_INTERFACE_INFO*)&interface_list->InterfaceInfo[i];
|
||||
int iRet = StringFromGUID2(interface_info_entry->InterfaceGuid, (LPOLESTR)&guid,
|
||||
sizeof(guid) / sizeof(*guid));
|
||||
|
||||
if (WlanGetAvailableNetworkList(handle,
|
||||
&interface_info_entry->InterfaceGuid,
|
||||
0,
|
||||
NULL,
|
||||
&available_network_list)
|
||||
!= ERROR_SUCCESS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (unsigned int j = 0; j < available_network_list->dwNumberOfItems; j++)
|
||||
{
|
||||
PWLAN_AVAILABLE_NETWORK available_network_entry = NULL;
|
||||
wxString ssid;
|
||||
|
||||
// Store SSID into the map.
|
||||
available_network_entry =
|
||||
(WLAN_AVAILABLE_NETWORK*)&available_network_list->Network[j];
|
||||
|
||||
if (available_network_entry->dot11Ssid.uSSIDLength != 0)
|
||||
ssid = wxString(available_network_entry->dot11Ssid.ucSSID,
|
||||
available_network_entry->dot11Ssid.uSSIDLength);
|
||||
|
||||
if (ssid.empty())
|
||||
continue;
|
||||
|
||||
if (wifi_map.find(ssid) != wifi_map.end())
|
||||
continue;
|
||||
|
||||
wifi_map[ssid] = std::string();
|
||||
|
||||
if (WlanGetProfileList(handle, &interface_list->InterfaceInfo[i].InterfaceGuid,
|
||||
NULL, &profile_list) != ERROR_SUCCESS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// enmurate all stored profiles, take password from matching one.
|
||||
for (DWORD k = 0; k < profile_list->dwNumberOfItems; k++)
|
||||
{
|
||||
DWORD flags = WLAN_PROFILE_GET_PLAINTEXT_KEY;
|
||||
DWORD access = 0;
|
||||
DWORD ret = 0;
|
||||
LPWSTR xmlstr = NULL;
|
||||
wxString s(profile_list->ProfileInfo[k].strProfileName);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Enumerating wlan profiles, SSID found:" << s << " looking for:" << ssid;
|
||||
|
||||
if (s != ssid)
|
||||
continue;
|
||||
|
||||
if ((ret = WlanGetProfile(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, profile_list->ProfileInfo[k].strProfileName,
|
||||
NULL, &xmlstr, &flags, &access)) == ERROR_SUCCESS && xmlstr)
|
||||
{
|
||||
wxString xml(xmlstr);
|
||||
boost::property_tree::ptree pt;
|
||||
std::stringstream ss(boost::nowide::narrow(xml));
|
||||
BOOST_LOG_TRIVIAL(error) << ss.str();
|
||||
boost::property_tree::read_xml(ss, pt);
|
||||
std::string password;
|
||||
std::string psk_protected;
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "XML wlan profile:" << xml;
|
||||
|
||||
// break if password is not readable
|
||||
// TODO: what if there is other line "protected" in the XML?
|
||||
if (ptree_get_value(pt, "protected", psk_protected) && psk_protected != "false")
|
||||
break;
|
||||
|
||||
if (ptree_get_value(pt, "keyMaterial", password))
|
||||
wifi_map[ssid] = password;
|
||||
|
||||
WlanFreeMemory(xmlstr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (profile_list) {
|
||||
WlanFreeMemory(profile_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interface_list)
|
||||
WlanFreeMemory(interface_list);
|
||||
WlanCloseHandle(handle, NULL);
|
||||
}
|
||||
#elif __APPLE__
|
||||
void get_connected_ssid(std::string& connected_ssid)
|
||||
{
|
||||
std::string program = "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I";
|
||||
std::string regexpstr = "[ \t]+SSID: (.+)";
|
||||
|
||||
std::ostringstream output;
|
||||
std::string line;
|
||||
|
||||
// Run the process and capture its output
|
||||
FILE* pipe = popen(program.c_str(), "r");
|
||||
if (!pipe) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error executing airport command." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[128];
|
||||
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
|
||||
line = buffer;
|
||||
output << line;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(error) << output.str();
|
||||
pclose(pipe);
|
||||
|
||||
// Process the captured output using regular expressions
|
||||
std::regex rx(regexpstr);
|
||||
std::smatch match;
|
||||
|
||||
std::istringstream outputStream(output.str());
|
||||
while (std::getline(outputStream, line)) {
|
||||
BOOST_LOG_TRIVIAL(error) << line;
|
||||
if (std::regex_search(line, match, rx)) {
|
||||
connected_ssid = match[1].str();
|
||||
// airport -I gets data only about current connection, so only 1 network.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
DBusMessage* dbus_query(DBusConnection* connection, const char* service, const char* object, const char* interface, const char* method)
|
||||
{
|
||||
DBusError error;
|
||||
dbus_error_init(&error);
|
||||
|
||||
DBusMessage* msg = dbus_message_new_method_call(service, object, interface, method);
|
||||
|
||||
DBusMessage* reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, &error);
|
||||
dbus_message_unref(msg);
|
||||
|
||||
if (dbus_error_is_set(&error)) {
|
||||
// todo (debug)
|
||||
BOOST_LOG_TRIVIAL(debug) << "D-Bus method call error: " << error.message << std::endl;
|
||||
dbus_error_free(&error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
// On each access point call method Get on interface org.freedesktop.DBus.Properties to get the ssid
|
||||
void iter_access_points(DBusConnection* connection, DBusMessage* access_points, Slic3r::WifiSsidPskMap& wifi_map)
|
||||
{
|
||||
DBusError error;
|
||||
dbus_error_init(&error);
|
||||
|
||||
DBusMessageIter iter;
|
||||
dbus_message_iter_init(access_points, &iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Error iterating access points reply - not an array.";
|
||||
return;
|
||||
}
|
||||
DBusMessageIter array_iter;
|
||||
dbus_message_iter_recurse(&iter, &array_iter);
|
||||
|
||||
while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_OBJECT_PATH) {
|
||||
const char* object_path;
|
||||
dbus_message_iter_get_basic(&array_iter, &object_path);
|
||||
|
||||
DBusMessage* msg = dbus_message_new_method_call(
|
||||
"org.freedesktop.NetworkManager",
|
||||
object_path,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"Get");
|
||||
|
||||
const char* arg1 = "org.freedesktop.NetworkManager.AccessPoint";
|
||||
const char* arg2 = "Ssid";
|
||||
dbus_message_append_args(
|
||||
msg,
|
||||
DBUS_TYPE_STRING, &arg1,
|
||||
DBUS_TYPE_STRING, &arg2,
|
||||
DBUS_TYPE_INVALID
|
||||
);
|
||||
|
||||
DBusMessage* reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, &error);
|
||||
dbus_message_unref(msg);
|
||||
|
||||
if (dbus_error_is_set(&error)) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "D-Bus method call error: " << error.message << std::endl;
|
||||
dbus_error_free(&error);
|
||||
dbus_message_iter_next(&array_iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
// process reply
|
||||
DBusMessageIter rep_iter;
|
||||
dbus_message_iter_init(reply, &rep_iter);
|
||||
dbus_message_unref(reply);
|
||||
if (dbus_message_iter_get_arg_type(&rep_iter) != DBUS_TYPE_VARIANT) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Reply does not contain a Variant";
|
||||
dbus_message_iter_next(&array_iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
DBusMessageIter variant_iter;
|
||||
dbus_message_iter_recurse(&rep_iter, &variant_iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Variant does not contain an array";
|
||||
dbus_message_iter_next(&array_iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
DBusMessageIter var_array_iter;
|
||||
dbus_message_iter_recurse(&variant_iter, &var_array_iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&var_array_iter) != DBUS_TYPE_BYTE) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Array does not contain bytes";
|
||||
dbus_message_iter_next(&array_iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned char *result;
|
||||
int result_len;
|
||||
|
||||
// Get the array of bytes and its length
|
||||
dbus_message_iter_get_fixed_array(&var_array_iter, &result, &result_len);
|
||||
|
||||
wifi_map[result] = std::string();
|
||||
|
||||
dbus_message_iter_next(&array_iter);
|
||||
}
|
||||
}
|
||||
|
||||
// For each device call method GetAllAccessPoints to get object path to all Access Point objects
|
||||
void iter_devices(DBusConnection* connection, DBusMessage* devices, Slic3r::WifiSsidPskMap& wifi_map)
|
||||
{
|
||||
DBusError error;
|
||||
dbus_error_init(&error);
|
||||
|
||||
DBusMessageIter iter;
|
||||
dbus_message_iter_init(devices, &iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Error iterating devices reply - not an array.";
|
||||
return;
|
||||
}
|
||||
DBusMessageIter array_iter;
|
||||
dbus_message_iter_recurse(&iter, &array_iter);
|
||||
|
||||
while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_OBJECT_PATH) {
|
||||
const char* object_path;
|
||||
dbus_message_iter_get_basic(&array_iter, &object_path);
|
||||
|
||||
// Create a new message to get all access points for this device
|
||||
DBusMessage* reply = dbus_query(
|
||||
connection,
|
||||
"org.freedesktop.NetworkManager", // Service name
|
||||
object_path, // Object path (device path)
|
||||
"org.freedesktop.NetworkManager.Device.Wireless", // Interface for Wi-Fi devices
|
||||
"GetAllAccessPoints" // Method name
|
||||
);
|
||||
if (reply) {
|
||||
iter_access_points(connection, reply, wifi_map);
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
|
||||
dbus_message_iter_next(&array_iter);
|
||||
}
|
||||
}
|
||||
|
||||
// Query NetworkManager for available Wi-Fi.
|
||||
// On org.freedesktop.NetworkManager call method GetAllDevices to get object paths to all device objects.
|
||||
// For each device call method GetAllAccessPoints to get object path to all Access Point objects (iter_devices function here).
|
||||
// On each access point call method Get on interface org.freedesktop.DBus.Properties to get the ssid (iter_access_points function here).
|
||||
void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map)
|
||||
{
|
||||
DBusConnection* connection;
|
||||
DBusError error;
|
||||
dbus_error_init(&error);
|
||||
|
||||
// Connect to the system bus
|
||||
connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
|
||||
|
||||
if (dbus_error_is_set(&error)) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "D-Bus connection error: " << error.message << std::endl;
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
|
||||
//
|
||||
DBusMessage* reply = dbus_query(
|
||||
connection,
|
||||
"org.freedesktop.NetworkManager", // Service name
|
||||
"/org/freedesktop/NetworkManager", // Object path
|
||||
"org.freedesktop.NetworkManager", // Interface
|
||||
"GetAllDevices" // Method name
|
||||
);
|
||||
if (reply) {
|
||||
iter_devices(connection, reply, wifi_map);
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
|
||||
dbus_connection_unref(connection);
|
||||
}
|
||||
#endif //__linux__
|
||||
}
|
||||
namespace Slic3r
|
||||
{
|
||||
WifiScanner::WifiScanner()
|
||||
{}
|
||||
WifiScanner::~WifiScanner()
|
||||
{}
|
||||
void WifiScanner::scan()
|
||||
{
|
||||
m_map.clear();
|
||||
#ifdef _WIN32
|
||||
fill_wifi_map(m_map, m_current_ssid);
|
||||
#elif __APPLE__
|
||||
std::vector<std::string> ssids;
|
||||
try
|
||||
{
|
||||
// Objective-c implementation using CoreWLAN library
|
||||
// This failed to get data at ARM Sonoma
|
||||
get_ssids_mac(ssids);
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Exception caught: Getting SSIDs failed.";
|
||||
}
|
||||
|
||||
for ( const std::string& ssid : ssids)
|
||||
{
|
||||
m_map[boost::nowide::widen(ssid)] = {};
|
||||
}
|
||||
if (m_map.empty()) {
|
||||
try
|
||||
{
|
||||
// Second implementation calling "airport" system command
|
||||
get_connected_ssid(m_current_ssid);
|
||||
m_map[m_current_ssid] = std::string();
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Exception caught: get_connected_ssid failed.";
|
||||
}
|
||||
} else {
|
||||
try
|
||||
{
|
||||
m_current_ssid = get_current_ssid_mac();
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Exception caught: Getting current SSID failed.";
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
fill_wifi_map(m_map);
|
||||
#endif
|
||||
}
|
||||
std::string WifiScanner::get_psk(const std::string& ssid)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
return get_psk_mac(ssid);
|
||||
#endif
|
||||
if (m_map.find(ssid) != m_map.end())
|
||||
{
|
||||
return m_map[ssid];
|
||||
}
|
||||
return {};
|
||||
}
|
||||
} // Slic3r
|
40
src/slic3r/Utils/WifiScanner.hpp
Normal file
40
src/slic3r/Utils/WifiScanner.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef slic3r_WifiScanner_hpp_
|
||||
#define slic3r_WifiScanner_hpp_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
typedef std::map<wxString, std::string> WifiSsidPskMap;
|
||||
|
||||
class WifiScanner
|
||||
{
|
||||
public:
|
||||
WifiScanner();
|
||||
~WifiScanner();
|
||||
|
||||
const WifiSsidPskMap& get_map() const { return m_map; }
|
||||
// returns psk for given ssid
|
||||
// used on APPLE where each psk query requires user to give their password
|
||||
std::string get_psk(const std::string& ssid);
|
||||
const std::string get_current_ssid() { return m_current_ssid; }
|
||||
// fills map with ssid psk couples (or only ssid if no psk)
|
||||
// on APPLE only ssid
|
||||
void scan();
|
||||
private:
|
||||
WifiSsidPskMap m_map;
|
||||
std::string m_current_ssid;
|
||||
#if __APPLE__
|
||||
void get_ssids_mac(std::vector<std::string>& ssids);
|
||||
std::string get_psk_mac(const std::string& ssid);
|
||||
std::string get_current_ssid_mac();
|
||||
void* m_impl_osx { nullptr };
|
||||
#endif
|
||||
};
|
||||
|
||||
} // Slic3r
|
||||
|
||||
#endif
|
21
src/slic3r/Utils/WifiScannerMac.h
Normal file
21
src/slic3r/Utils/WifiScannerMac.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef WiFiScanner_h
|
||||
#define WiFiScanner_h
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
extern "C" {
|
||||
#import <CoreWLAN/CoreWLAN.h>
|
||||
}
|
||||
|
||||
@interface WifiScannerMac : NSObject
|
||||
|
||||
- (instancetype)init;
|
||||
- (void)dealloc;
|
||||
- (NSArray<NSString *> *)scan_ssids;
|
||||
- (NSString *)retrieve_password_for_ssid:(NSString *)ssid;
|
||||
- (NSString *)current_ssid;
|
||||
|
||||
@property (strong, nonatomic) CWInterface *wifiInterface;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* WiFiScanner_h */
|
94
src/slic3r/Utils/WifiScannerMac.mm
Normal file
94
src/slic3r/Utils/WifiScannerMac.mm
Normal file
@ -0,0 +1,94 @@
|
||||
#import "WifiScanner.hpp"
|
||||
#import "WifiScannerMac.h"
|
||||
|
||||
@implementation WifiScannerMac
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
// Create a CWInterface object to work with Wi-Fi interfaces
|
||||
self->_wifiInterface = [CWInterface interface];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSArray *)scan_ssids {
|
||||
NSMutableArray *ssids = [NSMutableArray array];
|
||||
NSError *error = nil;
|
||||
// Retrieve the list of available Wi-Fi networks
|
||||
NSSet<CWNetwork *> *networksSet = [self->_wifiInterface scanForNetworksWithName:nil error:&error];
|
||||
if (error) {
|
||||
return ssids;
|
||||
}
|
||||
NSArray<CWNetwork *> *availableNetworks = [networksSet allObjects];
|
||||
|
||||
// Loop through the list of available networks and store their SSIDs
|
||||
for (CWNetwork *network in availableNetworks) {
|
||||
if (network.ssid != nil)
|
||||
{
|
||||
[ssids addObject:network.ssid];
|
||||
}
|
||||
}
|
||||
return ssids;
|
||||
}
|
||||
|
||||
- (NSString *)retrieve_password_for_ssid:(NSString *)ssid {
|
||||
NSString * psk;
|
||||
OSStatus status = CWKeychainFindWiFiPassword(kCWKeychainDomainSystem, [ssid dataUsingEncoding:NSUTF8StringEncoding], &psk);
|
||||
if (status == errSecSuccess) {
|
||||
return psk;
|
||||
}
|
||||
return @""; // Password not found or an error occurred
|
||||
|
||||
}
|
||||
|
||||
- (NSString *)current_ssid
|
||||
{
|
||||
if (self->_wifiInterface && self->_wifiInterface.ssid != nil) {
|
||||
return self->_wifiInterface.ssid;
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
void WifiScanner::get_ssids_mac(std::vector<std::string>& ssids)
|
||||
{
|
||||
if (!m_impl_osx)
|
||||
m_impl_osx = [[WifiScannerMac alloc] init];
|
||||
if (m_impl_osx) {
|
||||
NSArray *arr = [(id)m_impl_osx scan_ssids];
|
||||
for (NSString* ssid in arr)
|
||||
ssids.push_back(std::string([ssid UTF8String]));
|
||||
}
|
||||
}
|
||||
|
||||
std::string WifiScanner::get_psk_mac(const std::string &ssid)
|
||||
{
|
||||
if (!m_impl_osx)
|
||||
m_impl_osx = [[WifiScannerMac alloc] init];
|
||||
if (m_impl_osx) {
|
||||
NSString *ns_ssid = [NSString stringWithCString:ssid.c_str() encoding:[NSString defaultCStringEncoding]];
|
||||
NSString *psk = [(id)m_impl_osx retrieve_password_for_ssid:ns_ssid];
|
||||
return std::string([psk UTF8String]);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string WifiScanner::get_current_ssid_mac()
|
||||
{
|
||||
if (!m_impl_osx)
|
||||
m_impl_osx = [[WifiScannerMac alloc] init];
|
||||
if (m_impl_osx) {
|
||||
NSString *ssid = [(id)m_impl_osx current_ssid];
|
||||
return std::string([ssid UTF8String]);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user