xenadmin/XenAdmin/Dialogs/AddServerDialog.cs
Gabor Apati-Nagy 0c07daf42d CA-232294: Can't connect if an Add Server dialog has been cancelled before
This commit is to fix the following: "when right clicking a disconnected pool the context menu gives you the option to connect, this opens a window to enter credentials. if you close this window (either by cancel or the X), next time when you right click and click connect, nothing happens. you have to restart XenCenter to connect to the pool"

Signed-off-by: Gabor Apati-Nagy <gabor.apati-nagy@citrix.com>
2016-11-24 17:01:53 +00:00

367 lines
14 KiB
C#

/* 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<CachePopulatedEventArgs> CachePopulated;
/// <summary>
/// Dialog with defaults taken from an existing IXenConnection
/// </summary>
/// <param name="connection">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.</param>
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<CachePopulatedEventArgs> 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();
}
/// <param name="connection">May be null, in which case a new connection will be created</param>
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);
}
/// <summary>
/// Used for testing. Parses text for a semi-colon separated list of files that are loaded by DbProxy.
/// </summary>
/// <param name="text">The text to be parsed</param>
/// <param name="hosts">The parse results</param>
/// <returns>A value indicating whether the operation succeeded.</returns>
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<string> hostList = new List<string>();
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;
}
}
}
}