package ftp_protocol_crawler

import (
	"git.loafle.net/overflow/overflow_probe/matcher/packet"
	"git.loafle.net/overflow/overflow_probe/model/scaninfo"
	"log"
)

const (
	statusReadyServer         = "120"
	statusOK                  = "200"
	statusNewConnectOK        = "220"
	statusSystemNameOK        = "215"
	statusCloseConnect        = "221"
	statusUnkownCMD           = "202"
	statusTlsUseOK            = "234"
	statusCloseControlConnect = "421"
	statusSyntaxErr           = "500"
	statusParamSyntaxErr      = "501"
	statusNotUseCMD           = "502"
	statusIncorrectCMD        = "503"
	statusUserLoginRequied    = "530"
	statusTlsNotUse           = "534"
	statusNeedUserId          = "332"
)

type FTPMatcher struct {
	sendPackets []*packet.Packet
	isFtps      bool
}

func NewFTPMatcher() *FTPMatcher {

	ftm := FTPMatcher{}

	sysStr := "SYST\r\n"
	systByte := make([]byte, len(sysStr))
	copy(systByte[:], sysStr)
	ftm.sendPackets = append(ftm.sendPackets, packet.NewPacket(systByte, len(sysStr)))

	passStr := "PASS \r\n"
	passByte := make([]byte, len(passStr))
	copy(passByte[:], passStr)
	ftm.sendPackets = append(ftm.sendPackets, packet.NewPacket(passByte, len(passStr)))

	quitStr := "QUIT\r\n"
	quitByte := make([]byte, len(quitStr))
	copy(quitByte[:], quitStr)
	ftm.sendPackets = append(ftm.sendPackets, packet.NewPacket(quitByte, len(quitStr)))

	return &ftm
}

func (r *FTPMatcher) Match(idx int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {
	result := false

	if packet == nil || packet.Buffer == nil || packet.Len == 0 {
		log.Println("Packet nil")
		return result
	}

	str := string(packet.Buffer)

	code := str[:3]

	if idx == 0 {
		switch code {
		case statusNewConnectOK, statusReadyServer:
			//fmt.Println(code)
			result = true
			break
		}
	} else if idx == 1 {
		switch code {
		case statusSystemNameOK, statusSyntaxErr, statusParamSyntaxErr, statusNotUseCMD, statusUserLoginRequied:
			//fmt.Println(code)
			result = true
			break
		}
	} else if idx == 2 {
		switch code {
		case statusIncorrectCMD, statusParamSyntaxErr, statusNotUseCMD, statusNeedUserId, statusUserLoginRequied:
			//fmt.Println(code)
			result = true
			break
		}
	} else if idx == 3 {
		switch code {
		case statusCloseConnect, statusSyntaxErr:
			//fmt.Println(code)
			result = true
			break
		}
	}

	return result
}

func (ftp *FTPMatcher) PacketCount() int {
	return len(ftp.sendPackets)
}

func (ftp *FTPMatcher) Packet(index int) *packet.Packet {
	return ftp.sendPackets[index]
}

func (ftp *FTPMatcher) ServiceName() string {
	return "FTP"
}

func (ftp *FTPMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {
	return false
}

func (ftp *FTPMatcher) IsNoResponse(index int) bool {
	return false
}

func (ftp *FTPMatcher) IsPrePacket() bool {
	return true
}
