[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/accessor_interface.h b/accessor_interface.h
index dfaf0fb..3a62696 100644
--- a/accessor_interface.h
+++ b/accessor_interface.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <string>
 #include <tr1/memory>
+#include <utility>
 #include <vector>
 
 #include <base/basictypes.h>
@@ -34,8 +35,35 @@
   DISALLOW_COPY_AND_ASSIGN(AccessorInterface);
 };
 
+// This class stores two dissimilar named properties, one named string
+// property and one named unsigned integer property.
+class StrIntPair {
+ public:
+  StrIntPair() {}
+  StrIntPair(std::pair<std::string, std::string> string_prop,
+             std::pair<std::string, uint32> uint_prop) {
+    string_property_[string_prop.first] = string_prop.second;
+    uint_property_[uint_prop.first] = uint_prop.second;
+  }
+  ~StrIntPair() {}
+
+  const std::map<std::string, std::string> &string_property() const {
+    return string_property_;
+  }
+  const std::map<std::string, uint32> &uint_property() const {
+    return uint_property_;
+  }
+
+ private:
+  // These are stored as maps because it's way easier to coerce them to
+  // the right DBus types than if they were pairs.
+  std::map<std::string, std::string> string_property_;
+  std::map<std::string, uint32> uint_property_;
+};
+
 typedef std::vector<std::string> Strings;
 typedef std::map<std::string, std::string> Stringmap;
+typedef std::vector<Stringmap> Stringmaps;
 
 // Using a smart pointer here allows pointers to classes derived from
 // AccessorInterface<> to be stored in maps and other STL container types.
@@ -44,7 +72,9 @@
 typedef std::tr1::shared_ptr<AccessorInterface<int32> > Int32Accessor;
 typedef std::tr1::shared_ptr<AccessorInterface<std::string> > StringAccessor;
 typedef std::tr1::shared_ptr<AccessorInterface<Stringmap> > StringmapAccessor;
+typedef std::tr1::shared_ptr<AccessorInterface<Stringmaps> > StringmapsAccessor;
 typedef std::tr1::shared_ptr<AccessorInterface<Strings> > StringsAccessor;
+typedef std::tr1::shared_ptr<AccessorInterface<StrIntPair> > StrIntPairAccessor;
 typedef std::tr1::shared_ptr<AccessorInterface<uint8> > Uint8Accessor;
 typedef std::tr1::shared_ptr<AccessorInterface<uint16> > Uint16Accessor;
 typedef std::tr1::shared_ptr<AccessorInterface<uint32> > Uint32Accessor;
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
diff --git a/cellular.h b/cellular.h
index 083c8e3..5b63b1d 100644
--- a/cellular.h
+++ b/cellular.h
@@ -6,8 +6,10 @@
 #define SHILL_CELLULAR_
 
 #include <string>
+#include <utility>
 
 #include <base/basictypes.h>
+#include <chromeos/dbus/service_constants.h>
 
 #include "shill/device.h"
 #include "shill/refptr_types.h"
@@ -17,6 +19,41 @@
 
 class Cellular : public Device {
  public:
+  class Network {
+   public:
+    Network();
+    virtual ~Network();
+
+    const std::string &GetStatus() const;
+    void SetStatus(const std::string &status);
+
+    const std::string &GetId() const;
+    void SetId(const std::string &id);
+
+    const std::string &GetShortName() const;
+    void SetShortName(const std::string &name);
+
+    const std::string &GetLongName() const;
+    void SetLongName(const std::string &name);
+
+    const std::string &GetTechnology() const;
+    void SetTechnology(const std::string &technology);
+
+    const Stringmap &ToDict() const;
+
+   private:
+    Stringmap dict_;
+    DISALLOW_COPY_AND_ASSIGN(Network);
+  };
+
+  struct SimLockStatus {
+   public:
+    SimLockStatus();
+    virtual ~SimLockStatus();
+    std::string lock_type;
+    uint32 retries_left;
+  };
+
   Cellular(ControlInterface *control_interface,
            EventDispatcher *dispatcher,
            Manager *manager,
@@ -28,6 +65,15 @@
   bool TechnologyIs(Device::Technology type);
 
  private:
+  Stringmaps EnumerateNetworks();
+  StrIntPair SimLockStatusToProperty();
+  void HelpRegisterDerivedStringmaps(const std::string &name,
+                                     Stringmaps(Cellular::*get)(void),
+                                     bool(Cellular::*set)(const Stringmaps&));
+  void HelpRegisterDerivedStrIntPair(const std::string &name,
+                                     StrIntPair(Cellular::*get)(void),
+                                     bool(Cellular::*set)(const StrIntPair&));
+
   ServiceRefPtr service_;
   bool service_registered_;
 
@@ -47,6 +93,8 @@
   int16 prl_version_;
   bool scanning_;
   uint16 scan_interval_;
+  std::vector<Network> found_networks_;
+  SimLockStatus sim_lock_status_;
 
   DISALLOW_COPY_AND_ASSIGN(Cellular);
 };
diff --git a/dbus_adaptor.cc b/dbus_adaptor.cc
index 3f197f5..bccecbb 100644
--- a/dbus_adaptor.cc
+++ b/dbus_adaptor.cc
@@ -9,6 +9,7 @@
 #include <base/logging.h>
 #include <dbus-c++/dbus.h>
 
+#include "shill/accessor_interface.h"
 #include "shill/dbus_adaptor.h"
 #include "shill/error.h"
 #include "shill/property_store.h"
@@ -171,8 +172,7 @@
 }
 
 // static
-::DBus::Variant DBusAdaptor::StringmapToVariant(
-    const map<string, string> &value) {
+::DBus::Variant DBusAdaptor::StringmapToVariant(const Stringmap &value) {
   ::DBus::Variant v;
   ::DBus::MessageIter writer = v.writer();
   writer << value;
@@ -180,8 +180,7 @@
 }
 
 // static
-::DBus::Variant DBusAdaptor::StringmapsToVariant(
-    const vector<map<string, string> > &value) {
+::DBus::Variant DBusAdaptor::StringmapsToVariant(const Stringmaps &value) {
   ::DBus::Variant v;
   ::DBus::MessageIter writer = v.writer();
   writer << value;
@@ -189,7 +188,7 @@
 }
 
 // static
-::DBus::Variant DBusAdaptor::StringsToVariant(const vector<string> &value) {
+::DBus::Variant DBusAdaptor::StringsToVariant(const Strings &value) {
   ::DBus::Variant v;
   ::DBus::MessageIter writer = v.writer();
   writer << value;
@@ -197,6 +196,15 @@
 }
 
 // static
+::DBus::Variant DBusAdaptor::StrIntPairToVariant(const StrIntPair &value) {
+  ::DBus::Variant v;
+  ::DBus::MessageIter writer = v.writer();
+  writer << value.string_property();
+  writer << value.uint_property();
+  return v;
+}
+
+// static
 ::DBus::Variant DBusAdaptor::Uint16ToVariant(uint16 value) {
   ::DBus::Variant v;
   v.writer().append_uint16(value);
diff --git a/dbus_adaptor.h b/dbus_adaptor.h
index 994fddd..d15e2e0 100644
--- a/dbus_adaptor.h
+++ b/dbus_adaptor.h
@@ -12,6 +12,8 @@
 #include <base/basictypes.h>
 #include <dbus-c++/dbus.h>
 
+#include "shill/accessor_interface.h"
+
 namespace shill {
 
 #define SHILL_INTERFACE "org.chromium.flimflam"
@@ -39,12 +41,10 @@
   static ::DBus::Variant Int32ToVariant(int32 value);
   static ::DBus::Variant PathToVariant(const ::DBus::Path &value);
   static ::DBus::Variant StringToVariant(const std::string &value);
-  static ::DBus::Variant StringmapToVariant(
-      const std::map<std::string, std::string> &value);
-  static ::DBus::Variant StringmapsToVariant(
-      const std::vector<std::map<std::string, std::string> > &value);
-  static ::DBus::Variant StringsToVariant(
-      const std::vector<std::string> &value);
+  static ::DBus::Variant StringmapToVariant(const Stringmap &value);
+  static ::DBus::Variant StringmapsToVariant(const Stringmaps &value);
+  static ::DBus::Variant StringsToVariant(const Strings &value);
+  static ::DBus::Variant StrIntPairToVariant(const StrIntPair &value);
   static ::DBus::Variant Uint16ToVariant(uint16 value);
   static ::DBus::Variant Uint32ToVariant(uint32 value);
 
diff --git a/device.cc b/device.cc
index 1f196ce..1e9127a 100644
--- a/device.cc
+++ b/device.cc
@@ -146,16 +146,16 @@
 }
 
 void Device::HelpRegisterDerivedString(const string &name,
-                                    string(Device::*get)(void),
-                                    bool(Device::*set)(const string&)) {
+                                       string(Device::*get)(void),
+                                       bool(Device::*set)(const string&)) {
   store_.RegisterDerivedString(
       name,
       StringAccessor(new CustomAccessor<Device, string>(this, get, set)));
 }
 
 void Device::HelpRegisterDerivedStrings(const string &name,
-                                     Strings(Device::*get)(void),
-                                     bool(Device::*set)(const Strings&)) {
+                                        Strings(Device::*get)(void),
+                                        bool(Device::*set)(const Strings&)) {
   store_.RegisterDerivedStrings(
       name,
       StringsAccessor(new CustomAccessor<Device, Strings>(this, get, set)));
diff --git a/device.h b/device.h
index 2b19897..b17acc9 100644
--- a/device.h
+++ b/device.h
@@ -87,11 +87,11 @@
   bool AcquireDHCPConfig();
 
   void HelpRegisterDerivedString(const std::string &name,
-                             std::string(Device::*get)(void),
-                             bool(Device::*set)(const std::string&));
+                                 std::string(Device::*get)(void),
+                                 bool(Device::*set)(const std::string&));
   void HelpRegisterDerivedStrings(const std::string &name,
-                              Strings(Device::*get)(void),
-                              bool(Device::*set)(const Strings&));
+                                  Strings(Device::*get)(void),
+                                  bool(Device::*set)(const Strings&));
 
   // Properties
   std::string hardware_address_;
diff --git a/property_store.cc b/property_store.cc
index e105ce0..4254f1a 100644
--- a/property_store.cc
+++ b/property_store.cc
@@ -25,16 +25,18 @@
 
 PropertyStore::~PropertyStore() {}
 
-bool PropertyStore::Contains(const std::string &property) {
-  return (bool_properties_.find(property) != bool_properties_.end() ||
-          int16_properties_.find(property) != int16_properties_.end() ||
-          int32_properties_.find(property) != int32_properties_.end() ||
-          string_properties_.find(property) != string_properties_.end() ||
-          stringmap_properties_.find(property) != stringmap_properties_.end() ||
-          strings_properties_.find(property) != strings_properties_.end() ||
-          uint8_properties_.find(property) != uint8_properties_.end() ||
-          uint16_properties_.find(property) != uint16_properties_.end() ||
-          uint32_properties_.find(property) != uint32_properties_.end());
+bool PropertyStore::Contains(const std::string &prop) {
+  return (bool_properties_.find(prop) != bool_properties_.end() ||
+          int16_properties_.find(prop) != int16_properties_.end() ||
+          int32_properties_.find(prop) != int32_properties_.end() ||
+          string_properties_.find(prop) != string_properties_.end() ||
+          stringmap_properties_.find(prop) != stringmap_properties_.end() ||
+          stringmaps_properties_.find(prop) != stringmaps_properties_.end() ||
+          strintpair_properties_.find(prop) != strintpair_properties_.end() ||
+          strings_properties_.find(prop) != strings_properties_.end() ||
+          uint8_properties_.find(prop) != uint8_properties_.end() ||
+          uint16_properties_.find(prop) != uint16_properties_.end() ||
+          uint32_properties_.find(prop) != uint32_properties_.end());
 }
 
 bool PropertyStore::SetBoolProperty(const std::string& name,
@@ -161,6 +163,10 @@
   return PropertyConstIterator<Strings>(strings_properties_);
 }
 
+PropertyConstIterator<StrIntPair> PropertyStore::GetStrIntPairPropertiesIter() {
+  return PropertyConstIterator<StrIntPair>(strintpair_properties_);
+}
+
 PropertyConstIterator<uint8> PropertyStore::GetUint8PropertiesIter() {
   return PropertyConstIterator<uint8>(uint8_properties_);
 }
@@ -225,6 +231,16 @@
       StringsAccessor(new PropertyAccessor<Strings>(prop));
 }
 
+void PropertyStore::RegisterConstStrings(const string &name,
+                                         const Strings *prop) {
+  strings_properties_[name] =
+      StringsAccessor(new ConstPropertyAccessor<Strings>(prop));
+}
+
+void PropertyStore::RegisterUint8(const string &name, uint8 *prop) {
+  uint8_properties_[name] = Uint8Accessor(new PropertyAccessor<uint8>(prop));
+}
+
 void PropertyStore::RegisterConstUint8(const string &name, const uint8 *prop) {
   uint8_properties_[name] =
       Uint8Accessor(new ConstPropertyAccessor<uint8>(prop));
@@ -255,4 +271,14 @@
   strings_properties_[name] = accessor;
 }
 
+void PropertyStore::RegisterDerivedStringmaps(const std::string &name,
+                                              const StringmapsAccessor &acc) {
+  stringmaps_properties_[name] = acc;
+}
+
+void PropertyStore::RegisterDerivedStrIntPair(const std::string &name,
+                                              const StrIntPairAccessor &acc) {
+  strintpair_properties_[name] = acc;
+}
+
 }  // namespace shill
diff --git a/property_store.h b/property_store.h
index fdea66a..c452d79 100644
--- a/property_store.h
+++ b/property_store.h
@@ -74,6 +74,8 @@
   PropertyConstIterator<int32> GetInt32PropertiesIter();
   PropertyConstIterator<std::string> GetStringPropertiesIter();
   PropertyConstIterator<Stringmap> GetStringmapPropertiesIter();
+  PropertyConstIterator<Stringmaps> GetStringmapsPropertiesIter();
+  PropertyConstIterator<StrIntPair> GetStrIntPairPropertiesIter();
   PropertyConstIterator<Strings> GetStringsPropertiesIter();
   PropertyConstIterator<uint8> GetUint8PropertiesIter();
   PropertyConstIterator<uint16> GetUint16PropertiesIter();
@@ -90,6 +92,8 @@
   void RegisterStringmap(const std::string &name, Stringmap *prop);
   void RegisterConstStringmap(const std::string &name, const Stringmap *prop);
   void RegisterStrings(const std::string &name, Strings *prop);
+  void RegisterConstStrings(const std::string &name, const Strings *prop);
+  void RegisterUint8(const std::string &name, uint8 *prop);
   void RegisterConstUint8(const std::string &name, const uint8 *prop);
   void RegisterUint16(const std::string &name, uint16 *prop);
   void RegisterConstUint16(const std::string &name, const uint16 *prop);
@@ -98,8 +102,12 @@
                            const BoolAccessor &accessor);
   void RegisterDerivedString(const std::string &name,
                              const StringAccessor &accessor);
+  void RegisterDerivedStringmaps(const std::string &name,
+                                 const StringmapsAccessor &accessor);
   void RegisterDerivedStrings(const std::string &name,
                               const StringsAccessor &accessor);
+  void RegisterDerivedStrIntPair(const std::string &name,
+                                 const StrIntPairAccessor &accessor);
 
  private:
   // These are std::maps instead of something cooler because the common
@@ -109,7 +117,9 @@
   std::map<std::string, Int32Accessor> int32_properties_;
   std::map<std::string, StringAccessor> string_properties_;
   std::map<std::string, StringmapAccessor> stringmap_properties_;
+  std::map<std::string, StringmapsAccessor> stringmaps_properties_;
   std::map<std::string, StringsAccessor> strings_properties_;
+  std::map<std::string, StrIntPairAccessor> strintpair_properties_;
   std::map<std::string, Uint8Accessor> uint8_properties_;
   std::map<std::string, Uint16Accessor> uint16_properties_;
   std::map<std::string, Uint32Accessor> uint32_properties_;
diff --git a/property_store_unittest.cc b/property_store_unittest.cc
index 2dd049c..f63439c 100644
--- a/property_store_unittest.cc
+++ b/property_store_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <map>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include <dbus-c++/dbus.h>
@@ -19,8 +20,9 @@
 #include "shill/property_store.h"
 #include "shill/shill_event.h"
 
-using std::string;
+using std::make_pair;
 using std::map;
+using std::string;
 using std::vector;
 using ::testing::Values;
 
@@ -44,11 +46,15 @@
     DBusAdaptor::StringmapToVariant(Stringmap());
 // static
 const ::DBus::Variant PropertyStoreTest::kStringmapsV =
-    DBusAdaptor::StringmapsToVariant(vector<map<string, string> >());
+    DBusAdaptor::StringmapsToVariant(Stringmaps());
 // static
 const ::DBus::Variant PropertyStoreTest::kStringsV =
     DBusAdaptor::StringsToVariant(Strings(1, ""));
 // static
+const ::DBus::Variant PropertyStoreTest::kStrIntPairV =
+    DBusAdaptor::StrIntPairToVariant(StrIntPair(make_pair("", ""),
+                                                make_pair("", 12)));
+// static
 const ::DBus::Variant PropertyStoreTest::kUint16V =
     DBusAdaptor::Uint16ToVariant(0);
 // static
@@ -79,10 +85,11 @@
            PropertyStoreTest::kStringV,
            PropertyStoreTest::kInt16V,
            PropertyStoreTest::kInt32V,
-           PropertyStoreTest::kUint16V,
-           PropertyStoreTest::kUint32V,
-           PropertyStoreTest::kStringsV,
            PropertyStoreTest::kStringmapV,
-           PropertyStoreTest::kStringmapsV));
+           PropertyStoreTest::kStringmapsV,
+           PropertyStoreTest::kStringsV,
+           PropertyStoreTest::kStrIntPairV,
+           PropertyStoreTest::kUint16V,
+           PropertyStoreTest::kUint32V));
 
 }  // namespace shill
diff --git a/property_store_unittest.h b/property_store_unittest.h
index 608ae52..b08f5ac 100644
--- a/property_store_unittest.h
+++ b/property_store_unittest.h
@@ -37,6 +37,7 @@
   static const ::DBus::Variant kStringmapV;
   static const ::DBus::Variant kStringmapsV;
   static const ::DBus::Variant kStringsV;
+  static const ::DBus::Variant kStrIntPairV;
   static const ::DBus::Variant kUint16V;
   static const ::DBus::Variant kUint32V;