// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "service-cellular/RequestFactory.hpp" #include #include #include #include "service-cellular/requests/CallRequest.hpp" #include "service-cellular/requests/SupplementaryServicesRequest.hpp" #include "service-cellular/requests/PasswordRegistrationRequest.hpp" #include "service-cellular/requests/PinChangeRequest.hpp" #include "service-cellular/requests/ImeiRequest.hpp" #include "service-cellular/requests/UssdRequest.hpp" #include "service-cellular/requests/RejectRequest.hpp" #include #include #include namespace cellular { RequestFactory::RequestFactory(const std::string &data, at::BaseChannel &channel, cellular::api::CallMode callMode, bool simInserted) : request(data), channel(channel), callMode(callMode), simInserted(simInserted) { registerRequest(ImeiRegex, ImeiRequest::create, SimRequirement::NotRequired); registerRequest(PasswordRegistrationRegex, PasswordRegistrationRequest::create); registerRequest(PinChangeRegex, PinChangeRequest::create); registerRequest(SupplementaryServicesRegex, SupplementaryServicesRequest::create); /* It has to be last check due to 3GPP TS 22.030 */ registerRequest(UssdRegex, UssdRequest::create); } void RequestFactory::registerRequest(const std::string ®ex, const CreateCallback &callback, SimRequirement simRequirement) { requestMap.emplace_back(std::make_tuple(regex, callback, simRequirement)); } std::unique_ptr RequestFactory::emergencyCheck() { at::cmd::QECCNUM cmd; auto qeccnumResult = channel.cmd(cmd); auto qeccnumResponse = cmd.parseQECCNUM(qeccnumResult); auto isSimEmergency = std::find(qeccnumResponse.eccNumbersSim.begin(), qeccnumResponse.eccNumbersSim.end(), request) != qeccnumResponse.eccNumbersSim.end(); auto isNoSimEmergency = std::find(qeccnumResponse.eccNumbersNoSim.begin(), qeccnumResponse.eccNumbersNoSim.end(), request) != qeccnumResponse.eccNumbersNoSim.end(); if (isSimEmergency || isNoSimEmergency) { if (simInserted || isNoSimEmergency) { return std::make_unique(request); } return std::make_unique(RejectRequest::RejectReason::NoSim, request); } else if (callMode == cellular::api::CallMode::Emergency) { return std::make_unique(RejectRequest::RejectReason::NotAnEmergencyNumber, request); } return nullptr; } bool RequestFactory::isConnectedToNetwork() { const at::Cmd buildCmd = at::factory(at::AT::COPS) + "?"; auto resp = channel.cmd(buildCmd); at::response::cops::CurrentOperatorInfo ret; if ((resp.code == at::Result::Code::OK) && (at::response::parseCOPS(resp, ret))) { return ret.getOperator().has_value(); } return false; } std::unique_ptr RequestFactory::create() { if (auto req = emergencyCheck(); req != nullptr) { return req; } std::string groupA, groupB, groupC, groupD, groupE, groupF; GroupMatch matchPack = {groupA, groupB, groupC, groupD, groupE, groupF}; std::vector results; for (const auto &element : requestMap) { const auto [regex, requestCreateCallback, simRequirement] = element; const re2::StringPiece input(request); const re2::RE2 reg(regex); std::vector reArguments; std::vector reArgumentPtrs; const std::size_t numberOfGroups = reg.NumberOfCapturingGroups(); if (numberOfGroups > matchPack.size()) { LOG_ERROR("Internal error, GroupMatch has to be redefined."); break; } reArguments.resize(numberOfGroups); reArgumentPtrs.resize(numberOfGroups); results.resize(numberOfGroups); for (std::size_t i = 0; i < numberOfGroups; ++i) { /// Bind RE arguments to strings from vector. reArguments[i] = &matchPack[i].get(); /// Assign pointers to arguments. reArgumentPtrs[i] = &reArguments[i]; } if (re2::RE2::FullMatchN(input, reg, reArgumentPtrs.data(), static_cast(numberOfGroups))) { if ((simRequirement == SimRequirement::Required) && !simInserted) { return std::make_unique(RejectRequest::RejectReason::NoSim, request); } try { if (auto req = requestCreateCallback(request, matchPack)) { return req; } } catch (const std::runtime_error &except) { LOG_ERROR("Failed to create MMI request. Error message: %s", except.what()); } } } if (!simInserted) { return std::make_unique(RejectRequest::RejectReason::NoSim, request); } const auto isRegisteredToNetwork = isConnectedToNetwork(); if (!isRegisteredToNetwork) { return std::make_unique(RejectRequest::RejectReason::NoNetworkConnection, request); } return std::make_unique(request); } } // namespace cellular