• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ProviderTypeToString(chromeos::VirtualNetwork::ProviderType type)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 
GetItemCount()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 
GetItemAt(int index)55 string16 VPNConfigView::ProviderTypeComboboxModel::GetItemAt(int index) {
56   VirtualNetwork::ProviderType type =
57       static_cast<VirtualNetwork::ProviderType>(index);
58   return ProviderTypeToString(type);
59 }
60 
UserCertComboboxModel()61 VPNConfigView::UserCertComboboxModel::UserCertComboboxModel() {
62   // TODO(jamescook): populate user_certs_. chromium-os:14111
63 }
64 
GetItemCount()65 int VPNConfigView::UserCertComboboxModel::GetItemCount() {
66   return static_cast<int>(user_certs_.size());
67 }
68 
GetItemAt(int index)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 
VPNConfigView(NetworkConfigView * parent,VirtualNetwork * vpn)75 VPNConfigView::VPNConfigView(NetworkConfigView* parent, VirtualNetwork* vpn)
76     : ChildNetworkConfigView(parent, vpn) {
77   Init(vpn);
78 }
79 
VPNConfigView(NetworkConfigView * parent)80 VPNConfigView::VPNConfigView(NetworkConfigView* parent)
81     : ChildNetworkConfigView(parent) {
82   Init(NULL);
83 }
84 
~VPNConfigView()85 VPNConfigView::~VPNConfigView() {
86 }
87 
UpdateCanLogin()88 void VPNConfigView::UpdateCanLogin() {
89   parent_->GetDialogClientView()->UpdateDialogButtons();
90 }
91 
GetTitle()92 string16 VPNConfigView::GetTitle() {
93   return l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_ADD_VPN);
94 }
95 
CanLogin()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 
UpdateErrorLabel()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 
ContentsChanged(views::Textfield * sender,const string16 & new_contents)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 
HandleKeyEvent(views::Textfield * sender,const views::KeyEvent & key_event)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 
ButtonPressed(views::Button * sender,const views::Event & event)163 void VPNConfigView::ButtonPressed(views::Button* sender,
164                                   const views::Event& event) {
165 }
166 
ItemChanged(views::Combobox * combo_box,int prev_index,int new_index)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 
Login()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 
Cancel()233 void VPNConfigView::Cancel() {
234 }
235 
InitFocus()236 void VPNConfigView::InitFocus() {
237   // TODO(jamescook): Put focus in a more reasonable widget.
238 }
239 
GetTextFromField(views::Textfield * textfield,bool trim_whitespace) const240 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 
GetService() const250 const std::string VPNConfigView::GetService() const {
251   if (service_textfield_ != NULL)
252     return GetTextFromField(service_textfield_, true);
253   return service_path_;
254 }
255 
GetServer() const256 const std::string VPNConfigView::GetServer() const {
257   if (server_textfield_ != NULL)
258     return GetTextFromField(server_textfield_, true);
259   return server_hostname_;
260 }
261 
GetPSKPassphrase() const262 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 
GetUsername() const269 const std::string VPNConfigView::GetUsername() const {
270   return GetTextFromField(username_textfield_, true);
271 }
272 
GetUserPassphrase() const273 const std::string VPNConfigView::GetUserPassphrase() const {
274   return GetTextFromField(user_passphrase_textfield_, false);
275 }
276 
Init(VirtualNetwork * vpn)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 
EnableControls()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