'*************************************************************************
'
'      Author       : Esben Laursen (hyber@hyber.dk)
'      
'      Webpage      : http://www.hyber.dk or http://netsmsgw.sf.net
'
'      Notes        :
'
'      License      : This program is free software; you can redistribute
'                     it and/or modify it under the terms of the GNU
'                     General Public License as published by the Free
'                     Software Foundation version 2 of the License.
'
'*************************************************************************


Imports System.Net.Sockets
Imports System.Text
Imports Microsoft.VisualBasic
Imports System.Threading
Imports System

Public Class smtpd
    Inherits logUtils
    Dim mintPort As Integer
    Dim mIPadr As System.Net.IPAddress
    Dim WithEvents newClient As smtpClientHandle
    Dim mstrServerName As String = "sms.hyber.dk"
    Dim mtcpListener As TcpListener
    Dim mcolHosts As New Collection
    Dim mbolAllowAll As Boolean = True 'default rule

    Event ReturnSMSs(ByVal pcolMsgs As Collection)
    Event Log(ByVal pstrLog As String, ByVal penuLoglevel As LogLevels)


    Public Sub New(ByVal pintPort As Integer, ByVal pstrIPAddress As String)
        mIPadr = Net.IPAddress.Parse(pstrIPAddress)
        mintPort = pintPort
    End Sub

    Public Property smtpHosts() As Collection
        Get
            Return mcolHosts
        End Get
        Set(ByVal value As Collection)
            mcolHosts = value
        End Set
    End Property

    Public Property AllowAllPrDefault() As Boolean
        Get
            Return mbolAllowAll
        End Get
        Set(ByVal value As Boolean)
            mbolAllowAll = value
        End Set
    End Property

    Public Sub srvStop()

        Try

            RaiseEvent Log(gstrStopService, LogLevels.Info)

            mtcpListener.Server.Close()
            mtcpListener.Stop()


        Catch ex As Exception
            RaiseEvent Log(gstrCriticalErr & ex.Message.ToString, LogLevels.Critical)
        End Try

    End Sub

    Public Sub srvStart()
        Try

            ' Must listen on correct port- must be same as port client wants to connect on.
            Dim tcpCli As TcpClient
            Dim ipEndPoint As System.Net.IPEndPoint
            Dim bol As Boolean = False
            Dim util As New netSMSgw.ipUtils
            Dim str(1) As String
            Dim strHost As String
            Dim bolAllowClient As Boolean = False
            Dim bolFoundMatch As Boolean = False
            Dim strClientIP As String
            Dim arrIP(1) As String



            mtcpListener = New TcpListener(mIPadr, mintPort)


            RaiseEvent Log(gstrStartService & mIPadr.ToString & ":" & mintPort, LogLevels.Info)
            mtcpListener.Start()

            While True

                'Accept the pending client connection and return 
                'a TcpClient initialized for communication. 
                tcpCli = mtcpListener.AcceptTcpClient()
                ipEndPoint = tcpCli.Client.RemoteEndPoint

                arrIP = Split(ipEndPoint.ToString, ":", 2)
                strClientIP = arrIP(0)

                bol = False
                For Each strHost In mcolHosts

                    str = Split(strHost, "/", 2)
                    'match endpoint ip to ranges in mcolhosts.
                    bol = util.MatchIpInRange(str(0), str(1), strClientIP)

                    RaiseEvent Log(gstrFoundHost & bol.ToString, LogLevels.Debug)

                    'if matched then
                    If bol Then
                        'if we allow all, deny the matched IP
                        If mbolAllowAll Then
                            bolFoundMatch = True
                            bolAllowClient = False
                            Exit For
                            'if we do not allow all then deny the matched ip
                        Else
                            bolFoundMatch = True
                            bolAllowClient = True
                            Exit For
                        End If
                    Else
                    End If
                Next


                'if the client was not matched, then check default rule.
                If Not bolFoundMatch Then
                    If mbolAllowAll = True Then
                        bolAllowClient = True
                    Else
                        bolAllowClient = False
                    End If
                End If


                'if client was allowed, start receiving email
                If bolAllowClient Then
                    RaiseEvent Log(gstrNewEmail, LogLevels.Info)
                    newClient = New smtpClientHandle(tcpCli)
                    newClient.smtpName = mstrServerName
                    Dim thread As New Thread(AddressOf newClient.GetEmail)

                    RaiseEvent Log(gstrAllowedHost & ipEndPoint.ToString, LogLevels.Info)
                    thread.Start()

                Else
                    'if not allowed, simply disconnect the session.

                    RaiseEvent Log(gstrDeniedHost & ipEndPoint.ToString, LogLevels.Info)
                    tcpCli.Client.Disconnect(False)
                End If



            End While

        Catch ex As Exception
            RaiseEvent Log(gstrCriticalErr & ex.Message.ToString, LogLevels.Critical)
        End Try
    End Sub

    Private Function AllowClient(ByVal pstrIPadr As String, ByVal pintCIDR As Integer) As Boolean
        Dim iputil As New netSMSgw.ipUtils
        Dim strHost As String
        Dim strBinIP1 As String
        Dim strBinIP2 As String
        Dim strArr(1) As String

        'if we allow all and there is no one in collection, always return true
        If mbolAllowAll = False And mcolHosts.Count = 0 Then
            Return True
        End If

        'if we deny all and thre is no in collection, always return false.
        If mbolAllowAll = True And mcolHosts.Count = 0 Then
            Return False
        End If

        strBinIP1 = iputil.GetNetworkAdr(pstrIPadr, pintCIDR)

        For Each strHost In mcolHosts
            Split(strHost, "/", 2)
            strBinIP2 = iputil.GetNetworkAdr(strHost(0), CInt(strHost(1).ToString))

            'if we deny all and we match, return true
            'remember its all execpt list in mcolhosts
            If mbolAllowAll = True Then
                If strBinIP1 = strBinIP2 Then
                    Return False
                End If
            End If

            'if we allow all and we mathe, return false
            'remember its all execpt list in mcolhosts
            If mbolAllowAll = False Then
                If strBinIP1 = strBinIP2 Then
                    Return False
                End If
            End If
        Next

        'IP address was not found, return default rule.
        If mbolAllowAll = True Then
            Return True
        Else
            Return False
        End If
    End Function

    Private Sub newClient_Log(ByVal pstrLog As String, ByVal penuLoglevel As logUtils.LogLevels) Handles newClient.Log
        'forward event, it set so in settings.
        RaiseEvent Log(pstrLog, penuLoglevel)
    End Sub


    Public ReadOnly Property ListenPort() As Integer
        Get
            Return mintPort
        End Get
    End Property

    Public ReadOnly Property ListenIP() As System.Net.IPAddress
        Get
            Return mIPadr

        End Get
    End Property

    Public Property ServerName() As String
        Get
            Return mstrServerName
        End Get
        Set(ByVal value As String)
            mstrServerName = value
        End Set
    End Property

    Private Sub newClient_ReturnSMSs1(ByVal pcolSMSMsgs As Microsoft.VisualBasic.Collection) Handles newClient.ReturnSMSs
        'forward the event
        RaiseEvent Log(gstrGotEmail, LogLevels.Info)
        RaiseEvent ReturnSMSs(pcolSMSMsgs)
    End Sub
End Class

