Merge branch 'lm_spe2118' into master_27x

This commit is contained in:
Lukas Matena 2024-01-24 09:54:38 +01:00
commit 31ad7375e5
3 changed files with 216 additions and 140 deletions

View File

@ -29,6 +29,19 @@ WifiConfigDialog::WifiConfigDialog(wxWindow* parent, std::string& file_path, Rem
, out_file_path(file_path) , out_file_path(file_path)
, m_removable_manager(removable_manager) , m_removable_manager(removable_manager)
{ {
// Propagation of error in wifi scanner construtor
if (!m_wifi_scanner->is_init()) {
// TRN Error dialog of configuration -> wifi configuration file
wxString msg = format_wxstr(L"%1%\n\n%2%", _L("Failed to scan wireless networks. Please fill SSID manually."),
#ifdef _WIN32
// TRN Windows specific second line of error dialog of configuration -> wifi configuration file
_L("Library wlanapi.dll was not loaded.")
#else
""
#endif // _WIN32
);
show_error(this, msg);
}
wxPanel* panel = new wxPanel(this); wxPanel* panel = new wxPanel(this);
wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL);
panel->SetSizer(vsizer); panel->SetSizer(vsizer);
@ -188,6 +201,9 @@ void WifiConfigDialog::on_rescan_networks(wxCommandEvent& e)
void WifiConfigDialog::rescan_networks(bool select) void WifiConfigDialog::rescan_networks(bool select)
{ {
assert(m_ssid_combo && m_wifi_scanner); assert(m_ssid_combo && m_wifi_scanner);
// Do not do anything if scanner is in faulty state (which should has been propageted in constructor call)
if (!m_wifi_scanner->is_init())
return;
m_wifi_scanner->scan(); m_wifi_scanner->scan();
std::string current = m_wifi_scanner->get_current_ssid(); std::string current = m_wifi_scanner->get_current_ssid();
const auto& map = m_wifi_scanner->get_map(); const auto& map = m_wifi_scanner->get_map();

View File

@ -8,13 +8,11 @@
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#include <wlanapi.h>
#include <objbase.h> #include <objbase.h>
#include <wtypes.h> #include <wtypes.h>
// Need to link with Wlanapi.lib and Ole32.lib #include "libslic3r//Utils.hpp"
#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "ole32.lib")
#elif __APPLE_ #elif __APPLE_
#include "WifiScannerMac.h" #include "WifiScannerMac.h"
#endif #endif
@ -43,138 +41,6 @@ bool ptree_get_value(const boost::property_tree::ptree& pt, const std::string& t
return false; // Element not found in this subtree return false; // Element not found in this subtree
} }
// 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::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__ #elif __APPLE__
void get_connected_ssid(std::string& connected_ssid) void get_connected_ssid(std::string& connected_ssid)
{ {
@ -395,11 +261,39 @@ void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map)
namespace Slic3r namespace Slic3r
{ {
WifiScanner::WifiScanner() WifiScanner::WifiScanner()
{} {
#ifdef _WIN32
m_wlanapi_handle = LoadLibrary(L"wlanapi.dll");
if (m_wlanapi_handle == NULL)
return;
wlanOpenHandleFunc = reinterpret_cast<WlanOpenHandleFunc>(GetProcAddress(m_wlanapi_handle, "WlanOpenHandle"));
wlanEnumInterfacesFunc = reinterpret_cast<WlanEnumInterfacesFunc>(GetProcAddress(m_wlanapi_handle, "WlanEnumInterfaces"));
wlanQueryInterfaceFunc = reinterpret_cast<WlanQueryInterfaceFunc>(GetProcAddress(m_wlanapi_handle, "WlanQueryInterface"));
wlanFreeMemoryFunc = reinterpret_cast<WlanFreeMemoryFunc>(GetProcAddress(m_wlanapi_handle, "WlanFreeMemory"));
wlanGetProfileFunc = reinterpret_cast<WlanGetProfileFunc>(GetProcAddress(m_wlanapi_handle, "WlanGetProfile"));
wlanGetProfileListFunc = reinterpret_cast<WlanGetProfileListFunc>(GetProcAddress(m_wlanapi_handle, "WlanGetProfileList"));
wlanGetAvailableNetworkListFunc = reinterpret_cast<WlanGetAvailableNetworkListFunc>(GetProcAddress(m_wlanapi_handle, "WlanGetAvailableNetworkList"));
wlanCloseHandleFunc = reinterpret_cast<WlanCloseHandleFunc>(GetProcAddress(m_wlanapi_handle, "WlanCloseHandle"));
if (!wlanOpenHandleFunc || !wlanEnumInterfacesFunc || !wlanQueryInterfaceFunc || !wlanFreeMemoryFunc
|| !wlanGetProfileFunc || !wlanGetProfileListFunc || !wlanGetAvailableNetworkListFunc || !wlanCloseHandleFunc)
return;
#endif // _WIN32
m_init = true;
}
WifiScanner::~WifiScanner() WifiScanner::~WifiScanner()
{} {
#ifdef _WIN32
if (m_wlanapi_handle)
FreeLibrary(m_wlanapi_handle);
#endif // _WIN32
}
void WifiScanner::scan() void WifiScanner::scan()
{ {
if (!m_init)
return;
m_map.clear(); m_map.clear();
#ifdef _WIN32 #ifdef _WIN32
fill_wifi_map(m_map, m_current_ssid); fill_wifi_map(m_map, m_current_ssid);
@ -459,4 +353,140 @@ std::string WifiScanner::get_psk(const std::string& ssid)
} }
return {}; return {};
} }
#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 WifiScanner::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 (!m_init)
return;
if (wlanOpenHandleFunc(client_version, NULL, &supported_version, &handle) != ERROR_SUCCESS)
return;
Slic3r::ScopeGuard guard([this, &handle] { wlanCloseHandleFunc(handle, NULL); });
if (wlanEnumInterfacesFunc(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 (wlanQueryInterfaceFunc(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);
wlanFreeMemoryFunc(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 (wlanGetAvailableNetworkListFunc(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 (wlanGetProfileListFunc(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 = wlanGetProfileFunc(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::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;
wlanFreeMemoryFunc(xmlstr);
break;
}
}
if (profile_list) {
wlanFreeMemoryFunc(profile_list);
}
}
}
if (interface_list)
wlanFreeMemoryFunc(interface_list);
}
#endif // _WIN32
} // Slic3r } // Slic3r

View File

@ -6,9 +6,13 @@
#include <string> #include <string>
#include <wx/string.h> #include <wx/string.h>
#ifdef _WIN32
#include <wlanapi.h>
#endif //_WIN32
namespace Slic3r { namespace Slic3r {
typedef std::map<wxString, std::string> WifiSsidPskMap; using WifiSsidPskMap = std::map<wxString, std::string>;
class WifiScanner class WifiScanner
{ {
@ -16,6 +20,8 @@ public:
WifiScanner(); WifiScanner();
~WifiScanner(); ~WifiScanner();
bool is_init() const { return m_init; }
const WifiSsidPskMap& get_map() const { return m_map; } const WifiSsidPskMap& get_map() const { return m_map; }
// returns psk for given ssid // returns psk for given ssid
// used on APPLE where each psk query requires user to give their password // used on APPLE where each psk query requires user to give their password
@ -27,7 +33,31 @@ public:
private: private:
WifiSsidPskMap m_map; WifiSsidPskMap m_map;
std::string m_current_ssid; std::string m_current_ssid;
#if __APPLE__
bool m_init { false };
#ifdef _WIN32
void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid);
HINSTANCE m_wlanapi_handle;
// Functions of wlanapi used by fill_wifi_map
using WlanOpenHandleFunc = DWORD(WINAPI*)(DWORD, PVOID, PDWORD, PHANDLE);
using WlanEnumInterfacesFunc = DWORD(WINAPI*)(HANDLE, PVOID, PWLAN_INTERFACE_INFO_LIST*);
using WlanQueryInterfaceFunc = DWORD(WINAPI*)(HANDLE, const GUID*, WLAN_INTF_OPCODE, PVOID, PDWORD, PVOID*, PWLAN_OPCODE_VALUE_TYPE);
using WlanFreeMemoryFunc = VOID(WINAPI*)(PVOID);
using WlanGetProfileFunc = DWORD(WINAPI*)(HANDLE, const GUID*, LPCWSTR, PVOID, LPWSTR*, DWORD*, DWORD*);
using WlanGetProfileListFunc = DWORD(WINAPI*)(HANDLE, const GUID*, PVOID, PWLAN_PROFILE_INFO_LIST*);
using WlanGetAvailableNetworkListFunc = DWORD(WINAPI*)(HANDLE, const GUID*, DWORD, PVOID, PWLAN_AVAILABLE_NETWORK_LIST*);
using WlanCloseHandleFunc = DWORD(WINAPI*)(HANDLE, PVOID);
WlanOpenHandleFunc wlanOpenHandleFunc;
WlanEnumInterfacesFunc wlanEnumInterfacesFunc;
WlanQueryInterfaceFunc wlanQueryInterfaceFunc;
WlanFreeMemoryFunc wlanFreeMemoryFunc;
WlanGetProfileFunc wlanGetProfileFunc;
WlanGetProfileListFunc wlanGetProfileListFunc;
WlanGetAvailableNetworkListFunc wlanGetAvailableNetworkListFunc;
WlanCloseHandleFunc wlanCloseHandleFunc;
#elif __APPLE__
void get_ssids_mac(std::vector<std::string>& ssids); void get_ssids_mac(std::vector<std::string>& ssids);
std::string get_psk_mac(const std::string& ssid); std::string get_psk_mac(const std::string& ssid);
std::string get_current_ssid_mac(); std::string get_current_ssid_mac();