dsneditor/EsOdbcDsnEditor/DSNEditorForm.cs (407 lines of code) (raw):

/* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ using System; using System.Data.Odbc; using System.Windows.Forms; using System.IO; using System.Linq; // uncomment to have the assembly loading to ask for (various) resources; various solutions: // https://stackoverflow.com/questions/4368201/appdomain-currentdomain-assemblyresolve-asking-for-a-appname-resources-assembl // [assembly: NeutralResourcesLanguageAttribute("en-GB", UltimateResourceFallbackLocation.MainAssembly)] namespace EsOdbcDsnEditor { /// <summary> /// Delegate for the driver callbacks. /// </summary> public delegate int DriverCallbackDelegate(string connectionString, ref string errorMessage, uint flags); public partial class DsnEditorForm : Form { private const int ESODBC_DSN_EXISTS_ERROR = -1; private const int ESODBC_DSN_NAME_INVALID_ERROR = -4; private DriverCallbackDelegate testConnection; private DriverCallbackDelegate saveDsn; private readonly bool isConnecting; public OdbcConnectionStringBuilder Builder { get; set; } = new OdbcConnectionStringBuilder(); public DsnEditorForm( bool onConnect, string dsn, DriverCallbackDelegate connectionTest, DriverCallbackDelegate dsnSave) { InitializeComponent(); // Wire up default button behaviours AcceptButton = saveButton; CancelButton = cancelButton; isConnecting = onConnect; testConnection = connectionTest; saveDsn = dsnSave; // If connecting then disable some user inputs if (isConnecting) { textName.ReadOnly = textDescription.ReadOnly = true; textName.Enabled = textDescription.Enabled = false; } // If this is a call serving a connect request, name the button "Connect", otherwise it's a DSN editing, so it's going to be a "Save". saveButton.Text = onConnect ? "Connect" : "Save"; // Parse DSN into the builder Builder.ConnectionString = dsn; // Basic Panel textName.Text = Builder.ContainsKey("dsn") ? Builder["dsn"].ToString().StripBraces() : string.Empty; textDescription.Text = Builder.ContainsKey("description") ? Builder["description"].ToString().StripBraces() : string.Empty; textUsername.Text = Builder.ContainsKey("uid") ? Builder["uid"].ToString().StripBraces() : string.Empty; textPassword.Text = Builder.ContainsKey("pwd") ? Builder["pwd"].ToString().StripBraces() : string.Empty; textApiKey.Text = Builder.ContainsKey("apikey") ? Builder["apikey"].ToString().StripBraces() : string.Empty; textCloudID.Text = Builder.ContainsKey("cloudid") ? Builder["cloudid"].ToString().StripBraces() : string.Empty; textHostname.Text = Builder.ContainsKey("server") ? Builder["server"].ToString().StripBraces() : string.Empty; numericUpDownPort.Text = Builder.ContainsKey("port") ? Builder["port"].ToString().StripBraces() : string.Empty; toolTipName.SetToolTip(textName, "The name the DSN will be referred by."); toolTipDescription.SetToolTip(textDescription, "Allows arbitrary text, generally used for short notes about the configured connection."); toolTipCloudID.SetToolTip(textCloudID, "The Cloud ID, if connecting to Elastic Cloud. Settings will be automatically configured."); toolTipHostname.SetToolTip(textHostname, "IP address or a resolvable DNS name of the Elasticsearch instance that the driver will connect to."); toolTipPort.SetToolTip(numericUpDownPort, "The port which the Elasticsearch listens on."); toolTipUsername.SetToolTip(textUsername, "If security is enabled, the username configured to access the REST SQL endpoint."); toolTipPassword.SetToolTip(textPassword, "If security is enabled, the password configured to access the REST SQL endpoint."); toolTipApiKey.SetToolTip(textApiKey, "If security is enabled, the Base64-encoded API key credentials configured to access the REST SQL endpoint."); // Security Panel textCertificatePath.Text = Builder.ContainsKey("capath") ? Builder["capath"].ToString().StripBraces() : string.Empty; radioEnabledNoValidation.Checked = true; // Default setting if (Builder.ContainsKey("secure")) { var result = int.TryParse(Builder["secure"].ToString(), out int val); if (result) { switch (val) { case 0: radioButtonDisabled.Checked = true; break; case 1: radioEnabledNoValidation.Checked = true; break; case 2: radioEnabledNoHostname.Checked = true; break; case 3: radioEnabledHostname.Checked = true; break; case 4: radioEnabledFull.Checked = true; break; } } } toolTipDisabled.SetToolTip(radioButtonDisabled, "The communication between the driver and the Elasticsearch instance is performed over a clear-text connection." + Environment.NewLine + "This setting can expose the access credentials to a 3rd party intercepting the network traffic and is not recommended."); toolTipEnabledNoValidation.SetToolTip(radioEnabledNoValidation, "The connection encryption is enabled, but the certificate of the server is not validated." + Environment.NewLine + "This setting allows a 3rd party to act with ease as a man-in-the-middle and thus intercept all communications."); toolTipEnabledNoHostname.SetToolTip(radioEnabledNoHostname, "The connection encryption is enabled and the driver verifies that server's certificate is valid," + Environment.NewLine + "but it does not verify if the certificate is running on the server it was meant for." + Environment.NewLine + "This setting allows a 3rd party that had access to server's certificate to act as a man-in-the-middle" + Environment.NewLine + "and thus intercept all the communications."); toolTipEnabledHostname.SetToolTip(radioEnabledHostname, "The connection encryption is enabled and the driver verifies that both the certificate is valid," + Environment.NewLine + "as well as that it is being deployed on the server that the certificate was meant for."); toolTipEnabledFull.SetToolTip(radioEnabledFull, "This setting is equivalent to the previous one, with one additional check against certificate's revocation." + Environment.NewLine + "This offers the strongest security option and is the recommended setting for production deployments."); toolTipCertificatePath.SetToolTip(textCertificatePath, "In case the server uses a certificate that is not part of the PKI, for example using a self-signed certificate," + Environment.NewLine + "you can configure the path to a X509 certificate file that will be used by the driver to validate server's offered certificate."); // Proxy Panel string[] noes = {"no", "false", "0"}; checkProxyEnabled.Checked = !noes.Contains(Builder.ContainsKey("ProxyEnabled") ? Builder["ProxyEnabled"].ToString() : "no"); comboBoxProxyType.Text = Builder.ContainsKey("ProxyType") ? Builder["ProxyType"].ToString() : "HTTP"; textProxyHostname.Text = Builder.ContainsKey("ProxyHost") ? Builder["ProxyHost"].ToString().StripBraces() : string.Empty; numericUpDownProxyPort.Text = Builder.ContainsKey("ProxyPort") ? Builder["ProxyPort"].ToString() : string.Empty; checkProxyAuthEnabled.Checked = !noes.Contains(Builder.ContainsKey("ProxyAuthEnabled") ? Builder["ProxyAuthEnabled"].ToString() : "no"); textBoxProxyUsername.Text = Builder.ContainsKey("ProxyAuthUID") ? Builder["ProxyAuthUID"].ToString().StripBraces() : string.Empty; textBoxProxyPassword.Text = Builder.ContainsKey("ProxyAuthPWD") ? Builder["ProxyAuthPWD"].ToString().StripBraces() : string.Empty; toolTipProxyEnabled.SetToolTip(checkProxyEnabled, "This will enable relaying the connection to Elasticsearch over a proxy."); toolTipProxyType.SetToolTip(comboBoxProxyType, "The protocol to use when connecting to the proxy."); toolTipProxyHostname.SetToolTip(textProxyHostname, "The IP or domain name of the proxy server."); toolTipProxyPort.SetToolTip(numericUpDownProxyPort, "The port the proxy is listening on for connections."); toolTipProxyAuthEnabled.SetToolTip(checkProxyAuthEnabled, "Enables the authentication of the connection to the proxy."); toolTipProxyUsername.SetToolTip(textBoxProxyUsername, "The ID to use when authenticating to the proxy."); toolTipProxyPassword.SetToolTip(textBoxProxyPassword, "The password to use when authenticating to the proxy"); // Logging Panel textLogDirectoryPath.Text = Builder.ContainsKey("tracefile") ? Builder["tracefile"].ToString().StripBraces() : string.Empty; comboLogLevel.Text = "DEBUG"; // Default setting checkLoggingEnabled.Checked = true; // Default setting if (Builder.ContainsKey("tracelevel")) { switch (Builder["tracelevel"].ToString().ToUpperInvariant()) { case "DEBUG": comboLogLevel.Text = "DEBUG"; break; case "INFO": comboLogLevel.Text = "INFO"; break; case "WARN": comboLogLevel.Text = "WARN"; break; case "ERROR": comboLogLevel.Text = "ERROR"; break; } } if (Builder.ContainsKey("traceenabled")) { var result = int.TryParse(Builder["traceenabled"].ToString(), out int val); if (result) { switch (val) { case 0: checkLoggingEnabled.Checked = false; break; default: checkLoggingEnabled.Checked = true; break; } } } else { checkLoggingEnabled.Checked = false; } toolTipLoggingEnabled.SetToolTip(checkLoggingEnabled, "Ticking this will enable driver's logging. A logging directory is also mandatory when this option is enabled," + Environment.NewLine + "however the specified logging directory will be saved in the DSN if provided, even if logging is disabled."); toolTipLogDirectoryPath.SetToolTip(textLogDirectoryPath, "Specify which directory to write the log files in."); toolTipLogLevel.SetToolTip(comboLogLevel, "Configure the verbosity of the logs."); // Misc Panel numericUpDownTimeout.Text = Builder.ContainsKey("Timeout") ? Builder["Timeout"].ToString().StripBraces() : "0"; numericUpDownFetchSize.Text = Builder.ContainsKey("MaxFetchSize") ? Builder["MaxFetchSize"].ToString().StripBraces() : "1000"; numericUpDownBodySize.Text = Builder.ContainsKey("MaxBodySizeMB") ? Builder["MaxBodySizeMB"].ToString().StripBraces() : "100"; numericUpDownVarcharLimit.Text = Builder.ContainsKey("VarcharLimit") ? Builder["VarcharLimit"].ToString().StripBraces() : "0"; comboBoxFloatsFormat.Text = Builder.ContainsKey("ScientificFloats") ? Builder["ScientificFloats"].ToString().StripBraces() : "default"; comboBoxDataEncoding.Text = Builder.ContainsKey("Packing") ? Builder["Packing"].ToString() : "CBOR"; comboBoxDataCompression.Text = Builder.ContainsKey("Compression") ? Builder["Compression"].ToString() : "auto"; checkBoxFollowRedirects.Checked = !noes.Contains(Builder.ContainsKey("Follow") ? Builder["Follow"].ToString().StripBraces() : "yes"); checkBoxApplyTZ.Checked = !noes.Contains(Builder.ContainsKey("ApplyTZ") ? Builder["ApplyTZ"].ToString().StripBraces() : "no"); checkBoxAutoEscapePVA.Checked = !noes.Contains(Builder.ContainsKey("AutoEscapePVA") ? Builder["AutoEscapePVA"].ToString().StripBraces() : "yes"); checkBoxEarlyExecution.Checked = !noes.Contains(Builder.ContainsKey("EarlyExecution") ? Builder["EarlyExecution"].ToString().StripBraces() : "yes"); checkBoxMultiFieldLenient.Checked = !noes.Contains(Builder.ContainsKey("MultiFieldLenient") ? Builder["MultiFieldLenient"].ToString().StripBraces() : "yes"); checkBoxIndexIncludeFrozen.Checked = !noes.Contains(Builder.ContainsKey("IndexIncludeFrozen") ? Builder["IndexIncludeFrozen"].ToString().StripBraces() : "no"); toolTipTimeout.SetToolTip(numericUpDownTimeout, "The maximum number of seconds for a request to the server. The value 0 disables the timeout."); toolTipFetchSize.SetToolTip(numericUpDownFetchSize, "The maximum number of rows that Elasticsearch SQL server should send back to the driver for one page."); toolTipBodySize.SetToolTip(numericUpDownBodySize, "The maximum number of megabytes that the driver will accept for one page."); toolTipVarcharLimit.SetToolTip(numericUpDownVarcharLimit, "The maximum number of characters that the string type (TEXT, KEYWORD etc.) columns will exhibit. " + "The value 0 disables the driver limitation."); toolTipFloatsFormat.SetToolTip(comboBoxFloatsFormat, "How should the floating point numbers be printed, when these are converted to string by the driver."); toolTipDataEncoding.SetToolTip(comboBoxDataEncoding, "How should the data between the server and the driver be encoded as."); toolTipDataCompression.SetToolTip(comboBoxDataCompression, "Should the data between the server and the driver be compressed?"); toolTipFollowRedirects.SetToolTip(checkBoxFollowRedirects, "Should the driver follow HTTP redirects of the requests to the server?"); toolTipApplyTZ.SetToolTip(checkBoxApplyTZ, "Should the driver use machine's local timezone? The default is UTC."); toolTipAutoEscapePVA.SetToolTip(checkBoxAutoEscapePVA, "Should the driver auto-escape the pattern-value arguments?"); toolTipMultiFieldLenient.SetToolTip(checkBoxMultiFieldLenient, "Should the server return one value out of a multi-value field (instead of rejecting the request)?"); toolTipEarlyExecution.SetToolTip(checkBoxEarlyExecution, "Should a query be executed already at preparation time? This will only happen if the query lacks parameters."); toolTipIndexIncludeFrozen.SetToolTip(checkBoxIndexIncludeFrozen, "Should the server consider the frozen indices when servicing a request?"); // Set initial state of action buttons. EnableDisableActionButtons(); } /// <summary> /// On save, call the driver's callback. If operation succeeds, close the window. /// On failure, display the error received from the driver and keep editing. /// </summary> private void SaveButton_Click(object sender, EventArgs e) => SaveDsn(false); private void SaveDsn(bool forceOverwrite) { var errorMessage = string.Empty; var dsnResult = RebuildAndValidateDsn(); if (!dsnResult) return; var dsn = Builder.ToString(); var flag = forceOverwrite ? 1u : 0; var result = saveDsn(dsn, ref errorMessage, flag); if (result >= 0 || (forceOverwrite && result == ESODBC_DSN_EXISTS_ERROR)) { Close(); return; } // Specific handling for prompting the user if result is an overwrite action if (forceOverwrite == false && result == ESODBC_DSN_EXISTS_ERROR) { var dialogResult = MessageBox.Show("The DSN already exists, are you sure you wish to overwrite it?", "Overwrite", MessageBoxButtons.YesNo); if (dialogResult == DialogResult.Yes) { SaveDsn(true); } return; } if (errorMessage.Length <= 0) { errorMessage = (result == ESODBC_DSN_NAME_INVALID_ERROR) ? "Invalid DSN name" : "Saving the DSN failed"; } MessageBox.Show(errorMessage, "Operation failure", MessageBoxButtons.OK, MessageBoxIcon.Error); } /// <summary> /// With the Test button the user checks if the input data leads to a connection. /// The function calls the driver callback and displays the result of the operation. /// </summary> private void TestConnectionButton_Click(object sender, EventArgs e) { var errorMessage = string.Empty; var dsnResult = RebuildAndValidateDsn(); if (!dsnResult) return; var dsn = Builder.ToString(); // Wrap slow operation in a wait cursor Cursor = Cursors.WaitCursor; var result = testConnection(dsn, ref errorMessage, 0); Cursor = Cursors.Arrow; if (result >= 0) { MessageBox.Show("Connection Success", "Connection Test", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { var message = "Connection Failed"; if (0 < errorMessage.Length) { message += $": {errorMessage}"; } MessageBox.Show(message, "Connection Test", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private bool RebuildAndValidateDsn() { // Basic Panel Builder["dsn"] = textName.Text; Builder["description"] = textDescription.Text; // https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-put-user.html#security-api-put-user-path-params : // "Leading or trailing whitespace is not allowed." -> it is more likely that a user will insert a // (trailing) white space by mistake than intentionally trying to set it. Builder["uid"] = textUsername.Text.Trim(); Builder["pwd"] = textPassword.Text; Builder["apikey"] = textApiKey.Text; Builder["cloudid"] = "{" + textCloudID.Text.StripBraces().Trim() + "}"; Builder["server"] = textHostname.Text.Trim(); Builder["port"] = numericUpDownPort.Text; // Security Panel Builder["capath"] = textCertificatePath.Text; if (radioButtonDisabled.Checked) Builder["secure"] = 0; if (radioEnabledNoValidation.Checked) Builder["secure"] = 1; if (radioEnabledNoHostname.Checked) Builder["secure"] = 2; if (radioEnabledHostname.Checked) Builder["secure"] = 3; if (radioEnabledFull.Checked) Builder["secure"] = 4; // Proxy Panel Builder["ProxyEnabled"] = checkProxyEnabled.Checked ? "true" : "false"; Builder["ProxyType"] = comboBoxProxyType.Text; Builder["ProxyHost"] = textProxyHostname.Text; Builder["ProxyPort"] = numericUpDownProxyPort.Text; Builder["ProxyAuthEnabled"] = checkProxyAuthEnabled.Checked ? "true" : "false"; Builder["ProxyAuthUID"] = textBoxProxyUsername.Text; Builder["ProxyAuthPWD"] = textBoxProxyPassword.Text; // Logging Panel Builder["tracefile"] = textLogDirectoryPath.Text; Builder["tracelevel"] = comboLogLevel.Text; Builder["traceenabled"] = checkLoggingEnabled.Checked ? "1" : "0"; // Misc Panel Builder["Timeout"] = numericUpDownTimeout.Text; Builder["MaxFetchSize"] = numericUpDownFetchSize.Text; Builder["MaxBodySizeMB"] = numericUpDownBodySize.Text; Builder["VarcharLimit"] = numericUpDownVarcharLimit.Text; Builder["ScientificFloats"] = comboBoxFloatsFormat.Text; Builder["Packing"] = comboBoxDataEncoding.Text; Builder["Compression"] = comboBoxDataCompression.Text; Builder["Follow"] = checkBoxFollowRedirects.Checked ? "true" : "false"; Builder["ApplyTZ"] = checkBoxApplyTZ.Checked ? "true" : "false"; Builder["AutoEscapePVA"] = checkBoxAutoEscapePVA.Checked ? "true" : "false"; Builder["EarlyExecution"] = checkBoxEarlyExecution.Checked ? "true" : "false"; Builder["MultiFieldLenient"] = checkBoxMultiFieldLenient.Checked ? "true" : "false"; Builder["IndexIncludeFrozen"] = checkBoxIndexIncludeFrozen.Checked ? "true" : "false"; // Validations var keynameOK = true; var certificateFileOK = true; var logDirectoryOK = true; if (!string.IsNullOrEmpty(textName.Text)) { keynameOK = ValidateKeyName(textName.Text); } if (!string.IsNullOrEmpty(textCertificatePath.Text)) { certificateFileOK = ValidateCertificateFile(textCertificatePath.Text); } if (!string.IsNullOrEmpty(textLogDirectoryPath.Text)) { logDirectoryOK = ValidateLogFolderPath(textLogDirectoryPath.Text); } return keynameOK && certificateFileOK && logDirectoryOK; } private void LogDirectoryPathButton_Click(object sender, EventArgs e) { var result = folderLogDirectoryDialog.ShowDialog(); if (result == DialogResult.OK) { var path = folderLogDirectoryDialog.SelectedPath; if (ValidateLogFolderPath(path)) { textLogDirectoryPath.Text = path; } } } private bool ValidateLogFolderPath(string path) { if (!checkLoggingEnabled.Checked || string.IsNullOrEmpty(path) || Directory.Exists(path)) { return true; } MessageBox.Show("Log directory invalid, path does not exist", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } private void CertificatePathButton_Click(object sender, EventArgs e) { var result = certificateFileDialog.ShowDialog(); if (result == DialogResult.OK) { var file = certificateFileDialog.FileName; if (ValidateCertificateFile(file)) { textCertificatePath.Text = file; } } } private bool ValidateKeyName(string keyname) { if (keyname.Length > 255) { MessageBox.Show("Name must be less than 255 characters", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } if (keyname.Contains("\\")) { MessageBox.Show("Name cannot contain backslash \\ characters", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } return true; } private bool ValidateCertificateFile(string file) { if (string.IsNullOrEmpty(file)) { return true; } var info = new FileInfo(file); if (info.Exists && info.Length > 0) { return true; } MessageBox.Show("Certificate file invalid", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } private void TextName_TextChanged(object sender, EventArgs e) => EnableDisableActionButtons(); private void TextHostname_TextChanged(object sender, EventArgs e) => EnableDisableActionButtons(); private void TextCloudID_TextChanged(object sender, EventArgs e) => EnableDisableActionButtons(); private void TextUsername_TextChanged(object sender, EventArgs e) => EnableDisableActionButtons(); private void TextPassword_TextChanged(object sender, EventArgs e) => EnableDisableActionButtons(); private void TextApiKey_TextChanged(object sender, EventArgs e) => EnableDisableActionButtons(); private void NumericUpDownPort_ValueChanged(object sender, EventArgs e) => EnableDisableActionButtons(); private void CheckLoggingEnabled_CheckedChanged(object sender, EventArgs e) => EnableDisableLoggingControls(); private void CheckProxyEnabled_CheckedChanged(object sender, EventArgs e) => EnableDisableProxyControls(); private void CheckProxyAuthEnabled_CheckedChanged(object sender, EventArgs e) => EnableDisableProxyAuthControls(); private void ComboBoxProxyType_SelectedIndexChanged(object sender, EventArgs e) => UpdateDefaultPort(); private void EnableDisableActionButtons() { if (string.IsNullOrEmpty(textCloudID.Text) == false) { radioButtonDisabled.Checked = false; radioEnabledNoValidation.Checked = false; radioEnabledNoHostname.Checked = false; radioEnabledHostname.Checked = false; radioEnabledFull.Checked = false; groupSSL.Enabled = false; Builder.Remove("secure"); textHostname.ResetText(); Builder.Remove("server"); numericUpDownPort.ResetText(); Builder.Remove("port"); } else { groupSSL.Enabled = true; } textCloudID.Enabled = string.IsNullOrEmpty(textHostname.Text); textHostname.Enabled = numericUpDownPort.Enabled = textCertificatePath.Enabled = certificatePathButton.Enabled = string.IsNullOrEmpty(textCloudID.Text); if (string.IsNullOrEmpty(textApiKey.Text) == false) { textUsername.ResetText(); Builder.Remove("uid"); textPassword.ResetText(); Builder.Remove("pwd"); } textApiKey.Enabled = string.IsNullOrEmpty(textUsername.Text) && string.IsNullOrEmpty(textPassword.Text); textUsername.Enabled = textPassword.Enabled = string.IsNullOrEmpty(textApiKey.Text); if (isConnecting) { // If connecting, enable the button if we have a hostname. // This can be triggered by app connecting or FileDSN verifying the connection. saveButton.Enabled = string.IsNullOrEmpty(textHostname.Text) == false || string.IsNullOrEmpty(textCloudID.Text) == false; } else { // If editing a (User/System) DSN, enable the buton if both DSN name and hostname are available. saveButton.Enabled = string.IsNullOrEmpty(textName.Text) == false && (string.IsNullOrEmpty(textHostname.Text) == false || string.IsNullOrEmpty(textCloudID.Text) == false); } testButton.Enabled = string.IsNullOrEmpty(textHostname.Text) == false || string.IsNullOrEmpty(textCloudID.Text) == false; } private void EnableDisableLoggingControls() { textLogDirectoryPath.Enabled = checkLoggingEnabled.Checked; comboLogLevel.Enabled = checkLoggingEnabled.Checked; logDirectoryPathButton.Enabled = checkLoggingEnabled.Checked; } private void EnableDisableProxyControls() { comboBoxProxyType.Enabled = checkProxyEnabled.Checked; textProxyHostname.Enabled = checkProxyEnabled.Checked; numericUpDownProxyPort.Enabled = checkProxyEnabled.Checked; checkProxyAuthEnabled.Enabled = checkProxyEnabled.Checked; textBoxProxyUsername.Enabled = checkProxyAuthEnabled.Checked && checkProxyEnabled.Checked; textBoxProxyPassword.Enabled = checkProxyAuthEnabled.Checked && checkProxyEnabled.Checked; } private void EnableDisableProxyAuthControls() { textBoxProxyUsername.Enabled = checkProxyAuthEnabled.Checked; textBoxProxyPassword.Enabled = checkProxyAuthEnabled.Checked; } private void UpdateDefaultPort() { switch(comboBoxProxyType.Text.ToUpperInvariant()) { case "HTTP": numericUpDownProxyPort.Text = "8080"; break; // TODO: https://github.com/jeroen/curl/issues/186 : "Schannel backend doesn't support HTTPS proxy" case "HTTPS": numericUpDownProxyPort.Text = "443"; break; case "SOCKS4": case "SOCKS4A": case "SOCKS5": case "SOCKS5H": numericUpDownProxyPort.Text = "1080"; break; } } private void CancelButton_Click(object sender, EventArgs e) { // Clear the builder so that the resulting int returned to the caller is 0. Builder.Clear(); Close(); } // Remove the [X] close button in top right to force user to use the cancel button. protected override CreateParams CreateParams { get { const int WS_SYSMENU = 0x80000; var cp = base.CreateParams; cp.Style &= ~WS_SYSMENU; return cp; } } } }