blob: f65aa1b56feb86687be5ccfc41de5f35f1dae11f [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 Masone6791a432011-07-12 13:23:19 -07007#include <map>
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 Masone6791a432011-07-12 13:23:19 -070026using std::map;
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 Masone9d779932011-08-25 16:33:41 -070058Profile::~Profile() {
59 DCHECK_EQ(services_.size(), 0);
60}
Chris Masone52cd19b2011-06-29 17:23:04 -070061
Chris Masoneb9c00592011-10-06 13:10:39 -070062bool Profile::InitStorage(GLib *glib) {
63 FilePath final_path;
64 if (!GetStoragePath(&final_path)) {
65 PLOG(ERROR) <<
66 base::StringPrintf("Could not set up profile storage for %s:%s",
67 name_.user.c_str(), name_.identifier.c_str());
68 return false;
69 }
70 scoped_ptr<KeyFileStore> storage(new KeyFileStore(glib));
71 storage->set_path(final_path);
72 if (!storage->Open()) {
73 PLOG(ERROR) <<
74 base::StringPrintf("Could not open profile storage for %s:%s",
75 name_.user.c_str(), name_.identifier.c_str());
76 return false;
77 }
78 set_storage(storage.release());
79 return true;
80}
81
Chris Masone7df0c672011-07-15 10:24:54 -070082string Profile::GetFriendlyName() {
83 return (name_.user.empty() ? "" : name_.user + "/") + name_.identifier;
84}
85
86string Profile::GetRpcIdentifier() {
87 return adaptor_->GetRpcIdentifier();
88}
89
Chris Masoneb9c00592011-10-06 13:10:39 -070090void Profile::set_storage(StoreInterface *storage) {
91 storage_.reset(storage);
92}
93
Chris Masone6791a432011-07-12 13:23:19 -070094bool Profile::AdoptService(const ServiceRefPtr &service) {
95 if (ContainsKey(services_, service->UniqueName()))
96 return false;
97 service->set_profile(this);
98 services_[service->UniqueName()] = service;
99 return true;
100}
101
102bool Profile::AbandonService(const string &name) {
103 map<string, ServiceRefPtr>::iterator to_abandon = services_.find(name);
104 if (to_abandon != services_.end()) {
105 services_.erase(to_abandon);
106 return true;
107 }
108 return false;
109}
110
111bool Profile::DemoteService(const string &name) {
112 map<string, ServiceRefPtr>::iterator to_demote = services_.find(name);
113 if (to_demote == services_.end())
114 return false;
115 return true; // TODO(cmasone): mark |to_demote| as inactive or something.
116}
117
118bool Profile::MergeService(const ServiceRefPtr &service) {
Chris Masoneb9c00592011-10-06 13:10:39 -0700119 // TODO(cmasone): Make |service| just load itself from |store_|.
Chris Masone6791a432011-07-12 13:23:19 -0700120 map<string, ServiceRefPtr>::iterator it;
121 for (it = services_.begin(); it != services_.end(); ++it) {
122 if (Mergeable(it->second, service))
Chris Masoneb9c00592011-10-06 13:10:39 -0700123 return true;
Chris Masone6791a432011-07-12 13:23:19 -0700124 }
125 return false;
126}
127
128ServiceRefPtr Profile::FindService(const std::string& name) {
129 if (ContainsKey(services_, name))
130 return services_[name];
131 return NULL;
132}
133
Chris Masoneb9c00592011-10-06 13:10:39 -0700134void Profile::Finalize() {
135 Save();
Chris Masone6791a432011-07-12 13:23:19 -0700136 services_.clear();
Chris Masone7aa5f902011-07-11 11:13:35 -0700137}
138
Darin Petkova4766822011-07-07 10:42:22 -0700139bool Profile::IsValidIdentifierToken(const std::string &token) {
140 if (token.empty()) {
141 return false;
142 }
143 for (string::const_iterator it = token.begin(); it != token.end(); ++it) {
144 if (!IsAsciiAlpha(*it) && !IsAsciiDigit(*it)) {
145 return false;
146 }
147 }
148 return true;
149}
150
151bool Profile::ParseIdentifier(const string &raw, Identifier *parsed) {
152 if (raw.empty()) {
153 return false;
154 }
155 if (raw[0] == '~') {
156 // Format: "~user/identifier".
157 size_t slash = raw.find('/');
158 if (slash == string::npos) {
159 return false;
160 }
161 string user(raw.begin() + 1, raw.begin() + slash);
162 string identifier(raw.begin() + slash + 1, raw.end());
163 if (!IsValidIdentifierToken(user) || !IsValidIdentifierToken(identifier)) {
164 return false;
165 }
166 parsed->user = user;
167 parsed->identifier = identifier;
168 return true;
169 }
170
171 // Format: "identifier".
172 if (!IsValidIdentifierToken(raw)) {
173 return false;
174 }
175 parsed->user = "";
176 parsed->identifier = raw;
177 return true;
178}
179
Chris Masoneb9c00592011-10-06 13:10:39 -0700180bool Profile::Save() {
181 return SaveServices() && storage_->Flush();
Chris Masone9d779932011-08-25 16:33:41 -0700182}
183
Chris Masone2ae797d2011-08-23 20:41:00 -0700184bool Profile::GetStoragePath(FilePath *path) {
185 if (name_.user.empty()) {
186 LOG(ERROR) << "Non-default profiles cannot be stored globally.";
187 return false;
188 }
189 FilePath dir(base::StringPrintf(storage_format_.c_str(), name_.user.c_str()));
Darin Petkova4766822011-07-07 10:42:22 -0700190 // TODO(petkov): Validate the directory permissions, etc.
191 *path = dir.Append(base::StringPrintf("%s.profile",
Chris Masone2ae797d2011-08-23 20:41:00 -0700192 name_.identifier.c_str()));
Darin Petkova4766822011-07-07 10:42:22 -0700193 return true;
194}
195
Chris Masone6791a432011-07-12 13:23:19 -0700196vector<string> Profile::EnumerateAvailableServices() {
197 return manager_->EnumerateAvailableServices();
198}
199
200vector<string> Profile::EnumerateEntries() {
201 vector<string> rpc_ids;
202 map<string, ServiceRefPtr>::const_iterator it;
203 for (it = services_.begin(); it != services_.end(); ++it) {
204 rpc_ids.push_back(it->second->GetRpcIdentifier());
205 }
206 return rpc_ids;
207}
208
mukesh agrawalffa3d042011-10-06 15:26:10 -0700209void Profile::HelpRegisterDerivedStrings(
210 const string &name,
211 Strings(Profile::*get)(void),
212 void(Profile::*set)(const Strings&, Error *)) {
Chris Masone6791a432011-07-12 13:23:19 -0700213 store_.RegisterDerivedStrings(
214 name,
215 StringsAccessor(new CustomAccessor<Profile, Strings>(this, get, set)));
216}
217
Chris Masoneb9c00592011-10-06 13:10:39 -0700218bool Profile::SaveServices() {
Chris Masone9d779932011-08-25 16:33:41 -0700219 for (map<string, ServiceRefPtr>::iterator it = services_.begin();
220 it != services_.end();
221 ++it) {
222 VLOG(1) << "Saving service named " << it->first;
Chris Masoneb9c00592011-10-06 13:10:39 -0700223 if (!it->second->Save(storage()))
Chris Masone9d779932011-08-25 16:33:41 -0700224 return false;
225 }
226 return true;
227}
228
Chris Masone52cd19b2011-06-29 17:23:04 -0700229} // namespace shill