/* Copyright (c) Citrix Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Text.RegularExpressions; using System.Windows.Forms; using XenAdmin.Core; using XenAdmin.Network; using XenAdmin.TestResources; namespace XenAdmin.Dialogs { public partial class AddServerDialog : XenDialogBase { protected readonly bool _changedPass; public event EventHandler CachePopulated; /// /// Dialog with defaults taken from an existing IXenConnection /// /// The IXenConnection from which the values will be taken. May be null, in which case an appropriate new /// connection will be created when the dialog is completed. public AddServerDialog(IXenConnection connection, bool changedPass) : base(connection) { _changedPass = changedPass; InitializeComponent(); PopulateXenServerHosts(); if (connection != null) { ServerNameComboBox.Text = connection.HostnameWithPort; UsernameTextBox.Text = connection.Username; PasswordTextBox.Text = connection.Password ?? ""; } // we have an inner table layout panel due to the group box. Align the columns by examining lables sizes Label[] labels = { UsernameLabel, PasswordLabel, ServerNameLabel }; int biggest = 0; foreach (Label l in labels) { if (l.Width > biggest) biggest = l.Width; } // set the minimum size of one label from each table which will make sure the columns line up UsernameLabel.MinimumSize = new Size(biggest, UsernameLabel.Height); ServerNameLabel.MinimumSize = new Size(biggest, ServerNameLabel.Height); } protected void PopulateXenServerHosts() { AutoCompleteStringCollection history = Settings.GetServerHistory(); string[] historyArray = new string[history.Count]; history.CopyTo(historyArray, 0); Array.Sort(historyArray, StringUtility.NaturalCompare); foreach (string serverName in historyArray) { if (serverName != null) ServerNameComboBox.Items.Add(serverName); } // Use a clone as the auto-complete source because of CA-38715 AutoCompleteStringCollection historyClone = new AutoCompleteStringCollection(); historyClone.AddRange(historyArray); ServerNameComboBox.AutoCompleteCustomSource = historyClone; } protected virtual void OnCachePopulated(CachePopulatedEventArgs e) { EventHandler handler = CachePopulated; if (handler != null) { handler(this, e); } } protected void AddServerDialog_Load(object sender, EventArgs e) { UpdateText(); CenterToParent(); } private void AddServerDialog_Shown(object sender, EventArgs e) { //Set focus to the password field if there's a connection and a username. //CA-68596: Focus has to be set when the dialog is shown rather than loaded //(which happens before it's shown), so a warning can pop up if CapsLock is on if (!ServerNameComboBox.Enabled && connection != null && !string.IsNullOrEmpty(connection.Username)) { Win32.SetFocus(PasswordTextBox.Handle); } } protected void UpdateText() { if (connection == null) { Text = Messages.ADD_NEW_CONNECT_TO; labelInstructions.Text = Messages.ADD_NEW_ENTER_CREDENTIALS; labelError.Text = ""; ServerNameComboBox.Enabled = true; AddButton.Text = Messages.ADD; } if (_changedPass && connection.Password == null) { Text = Messages.CONNECT_TO_SERVER; labelInstructions.Text = Messages.CONNECT_TO_SERVER_BLURB; labelError.Text = ""; ServerNameComboBox.Enabled = false; AddButton.Text = Messages.CONNECT; } else if (_changedPass && connection.ExpectPasswordIsCorrect) { // This situation should be rare, it normally comes from logging in a new session after an existing one has been made // We now use duplicate sessions instead most of the time which don't log in again. Text = Messages.CONNECT_TO_SERVER; labelInstructions.Text = Messages.ADDSERVER_PASS_NEW; labelError.Text = ""; ServerNameComboBox.Enabled = false; AddButton.Text = Messages.OK; } else if (_changedPass) // the password probably hasnt actually changed but we do know the user has typed it in wrong { Text = Messages.CONNECT_TO_SERVER; labelInstructions.Text = Messages.ERROR_CONNECTING_BLURB; labelError.Text = Messages.ADD_NEW_INCORRECT; ServerNameComboBox.Enabled = false; AddButton.Text = Messages.CONNECT; } } public virtual void AddButton_Click(object sender, EventArgs e) { string hostnameAndPort = ServerNameComboBox.Text.Trim(); string username = UsernameTextBox.Text.Trim(); string password = PasswordTextBox.Text; string[] multipleHosts; if (TryGetMultipleHosts(hostnameAndPort, out multipleHosts)) { foreach (string h in multipleHosts) { ConnectToServer(null, h, ConnectionsManager.DEFAULT_XEN_PORT, username, password, comboBoxClouds.SelectedItem != null ? comboBoxClouds.SelectedItem.ToString() : string.Empty); } } else { string hostname; int port; if (!StringUtility.TryParseHostname(hostnameAndPort, ConnectionsManager.DEFAULT_XEN_PORT, out hostname, out port)) { hostname = hostnameAndPort; port = ConnectionsManager.DEFAULT_XEN_PORT; } ConnectToServer(connection, hostname, port, username, password, comboBoxClouds.SelectedItem != null ? comboBoxClouds.SelectedItem.ToString() : string.Empty); } Close(); } /// May be null, in which case a new connection will be created protected void ConnectToServer(IXenConnection conn, string hostname, int port, string username, string password, string version) { if (conn == null) { XenConnection connection = new XenConnection(); connection.CachePopulated += conn_CachePopulated; connection.fromDialog = true; conn = connection; } else if (!_changedPass) { conn.EndConnect(); // in case we're already connected } conn.Hostname = hostname; conn.Port = port; conn.Username = username; conn.Password = password; conn.ExpectPasswordIsCorrect = false; conn.Version = version; if (!_changedPass) XenConnectionUI.BeginConnect(conn, true, Owner, false); } private void conn_CachePopulated(object sender, EventArgs e) { IXenConnection connection = (IXenConnection)sender; connection.CachePopulated -= conn_CachePopulated; OnCachePopulated(new CachePopulatedEventArgs(connection)); } private void CancelButton2_Click(object sender, EventArgs e) { Close(); } private void TextFields_TextChanged(object sender, EventArgs e) { UpdateButtons(); } protected void UpdateButtons() { AddButton.Enabled = OKButtonEnabled(); } protected virtual bool OKButtonEnabled() { return ServerNameComboBox.Text.Trim().Length > 0 && UsernameTextBox.Text.Trim().Length > 0; } private void CancelButton2_KeyDown(object sender, KeyEventArgs e) { if (e.Control || e.Alt) { switch (e.KeyCode) { case Keys.D1: Launch(TestResource.Resource.InterestingProduction); break; case Keys.D2: Launch(TestResource.Resource.InterestingDevelopment); break; case Keys.D3: Launch(TestResource.Resource.InterestingXenApp); break; case Keys.D4: Launch(TestResource.Resource.Credits); break; default: break; } } } private void Launch(TestResource.Resource r) { ServerNameComboBox.Text = TestResource.Location(r); AddButton_Click(this, null); } /// /// Used for testing. Parses text for a semi-colon separated list of files that are loaded by DbProxy. /// /// The text to be parsed /// The parse results /// A value indicating whether the operation succeeded. private static bool TryGetMultipleHosts(string text, out string[] hosts) { hosts = new string[0]; string[] splitStr = text.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); if (splitStr.Length > 0) { List hostList = new List(); foreach (string element in splitStr) { string host = element.Trim(); if (string.IsNullOrEmpty(host)) // ignore "empty" entry continue; if (Regex.IsMatch(host, @"^[A-Za-z]\:\\") && File.Exists(host)) { // is a file hostList.Add(host); continue; } if (Regex.IsMatch(host, @"^http\:|^[A-Za-z]\:")) { Uri uri; if (Uri.TryCreate(host, UriKind.Absolute, out uri)) { hostList.Add(host); continue; } } else { // some sort of ip address or hostname, just add hostList.Add(host); } } if (hostList.Count < 2) { return false; } hosts = hostList.ToArray(); return true; } return false; } private void labelError_TextChanged(object sender, EventArgs e) { pictureBoxError.Visible = labelError.Visible = (labelError.Text != ""); } private void AddServerDialog_FormClosing(object sender, FormClosingEventArgs e) { if (connection != null) XenConnectionUI.connectionDialogs.Remove(connection); } } public class CachePopulatedEventArgs : EventArgs { private readonly IXenConnection _connection; public CachePopulatedEventArgs(IXenConnection connection) { Util.ThrowIfParameterNull(connection, "connection"); _connection = connection; } public IXenConnection Connection { get { return _connection; } } } }