'*************************************************************************
'
'      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 Microsoft.Win32
Imports System.Net.Sockets
Imports System.Text

Module basPhoneHome

    Dim mtcpClient As New System.Net.Sockets.TcpClient()
    Dim networkStream As NetworkStream

    Private Enum CMDs

        HelloServer = 100
        HelloClient = 110
        ReadyForData = 120
        Version = 130
        ClientInfo = 200
        Stats = 300
        OK = 400
        AllDone = 500
        ByeBye = 510
        UnknownCMD = 800
        ErrClose = 900

    End Enum

    Private Function SendCMD(ByVal pCMD As CMDs) As String

        Dim str As String = ""
        Dim strRes As String

        Select Case pCMD

            Case CMDs.ClientInfo : str = "200 Can I send my Client Information now?"
            Case CMDs.AllDone : str = "500 I am all done, nice to talk to you and godbye"
            Case CMDs.ByeBye : str = "510 Bye Bye, and thanks for the stats :-)"
            Case CMDs.HelloClient : str = "110 Hi there, nice to meet you"
            Case CMDs.HelloServer : str = "100 Hi I am the netSMSgw statistics collector, I run version " & System.Environment.Version.ToString
            Case CMDs.OK : str = "400 OK, thanks"
            Case CMDs.ReadyForData : str = "120 I am ready for some data now, if you please"
            Case CMDs.Stats : str = "300 Can I send you my statistics now?"
            Case CMDs.Version : str = "130 Can I send you my stats version?"
            Case CMDs.UnknownCMD : str = "800 Sorry but that was a unknown command, try again please"
            Case CMDs.ErrClose : str = "900 Critical error happened, Im closing the connection!"
        End Select

        strRes = SendAndGet(str)
        Return strRes

    End Function

    Private Function SendAndGet(ByVal pstr As String) As String
        Try

            Dim netStream As NetworkStream

            netStream = mtcpClient.GetStream()

            Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(pstr)
            netStream.Write(sendBytes, 0, sendBytes.Length)


            Dim bytes(mtcpClient.ReceiveBufferSize) As Byte
            netStream.Read(bytes, 0, CInt(mtcpClient.ReceiveBufferSize))
            ' Return the data received from the client to the console.
            Return Encoding.ASCII.GetString(bytes)

        Catch ex As Exception
            Call AddToLog(gstrPHCritical, logUtils.LogLevels.Critical)
            Return ""
        End Try
    End Function




    Public Function PhoneHome(ByVal psmsStatistics As smsStatistics, ByVal pPhoneInfo As smsTools.smsd.PhoneInfo) As Boolean
        Try

            Dim str As String
            mtcpClient = New System.Net.Sockets.TcpClient
            mtcpClient.Connect(gSettings.statsPhoneHomeAdr, gSettings.statsPhoneHomePort)

            'get reponse from stat server
            networkStream = mtcpClient.GetStream()
            Dim bytes(mtcpClient.ReceiveBufferSize) As Byte

            networkStream.Read(bytes, 0, CInt(mtcpClient.ReceiveBufferSize))
            ' Output the data received from the host to the console.
            str = Encoding.ASCII.GetString(bytes)


            'if it was not a hello, errclose
            If Not Left(str, 3) = CMDs.HelloServer Then GoTo ErrClose

            'send helo back
            str = SendCMD(CMDs.HelloClient)
            If Not Left(str, 3) = CMDs.ReadyForData Then GoTo ErrClose

            'ready for client version?
            str = SendCMD(CMDs.Version)
            If Not Left(str, 3) = CMDs.OK Then GoTo ErrClose

            'send client version
            str = SendAndGet(MyVersion)
            If Not Left(str, 3) = CMDs.OK Then GoTo ErrClose

            'ready for client data?
            str = SendCMD(CMDs.ClientInfo)
            If Not Left(str, 3) = CMDs.OK Then GoTo ErrClose

            'send client info
            str = SendAndGet(GetClientInfo(pPhoneInfo))
            If Not Left(str, 3) = CMDs.OK Then GoTo ErrClose

            'ready for stats?
            str = SendCMD(CMDs.Stats)
            If Not Left(str, 3) = CMDs.OK Then GoTo ErrClose

            'annonymize stats and send it
            str = SendAndGet(Serialize(annonymizeStats(psmsStatistics)))
            If Not Left(str, 3) = CMDs.OK Then GoTo ErrClose

            'send all done.
            str = SendCMD(CMDs.AllDone)
            If Not Left(str, 3) = CMDs.ByeBye Then GoTo ErrClose


            GoTo Close


ErrClose:
            SendCMD(CMDs.ErrClose)
            mtcpClient.Client.Close()
            Return False

Close:
            mtcpClient.Client.Close()
            Return True

        Catch ex As System.Net.Sockets.SocketException
            Call AddToLog(gstrPHSocketErr & ex.Message.ToString, logUtils.LogLevels.Warnings)

        Catch ex As Exception
            Call AddToLog(gstrPHCritical, logUtils.LogLevels.Critical)
            'MsgBox(ex.Message.ToString, MsgBoxStyle.Critical, "Error")
        End Try
    End Function

    Private Function GetClientInfo(ByVal pPhoneInfo As smsTools.smsd.PhoneInfo) As String

        Try

            Dim inf As New statsClientInfo
            Dim str As String


            With inf
                .Country = RegValue(RegistryHive.Users, ".DEFAULT\Control Panel\International", "sCountry")
                .ID = gSettings.InstallationID
                .OS = System.Environment.OSVersion.VersionString
                .PhoneManufacturer = pPhoneInfo.Manufacturer
                .PhoneModel = pPhoneInfo.Model
                .PhoneVersion = pPhoneInfo.Version
                .HTTPdEnabled = gSettings.httpEnabled
                .HTTPdUsersEnabled = gSettings.httpEnableUsers
                .SMTPdEnabled = gSettings.smtpEnabled
            End With

            str = Serialize(inf)

            Return str

        Catch ex As Exception
            Call AddToLog(gstrPHCritical, logUtils.LogLevels.Critical)
            Return ""
        End Try

    End Function

    Private Function Serialize(ByVal pItem As Object) As String

        Try
            ' Create a new XmlSerializer instance.
            Dim s As New Xml.Serialization.XmlSerializer(pItem.GetType())



            Dim sb As New System.Text.StringBuilder
            Dim stream As New IO.StringWriter(sb)

            ' Serialize the object, and close the StreamWriter.

            s.Serialize(stream, pItem)
            stream.Close()

            Return sb.ToString

        Catch ex As Exception
            Call AddToLog(gstrPHCritical, logUtils.LogLevels.Critical)
            Return ""
        End Try

    End Function

    Private Function annonymizeStats(ByVal pStatistics As smsStatistics) As smsStatistics
        Try


            Dim stat As smsStat

            For Each stat In pStatistics.Stats
                stat.MobileNum = "<removed>"
            Next

            Return pStatistics


        Catch ex As Exception
            Call AddToLog(gstrPHCritical, logUtils.LogLevels.Critical)

            Return Nothing
        End Try

    End Function



    Private Function RegValue(ByVal Hive As RegistryHive, ByVal Key As String, ByVal ValueName As String, _
                             Optional ByRef ErrInfo As String = "") As String

        'DEMO USAGE

        'Dim sAns As String
        'Dim sErr As String = ""

        'sAns = RegValue(RegistryHive.LocalMachine, _
        '  "SOFTWARE\Microsoft\Windows\CurrentVersion", _
        '  "ProgramFilesDir", sErr)
        'If sAns <> "" Then
        '    Debug.WriteLine("Value = " & sAns)
        'Else
        '    Debug.WriteLine("This error occurred: " & sErr)

        'End If

        Dim objParent As RegistryKey
        Dim objSubkey As RegistryKey
        Dim sAns As String = ""

        Select Case Hive
            Case RegistryHive.ClassesRoot
                objParent = Registry.ClassesRoot
            Case RegistryHive.CurrentConfig
                objParent = Registry.CurrentConfig
            Case RegistryHive.CurrentUser
                objParent = Registry.CurrentUser
            Case RegistryHive.DynData
                objParent = Registry.DynData
            Case RegistryHive.LocalMachine
                objParent = Registry.LocalMachine
            Case RegistryHive.PerformanceData
                objParent = Registry.PerformanceData
            Case RegistryHive.Users
                objParent = Registry.Users
            Case Else
                objParent = Registry.LocalMachine

        End Select

        Try
            objSubkey = objParent.OpenSubKey(Key)
            'if can't be found, object is not initialized

            If Not objSubkey Is Nothing Then
                sAns = (objSubkey.GetValue(ValueName))
            End If

        Catch ex As Exception
            ErrInfo = ex.Message
            Call AddToLog(gstrPHCritical, logUtils.LogLevels.Warnings)

        Finally

            'if no error but value is empty, populate errinfo
            If ErrInfo = "" And sAns = "" Then
                ErrInfo = "No value found for requested registry key"
            End If
        End Try
        Return sAns
    End Function


End Module
