shill: Move network scanning to capability delegates.

Mostly refactor only. This patch also moves networks_found and scanning
properties registration from the device to the GSM capability delegate.

BUG=chromium-os:18735
TEST=unit tests

Change-Id: I0e3c06cf8320704ef01d8ea3dfa24047c19377d7
Reviewed-on: https://gerrit.chromium.org/gerrit/11482
Commit-Ready: Darin Petkov <petkov@chromium.org>
Reviewed-by: Darin Petkov <petkov@chromium.org>
Tested-by: Darin Petkov <petkov@chromium.org>
diff --git a/cellular_capability_gsm.cc b/cellular_capability_gsm.cc
index 5954a98..74be529 100644
--- a/cellular_capability_gsm.cc
+++ b/cellular_capability_gsm.cc
@@ -5,8 +5,11 @@
 #include "shill/cellular_capability_gsm.h"
 
 #include <base/logging.h>
+#include <base/stl_util-inl.h>
+#include <base/string_number_conversions.h>
 #include <chromeos/dbus/service_constants.h>
 #include <mm/mm-modem.h>
+#include <mobile_provider.h>
 
 #include "shill/cellular.h"
 #include "shill/proxy_factory.h"
@@ -15,9 +18,25 @@
 
 namespace shill {
 
+const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
+    "access-tech";
+const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
+const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
+const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
+    "operator-short";
+const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
+
 CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular)
     : CellularCapability(cellular),
-      task_factory_(this) {}
+      task_factory_(this),
+      scanning_(false),
+      scan_interval_(0) {
+  PropertyStore *store = cellular->mutable_store();
+  store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
+                                 &found_networks_);
+  store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
+  store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
+}
 
 void CellularCapabilityGSM::InitProxies() {
   VLOG(2) << __func__;
@@ -129,6 +148,98 @@
   card_proxy_->ChangePIN(old_pin, new_pin);
 }
 
+void CellularCapabilityGSM::Scan(Error */*error*/) {
+  VLOG(2) << __func__;
+  // Defer because we may be in a dbus-c++ callback.
+  dispatcher()->PostTask(
+      task_factory_.NewRunnableMethod(&CellularCapabilityGSM::ScanTask));
+}
+
+void CellularCapabilityGSM::ScanTask() {
+  VLOG(2) << __func__;
+  // TODO(petkov): Defer scan requests if a scan is in progress already.
+  //
+  // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583). This is a
+  // must for this call which is basically a stub at this point.
+  ModemGSMNetworkProxyInterface::ScanResults results =
+      cellular()->modem_gsm_network_proxy()->Scan();
+  found_networks_.clear();
+  for (ModemGSMNetworkProxyInterface::ScanResults::const_iterator it =
+           results.begin(); it != results.end(); ++it) {
+    found_networks_.push_back(ParseScanResult(*it));
+  }
+}
+
+Stringmap CellularCapabilityGSM::ParseScanResult(
+    const ModemGSMNetworkProxyInterface::ScanResult &result) {
+  Stringmap parsed;
+  for (ModemGSMNetworkProxyInterface::ScanResult::const_iterator it =
+           result.begin(); it != result.end(); ++it) {
+    // TODO(petkov): Define these in system_api/service_constants.h. The
+    // numerical values are taken from 3GPP TS 27.007 Section 7.3.
+    static const char * const kStatusString[] = {
+      "unknown",
+      "available",
+      "current",
+      "forbidden",
+    };
+    static const char * const kTechnologyString[] = {
+      flimflam::kNetworkTechnologyGsm,
+      "GSM Compact",
+      flimflam::kNetworkTechnologyUmts,
+      flimflam::kNetworkTechnologyEdge,
+      "HSDPA",
+      "HSUPA",
+      flimflam::kNetworkTechnologyHspa,
+    };
+    VLOG(2) << "Network property: " << it->first << " = " << it->second;
+    if (it->first == kNetworkPropertyStatus) {
+      int status = 0;
+      if (base::StringToInt(it->second, &status) &&
+          status >= 0 &&
+          status < static_cast<int>(arraysize(kStatusString))) {
+        parsed[flimflam::kStatusProperty] = kStatusString[status];
+      } else {
+        LOG(ERROR) << "Unexpected status value: " << it->second;
+      }
+    } else if (it->first == kNetworkPropertyID) {
+      parsed[flimflam::kNetworkIdProperty] = it->second;
+    } else if (it->first == kNetworkPropertyLongName) {
+      parsed[flimflam::kLongNameProperty] = it->second;
+    } else if (it->first == kNetworkPropertyShortName) {
+      parsed[flimflam::kShortNameProperty] = it->second;
+    } else if (it->first == kNetworkPropertyAccessTechnology) {
+      int tech = 0;
+      if (base::StringToInt(it->second, &tech) &&
+          tech >= 0 &&
+          tech < static_cast<int>(arraysize(kTechnologyString))) {
+        parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
+      } else {
+        LOG(ERROR) << "Unexpected technology value: " << it->second;
+      }
+    } else {
+      LOG(WARNING) << "Unknown network property ignored: " << it->first;
+    }
+  }
+  // If the long name is not available but the network ID is, look up the long
+  // name in the mobile provider database.
+  if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
+       parsed[flimflam::kLongNameProperty].empty()) &&
+      ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
+    mobile_provider *provider =
+        mobile_provider_lookup_by_network(
+            cellular()->provider_db(),
+            parsed[flimflam::kNetworkIdProperty].c_str());
+    if (provider) {
+      const char *long_name = mobile_provider_get_name(provider);
+      if (long_name && *long_name) {
+        parsed[flimflam::kLongNameProperty] = long_name;
+      }
+    }
+  }
+  return parsed;
+}
+
 string CellularCapabilityGSM::GetNetworkTechnologyString() const {
   if (cellular()->gsm_registration_state() ==
       MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||