[shill] Add support for weird Cellular.SimLockStatus property

SimLockStatus is bizarre in that its type is a dictionary that maps
names to values of different types.  It's { string:string,
string:uint32 }, which doesn't fit nicely into dbus-c++, because you
can't represent it trivially with an STL container -- and therefore I
have to do something special to convert it.

BUG=chromium-os:17281
TEST=unit tests
STATUS=Verified

Change-Id: I9c4e43f75c666570caae66e04293bce6207a1b99
Reviewed-on: http://gerrit.chromium.org/gerrit/3619
Reviewed-by: Chris Masone <cmasone@chromium.org>
Tested-by: Chris Masone <cmasone@chromium.org>
diff --git a/cellular.cc b/cellular.cc
index 6ab80b6..251eaf4 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -5,6 +5,8 @@
 #include "shill/cellular.h"
 
 #include <string>
+#include <utility>
+#include <vector>
 
 #include <base/logging.h>
 #include <chromeos/dbus/service_constants.h>
@@ -14,12 +16,73 @@
 #include "shill/device.h"
 #include "shill/device_info.h"
 #include "shill/manager.h"
+#include "shill/property_accessor.h"
 #include "shill/shill_event.h"
 
+using std::make_pair;
 using std::string;
+using std::vector;
 
 namespace shill {
 
+Cellular::Network::Network() {
+  dict_[flimflam::kStatusProperty] = "";
+  dict_[flimflam::kNetworkIdProperty] = "";
+  dict_[flimflam::kShortNameProperty] = "";
+  dict_[flimflam::kLongNameProperty] = "";
+  dict_[flimflam::kTechnologyProperty] = "";
+}
+
+Cellular::Network::~Network() {}
+
+const std::string &Cellular::Network::GetStatus() const {
+  return dict_.find(flimflam::kStatusProperty)->second;
+}
+
+void Cellular::Network::SetStatus(const std::string &status) {
+  dict_[flimflam::kStatusProperty] = status;
+}
+
+const std::string &Cellular::Network::GetId() const {
+  return dict_.find(flimflam::kNetworkIdProperty)->second;
+}
+
+void Cellular::Network::SetId(const std::string &id) {
+  dict_[flimflam::kNetworkIdProperty] = id;
+}
+
+const std::string &Cellular::Network::GetShortName() const {
+  return dict_.find(flimflam::kShortNameProperty)->second;
+}
+
+void Cellular::Network::SetShortName(const std::string &name) {
+  dict_[flimflam::kShortNameProperty] = name;
+}
+
+const std::string &Cellular::Network::GetLongName() const {
+  return dict_.find(flimflam::kLongNameProperty)->second;
+}
+
+void Cellular::Network::SetLongName(const std::string &name) {
+  dict_[flimflam::kLongNameProperty] = name;
+}
+
+const std::string &Cellular::Network::GetTechnology() const {
+  return dict_.find(flimflam::kTechnologyProperty)->second;
+}
+
+void Cellular::Network::SetTechnology(const std::string &technology) {
+  dict_[flimflam::kTechnologyProperty] = technology;
+}
+
+const Stringmap &Cellular::Network::ToDict() const {
+  return dict_;
+}
+
+Cellular::SimLockStatus::SimLockStatus() {}
+
+Cellular::SimLockStatus::~SimLockStatus() {}
+
 Cellular::Cellular(ControlInterface *control_interface,
                    EventDispatcher *dispatcher,
                    Manager *manager,
@@ -51,9 +114,12 @@
   store_.RegisterConstString(flimflam::kModelIDProperty, &model_id_);
   store_.RegisterConstInt16(flimflam::kPRLVersionProperty, &prl_version_);
 
-  // TODO(cmasone): Deal with these compound properties
-  // known_properties_.push_back(flimflam::kSIMLockStatusProperty);
-  // known_properties_.push_back(flimflam::kFoundNetworksProperty);
+  HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
+                                &Cellular::SimLockStatusToProperty,
+                                NULL);
+  HelpRegisterDerivedStringmaps(flimflam::kFoundNetworksProperty,
+                                &Cellular::EnumerateNetworks,
+                                NULL);
 
   store_.RegisterConstBool(flimflam::kScanningProperty, &scanning_);
   store_.RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
@@ -78,4 +144,41 @@
   return type == Device::kCellular;
 }
 
+Stringmaps Cellular::EnumerateNetworks() {
+  Stringmaps to_return;
+  for (vector<Network>::const_iterator it = found_networks_.begin();
+       it != found_networks_.end();
+       ++it) {
+    to_return.push_back(it->ToDict());
+  }
+  return to_return;
+}
+
+StrIntPair Cellular::SimLockStatusToProperty() {
+  return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
+                              sim_lock_status_.lock_type),
+                    make_pair(flimflam::kSIMLockRetriesLeftProperty,
+                              sim_lock_status_.retries_left));
+}
+
+void Cellular::HelpRegisterDerivedStringmaps(
+    const string &name,
+    Stringmaps(Cellular::*get)(void),
+    bool(Cellular::*set)(const Stringmaps&)) {
+  store_.RegisterDerivedStringmaps(
+      name,
+      StringmapsAccessor(
+          new CustomAccessor<Cellular, Stringmaps>(this, get, set)));
+}
+
+void Cellular::HelpRegisterDerivedStrIntPair(
+    const string &name,
+    StrIntPair(Cellular::*get)(void),
+    bool(Cellular::*set)(const StrIntPair&)) {
+  store_.RegisterDerivedStrIntPair(
+      name,
+      StrIntPairAccessor(
+          new CustomAccessor<Cellular, StrIntPair>(this, get, set)));
+}
+
 }  // namespace shill