'  
'   Rebex Sample Code License
' 
'   Copyright 2026, REBEX CR s.r.o.
'   All rights reserved.
'   https://www.rebex.net/
' 
'   Permission to use, copy, modify, and/or distribute this software for any
'   purpose with or without fee is hereby granted.
' 
'   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
'   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
'   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
'   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
'   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
'   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
'   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
'   OTHER DEALINGS IN THE SOFTWARE.
' 

Imports System
Imports System.Drawing
Imports System.IO
Imports System.Linq
Imports System.Windows.Forms

Imports Rebex.Mail
Imports Rebex.Mime.Headers

''' <summary>
''' MsgMessage editor.
''' </summary>
Partial Public Class MailEditor
    Inherits System.Windows.Forms.Form

    ' Indicates whether the message was saved.
    Private _modified As Boolean

    ' Current mail message.
    Private _message As MsgMessage

    ' Message file path.
    Private _path As String


    ''' <summary>
    ''' Constructor.
    ''' </summary>
    Public Sub New()
        '
        ' Required for Windows Form Designer support
        '
        InitializeComponent()

        _message = New MsgMessage()
    End Sub 'New


    ''' <summary>
    ''' Saves the message to its current location.
    ''' </summary>
    Private Overloads Sub SaveMessage()
        If _path Is Nothing Then
            _path = SaveAs()
            Return
        End If

        SaveMessage(_path)
    End Sub 'SaveMessage


    ''' <summary>
    ''' Saves message.
    ''' </summary>
    Private Overloads Sub SaveMessage(ByVal path As String)
        Try
            Dim message As MsgMessage = ToMessage()
            message.Save(path)
            _modified = False
            MessageBox.Show("Message saved.")
        Catch x As Exception
            MessageBox.Show(x.ToString())
        End Try
    End Sub 'SaveMessage


    ''' <summary>
    ''' Creates new message.
    ''' </summary>
    Private Sub NewMessage()
        If Not CheckModifications() Then
            Return
        End If

        Dim message As New MsgMessage
        LoadMessage(message)
        _path = Nothing
    End Sub 'NewMessage


    ''' <summary>
    ''' Closes the message.
    ''' </summary>
    Private Sub CloseMessage()
        If Not CheckModifications() Then
            Return
        End If
        MyBase.Close()
    End Sub 'CloseMessage


    ''' <summary>
    ''' Opens a new message.
    ''' </summary>
    Private Sub OpenMessage()
        If Not CheckModifications() Then
            Return
        End If

        If openFileDialogMessage.ShowDialog() <> System.Windows.Forms.DialogResult.OK Then
            Return
        End If

        LoadMessage(openFileDialogMessage.FileName)
    End Sub 'OpenMessage


    ''' <summary>
    ''' Asks the user whether to save or discard modifications, and save the message if desired.
    ''' </summary>
    ''' <returns>True if caller should proceed, false if cancel was selected.</returns>
    Private Function CheckModifications() As Boolean
        If Not _modified Then
            Return True
        End If

        Dim res As DialogResult = MessageBox.Show(Me, "Would you like to save the changes you made to the current message?", "Message Editor", MessageBoxButtons.YesNoCancel)
        If res = System.Windows.Forms.DialogResult.No Then
            Return True
        End If

        If res <> System.Windows.Forms.DialogResult.Yes Then
            Return False
        End If

        If _path Is Nothing Then
            _path = SaveAs()
        Else
            SaveMessage(_path)
        End If

        Return True
    End Function 'CheckModifications


    ''' <summary>
    ''' Saves attachments to a folder.
    ''' </summary>
    Private Sub SaveAttachments()
        If folderBrowserDialog.ShowDialog() <> System.Windows.Forms.DialogResult.OK Then
            Return
        End If

        Dim mypath As String = folderBrowserDialog.SelectedPath
        For Each att As MsgAttachment In _message.Attachments
            att.Save(Path.Combine(mypath, att.FileName))
        Next att
    End Sub 'SaveAttachments


    ''' <summary>
    ''' Saves message to a new file.
    ''' </summary>
    Private Function SaveAs() As String
        If saveFileDialogMessage.ShowDialog() <> System.Windows.Forms.DialogResult.OK Then
            Return Nothing
        End If

        Dim path As String = saveFileDialogMessage.FileName

        SaveMessage(path)

        Return path
    End Function 'SaveAs


    ''' <summary>
    ''' Removes attachment specified by file name.
    ''' </summary>
    Private Sub RemoveAttachment(ByVal name As String)
        listBoxAttachments.Items.Remove(name)

        Dim i As Integer
        For i = 0 To _message.Attachments.Count - 1
            If _message.Attachments(i).FileName = name Then
                _message.Attachments.RemoveAt(i)
                _modified = True
                Exit For
            End If
        Next i
    End Sub 'RemoveAttachment


    ''' <summary>
    ''' Loads a mail message.
    ''' </summary>
    ''' <param name="path">Path to file.</param>
    Public Overloads Sub LoadMessage(ByVal path As String)
        Try
            Dim message As New MsgMessage
            _path = path
            message.Load(_path)
            LoadMessage(message)
        Catch err As Exception
            MessageBox.Show(err.ToString())
        End Try
    End Sub 'LoadMessage


    ''' <summary>
    ''' Creates MSG message from dialog's data.
    ''' </summary>
    Public Function ToMessage() As MsgMessage
        Dim msg As MsgMessage = _message

        msg.Subject = txtSubject.Text
        msg.SetBody(txtBody.Text)

        Return msg
    End Function 'ToMessage


    ''' <summary>
    ''' Initializes the editor with MsgMessage data.
    ''' </summary>
    Public Overloads Sub LoadMessage(ByVal message As MsgMessage)
        _message = message

        ' allow editing of SMTP addresses only
        txtFrom.Enabled = IsSmtpAddress(_message.From)
        txtTo.Enabled = _message.To.All(Function(address) IsSmtpAddress(address))
        txtCc.Enabled = _message.CC.All(Function(address) IsSmtpAddress(address))

        txtFrom.Text = MsgAddressFormatter.ToString(_message.From)
        txtTo.Text = MsgAddressFormatter.ToString(_message.To)
        txtCc.Text = MsgAddressFormatter.ToString(_message.CC)

        txtSubject.Text = _message.Subject
        txtBody.Text = _message.BodyText

        listBoxAttachments.Items.Clear()
        Dim i As Integer
        For i = 0 To _message.Attachments.Count - 1
            Dim attachment As MsgAttachment = _message.Attachments(i)

            Dim name As String = attachment.FileName
            If String.IsNullOrEmpty(name) Then
                name = String.Format("ATT{0}.dat", i)
            End If
            listBoxAttachments.Items.Add(name)
        Next i

        ' update Window title
        [Text] = message.Subject

        _modified = False
    End Sub 'LoadMessage


    ''' <summary>
    ''' Indicates whether the specified address has SMTP type.
    ''' </summary>
    Private Function IsSmtpAddress(ByVal address As MsgAddress) As Boolean
        Return address.AddressType = MsgAddressType.Smtp
    End Function


    ''' <summary>
    ''' Deletes attachment.
    ''' </summary>
    Private Sub menuItemDelete_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles menuItemDelete.Click
        If listBoxAttachments.SelectedItem Is Nothing Then
            Return
        End If

        Dim file As String = listBoxAttachments.SelectedItem.ToString()
        RemoveAttachment(file)
    End Sub 'menuItemDelete_Click


    ''' <summary>
    ''' Adds new attached file.
    ''' </summary>
    Private Sub menuItemFileAttachment_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles menuItemFileAttachment.Click
        If openFileDialogAttachment.ShowDialog() <> System.Windows.Forms.DialogResult.OK Then
            Return
        End If

        Dim att As MsgAttachment = _message.Attachments.Add(openFileDialogAttachment.FileName, Nothing)
        listBoxAttachments.Items.Add(att.FileName)

        _modified = True
    End Sub 'menuItemFileAttachment_Click


    ''' <summary>
    ''' Creates new message.
    ''' </summary>
    Private Sub menuItemNewMessage_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles menuItemNewMessage.Click
        NewMessage()
    End Sub 'menuItemNewMessage_Click


    ''' <summary>
    ''' Opens message from file.
    ''' </summary>
    Private Sub menuItemOpenMessage_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles menuItemOpenMessage.Click
        OpenMessage()
    End Sub 'menuItemOpenMessage_Click


    ''' <summary>
    ''' Save message to file.
    ''' </summary>
    Private Sub menuItemSave_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles menuItemSave.Click
        SaveMessage()
    End Sub 'menuItemSave_Click


    ''' <summary>
    ''' Saves message to a new file.
    ''' </summary>
    Private Sub menuItemSaveAs_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles menuItemSaveAs.Click
        SaveAs()
    End Sub 'menuItemSaveAs_Click


    ''' <summary>
    ''' Save all attachments to folder.
    ''' </summary>
    Private Sub menuItemSaveAttachments_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles menuItemSaveAttachment.Click
        SaveAttachments()
    End Sub 'menuItemSaveAttachments_Click


    ''' <summary>
    ''' Closes application.
    ''' </summary>
    Private Sub menuItemClose_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles menuItemClose.Click
        CloseMessage()
    End Sub 'menuItemClose_Click


    ''' <summary>
    ''' Handles 'From' textbox changes.
    ''' </summary>
    Private Sub txtFrom_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtFrom.TextChanged
        txtFrom.BackColor = SystemColors.Window
        If Not txtFrom.Enabled Then
            Return
        End If

        _message.From = Nothing
        _modified = True

        Dim text As String = txtFrom.Text.Trim()
        If text.Length = 0 Then
            Return
        End If

        Dim addresses As MailAddressCollection = ParseSmtpAddressCollection(text)
        If addresses Is Nothing OrElse addresses.Count <> 1 Then
            txtFrom.BackColor = Color.Red
        Else
            Dim add As MailAddress = addresses(0)
            _message.From = New MsgAddress(add.Address, add.DisplayName)
        End If
    End Sub 'txtFrom_TextChanged


    ''' <summary>
    ''' Handles 'To' textbox changes.
    ''' </summary>
    Private Sub txtTo_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtTo.TextChanged
        txtTo.BackColor = SystemColors.Window
        If Not txtTo.Enabled Then
            Return
        End If

        _message.To.Clear()
        _modified = True

        Dim text As String = txtTo.Text.Trim()
        If text.Length = 0 Then
            Return
        End If

        Dim addresses As MailAddressCollection = ParseSmtpAddressCollection(text)
        If addresses Is Nothing Then
            txtTo.BackColor = Color.Red
        Else
            For Each add As MailAddress In addresses
                _message.[To].Add(add.Address, add.DisplayName)
            Next
        End If
    End Sub 'txtTo_TextChanged


    ''' <summary>
    ''' Handles 'Cc' textbox changes.
    ''' </summary>
    Private Sub txtCc_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtCc.TextChanged
        txtCc.BackColor = SystemColors.Window
        If Not txtCc.Enabled Then
            Return
        End If

        _message.CC.Clear()
        _modified = True

        Dim text As String = txtCc.Text.Trim()
        If text.Length = 0 Then
            Return
        End If

        Dim addresses As MailAddressCollection = ParseSmtpAddressCollection(text)
        If addresses Is Nothing Then
            txtCc.BackColor = Color.Red
        Else
            For Each add As MailAddress In addresses
                Try
                    _message.CC.Add(add.DisplayName, add.Address)
                Catch x As ArgumentException
                    txtCc.BackColor = Color.Red
                End Try
            Next
        End If
    End Sub 'txtCc_TextChanged


    ''' <summary>
    ''' Handles 'Subject' textbox changes.
    ''' </summary>
    Private Sub txtSubject_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtSubject.TextChanged
        _modified = True

        ' update Window title
        [Text] = txtSubject.Text
    End Sub 'txtSubject_TextChanged


    ''' <summary>
    ''' Handles 'Body' textbox changes.
    ''' </summary>
    Private Sub txtBody_TextChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles txtBody.KeyPress
        _modified = True
    End Sub 'txtBody_TextChanged
End Class 'MailEditor 
