Imports System.Text
Imports ComponentPro.Net
Imports ComponentPro.Net.Mail
Imports ComponentPro
Imports System.Web.UI.WebControls
Imports System.IO

''' <summary>
''' Contains information for sending notification to the administrator.
''' </summary>
Public Class NotificationInfo
	Public MailFrom As String ' Send from.
	Public MailTo As String ' Who will receive the notification email.
	Public SmtpServer As String ' SMTP server address.
	Public SmtpPort As Integer ' SMTP server port (default is 25).
	Public SmtpUser As String ' SMTP credentials.
	Public SmtpPassword As String ' SMTP credentials.
	Public SecurityMode As SecurityMode ' Implicit, Explicit or Unsecure
	Public AuthenticationMethod As SmtpAuthenticationMethod ' SMTP Authentication method.
End Class

Partial Public Class _Default
	Inherits System.Web.UI.Page
	Private Sub PopulateEnum(ByVal enumType As Type, ByVal ddl As DropDownList)
		Dim arr As Array = System.Enum.GetValues(enumType)

		For Each item As Object In arr
			ddl.Items.Add(New ListItem(item.ToString(), CInt(Fix(item)).ToString()))
		Next item

		Dim index As Integer
		If Integer.TryParse(Request.Form(ddl.ID), index) Then
			ddl.SelectedIndex = index
		End If
	End Sub

	Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
		PopulateEnum(GetType(SmtpAuthenticationMethod), ddlSmtpAuth)
		PopulateEnum(GetType(ImapAuthenticationMethod), ddlAuthentication)
	End Sub

	Protected Sub btnSmtp_Click(ByVal sender As Object, ByVal e As EventArgs)
		Try
			' Setup the notification info.
			Dim info As New NotificationInfo()
			info.MailFrom = txtFrom.Text
			info.MailTo = txtTo.Text
			info.SmtpServer = txtSmtpServer.Text
			info.SmtpPort = Integer.Parse(txtSmtpPort.Text)
			info.SmtpUser = txtSmtpUser.Text
			info.SmtpPassword = txtSmtpPassword.Text
			info.AuthenticationMethod = CType(Integer.Parse(ddlSmtpAuth.SelectedValue), SmtpAuthenticationMethod)
			info.SecurityMode = CType(ddlSmtpSec.SelectedIndex, SecurityMode)

			' Send a test message.
			SendMail(info, "Test Subject", "Test SMTP for BounceInspector")
			' Show result.
			lblResult.Text = "Test message has been sent to " & info.MailTo
		Catch exc As Exception
			' An error occurred.
			lblResult.Text = exc.Message
		End Try
	End Sub

	Protected Sub btnProcess_Click(ByVal sender As Object, ByVal e As EventArgs)
		Try
			' Setup the directory for storing messages.
			Dim mailsPath As String = AppDomain.CurrentDomain.BaseDirectory & "Mails"
			If Not System.IO.Directory.Exists(mailsPath) Then
				System.IO.Directory.CreateDirectory(mailsPath)
			End If

			' Initialize the message string.
			Dim sb As New StringBuilder()
			' Parse the IMAP port.
			Dim port As Integer = Integer.Parse(txtPort.Text)

			Dim client As New Imap()

			' Connect to the server.
			client.Connect(txtServer.Text, port, CType(ddlSecurityMode.SelectedIndex, SecurityMode))

			' Login to the server.
			Dim ia As ImapAuthenticationMethod = CType(Integer.Parse(ddlAuthentication.SelectedValue), ImapAuthenticationMethod)
			' Login to the IMAP server.
			client.Authenticate(txtUser.Text, txtPassword.Text, ia)

			' Selecting folder is needed.
			client.Select(txtFolder.Text)

			' Create a new instance of the BounceInspector class for detecting and filtering bounced messages.
			Dim filter As New BounceInspector()
			' Delete hard bounce file?
			filter.AllowDelete = chkDelete.Checked
			' Delete bard bounce in inbox as well?
			filter.AllowInboxDelete = chkDelete.Checked
			' The maximum number of message to be downloaded.
			filter.MaxMessages = Integer.Parse(txtMessages.Text)

			' Register an event handler when messages are processed.
			AddHandler filter.ProcessMessagesCompleted, AddressOf filter_ProcessMessagesCompleted

			' Setup the notification info.
			Dim info As New NotificationInfo()
			info.MailFrom = txtFrom.Text
			info.MailTo = txtTo.Text
			info.SmtpServer = txtSmtpServer.Text
			info.SmtpPort = Integer.Parse(txtSmtpPort.Text)
			info.SmtpUser = txtSmtpUser.Text
			info.SmtpPassword = txtSmtpPassword.Text
			info.AuthenticationMethod = CType(Integer.Parse(ddlSmtpAuth.SelectedValue), SmtpAuthenticationMethod)
			info.SecurityMode = CType(ddlSmtpSec.SelectedIndex, SecurityMode)

			' Get the newest messages only.
			Dim list As ImapMessageCollection = client.ListMessages(ImapEnvelopeParts.MessageInboxIndex Or ImapEnvelopeParts.UniqueId)
			Dim newList As New ImapMessageCollection()
			For i As Integer = 0 To filter.MaxMessages - 1
				newList.Add(list(list.Count - i - 1))
			Next i

			' Start a new thread to process messages. 
			' You do not have to care about this. The BounceInspector will do the job for you.
			' Asynchronously process messages. The method filter_ProcessMessagesCompleted will be invoked when messages are processed.
			filter.ProcessMessagesAsync(client, txtFolder.Text, newList, mailsPath, info)

			' Show result.
			lblResult.Text = "The bounce processing has begun. You will receive a notification via e-mail when it is completed."
		Catch exc As Exception
			lblResult.Text = String.Format(Nothing, "Exception: {0}", exc.Message)
		End Try
	End Sub

	Private Sub SendMail(ByVal info As NotificationInfo, ByVal subject As String, ByVal content As String)
		' Create a new instance of the SmtpClient for sending notification email.
		Dim client As New Smtp()

		' Connect to the specified SMTP server.
		client.Connect(info.SmtpServer, info.SmtpPort, info.SecurityMode)

		If Not String.IsNullOrEmpty(info.SmtpUser) Then
			' Login.
			client.Authenticate(info.SmtpUser, info.SmtpPassword)
		End If

		' Prepare a notification message.
		Dim msg As New MailMessage()
		msg.From.Add(info.MailFrom)
		msg.To.Add(info.MailTo)
		msg.Subject = subject
		msg.BodyHtml = content
		' Send it.
		client.Send(msg)

		' Close the SMTP session.
		client.Disconnect()
	End Sub

	Private Sub LogError(ByVal info As NotificationInfo, ByVal exc As Exception)
		Try
			' Send error information.
			SendMail(info, "Bounce processing completed with an exception", exc.Message)
		Catch exc2 As Exception
			' Write to a log file when SMTP sending has a problem.
			Dim s As New StreamWriter(AppDomain.CurrentDomain.BaseDirectory & "Error.log")
			s.WriteLine(exc2.Message)
			s.Close()
		End Try
	End Sub

	Private Sub filter_ProcessMessagesCompleted(ByVal sender As Object, ByVal e As ExtendedAsyncCompletedEventArgs(Of BounceResultCollection))
		' Get the state object.
		Dim info As NotificationInfo = CType(e.UserState, NotificationInfo)

		If e.Error IsNot Nothing Then
			LogError(info, e.Error)
			Return
		End If

		' sender is the filter instance that we have created before.
		Dim filter As BounceInspector = CType(sender, BounceInspector)

		Try
			' Retrieve a collection of BounceResult class.
			Dim result As BounceResultCollection = e.Result

			' Init a StringBuilder object for creating the notification message body.
			Dim sb As New StringBuilder()

			' Process the result.
			For Each r As BounceResult In result
				' If the processing message is a bounced message.
				If r.Identified Then
					' Add to the result string.
					If r.Addresses.Length > 0 Then
						sb.AppendFormat("FileName: {0}<br>Subject: {1}<br>" & "Address: {2}<br>" & "Bounce Category Name: {3}<br>" & "Bounce Type: {4}<br>" & "Deleted: {5}<br>" & "DSN-Action: {6}<br>" & "DSN-DiagnosticCode: {7}<br>" & "Received: {8}<br><br>", System.IO.Path.GetFileName(r.FilePath), r.MailMessage.Subject,r.Addresses(0), r.BounceCategory.Name, r.BounceType.Name, r.FileDeleted.ToString(), r.Dsn.Action.ToString(), r.Dsn.DiagnosticCode, r.MailMessage.ReceivedDate)
					Else
						sb.AppendFormat("FileName: {0}<br>Subject: {1}<br>" & "Address: {2}<br>" & "Bounce Category Name: {3}<br>" & "Bounce Type: {4}<br>" & "Deleted: {5}<br>" & "DSN-Action: {6}<br>" & "DSN-DiagnosticCode: {7}<br>" & "Received: {8}<br><br>", System.IO.Path.GetFileName(r.FilePath), r.MailMessage.Subject,String.Empty, r.BounceCategory.Name, r.BounceType.Name, r.FileDeleted.ToString(), r.Dsn.Action.ToString(), r.Dsn.DiagnosticCode, r.MailMessage.ReceivedDate)
					End If
				End If
			Next r

			If sb.Length = 0 Then
				sb.Append("No bounced messages found. You can extend the search range to scan more messages.")
			End If

			' Send the notification to the specified recipient.
			SendMail(info, "Bounce processing completed successfully", sb.ToString())
		Catch exc As Exception
			LogError(info, exc)
		End Try
	End Sub
End Class