Imports System.ComponentModel
Imports System.Security.Cryptography.X509Certificates
Imports System.Text
Imports ComponentPro
Imports SmtpSendMail.Security
Imports ComponentPro.Net
Imports ComponentPro.Net.Mail
Imports System.IO
Imports ComponentPro.Security.Certificates

Namespace SmtpSendMail
	Partial Public Class SmtpSendMail
		Inherits Form
		Private ReadOnly _exception As Boolean
		Private _sec As SecurityMode
		Private _sign As Boolean
		Private _encrypt As Boolean
		Private _cert As String
		Private _tls As Boolean
		Private _ssl As Boolean
		Private _suites As Integer
		Private _changed As Boolean
		Private _mailFileName As String
		Private _attachments As AttachmentCollection
		Private _internalChanges As Boolean

		Private _server As String
		Private _port As Integer
		Private _userName As String
		Private _password As String
		Private _method As SmtpAuthenticationMethod
		Private _timeout As Integer

		#Region "Proxy"

		Private _proxyServer As String
		Private _proxyUserName As String
		Private _proxyPassword As String
		Private _proxyDomain As String
		Private _proxyPort As Integer
		Private _proxyAuthenticationMethod As ProxyHttpConnectAuthMethod
		Private _proxyType As ProxyType

		#End Region

		Private _disconnect As Boolean
		Private _disconnected As Boolean

		Public Sub New()
			Try
				InitializeComponent()
			Catch exc As ComponentPro.Licensing.Mail.UltimateLicenseException
				MessageBox.Show(exc.Message, "Error")
				_exception = True
				Return
			End Try

			' Attachs the TextChanged event handler to all text boxes.
			AddHandler txtBcc.TextChanged, AddressOf txt_TextChanged
			AddHandler txtBody.TextChanged, AddressOf txt_TextChanged
			AddHandler txtCc.TextChanged, AddressOf txt_TextChanged
			AddHandler txtFrom.TextChanged, AddressOf txt_TextChanged
			AddHandler txtSubject.TextChanged, AddressOf txt_TextChanged
			AddHandler txtTo.TextChanged, AddressOf txt_TextChanged

			' New messages.
			NewMesssage()

			AddHandler Me.client.CertificateRequired, AddressOf client_CertificateRequired
			AddHandler Me.client.DisconnectCompleted, AddressOf smtpClient_DisconnectCompleted
			AddHandler Me.client.AuthenticateCompleted, AddressOf smtpClient_LoginCompleted
			AddHandler Me.client.CertificateReceived, AddressOf client_CertificateReceived
			AddHandler Me.client.ConnectCompleted, AddressOf smtpClient_ConnectCompleted
			AddHandler Me.client.SendCompleted, AddressOf smtpClient_SendCompleted
		End Sub

		''' <summary>
		''' Handles the form's Load event.
		''' </summary>
		''' <param name="e"></param>
		Protected Overrides Sub OnLoad(ByVal e As EventArgs)
			MyBase.OnLoad(e)
			If _exception Then
				Me.Close()
			End If

			' Load settings from the Registry.
			LoadConfig()
		End Sub

		#Region "Config"

		''' <summary>
		''' Loads settings from the Registry.
		''' </summary>
		Private Sub LoadConfig()
			_sec = CType(Util.GetIntProperty("SecurityMode", 0), SecurityMode)
			_sign = CStr(Util.GetProperty("Sign", "False")) = "True"
			_encrypt = CStr(Util.GetProperty("Encrypt", "False")) = "True"
			_cert = CStr(Util.GetProperty("Cert", String.Empty))
			_tls = CStr(Util.GetProperty("TLS", "True")) = "True"
			_ssl = CStr(Util.GetProperty("SSL", "True")) = "True"
			_suites = Util.GetIntProperty("Suites", 0)

			_server = CStr(Util.GetProperty("SmtpServer", String.Empty))
			_port = Util.GetIntProperty("SmtpPort", 25)
			_userName = CStr(Util.GetProperty("UserName", String.Empty))
			_password = CStr(Util.GetProperty("Password", String.Empty))
			_method = CType(Util.GetIntProperty("SmtpAuthenticationMethod", 0), SmtpAuthenticationMethod)
			_timeout = Util.GetIntProperty("Timeout", 60000)

			_proxyServer = CStr(Util.GetProperty("ProxyServer", String.Empty))
			_proxyUserName = CStr(Util.GetProperty("ProxyUserName", String.Empty))
			_proxyPassword = CStr(Util.GetProperty("ProxyPassword", String.Empty))
			_proxyDomain = CStr(Util.GetProperty("ProxyDomain", String.Empty))
			_proxyPort = Util.GetIntProperty("ProxyPort", 1080)
			_proxyAuthenticationMethod = CType(Util.GetIntProperty("ProxyAuthentication", 0), ProxyHttpConnectAuthMethod)
			_proxyType = CType(Util.GetIntProperty("ProxyType", 0), ProxyType)
		End Sub

		''' <summary>
		''' Saves settings to the Registry.
		''' </summary>
		Private Sub SaveConfig()
			Util.SaveProperty("SecurityMode", CInt(Fix(_sec)))
			Util.SaveProperty("Sign", _sign)
			Util.SaveProperty("Encrypt", _encrypt)
			Util.SaveProperty("Cert", _cert)
			Util.SaveProperty("TLS", _tls)
			Util.SaveProperty("SSL", _ssl)
			Util.SaveProperty("Suites", _suites)

			Util.SaveProperty("SmtpServer", _server)
			Util.SaveProperty("SmtpPort", _port)
			Util.SaveProperty("UserName", _userName)
			Util.SaveProperty("Password", _password)
			Util.SaveProperty("SmtpAuthenticationMethod", CInt(Fix(_method)))
			Util.SaveProperty("Timeout", _timeout)

			Util.SaveProperty("ProxyServer", _proxyServer)
			Util.SaveProperty("ProxyUserName", _proxyUserName)
			Util.SaveProperty("ProxyPassword", _proxyPassword)
			Util.SaveProperty("ProxyDomain", _proxyDomain)
			Util.SaveProperty("ProxyPort", _proxyPort)
			Util.SaveProperty("ProxyAuthentication", CInt(Fix(_proxyAuthenticationMethod)))
			Util.SaveProperty("ProxyType", CInt(Fix(_proxyType)))
		End Sub

		#End Region

		''' <summary>
		''' Handles the content text box's TextChanged event.
		''' </summary>
		''' <param name="sender">The content text box.</param>
		''' <param name="e">The event arguments.</param>
		Private Sub txt_TextChanged(ByVal sender As Object, ByVal e As EventArgs)
			' Changes the form's title if needed.
			Dim b As Boolean = _changed
			' Message content has been changed.
			_changed = True
			saveButton.Enabled = True
			If b = False Then
				SetTitle()
			End If
		End Sub

		''' <summary>
		''' Sets the title.
		''' </summary>
		Private Sub SetTitle()
			If Not _internalChanges Then
				' Sets form's title.
				Dim str As String = "Ultimate Mail Composer and Sender"

				If _mailFileName IsNot Nothing Then
					str &= " - " & Path.GetFileName(_mailFileName)
				End If

				If txtSubject.Text.Length > 0 Then
					str &= " - " & txtSubject.Text
				End If

				If _changed Then
					str &= "*"
				End If

				Me.Text = str
			End If
		End Sub

		''' <summary>
		''' Enables/disables the dialog.
		''' </summary>
		''' <param name="enable"></param>
		Private Sub EnableDialog(ByVal enable As Boolean)
			Util.EnableCloseButton(Me, enable)

			' Enable/Disable form's elements.
			newMessageButton.Enabled = enable
			openMessageButton.Enabled = enable
			saveButton.Enabled = enable
			saveAsButton.Enabled = enable
			saveAttachmentsButton.Enabled = enable

			tsbCancel.Enabled = Not enable
			tsbSend.Enabled = enable
			tsbSettings.Enabled = enable

			pasteButton.Enabled = enable
			cutButton.Enabled = enable
			copyButton.Enabled = enable
			selectAllButton.Enabled = enable

			toolStripProgressBar.Visible = Not enable
			toolStripProgressBar.Value = 0

			txtFrom.Enabled = enable
			txtBcc.Enabled = enable
			txtBody.Enabled = enable
			txtCc.Enabled = enable
			txtSubject.Enabled = enable
			txtTo.Enabled = enable
			cbxAttachment.Enabled = enable
			btnAddAttachment.Enabled = enable
			If Not enable Then
				btnRemoveAttachment.Enabled = False
			Else
				btnRemoveAttachment.Enabled = (cbxAttachment.Items.Count > 0)
			End If
		End Sub

		''' <summary>
		''' Sets the title.
		''' </summary>
		Private Sub txtSubject_TextChanged(ByVal sender As Object, ByVal e As EventArgs) Handles txtSubject.TextChanged
			' Changes the form's title whenever the subject is changed.
			SetTitle()
		End Sub

		''' <summary>
		''' Creates new message.
		''' </summary>
		Private Sub NewMesssage()
			_internalChanges = True
			txtBcc.Text = String.Empty
			txtBody.Text = String.Empty
			txtCc.Text = String.Empty
			txtFrom.Text = String.Empty
			txtSubject.Text = String.Empty
			txtTo.Text = String.Empty
			cbxAttachment.Items.Clear()
			_mailFileName = Nothing
			_attachments = Nothing
			_changed = False
			_internalChanges = False
			SetTitle()
			saveAttachmentsButton.Enabled = False
			saveButton.Enabled = False
		End Sub

		''' <summary>
		''' Opens an existing message.
		''' </summary>
		''' <param name="fileName"></param>
		Private Sub OpenMessage(ByVal fileName As String)
			_internalChanges = True
			' Create a new message object.
			Dim message As New MailMessage()
			_mailFileName = fileName
			' Load message from the specified file.
			message.Load(fileName)

			' Update subject and content text boxes.
			txtSubject.Text = message.Subject
			txtBody.Text = message.BodyText.Replace(vbLf, vbCrLf)

			Dim sb As New StringBuilder()

			For Each [to] As MailAddress In message.To
				Dim address As String = [to].ToString()
				If address.Length > 0 Then
					sb.Append(address)
					sb.Append(";"c)
				End If
			Next [to]
			If sb.Length > 0 Then
				sb.Length -= 1
			End If
			txtTo.Text = sb.ToString()

			sb.Length = 0
			For Each bcc As MailAddress In message.Bcc
				Dim address As String = bcc.ToString()
				If address.Length > 0 Then
					sb.Append(address)
					sb.Append(";"c)
				End If
			Next bcc
			If sb.Length > 0 Then
				sb.Length -= 1
			End If
			txtBcc.Text = sb.ToString()

			sb.Length = 0
			For Each cc As MailAddress In message.Cc
				Dim address As String = cc.ToString()
				If address.Length > 0 Then
					sb.Append(address)
					sb.Append(";"c)
				End If
			Next cc
			If sb.Length > 0 Then
				sb.Length -= 1
			End If
			txtCc.Text = sb.ToString()

			sb.Length = 0
			For Each [from] As MailAddress In message.From
				Dim address As String = [from].ToString()
				If address.Length > 0 Then
					sb.Append(address)
					sb.Append(";"c)
				End If
			Next [from]
			If sb.Length > 0 Then
				sb.Length -= 1
			End If
			txtFrom.Text = sb.ToString()

			cbxAttachment.Items.Clear()

			' Update attachment combo box.
			If message.Attachments.Count > 0 Then
				_attachments = New AttachmentCollection()
				For Each att As Attachment In message.Attachments
					_attachments.Add(att)
					cbxAttachment.Items.Add(Path.GetFileName(att.FileName))
				Next att
				cbxAttachment.SelectedIndex = 0
				btnRemoveAttachment.Enabled = True
				saveAttachmentsButton.Enabled = True
			Else
				saveAttachmentsButton.Enabled = False
			End If
			_changed = False
			saveButton.Enabled = False
			_internalChanges = False
		End Sub

		''' <summary>
		''' Shows Save as dialog and save the message to the specified file.
		''' </summary>
		Private Sub SaveMessageAs()
			Dim dlg As New SaveFileDialog()
			Try
				dlg.OverwritePrompt = True
				dlg.Filter = "Email files (*.eml)|*.eml|All files (*.*)|*.*"
				dlg.FilterIndex = 1
				dlg.Title = "Save the mail as"
				If dlg.ShowDialog() <> System.Windows.Forms.DialogResult.OK Then
					Return
				End If

				_mailFileName = dlg.FileName
				SaveMessageAs(dlg.FileName)
			Catch
				MessageBox.Show(dlg.FileName & " is not an email file", "Error")
			End Try
		End Sub

		''' <summary>
		''' Creates a new Message object.
		''' </summary>
		''' <returns>A new Message object.</returns>
		Private Function CreateMessage() As MailMessage
			Dim message As New MailMessage()

			message.Subject = txtSubject.Text
			message.BodyText = txtBody.Text

			For Each [to] As String In txtTo.Text.Split(New Char() { ";"c, ","c })
				Dim email As String = [to].Trim()
				If email.Length > 0 Then
					message.To.Add(email)
				End If
			Next [to]

			For Each bcc As String In txtBcc.Text.Split(New Char() { ";"c, ","c })
				Dim email As String = bcc.Trim()
				If email.Length > 0 Then
					message.Bcc.Add(email)
				End If
			Next bcc

			For Each cc As String In txtCc.Text.Split(New Char() { ";"c, ","c })
				Dim email As String = cc.Trim()
				If email.Length > 0 Then
					message.Cc.Add(email)
				End If
			Next cc

			For Each [from] As String In txtFrom.Text.Split(New Char() { ";"c, ","c })
				Dim email As String = [from].Trim()
				If email.Length > 0 Then
					message.From.Add(email)
				End If
			Next [from]

			If _attachments IsNot Nothing Then
				For Each att As Attachment In _attachments
					message.Attachments.Add(att)
				Next att
			End If

			Return message
		End Function

		''' <summary>
		''' Saves the current message as a file.
		''' </summary>
		''' <param name="fileName"></param>
		Private Sub SaveMessageAs(ByVal fileName As String)
			Dim message As MailMessage = CreateMessage()
			message.Save(fileName)
			_changed = False
			saveButton.Enabled = False
			SetTitle()
		End Sub

		''' <summary>
		''' Saves message, if message file name has not been set, a Save file as dialog will be shown to ask for the destination file name.
		''' </summary>
		Private Sub SaveMessage()
			If _mailFileName Is Nothing Then
				SaveMessageAs()
			Else
				Try
					SaveMessageAs(_mailFileName)
				Catch exc As Exception
					MessageBox.Show(String.Format("Unable to save the message to file: '{0}'" & vbCrLf & "{1}", _mailFileName, exc.Message), "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop)
				End Try
			End If
		End Sub

		''' <summary>
		''' Saves attachments to a specific folder.
		''' </summary>
		Private Sub SaveAttachmentAs(ByVal folder As String)
			For Each att As Attachment In _attachments
				att.Save(Path.Combine(folder, att.FileName))
			Next att
		End Sub

		''' <summary>
		''' Saves attachments to a specific folder. A browing folder dialog will be shown.
		''' </summary>
		Private Sub SaveAttachmentAs()
			Dim folderBrowserDialog As New FolderBrowserDialog()
			If folderBrowserDialog.ShowDialog() <> System.Windows.Forms.DialogResult.OK Then
				Return
			End If

			Dim path As String = folderBrowserDialog.SelectedPath
			SaveAttachmentAs(path)
		End Sub

		''' <summary>
		''' If the message has not been saved, shows a message box asking user to save the changes.
		''' </summary>
		''' <returns>A bool value indicating whether the closing action should be cancelled.</returns>
		Private Function AskSaving() As Boolean
			If _changed Then
				Dim result As DialogResult = MessageBox.Show("Do you want to save the changes you have made?", "Smtp Send Mail", MessageBoxButtons.YesNoCancel)
				If result = System.Windows.Forms.DialogResult.Cancel Then
					Return True
				End If
				If result = System.Windows.Forms.DialogResult.Yes Then
					SaveMessage()
				End If
			End If

			Return False
		End Function

		Private Sub newMessageButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles newMessageButton.Click
			If Not AskSaving() Then
				NewMesssage()
			End If
		End Sub

		Private Sub openMessageButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles openMessageButton.Click
			If Not AskSaving() Then
				Dim dlg As New OpenFileDialog()
				Try
					dlg.Filter = "Email files (*.eml)|*.eml|Outlook files (*.msg)|*.msg|All files (*.*)|*.*"
					dlg.FilterIndex = 1
					dlg.Title = "Select an email file"
					' Show open file dialog.
					If dlg.ShowDialog() <> System.Windows.Forms.DialogResult.OK Then
						Return
					End If

					OpenMessage(dlg.FileName)
					SetTitle()
				Catch
					MessageBox.Show(dlg.FileName & " is not an email file", "Error")
				End Try
			End If
		End Sub

		Private Sub saveButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles saveButton.Click
			If _changed Then
				SaveMessage()
			End If
		End Sub

		Private Sub saveAsButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles saveAsButton.Click
			SaveMessageAs()
		End Sub

		Private Sub saveAttachmentsButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles saveAttachmentsButton.Click
			SaveAttachmentAs()
		End Sub

		Private Sub exitButton_Click(ByVal sender As Object, ByVal e As EventArgs)
			Me.Close()
		End Sub

		Private Sub cutButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cutButton.Click
			txtBody.Cut()
		End Sub

		Private Sub copyButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles copyButton.Click
			txtBody.Copy()
		End Sub

		Private Sub pasteButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles pasteButton.Click
			txtBody.Paste()
		End Sub

		Private Sub selectAllButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles selectAllButton.Click
			txtBody.SelectAll()
		End Sub

		''' <summary>
		''' Handles the add attachment button's Click event.
		''' </summary>
		''' <param name="sender">The button object.</param>
		''' <param name="e">The event arguments.</param>
		Private Sub btnAddAttachment_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnAddAttachment.Click
			Dim dlg As New OpenFileDialog()
			Try
				Dim b As Boolean = _changed

				dlg.Filter = "All files (*.*)|*.*"
				dlg.FilterIndex = 1
				dlg.Title = "Select a file"
				dlg.Multiselect = True
				If dlg.ShowDialog() <> System.Windows.Forms.DialogResult.OK Then
					Return
				End If

				' Creates an AttachmentCollection if _attachments is null.
				If _attachments Is Nothing Then
					_attachments = New AttachmentCollection()
				End If

				' Adds selected files to the attachment collection and the combo box as well.
				For Each fileName As String In dlg.FileNames
					_attachments.Add(fileName)
					cbxAttachment.Items.Add(System.IO.Path.GetFileName(fileName))
				Next fileName
				' Selects the last item.
				cbxAttachment.SelectedIndex = cbxAttachment.Items.Count - 1

				btnRemoveAttachment.Enabled = True
				_changed = True
				saveButton.Enabled = True
				saveAttachmentsButton.Enabled = True
				If b = False Then ' sets the title if needed.
					SetTitle()
				End If
			Catch
				MessageBox.Show(dlg.FileName & " is not a file", "Error")
			End Try
		End Sub

		''' <summary>
		''' Handles the remove attachment button's Click event.
		''' </summary>
		''' <param name="sender">The button object.</param>
		''' <param name="e">The event arguments.</param>
		Private Sub btnRemoveAttachment_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnRemoveAttachment.Click
			Dim b As Boolean = _changed

			' Removes an attachment from the collection.
			_attachments.RemoveAt(cbxAttachment.SelectedIndex)

			' and the combo box.
			If _attachments.Count > 0 Then
				' and the combo box.
				cbxAttachment.Items.RemoveAt(cbxAttachment.SelectedIndex)
			Else
				cbxAttachment.SelectedItem = Nothing
				cbxAttachment.Items.Clear()
			End If

			If cbxAttachment.Items.Count = 0 Then
				' Disables the "Remove" button. 
				btnRemoveAttachment.Enabled = False
				_attachments = Nothing
				saveAttachmentsButton.Enabled = False
			ElseIf cbxAttachment.SelectedIndex = -1 Then
				cbxAttachment.SelectedIndex = cbxAttachment.Items.Count - 1
			End If

			_changed = True
			saveButton.Enabled = True
			If b = False Then
				SetTitle()
			End If
		End Sub

		''' <summary>
		''' Handles the Send toolbar button's Click event.
		''' </summary>
		''' <param name="sender">The button object.</param>
		''' <param name="e">The event arguments.</param>
		Private Sub tsbSend_Click(ByVal sender As Object, ByVal e As EventArgs) Handles tsbSend.Click
			If String.IsNullOrEmpty(_server) Then
				MessageBox.Show("Smtp server is not set, please click on the Settings toolbar button to configure", "Error")
				Return
			End If

			EnableDialog(False)
			_disconnected = False

			' Set timeout.
			client.Timeout = _timeout

			Dim proxy As New WebProxyEx()
			client.Proxy = proxy
			If _proxyServer.Length > 0 AndAlso _proxyPort > 0 Then
				' Set proxy settings.
				proxy.Server = _proxyServer
				proxy.Port = _proxyPort
				proxy.UserName = _proxyUserName
				proxy.Password = _proxyPassword
				proxy.Domain = _proxyDomain
				proxy.ProxyType = _proxyType
				proxy.AuthenticationMethod = _proxyAuthenticationMethod
			End If

			tssStatus.Text = String.Format("Connecting to {0}:{1}", _server, _port)

			' Asynchronously connect to the SMTP server.
			client.ConnectAsync(_server, _port, _sec)
		End Sub

		''' <summary>
		''' Handles the client's ConnectCompleted event.
		''' </summary>
		''' <param name="sender">The client object.</param>
		''' <param name="e">The event arguments.</param>
		Private Sub smtpClient_ConnectCompleted(ByVal sender As Object, ByVal e As ExtendedAsyncCompletedEventArgs(Of String))
			If e.Error IsNot Nothing Then
				Util.ShowError(e.Error)
				Disconnect()
				Return
			End If

			Login()
		End Sub

		Private Sub Login()
			If _disconnect Then
				Disconnect()
				Return
			End If

			' Authentication is required?
			If Not String.IsNullOrEmpty(_userName) Then
				SetStatusText("Logging in...")

				' Asynchronously login to the server.
				client.AuthenticateAsync(_userName, _password, _method)
			Else
				' Immediately send the message without authenticating.
				SendMessage()
			End If
		End Sub

		''' <summary>
		''' Handles the client's AuthenticateCompleted event.
		''' </summary>
		''' <param name="sender">The client object.</param>
		''' <param name="e">The event arguments.</param>
		Private Sub smtpClient_LoginCompleted(ByVal sender As Object, ByVal e As AsyncCompletedEventArgs)
			If e.Error IsNot Nothing Then
				Util.ShowError(e.Error)
				Disconnect()
				Return
			End If

			SendMessage()
		End Sub

		''' <summary>
		''' Sends the message.
		''' </summary>
		Private Sub SendMessage()
			If _disconnect Then
				Disconnect()
				Return
			End If

			SetStatusText("Sending message...")

			client.SendAsync(CreateMessage())
		End Sub

		''' <summary>
		''' Handles the client's SendCompleted event.
		''' </summary>
		''' <param name="sender">The client object.</param>
		''' <param name="e">The event arguments.</param>
		Private Sub smtpClient_SendCompleted(ByVal sender As Object, ByVal e As AsyncCompletedEventArgs)
			If e.Error IsNot Nothing Then
				Util.ShowError(e.Error)
				Disconnect()
				Return
			End If

			If _disconnect Then
				Disconnect()
				Return
			End If
			MessageBox.Show("Message sent.", "Smtp Send Mail")
			Disconnect()
		End Sub

		''' <summary>
		''' Handles the Settings toolbar button's Click event.
		''' </summary>
		''' <param name="sender">The button object.</param>
		''' <param name="e">The event arguments.</param>
		Private Sub tsbSettings_Click(ByVal sender As Object, ByVal e As EventArgs) Handles tsbSettings.Click
			Dim sec As New Settings()
			sec.Security = _sec
			sec.Sign = _sign
			sec.Encrypt = _encrypt
			sec.Cert = _cert
			sec.Suites = _suites
			sec.Server = _server
			sec.Port = _port
			sec.UserName = _userName
			sec.Password = _password
			sec.Method = _method
			sec.Timeout = _timeout

			' Proxy Settings
			sec.ProxyServer = _proxyServer
			sec.ProxyPort = _proxyPort
			sec.ProxyUserName = _proxyUserName
			sec.ProxyPassword = _proxyPassword
			sec.ProxyDomain = _proxyDomain
			sec.ProxyAuthenticationMethod = _proxyAuthenticationMethod
			sec.ProxyType = _proxyType

			' Popups the Settings form.
			If sec.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
				_sec = sec.Security
				_sign = sec.Sign
				_encrypt = sec.Encrypt
				_cert = sec.Cert
				_suites = sec.Suites
				_server = sec.Server
				_port = sec.Port
				_userName = sec.UserName
				_password = sec.Password
				_method = sec.Method
				_timeout = sec.Timeout

				_proxyServer = sec.ProxyServer
				_proxyPort = sec.ProxyPort
				_proxyUserName = sec.ProxyUserName
				_proxyPassword = sec.ProxyPassword
				_proxyDomain = sec.ProxyDomain
				_proxyAuthenticationMethod = sec.ProxyAuthenticationMethod
				_proxyType = sec.ProxyType
			End If
		End Sub

		''' <summary>
		''' Handles the form's Closing event.
		''' </summary>
		''' <param name="e">The event arguments.</param>
		Protected Overrides Sub OnClosing(ByVal e As CancelEventArgs)
			If AskSaving() Then
				e.Cancel = True
			Else
				SaveConfig()
			End If

			MyBase.OnClosing(e)
		End Sub

		''' <summary>
		''' Handles the form's Closing event.
		''' </summary>
		''' <param name="e">The event arguments.</param>
		Protected Overrides Sub OnClosed(ByVal e As EventArgs)
			If tsbCancel.Enabled Then
				_disconnect = True

				Do While Not _disconnected
					System.Threading.Thread.Sleep(50)
					System.Windows.Forms.Application.DoEvents()
				Loop
			End If

			MyBase.OnClosed(e)
		End Sub

		''' <summary>
		''' Handles the Cancel button's Click event.
		''' </summary>
		''' <param name="sender">The button object.</param>
		''' <param name="e">The event arguments.</param>
		Private Sub tsbCancel_Click(ByVal sender As Object, ByVal e As EventArgs) Handles tsbCancel.Click
			_disconnect = True
			client.Cancel()
			tsbCancel.Enabled = False
		End Sub

		''' <summary>
		''' Sets the status text.
		''' </summary>
		''' <param name="str">The new status text.</param>
		Private Sub SetStatusText(ByVal str As String)
			tssStatus.Text = str
		End Sub

		''' <summary>
		''' Sets the status text.
		''' </summary>
		''' <param name="str">The new status format text.</param>
		''' <param name="parameters">The parameters.</param>
		Private Sub SetStatusText(ByVal str As String, ParamArray ByVal parameters() As Object)
			tssStatus.Text = String.Format(str, parameters)
		End Sub

		''' <summary>
		''' Closes the connection and release used resources.
		''' </summary>
		Private Sub Disconnect()
			SetStatusText("Disconnecting...")
			client.DisconnectAsync()
		End Sub

		Private Sub SetDisconnectedStatus()
			SetStatusText("Ready")
			EnableDialog(True)
			_disconnect = False
			_disconnected = True
		End Sub

		''' <summary>
		''' Handles the client's DisconnectCompleted event.
		''' </summary>
		''' <param name="sender">The client object.</param>
		''' <param name="e">The event arguments.</param>
		Private Sub smtpClient_DisconnectCompleted(ByVal sender As Object, ByVal e As ExtendedAsyncCompletedEventArgs(Of String))
			If e.Error IsNot Nothing Then
				Util.ShowError(e.Error)
			End If

			SetDisconnectedStatus()
		End Sub

		''' <summary>
		''' Handles the client's Progress event.
		''' </summary>
		''' <param name="sender">The SMTP client object.</param>
		''' <param name="e">The event arguments.</param>
		Private Sub smtpClient_Progress(ByVal sender As Object, ByVal e As SmtpProgressEventArgs) Handles client.Progress
			If e.State = MailClientTransferState.Sending Then
				SetStatusText("Sending message... {0} bytes sent, {1}% completed", e.BytesTransferred, CInt(Fix(e.Percentage)))
				toolStripProgressBar.Value = CInt(Fix(e.Percentage))
			End If
		End Sub

		#Region "Certificate"

		''' <summary>
		''' Returns all issues of the given certificate.
		''' </summary>
		Private Shared Function GetCertProblem(ByVal status As CertificateVerificationStatus, ByVal code As Integer, ByRef showAddTrusted As Boolean) As String
			Select Case status
				Case CertificateVerificationStatus.TimeNotValid
					Return "Server's certificate has expired or is not valid yet."

				Case CertificateVerificationStatus.Revoked
					Return "Server's certificate has been revoked."

				Case CertificateVerificationStatus.UnknownCA
					Return "Server's certificate was issued by an unknown authority."

				Case CertificateVerificationStatus.RootNotTrusted
					showAddTrusted = True
					Return "Server's certificate was issued by an untrusted authority."

				Case CertificateVerificationStatus.IncompleteChain
					Return "Server's certificate does not chain up to a trusted root authority."

				Case CertificateVerificationStatus.Malformed
					Return "Server's certificate is malformed."

				Case CertificateVerificationStatus.CNNotMatch
					Return "Server hostname does not match the certificate."

				Case CertificateVerificationStatus.UnknownError
					Return String.Format("Error {0:x} encountered while validating server's certificate.", code)

				Case Else
					Return status.ToString()
			End Select
		End Function

		Private Sub client_CertificateReceived(ByVal sender As Object, ByVal e As ComponentPro.Security.CertificateReceivedEventArgs)
			Dim dlg As New CertValidator()

			Dim status As CertificateVerificationStatus = e.Status

			Dim values() As CertificateVerificationStatus = CType(System.Enum.GetValues(GetType(CertificateVerificationStatus)), CertificateVerificationStatus())

			Dim sbIssues As New StringBuilder()
			Dim showAddTrusted As Boolean = False
			For i As Integer = 0 To values.Length - 1
				' Matches the validation status?
				If (status And values(i)) = 0 Then
					Continue For
				End If

				' The issue is processed.
				status = status Xor values(i)

				sbIssues.AppendFormat("{0}" & vbCrLf, GetCertProblem(values(i), e.ErrorCode, showAddTrusted))
			Next i

			dlg.Certificate = e.ServerCertificates(0)
			dlg.Issues = sbIssues.ToString()
			dlg.ShowAddToTrustedList = showAddTrusted

			dlg.ShowDialog()

			e.AddToTrustedRoot = dlg.AddToTrustedList
			e.Accept = dlg.Accepted
		End Sub

		Private Sub client_CertificateRequired(ByVal sender As Object, ByVal e As ComponentPro.Security.CertificateRequiredEventArgs)
			' If the client cert file is specified.
			If Not String.IsNullOrEmpty(_cert) Then
				' Load Certificate.
				Dim passdlg As New PasswordPrompt()
				' Ask for cert's passpharse
				If passdlg.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
					Dim clientCert As New X509Certificate2(_cert, passdlg.Password)
					e.Certificates = New X509Certificate2Collection(clientCert)
					Return
				End If

				' Password has not been provided.
			End If
			Dim dlg As New CertProvider()
			dlg.ShowDialog()
			' Get the selected certificate.
			e.Certificates = New X509Certificate2Collection(dlg.SelectedCertificate)
		End Sub

		#End Region
	End Class
End Namespace
