1 // Copyright (c) 2011 The Chromium 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 "chrome/browser/chromeos/options/vpn_config_view.h" 6 7 #include "base/string_util.h" 8 #include "base/utf_string_conversions.h" 9 #include "chrome/browser/chromeos/cros/cros_library.h" 10 #include "chrome/browser/chromeos/login/user_manager.h" 11 #include "grit/chromium_strings.h" 12 #include "grit/generated_resources.h" 13 #include "grit/locale_settings.h" 14 #include "grit/theme_resources.h" 15 #include "ui/base/l10n/l10n_util.h" 16 #include "ui/base/resource/resource_bundle.h" 17 #include "views/controls/button/image_button.h" 18 #include "views/controls/button/native_button.h" 19 #include "views/controls/label.h" 20 #include "views/controls/textfield/textfield.h" 21 #include "views/layout/grid_layout.h" 22 #include "views/layout/layout_constants.h" 23 #include "views/window/window.h" 24 25 namespace { 26 27 string16 ProviderTypeToString(chromeos::VirtualNetwork::ProviderType type) { 28 switch (type) { 29 case chromeos::VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: 30 return l10n_util::GetStringUTF16( 31 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_PSK); 32 case chromeos::VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: 33 return l10n_util::GetStringUTF16( 34 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_USER_CERT); 35 case chromeos::VirtualNetwork::PROVIDER_TYPE_OPEN_VPN: 36 return l10n_util::GetStringUTF16( 37 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_OPEN_VPN); 38 case chromeos::VirtualNetwork::PROVIDER_TYPE_MAX: 39 break; 40 } 41 NOTREACHED(); 42 return string16(); 43 } 44 45 } // namespace 46 47 namespace chromeos { 48 49 int VPNConfigView::ProviderTypeComboboxModel::GetItemCount() { 50 // TODO(stevenjb): Include OpenVPN option once enabled. 51 return VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT + 1; 52 // return VirtualNetwork::PROVIDER_TYPE_MAX; 53 } 54 55 string16 VPNConfigView::ProviderTypeComboboxModel::GetItemAt(int index) { 56 VirtualNetwork::ProviderType type = 57 static_cast<VirtualNetwork::ProviderType>(index); 58 return ProviderTypeToString(type); 59 } 60 61 VPNConfigView::UserCertComboboxModel::UserCertComboboxModel() { 62 // TODO(jamescook): populate user_certs_. chromium-os:14111 63 } 64 65 int VPNConfigView::UserCertComboboxModel::GetItemCount() { 66 return static_cast<int>(user_certs_.size()); 67 } 68 69 string16 VPNConfigView::UserCertComboboxModel::GetItemAt(int index) { 70 if (index >= 0 && index < static_cast<int>(user_certs_.size())) 71 return ASCIIToUTF16(user_certs_[index]); 72 return string16(); 73 } 74 75 VPNConfigView::VPNConfigView(NetworkConfigView* parent, VirtualNetwork* vpn) 76 : ChildNetworkConfigView(parent, vpn) { 77 Init(vpn); 78 } 79 80 VPNConfigView::VPNConfigView(NetworkConfigView* parent) 81 : ChildNetworkConfigView(parent) { 82 Init(NULL); 83 } 84 85 VPNConfigView::~VPNConfigView() { 86 } 87 88 void VPNConfigView::UpdateCanLogin() { 89 parent_->GetDialogClientView()->UpdateDialogButtons(); 90 } 91 92 string16 VPNConfigView::GetTitle() { 93 return l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_ADD_VPN); 94 } 95 96 bool VPNConfigView::CanLogin() { 97 static const size_t kMinPassphraseLen = 0; // TODO(stevenjb): min length? 98 if (service_path_.empty() && 99 (GetService().empty() || GetServer().empty())) 100 return false; 101 if (provider_type_ == VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK && 102 psk_passphrase_textfield_->text().length() < kMinPassphraseLen) 103 return false; 104 if (GetUsername().empty()) 105 return false; 106 if (user_passphrase_textfield_->text().length() < kMinPassphraseLen) 107 return false; 108 return true; 109 } 110 111 void VPNConfigView::UpdateErrorLabel() { 112 std::string error_msg; 113 if (!service_path_.empty()) { 114 // TODO(kuan): differentiate between bad psk and user passphrases. 115 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); 116 VirtualNetwork* vpn = cros->FindVirtualNetworkByPath(service_path_); 117 if (vpn && vpn->failed()) { 118 if (vpn->error() == ERROR_BAD_PASSPHRASE) { 119 error_msg = l10n_util::GetStringUTF8( 120 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_PASSPHRASE); 121 } else { 122 error_msg = vpn->GetErrorString(); 123 } 124 } 125 } 126 if (!error_msg.empty()) { 127 error_label_->SetText(UTF8ToWide(error_msg)); 128 error_label_->SetVisible(true); 129 } else { 130 error_label_->SetVisible(false); 131 } 132 } 133 134 void VPNConfigView::ContentsChanged(views::Textfield* sender, 135 const string16& new_contents) { 136 if (sender == server_textfield_ && !service_text_modified_) { 137 // Set the service name to the server name up to '.', unless it has 138 // been explicityly set by the user. 139 string16 server = server_textfield_->text(); 140 string16::size_type n = server.find_first_of(L'.'); 141 service_name_from_server_ = server.substr(0, n); 142 service_textfield_->SetText(service_name_from_server_); 143 } 144 if (sender == service_textfield_) { 145 if (new_contents.empty()) 146 service_text_modified_ = false; 147 else if (new_contents != service_name_from_server_) 148 service_text_modified_ = true; 149 } 150 UpdateCanLogin(); 151 } 152 153 bool VPNConfigView::HandleKeyEvent(views::Textfield* sender, 154 const views::KeyEvent& key_event) { 155 if ((sender == psk_passphrase_textfield_ || 156 sender == user_passphrase_textfield_) && 157 key_event.key_code() == ui::VKEY_RETURN) { 158 parent_->GetDialogClientView()->AcceptWindow(); 159 } 160 return false; 161 } 162 163 void VPNConfigView::ButtonPressed(views::Button* sender, 164 const views::Event& event) { 165 } 166 167 void VPNConfigView::ItemChanged(views::Combobox* combo_box, 168 int prev_index, int new_index) { 169 if (prev_index == new_index) 170 return; 171 if (combo_box == provider_type_combobox_) { 172 provider_type_ = static_cast<VirtualNetwork::ProviderType>(new_index); 173 EnableControls(); 174 } else if (combo_box == user_cert_combobox_) { 175 // Nothing to do for now. 176 } else { 177 NOTREACHED(); 178 } 179 UpdateCanLogin(); 180 } 181 182 bool VPNConfigView::Login() { 183 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); 184 if (service_path_.empty()) { 185 switch (provider_type_) { 186 case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: 187 cros->ConnectToVirtualNetworkPSK(GetService(), 188 GetServer(), 189 GetPSKPassphrase(), 190 GetUsername(), 191 GetUserPassphrase()); 192 break; 193 case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: 194 case VirtualNetwork::PROVIDER_TYPE_OPEN_VPN: 195 // TODO(stevenjb): Add support for OpenVPN and user certs. 196 LOG(WARNING) << "Unsupported provider type: " << provider_type_; 197 break; 198 case VirtualNetwork::PROVIDER_TYPE_MAX: 199 break; 200 } 201 } else { 202 VirtualNetwork* vpn = cros->FindVirtualNetworkByPath(service_path_); 203 if (!vpn) { 204 // TODO(stevenjb): Add notification for this. 205 LOG(WARNING) << "VPN no longer exists: " << service_path_; 206 return true; // Close dialog. 207 } 208 switch (provider_type_) { 209 case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: 210 vpn->SetPSKPassphrase(GetPSKPassphrase()); 211 break; 212 case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: 213 case VirtualNetwork::PROVIDER_TYPE_OPEN_VPN: { 214 const std::string user_cert = UTF16ToUTF8( 215 user_cert_combobox_->model()->GetItemAt( 216 user_cert_combobox_->selected_item())); 217 vpn->SetUserCert(user_cert); 218 break; 219 } 220 case VirtualNetwork::PROVIDER_TYPE_MAX: 221 break; 222 } 223 vpn->SetUsername(GetUsername()); 224 vpn->SetUserPassphrase(GetUserPassphrase()); 225 226 cros->ConnectToVirtualNetwork(vpn); 227 } 228 // Connection failures are responsible for updating the UI, including 229 // reopening dialogs. 230 return true; // Close dialog. 231 } 232 233 void VPNConfigView::Cancel() { 234 } 235 236 void VPNConfigView::InitFocus() { 237 // TODO(jamescook): Put focus in a more reasonable widget. 238 } 239 240 const std::string VPNConfigView::GetTextFromField( 241 views::Textfield* textfield, bool trim_whitespace) const { 242 std::string untrimmed = UTF16ToUTF8(textfield->text()); 243 if (!trim_whitespace) 244 return untrimmed; 245 std::string result; 246 TrimWhitespaceASCII(untrimmed, TRIM_ALL, &result); 247 return result; 248 } 249 250 const std::string VPNConfigView::GetService() const { 251 if (service_textfield_ != NULL) 252 return GetTextFromField(service_textfield_, true); 253 return service_path_; 254 } 255 256 const std::string VPNConfigView::GetServer() const { 257 if (server_textfield_ != NULL) 258 return GetTextFromField(server_textfield_, true); 259 return server_hostname_; 260 } 261 262 const std::string VPNConfigView::GetPSKPassphrase() const { 263 if (psk_passphrase_textfield_->IsEnabled() && 264 psk_passphrase_textfield_->IsVisible()) 265 return GetTextFromField(psk_passphrase_textfield_, false); 266 return std::string(); 267 } 268 269 const std::string VPNConfigView::GetUsername() const { 270 return GetTextFromField(username_textfield_, true); 271 } 272 273 const std::string VPNConfigView::GetUserPassphrase() const { 274 return GetTextFromField(user_passphrase_textfield_, false); 275 } 276 277 void VPNConfigView::Init(VirtualNetwork* vpn) { 278 views::GridLayout* layout = views::GridLayout::CreatePanel(this); 279 SetLayoutManager(layout); 280 281 int column_view_set_id = 0; 282 views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id); 283 // Label. 284 column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1, 285 views::GridLayout::USE_PREF, 0, 0); 286 column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing); 287 // Textfield, combobox. 288 column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1, 289 views::GridLayout::USE_PREF, 0, 290 ChildNetworkConfigView::kPassphraseWidth); 291 column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing); 292 // Passphrase visible button. 293 column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, 1, 294 views::GridLayout::USE_PREF, 0, 0); 295 296 // Initialize members. 297 service_text_modified_ = false; 298 provider_type_ = vpn ? 299 vpn->provider_type() : 300 chromeos::VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK; 301 302 // Server label and input. 303 layout->StartRow(0, column_view_set_id); 304 layout->AddView(new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( 305 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME)))); 306 if (!vpn) { 307 server_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT); 308 server_textfield_->SetController(this); 309 layout->AddView(server_textfield_); 310 server_text_ = NULL; 311 } else { 312 server_hostname_ = vpn->server_hostname(); 313 server_text_ = new views::Label(UTF8ToWide(server_hostname_)); 314 server_text_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 315 layout->AddView(server_text_); 316 server_textfield_ = NULL; 317 } 318 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 319 320 // Service label and name or input. 321 layout->StartRow(0, column_view_set_id); 322 layout->AddView(new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( 323 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVICE_NAME)))); 324 if (!vpn) { 325 service_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT); 326 service_textfield_->SetController(this); 327 layout->AddView(service_textfield_); 328 service_text_ = NULL; 329 } else { 330 service_text_ = new views::Label(ASCIIToWide(vpn->name())); 331 service_text_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 332 layout->AddView(service_text_); 333 service_textfield_ = NULL; 334 } 335 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 336 337 // Provider type label and select. 338 layout->StartRow(0, column_view_set_id); 339 layout->AddView(new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( 340 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PROVIDER_TYPE)))); 341 if (!vpn) { 342 provider_type_combobox_ = 343 new views::Combobox(new ProviderTypeComboboxModel()); 344 provider_type_combobox_->set_listener(this); 345 layout->AddView(provider_type_combobox_); 346 provider_type_text_label_ = NULL; 347 } else { 348 provider_type_text_label_ = 349 new views::Label(UTF16ToWide(ProviderTypeToString(provider_type_))); 350 layout->AddView(provider_type_text_label_); 351 provider_type_combobox_ = NULL; 352 } 353 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 354 355 // PSK passphrase label, input and visible button. 356 layout->StartRow(0, column_view_set_id); 357 psk_passphrase_label_ = new views::Label(UTF16ToWide( 358 l10n_util::GetStringUTF16( 359 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PSK_PASSPHRASE))); 360 layout->AddView(psk_passphrase_label_); 361 psk_passphrase_textfield_ = new views::Textfield( 362 views::Textfield::STYLE_PASSWORD); 363 psk_passphrase_textfield_->SetController(this); 364 if (vpn && !vpn->psk_passphrase().empty()) 365 psk_passphrase_textfield_->SetText(UTF8ToUTF16(vpn->psk_passphrase())); 366 layout->AddView(psk_passphrase_textfield_); 367 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 368 369 // User certificate label and input. 370 layout->StartRow(0, column_view_set_id); 371 user_cert_label_ = new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( 372 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_CERT))); 373 layout->AddView(user_cert_label_); 374 user_cert_combobox_ = new views::Combobox(new UserCertComboboxModel()); 375 user_cert_combobox_->set_listener(this); 376 if (vpn && !vpn->user_cert().empty()) { 377 string16 user_cert = UTF8ToUTF16(vpn->user_cert()); 378 for (int i = 0; i < user_cert_combobox_->model()->GetItemCount(); ++i) { 379 if (user_cert_combobox_->model()->GetItemAt(i) == user_cert) { 380 user_cert_combobox_->SetSelectedItem(i); 381 break; 382 } 383 } 384 } 385 layout->AddView(user_cert_combobox_); 386 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 387 388 // Username label and input. 389 layout->StartRow(0, column_view_set_id); 390 layout->AddView(new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( 391 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USERNAME)))); 392 username_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT); 393 username_textfield_->SetController(this); 394 if (vpn && !vpn->username().empty()) 395 username_textfield_->SetText(UTF8ToUTF16(vpn->username())); 396 layout->AddView(username_textfield_); 397 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 398 399 // User passphrase label, input and visble button. 400 layout->StartRow(0, column_view_set_id); 401 layout->AddView(new views::Label(UTF16ToWide( 402 l10n_util::GetStringUTF16( 403 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_PASSPHRASE)))); 404 user_passphrase_textfield_ = new views::Textfield( 405 views::Textfield::STYLE_PASSWORD); 406 user_passphrase_textfield_->SetController(this); 407 if (vpn && !vpn->user_passphrase().empty()) 408 user_passphrase_textfield_->SetText(UTF8ToUTF16(vpn->user_passphrase())); 409 layout->AddView(user_passphrase_textfield_); 410 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 411 412 // Error label. 413 layout->StartRow(0, column_view_set_id); 414 layout->SkipColumns(1); 415 error_label_ = new views::Label(); 416 error_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 417 error_label_->SetColor(SK_ColorRED); 418 layout->AddView(error_label_); 419 420 // Enable controls based on provider type combo. 421 EnableControls(); 422 423 // Set or hide the error text. 424 UpdateErrorLabel(); 425 } 426 427 void VPNConfigView::EnableControls() { 428 switch (provider_type_) { 429 case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: 430 psk_passphrase_label_->SetEnabled(true); 431 psk_passphrase_textfield_->SetEnabled(true); 432 user_cert_label_->SetEnabled(false); 433 user_cert_combobox_->SetEnabled(false); 434 break; 435 case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: 436 case VirtualNetwork::PROVIDER_TYPE_OPEN_VPN: 437 psk_passphrase_label_->SetEnabled(false); 438 psk_passphrase_textfield_->SetEnabled(false); 439 user_cert_label_->SetEnabled(true); 440 user_cert_combobox_->SetEnabled(true); 441 break; 442 default: 443 NOTREACHED(); 444 } 445 } 446 447 } // namespace chromeos 448