blob: 46d979e4e797f484666ca2891a414fd30d27e3df [file] [log] [blame]
Chris Masone52cd19b2011-06-29 17:23:04 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/profile.h"
6
Chris Masone6515aab2011-10-12 16:19:09 -07007#include <set>
Chris Masone52cd19b2011-06-29 17:23:04 -07008#include <string>
Chris Masone6791a432011-07-12 13:23:19 -07009#include <vector>
Chris Masone52cd19b2011-06-29 17:23:04 -070010
Chris Masoneb9c00592011-10-06 13:10:39 -070011#include <base/file_path.h>
Chris Masone52cd19b2011-06-29 17:23:04 -070012#include <base/logging.h>
Chris Masone6791a432011-07-12 13:23:19 -070013#include <base/stl_util-inl.h>
Darin Petkova4766822011-07-07 10:42:22 -070014#include <base/string_util.h>
Chris Masone6791a432011-07-12 13:23:19 -070015#include <base/stringprintf.h>
Chris Masone88cbd5f2011-07-03 14:30:04 -070016#include <chromeos/dbus/service_constants.h>
Chris Masone52cd19b2011-06-29 17:23:04 -070017
18#include "shill/adaptor_interfaces.h"
19#include "shill/control_interface.h"
Chris Masoneb9c00592011-10-06 13:10:39 -070020#include "shill/key_file_store.h"
Chris Masone6791a432011-07-12 13:23:19 -070021#include "shill/manager.h"
Chris Masone52cd19b2011-06-29 17:23:04 -070022#include "shill/property_accessor.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070023#include "shill/service.h"
Chris Masone9d779932011-08-25 16:33:41 -070024#include "shill/store_interface.h"
Chris Masone52cd19b2011-06-29 17:23:04 -070025
Chris Masone6515aab2011-10-12 16:19:09 -070026using std::set;
Chris Masone52cd19b2011-06-29 17:23:04 -070027using std::string;
Chris Masone6791a432011-07-12 13:23:19 -070028using std::vector;
Chris Masone52cd19b2011-06-29 17:23:04 -070029
30namespace shill {
Darin Petkova4766822011-07-07 10:42:22 -070031
Darin Petkova4766822011-07-07 10:42:22 -070032Profile::Profile(ControlInterface *control_interface,
Chris Masone7df0c672011-07-15 10:24:54 -070033 Manager *manager,
34 const Identifier &name,
Chris Masone2ae797d2011-08-23 20:41:00 -070035 const string &user_storage_format,
Chris Masone7df0c672011-07-15 10:24:54 -070036 bool connect_to_rpc)
Chris Masone6791a432011-07-12 13:23:19 -070037 : manager_(manager),
Chris Masone7df0c672011-07-15 10:24:54 -070038 name_(name),
Chris Masone2ae797d2011-08-23 20:41:00 -070039 storage_format_(user_storage_format) {
Chris Masone7df0c672011-07-15 10:24:54 -070040 if (connect_to_rpc)
41 adaptor_.reset(control_interface->CreateProfileAdaptor(this));
42
Chris Masone88cbd5f2011-07-03 14:30:04 -070043 // flimflam::kCheckPortalListProperty: Registered in DefaultProfile
44 // flimflam::kCountryProperty: Registered in DefaultProfile
Chris Masone7df0c672011-07-15 10:24:54 -070045 store_.RegisterConstString(flimflam::kNameProperty, &name_.identifier);
Chris Masone88cbd5f2011-07-03 14:30:04 -070046
47 // flimflam::kOfflineModeProperty: Registered in DefaultProfile
48 // flimflam::kPortalURLProperty: Registered in DefaultProfile
49
Chris Masone6791a432011-07-12 13:23:19 -070050 HelpRegisterDerivedStrings(flimflam::kServicesProperty,
51 &Profile::EnumerateAvailableServices,
52 NULL);
Chris Masone7df0c672011-07-15 10:24:54 -070053 HelpRegisterDerivedStrings(flimflam::kEntriesProperty,
54 &Profile::EnumerateEntries,
55 NULL);
Chris Masone52cd19b2011-06-29 17:23:04 -070056}
57
Chris Masone6515aab2011-10-12 16:19:09 -070058Profile::~Profile() {}
Chris Masone52cd19b2011-06-29 17:23:04 -070059
Paul Stewart5dc40aa2011-10-28 19:43:43 -070060bool Profile::InitStorage(GLib *glib, InitStorageOption storage_option,
61 Error *error) {
Chris Masoneb9c00592011-10-06 13:10:39 -070062 FilePath final_path;
63 if (!GetStoragePath(&final_path)) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -070064 const string kMessage =
Chris Masoneb9c00592011-10-06 13:10:39 -070065 base::StringPrintf("Could not set up profile storage for %s:%s",
66 name_.user.c_str(), name_.identifier.c_str());
Paul Stewart5dc40aa2011-10-28 19:43:43 -070067 LOG(ERROR) << kMessage;
68 if (error) {
69 error->Populate(Error::kInvalidArguments, kMessage);
70 }
Chris Masoneb9c00592011-10-06 13:10:39 -070071 return false;
72 }
73 scoped_ptr<KeyFileStore> storage(new KeyFileStore(glib));
74 storage->set_path(final_path);
Paul Stewart5dc40aa2011-10-28 19:43:43 -070075 bool already_exists = storage->IsNonEmpty();
76 if (!already_exists && storage_option != kCreateNew &&
77 storage_option != kCreateOrOpenExisting) {
78 const string kMessage =
79 base::StringPrintf("Profile storage for %s:%s does not already exist",
80 name_.user.c_str(), name_.identifier.c_str());
81 LOG(ERROR) << kMessage;
82 if (error) {
83 error->Populate(Error::kNotFound, kMessage);
84 }
85 return false;
86 } else if (already_exists && storage_option != kOpenExisting &&
87 storage_option != kCreateOrOpenExisting) {
88 const string kMessage =
89 base::StringPrintf("Profile storage for %s:%s already exists",
90 name_.user.c_str(), name_.identifier.c_str());
91 LOG(ERROR) << kMessage;
92 if (error) {
93 error->Populate(Error::kAlreadyExists, kMessage);
94 }
95 return false;
96 }
Chris Masoneb9c00592011-10-06 13:10:39 -070097 if (!storage->Open()) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -070098 const string kMessage =
Chris Masoneb9c00592011-10-06 13:10:39 -070099 base::StringPrintf("Could not open profile storage for %s:%s",
100 name_.user.c_str(), name_.identifier.c_str());
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700101 LOG(ERROR) << kMessage;
102 if (error) {
103 error->Populate(Error::kInternalError, kMessage);
104 }
Chris Masoneb9c00592011-10-06 13:10:39 -0700105 return false;
106 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700107 if (!already_exists) {
108 // Add a descriptive header to the profile so even if nothing is stored
109 // to it, it still has some content. Completely empty keyfiles are not
110 // valid for reading.
111 storage->SetHeader(
112 base::StringPrintf("Profile %s:%s", name_.user.c_str(),
113 name_.identifier.c_str()));
114 }
Chris Masoneb9c00592011-10-06 13:10:39 -0700115 set_storage(storage.release());
116 return true;
117}
118
Chris Masone7df0c672011-07-15 10:24:54 -0700119string Profile::GetFriendlyName() {
120 return (name_.user.empty() ? "" : name_.user + "/") + name_.identifier;
121}
122
123string Profile::GetRpcIdentifier() {
124 return adaptor_->GetRpcIdentifier();
125}
126
Chris Masoneb9c00592011-10-06 13:10:39 -0700127void Profile::set_storage(StoreInterface *storage) {
128 storage_.reset(storage);
129}
130
Chris Masone6791a432011-07-12 13:23:19 -0700131bool Profile::AdoptService(const ServiceRefPtr &service) {
Chris Masone6515aab2011-10-12 16:19:09 -0700132 if (storage_->ContainsGroup(service->GetStorageIdentifier()))
Chris Masone6791a432011-07-12 13:23:19 -0700133 return false;
134 service->set_profile(this);
Chris Masone6515aab2011-10-12 16:19:09 -0700135 return service->Save(storage_.get()) && storage_->Flush();
Chris Masone6791a432011-07-12 13:23:19 -0700136}
137
Chris Masone6515aab2011-10-12 16:19:09 -0700138bool Profile::AbandonService(const ServiceRefPtr &service) {
139 if (service->profile() == this)
140 service->set_profile(NULL);
141 return storage_->DeleteGroup(service->GetStorageIdentifier()) &&
142 storage_->Flush();
Chris Masone6791a432011-07-12 13:23:19 -0700143}
144
Chris Masone6515aab2011-10-12 16:19:09 -0700145bool Profile::UpdateService(const ServiceRefPtr &service) {
146 return service->Save(storage_.get()) && storage_->Flush();
Chris Masone6791a432011-07-12 13:23:19 -0700147}
148
149bool Profile::MergeService(const ServiceRefPtr &service) {
Chris Masone6515aab2011-10-12 16:19:09 -0700150 if (!storage_->ContainsGroup(service->GetStorageIdentifier()))
151 return false;
152 service->set_profile(this);
153 return service->Load(storage_.get());
Chris Masone6791a432011-07-12 13:23:19 -0700154}
155
Chris Masone6515aab2011-10-12 16:19:09 -0700156bool Profile::ContainsService(const ServiceConstRefPtr &service) {
157 return storage_->ContainsGroup(service->GetStorageIdentifier());
Chris Masone7aa5f902011-07-11 11:13:35 -0700158}
159
Darin Petkova4766822011-07-07 10:42:22 -0700160bool Profile::IsValidIdentifierToken(const std::string &token) {
161 if (token.empty()) {
162 return false;
163 }
164 for (string::const_iterator it = token.begin(); it != token.end(); ++it) {
165 if (!IsAsciiAlpha(*it) && !IsAsciiDigit(*it)) {
166 return false;
167 }
168 }
169 return true;
170}
171
172bool Profile::ParseIdentifier(const string &raw, Identifier *parsed) {
173 if (raw.empty()) {
174 return false;
175 }
176 if (raw[0] == '~') {
177 // Format: "~user/identifier".
178 size_t slash = raw.find('/');
179 if (slash == string::npos) {
180 return false;
181 }
182 string user(raw.begin() + 1, raw.begin() + slash);
183 string identifier(raw.begin() + slash + 1, raw.end());
184 if (!IsValidIdentifierToken(user) || !IsValidIdentifierToken(identifier)) {
185 return false;
186 }
187 parsed->user = user;
188 parsed->identifier = identifier;
189 return true;
190 }
191
192 // Format: "identifier".
193 if (!IsValidIdentifierToken(raw)) {
194 return false;
195 }
196 parsed->user = "";
197 parsed->identifier = raw;
198 return true;
199}
200
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700201bool Profile::MatchesIdentifier(const Identifier &name) const {
202 return name.user == name_.user && name.identifier == name_.identifier;
203}
204
Chris Masoneb9c00592011-10-06 13:10:39 -0700205bool Profile::Save() {
Chris Masone6515aab2011-10-12 16:19:09 -0700206 return storage_->Flush();
Chris Masone9d779932011-08-25 16:33:41 -0700207}
208
Chris Masone2ae797d2011-08-23 20:41:00 -0700209bool Profile::GetStoragePath(FilePath *path) {
210 if (name_.user.empty()) {
211 LOG(ERROR) << "Non-default profiles cannot be stored globally.";
212 return false;
213 }
214 FilePath dir(base::StringPrintf(storage_format_.c_str(), name_.user.c_str()));
Darin Petkova4766822011-07-07 10:42:22 -0700215 // TODO(petkov): Validate the directory permissions, etc.
216 *path = dir.Append(base::StringPrintf("%s.profile",
Chris Masone2ae797d2011-08-23 20:41:00 -0700217 name_.identifier.c_str()));
Darin Petkova4766822011-07-07 10:42:22 -0700218 return true;
219}
220
Chris Masone6791a432011-07-12 13:23:19 -0700221vector<string> Profile::EnumerateAvailableServices() {
222 return manager_->EnumerateAvailableServices();
223}
224
225vector<string> Profile::EnumerateEntries() {
Chris Masone6515aab2011-10-12 16:19:09 -0700226 // TODO(someone): Determine if we care about this wasteful copying; consider
227 // making GetGroups return a vector.
228 set<string> groups(storage_->GetGroups());
229 return vector<string>(groups.begin(), groups.end());
Chris Masone6791a432011-07-12 13:23:19 -0700230}
231
mukesh agrawalffa3d042011-10-06 15:26:10 -0700232void Profile::HelpRegisterDerivedStrings(
233 const string &name,
234 Strings(Profile::*get)(void),
235 void(Profile::*set)(const Strings&, Error *)) {
Chris Masone6791a432011-07-12 13:23:19 -0700236 store_.RegisterDerivedStrings(
237 name,
238 StringsAccessor(new CustomAccessor<Profile, Strings>(this, get, set)));
239}
240
Chris Masone52cd19b2011-06-29 17:23:04 -0700241} // namespace shill