shill: Support for profile identifiers, and creating persistent storage.

BUG=chromium-os:17252
TEST=unit tests

Change-Id: Iaec7b6b5737a997fde3d5215196fdcbf72eefe09
Reviewed-on: http://gerrit.chromium.org/gerrit/3749
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Chris Masone <cmasone@chromium.org>
diff --git a/profile.cc b/profile.cc
index 2593e56..c1e92a4 100644
--- a/profile.cc
+++ b/profile.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include <base/logging.h>
+#include <base/string_util.h>
 #include <chromeos/dbus/service_constants.h>
 
 #include "shill/adaptor_interfaces.h"
@@ -16,8 +17,14 @@
 using std::string;
 
 namespace shill {
-Profile::Profile(ControlInterface *control_interface)
-    : adaptor_(control_interface->CreateProfileAdaptor(this)) {
+
+const char Profile::kGlobalStorageDir[] = "/var/cache/flimflam";
+const char Profile::kUserStorageDirFormat[] = "/home/%s/user/flimflam";
+
+Profile::Profile(ControlInterface *control_interface,
+                 GLib *glib)
+    : adaptor_(control_interface->CreateProfileAdaptor(this)),
+      storage_(glib) {
   // flimflam::kCheckPortalListProperty: Registered in DefaultProfile
   // flimflam::kCountryProperty: Registered in DefaultProfile
   store_.RegisterConstString(flimflam::kNameProperty, &name_);
@@ -36,4 +43,61 @@
 
 Profile::~Profile() {}
 
+bool Profile::IsValidIdentifierToken(const std::string &token) {
+  if (token.empty()) {
+    return false;
+  }
+  for (string::const_iterator it = token.begin(); it != token.end(); ++it) {
+    if (!IsAsciiAlpha(*it) && !IsAsciiDigit(*it)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool Profile::ParseIdentifier(const string &raw, Identifier *parsed) {
+  if (raw.empty()) {
+    return false;
+  }
+  if (raw[0] == '~') {
+    // Format: "~user/identifier".
+    size_t slash = raw.find('/');
+    if (slash == string::npos) {
+      return false;
+    }
+    string user(raw.begin() + 1, raw.begin() + slash);
+    string identifier(raw.begin() + slash + 1, raw.end());
+    if (!IsValidIdentifierToken(user) || !IsValidIdentifierToken(identifier)) {
+      return false;
+    }
+    parsed->user = user;
+    parsed->identifier = identifier;
+    return true;
+  }
+
+  // Format: "identifier".
+  if (!IsValidIdentifierToken(raw)) {
+    return false;
+  }
+  parsed->user = "";
+  parsed->identifier = raw;
+  return true;
+}
+
+string Profile::GetRpcPath(const Identifier &identifier) {
+  string user = identifier.user.empty() ? "" : identifier.user + "/";
+  return "/profile/" + user + identifier.identifier;
+}
+
+bool Profile::GetStoragePath(const Identifier &identifier, FilePath *path) {
+  FilePath dir(
+      identifier.user.empty() ?
+      kGlobalStorageDir :
+      base::StringPrintf(kUserStorageDirFormat, identifier.user.c_str()));
+  // TODO(petkov): Validate the directory permissions, etc.
+  *path = dir.Append(base::StringPrintf("%s.profile",
+                                        identifier.identifier.c_str()));
+  return true;
+}
+
 }  // namespace shill