| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/scanning/lorgnette_scanner_manager_util.h" |
| |
| #include "base/strings/string_util.h" |
| #include "chromeos/ash/components/dbus/lorgnette/lorgnette_service.pb.h" |
| #include "third_party/re2/src/re2/re2.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| // Regular expressions used to determine whether a device name contains an IPv4 |
| // address or URL. |
| constexpr char kIpv4Pattern[] = R"((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}))"; |
| constexpr char kUrlPattern[] = R"((://))"; |
| |
| // Prefixes of backends that need to be checked for duplicate zeroconf and |
| // lorgnette records. |
| constexpr char kEpsondsNetworkPrefix[] = "epsonds:net:"; |
| constexpr char kEpson2NetworkPrefix[] = "epson2:net:"; |
| |
| // Names of scanner protocol types. |
| constexpr char kMopriaProtocolType[] = "Mopria"; |
| constexpr char kWsdProtocolType[] = "WSD"; |
| |
| } // namespace |
| |
| void ParseScannerName(const std::string& scanner_name, |
| std::string& ip_address_out, |
| ScanProtocol& protocol_out) { |
| if (RE2::PartialMatch(scanner_name, kIpv4Pattern, &ip_address_out) || |
| RE2::PartialMatch(scanner_name, kUrlPattern)) { |
| protocol_out = ScanProtocol::kLegacyNetwork; |
| return; |
| } |
| |
| protocol_out = ScanProtocol::kLegacyUsb; |
| } |
| |
| bool MergeDuplicateScannerRecords(lorgnette::ScannerInfo* scanner_out, |
| Scanner& zeroconf_scanner) { |
| // Currently only epson2 and epsonds are detected by both lorgnette and |
| // zeroconf. |
| if (!scanner_out->name().starts_with(kEpson2NetworkPrefix) && |
| !scanner_out->name().starts_with(kEpsondsNetworkPrefix)) { |
| return false; |
| } |
| |
| auto device_names = |
| zeroconf_scanner.device_names.find(ScanProtocol::kLegacyNetwork); |
| if (device_names == zeroconf_scanner.device_names.end()) { |
| return false; |
| } |
| for (ScannerDeviceName& device_name : device_names->second) { |
| std::string alt_name = device_name.device_name; |
| if (device_name.device_name.starts_with(kEpsondsNetworkPrefix)) { |
| alt_name.replace(0, strlen(kEpsondsNetworkPrefix), kEpson2NetworkPrefix); |
| } else if (device_name.device_name.starts_with(kEpson2NetworkPrefix)) { |
| alt_name.replace(0, strlen(kEpson2NetworkPrefix), kEpsondsNetworkPrefix); |
| } |
| |
| // epson2 and epsonds scanners can be detected through both lorgnette and |
| // zeroconf. When we get two records for the same scanner, we want to |
| // prefer the lorgnette connection info because it is already validated, |
| // but we want to prefer the zeroconf display strings because they match |
| // the information shown in the printer settings page. To get the desired |
| // result, copy the desired fields from the zeroconf record into the |
| // lorgnette record and then disable further use of the zeroconf entry. |
| if (scanner_out->name() == device_name.device_name || |
| scanner_out->name() == alt_name) { |
| scanner_out->set_manufacturer(zeroconf_scanner.manufacturer); |
| scanner_out->set_model(zeroconf_scanner.model); |
| scanner_out->set_display_name(zeroconf_scanner.display_name); |
| if (!zeroconf_scanner.uuid.empty()) { |
| scanner_out->set_device_uuid(zeroconf_scanner.uuid); |
| } |
| device_name.usable = false; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| std::string ProtocolTypeForScanner(const lorgnette::ScannerInfo& scanner) { |
| // sane-airscan implements two protocols. For other backends, just return |
| // the backend name. |
| if (scanner.name().starts_with("airscan:escl:")) { |
| return kMopriaProtocolType; |
| } else if (scanner.name().starts_with("airscan:wsd:")) { |
| return kWsdProtocolType; |
| } else if (scanner.name().starts_with("ippusb:escl:")) { |
| return kMopriaProtocolType; |
| } else { |
| return base::ToLowerASCII( |
| scanner.name().substr(0, scanner.name().find(':'))); |
| } |
| } |
| |
| } // namespace ash |