Home | History | Annotate | Download | only in options
      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