diff --git a/examples/connmanctl.cpp b/examples/connmanctl.cpp index 64cac59..ad5acec 100644 --- a/examples/connmanctl.cpp +++ b/examples/connmanctl.cpp @@ -22,6 +22,8 @@ using Amarula::DBus::G::Connman::TechProperties; using State = Amarula::DBus::G::Connman::ServProperties::State; using TechnologyType = TechProperties::Type; +constexpr std::size_t MIN_WIFI_PASSPHRASE_LENGTH = 8; + std::atomic has_message{false}; std::ostringstream message; std::mutex message_mutex; @@ -65,7 +67,8 @@ enum class Command : std::uint8_t { Disconnect, Remove, Agent, - Quit + Quit, + Tethering }; inline const std::unordered_map command_map = { @@ -78,7 +81,8 @@ inline const std::unordered_map command_map = { {Command::Disconnect, "disconnect"}, {Command::Remove, "remove"}, {Command::Agent, "agent"}, - {Command::Quit, "quit"}}; + {Command::Quit, "quit"}, + {Command::Tethering, "tether"}}; inline const std::unordered_map tech_map = { {TechnologyType::Ethernet, "ethernet"}, @@ -170,7 +174,8 @@ auto completion(const char* text, int start, int end) -> char** { completion_mode = Mode::OnOff; } else if (command == command_map.at(Command::Enable) || command == command_map.at(Command::Disable) || - command == command_map.at(Command::Scan)) { + command == command_map.at(Command::Scan) || + command == command_map.at(Command::Tethering)) { completion_mode = Mode::TechHash; } else if (command == command_map.at(Command::Connect) || command == command_map.at(Command::Disconnect) || @@ -265,6 +270,10 @@ auto main() -> int { std::string cmd; std::string arg; iss >> cmd >> arg; + auto match_technology = [&arg](const auto& technology) { + const auto props = technology->properties(); + return tech_map.at(props.getType()) == arg; + }; auto match_service = [&arg](const auto& service) { const auto props = service->properties(); const auto name = props.getName(); @@ -362,26 +371,24 @@ auto main() -> int { } } const auto techs = manager->technologies(); - for (const auto& tech : techs) { - const auto props = tech->properties(); + auto iterator = std::ranges::find_if(techs, match_technology); + if (iterator != techs.end()) { + const auto props = (*iterator)->properties(); const auto name = props.getName(); - if (tech_map.at(props.getType()) == arg) { - std::cout << "Scanning " << name << "...\n"; - tech->scan([name](bool success) { - { - std::lock_guard lock(message_mutex); - if (success) { - message << "Technology " << name - << " scanned successfully.\n"; - } else { - message << "Failed to scan technology " << name - << ".\n"; - } + std::cout << "Scanning " << name << "...\n"; + (*iterator)->scan([name](bool success) { + { + std::lock_guard lock(message_mutex); + if (success) { + message << "Technology " << name + << " scanned successfully.\n"; + } else { + message << "Failed to scan technology " << name + << ".\n"; } - has_message = true; - }); - break; - } + } + has_message = true; + }); } } else if (cmd == command_map.at(Command::Enable) || cmd == command_map.at(Command::Disable)) { @@ -403,39 +410,111 @@ auto main() -> int { std::cout << (enable ? "Enabling" : "Disabling") << " technology: " << arg << "\n"; const auto techs = manager->technologies(); - for (const auto& tech : techs) { - const auto props = tech->properties(); + auto iterator = std::ranges::find_if(techs, match_technology); + if (iterator != techs.end()) { + const auto props = (*iterator)->properties(); const auto name = props.getName(); - if (tech_map.at(props.getType()) == arg) { - if ((!props.isPowered() && - cmd == enable_disable_container.at(0)) || - (props.isPowered() && - cmd == enable_disable_container.at(1))) { - std::cout << (enable ? "Enabling " : "Disabling ") - << name << "...\n"; - tech->setPowered(enable, [name, enable](bool success) { - { - std::lock_guard lock(message_mutex); - if (success) { - message - << "Technology " << name + if ((!props.isPowered() && + cmd == enable_disable_container.at(0)) || + (props.isPowered() && + cmd == enable_disable_container.at(1))) { + std::cout << (enable ? "Enabling " : "Disabling ") << name + << "...\n"; + (*iterator)->setPowered(enable, [name, + enable](bool success) { + { + std::lock_guard lock(message_mutex); + if (success) { + message << "Technology " << name << (enable ? " enabled" : " disabled") << " successfully.\n"; - } else { - message << "Failed to " - << (enable ? " enable" : " disable") - << " technology " << name << "\n"; - } + } else { + message << "Failed to " + << (enable ? " enable" : " disable") + << " technology " << name << "\n"; } + } - has_message = true; - }); + has_message = true; + }); - } else { - std::cout << "Technology " << name << " is already " - << (enable ? "enabled" : "disabled") << "\n"; + } else { + std::cout << "Technology " << name << " is already " + << (enable ? "enabled" : "disabled") << "\n"; + } + } + + } else if (cmd == command_map.at(Command::Tethering)) { + std::string arg1; + std::string arg2; + iss >> arg1 >> arg2; + { + std::lock_guard lock(hash_mutex); + if (arg.empty() || + std::find(technologies_container.begin(), + technologies_container.end(), + arg) == technologies_container.end() || + arg1.empty() || + (arg1 != on_off_container[0] && + arg1 != on_off_container[1]) || + (arg == tech_map.at(TechnologyType::Wifi) && + arg1 == on_off_container[0] && arg2.empty())) { + std::cout << "Usage: tether " + << on_off_container[0] << "/" + << on_off_container[1] + << " \n"; + std::cout << "Available technologies:"; + printContainer(technologies_container); + continue; + } + } + const auto techs = manager->technologies(); + auto iterator = std::ranges::find_if(techs, match_technology); + if (iterator != techs.end()) { + if (arg == tech_map.at(TechnologyType::Wifi)) { + std::string arg3; + std::string arg4; + iss >> arg3 >> arg4; + (*iterator)->setTetheringIdentifier(arg2); + + if (!arg3.empty()) { + if (arg3.size() >= MIN_WIFI_PASSPHRASE_LENGTH) { + (*iterator)->setTetheringPassphrase(arg3); + } else { + std::cout << "Error setting wifi passphrase\n" + << "Passphrase must be at least " + << MIN_WIFI_PASSPHRASE_LENGTH + << " characters long\n"; + continue; + } + } + + if (!arg4.empty() && + std::all_of(arg4.begin(), arg4.end(), ::isdigit)) { + (*iterator)->setTetheringFreq(std::stoi(arg4)); } } + + const auto enable = arg1 == on_off_container[0]; + std::cout << (enable ? "Enabling" : "Disabling") + << " tethering on " << arg << "\n"; + (*iterator)->setTethering(enable, [arg, enable](bool success) { + { + std::lock_guard lock(message_mutex); + if (success) { + message << "Tethering on technology " << arg + << (enable ? " enabled" : " disabled") + << " successfully.\n"; + } else { + message << "Failed to" + << (enable ? " enable" : " disable") + << " tethering on " + "technology " + << arg << "\n"; + } + } + has_message = true; + }); } } else if (cmd == command_map.at(Command::Connect) || cmd == command_map.at(Command::Disconnect)) { diff --git a/include/amarula/dbus/connman/gtechnology.hpp b/include/amarula/dbus/connman/gtechnology.hpp index 53010a2..04190fd 100644 --- a/include/amarula/dbus/connman/gtechnology.hpp +++ b/include/amarula/dbus/connman/gtechnology.hpp @@ -29,6 +29,12 @@ struct TechProperties { [[nodiscard]] auto isConnected() const { return connected_; } [[nodiscard]] auto isTethering() const { return tethering_; } [[nodiscard]] auto getTetheringFreq() const { return tethering_freq_; } + [[nodiscard]] auto getTetheringIdentifier() const { + return tethering_identifier_; + } + [[nodiscard]] auto getTetheringPassphrase() const { + return tethering_passphrase_; + } friend auto operator<<(std::ostream& ostr, const TechProperties& object) -> std::ostream&; @@ -37,8 +43,10 @@ struct TechProperties { bool connected_ = false; bool tethering_ = false; std::string name_; + std::string tethering_identifier_; + std::string tethering_passphrase_; Type type_; - int tethering_freq_{0}; + uint32_t tethering_freq_{0}; void update(const gchar* key, GVariant* value); @@ -54,6 +62,13 @@ class Technology : public DBusProxy { public: using Properties = TechProperties; void setPowered(bool powered, PropertiesSetCallback callback = nullptr); + void setTethering(bool tethering, PropertiesSetCallback callback = nullptr); + void setTetheringIdentifier(const std::string& identifier, + PropertiesSetCallback callback = nullptr); + void setTetheringPassphrase(const std::string& passphrase, + PropertiesSetCallback callback = nullptr); + void setTetheringFreq(uint32_t frequency, + PropertiesSetCallback callback = nullptr); void scan(PropertiesSetCallback callback = nullptr); friend class Manager; diff --git a/src/dbus/gconnman_technology.cpp b/src/dbus/gconnman_technology.cpp index 15359ef..e2a5cbc 100644 --- a/src/dbus/gconnman_technology.cpp +++ b/src/dbus/gconnman_technology.cpp @@ -34,6 +34,36 @@ void Technology::setPowered(bool powered, PropertiesSetCallback callback) { &Technology::finishAsyncCall, data.release()); } +void Technology::setTethering(bool tethering, PropertiesSetCallback callback) { + auto data = prepareCallback(std::move(callback)); + setProperty(TETHERING_STR, + g_variant_new_boolean(static_cast(tethering)), + nullptr, &Technology::finishAsyncCall, data.release()); +} + +void Technology::setTetheringIdentifier(const std::string& identifier, + PropertiesSetCallback callback) { + auto data = prepareCallback(std::move(callback)); + setProperty(TETHERINGIDENTIFIER_STR, + g_variant_new_string(identifier.c_str()), nullptr, + &Technology::finishAsyncCall, data.release()); +} + +void Technology::setTetheringPassphrase(const std::string& passphrase, + PropertiesSetCallback callback) { + auto data = prepareCallback(std::move(callback)); + setProperty(TETHERINGPASSPHRASE_STR, + g_variant_new_string(passphrase.c_str()), nullptr, + &Technology::finishAsyncCall, data.release()); +} + +void Technology::setTetheringFreq(const uint32_t frequency, + PropertiesSetCallback callback) { + auto data = prepareCallback(std::move(callback)); + setProperty(TETHERINGFREQ_STR, g_variant_new_uint32(frequency), nullptr, + &Technology::finishAsyncCall, data.release()); +} + void Technology::scan(PropertiesSetCallback callback) { auto data = prepareCallback(std::move(callback)); callMethod(nullptr, SCAN_STR, nullptr, &Technology::finishAsyncCall, @@ -54,6 +84,10 @@ void TechProperties::update(const gchar* key, GVariant* value) { tethering_ = g_variant_get_boolean(value) == 1U; } else if (g_strcmp0(key, TETHERINGFREQ_STR) == 0U) { tethering_freq_ = g_variant_get_int32(value); + } else if (g_strcmp0(key, TETHERINGIDENTIFIER_STR) == 0U) { + tethering_identifier_ = g_variant_get_string(value, nullptr); + } else if (g_strcmp0(key, TETHERINGPASSPHRASE_STR) == 0U) { + tethering_passphrase_ = g_variant_get_string(value, nullptr); } else { LCM_LOG("Unknown property for Technology: " << key << '\n'); } @@ -65,7 +99,13 @@ auto operator<<(std::ostream& ost, const TechProperties& obj) -> std::ostream& { ost << POWERED_STR << ": " << std::boolalpha << obj.powered_ << '\n'; ost << CONNECTED_STR << ": " << std::boolalpha << obj.connected_ << '\n'; ost << TETHERING_STR << ": " << std::boolalpha << obj.tethering_ << '\n'; - ost << TETHERINGFREQ_STR << ": " << obj.tethering_freq_ << " \n"; + if (obj.type_ == TechProperties::Type::Wifi) { + ost << TETHERINGIDENTIFIER_STR << ": " << obj.tethering_identifier_ + << '\n'; + ost << TETHERINGPASSPHRASE_STR << ": " << obj.tethering_passphrase_ + << '\n'; + ost << TETHERINGFREQ_STR << ": " << obj.tethering_freq_ << " \n"; + } return ost; }