|
@@ -0,0 +1,425 @@
|
|
|
+package door
|
|
|
+
|
|
|
+import (
|
|
|
+ "bufio"
|
|
|
+ "flag"
|
|
|
+ "fmt"
|
|
|
+ "os"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+ "syscall"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+/*
|
|
|
+door32.sys:
|
|
|
+
|
|
|
+0 Line 1 : Comm type (0=local, 1=serial, 2=telnet)
|
|
|
+0 Line 2 : Comm or socket handle
|
|
|
+38400 Line 3 : Baud rate
|
|
|
+Mystic 1.07 Line 4 : BBSID (software name and version)
|
|
|
+1 Line 5 : User record position (1-based)
|
|
|
+James Coyle Line 6 : User's real name
|
|
|
+g00r00 Line 7 : User's handle/alias
|
|
|
+255 Line 8 : User's security level
|
|
|
+58 Line 9 : User's time left (in minutes)
|
|
|
+1 Line 10: Emulation *See Below
|
|
|
+1 Line 11: Current node number
|
|
|
+*/
|
|
|
+
|
|
|
+func Color(arg ...int) string {
|
|
|
+ var result string = "\x1b["
|
|
|
+ for i := range arg {
|
|
|
+ result += fmt.Sprintf("%d;", arg[i])
|
|
|
+ }
|
|
|
+ result += "m"
|
|
|
+ return result
|
|
|
+}
|
|
|
+
|
|
|
+func ColorText(color string) string {
|
|
|
+ // split on spaces, uppercase, match first 3 letter
|
|
|
+ var result []int
|
|
|
+ var bg bool
|
|
|
+
|
|
|
+ result = append(result, 0)
|
|
|
+
|
|
|
+ parts := strings.Fields(strings.ToUpper(color))
|
|
|
+ for _, part := range parts {
|
|
|
+ switch part {
|
|
|
+ case "BLACK", "BLA":
|
|
|
+ if bg {
|
|
|
+ result = append(result, 40)
|
|
|
+ } else {
|
|
|
+ result = append(result, 30)
|
|
|
+ }
|
|
|
+
|
|
|
+ case "RED":
|
|
|
+ if bg {
|
|
|
+ result = append(result, 41)
|
|
|
+ } else {
|
|
|
+ result = append(result, 31)
|
|
|
+ }
|
|
|
+
|
|
|
+ case "GREEN", "GRE":
|
|
|
+ if bg {
|
|
|
+ result = append(result, 42)
|
|
|
+ } else {
|
|
|
+ result = append(result, 32)
|
|
|
+ }
|
|
|
+
|
|
|
+ case "BROWN", "BRO":
|
|
|
+ if bg {
|
|
|
+ result = append(result, 43)
|
|
|
+ } else {
|
|
|
+ result = append(result, 33)
|
|
|
+ }
|
|
|
+
|
|
|
+ case "YELLOW", "YEL":
|
|
|
+ if bg {
|
|
|
+ result = append(result, 43)
|
|
|
+ } else {
|
|
|
+ result = append(result, 33)
|
|
|
+ }
|
|
|
+
|
|
|
+ case "BLUE", "BLU":
|
|
|
+ if bg {
|
|
|
+ result = append(result, 44)
|
|
|
+ } else {
|
|
|
+ result = append(result, 34)
|
|
|
+ }
|
|
|
+
|
|
|
+ case "MAGENTA", "MAG":
|
|
|
+ if bg {
|
|
|
+ result = append(result, 45)
|
|
|
+ } else {
|
|
|
+ result = append(result, 35)
|
|
|
+ }
|
|
|
+
|
|
|
+ case "CYAN", "CYA":
|
|
|
+ if bg {
|
|
|
+ result = append(result, 46)
|
|
|
+ } else {
|
|
|
+ result = append(result, 36)
|
|
|
+ }
|
|
|
+
|
|
|
+ case "WHITE", "WHI":
|
|
|
+ if bg {
|
|
|
+ result = append(result, 47)
|
|
|
+ } else {
|
|
|
+ result = append(result, 37)
|
|
|
+ }
|
|
|
+
|
|
|
+ case "BOLD", "BOL", "BRIGHT", "BRI":
|
|
|
+ result = append(result, 1)
|
|
|
+
|
|
|
+ case "ON":
|
|
|
+ bg = true
|
|
|
+
|
|
|
+ case "BLINK", "BLI":
|
|
|
+ result = append(result, 5)
|
|
|
+
|
|
|
+ case "INVERT", "INVERSE", "INV":
|
|
|
+ result = append(result, 7)
|
|
|
+ default:
|
|
|
+ fmt.Println("ColorText Unknown:", part)
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ // fmt.Println("ColorText:", result)
|
|
|
+ return Color(result...)
|
|
|
+}
|
|
|
+
|
|
|
+var Reset string = Color(0)
|
|
|
+var READFD int
|
|
|
+var WRITEFD int
|
|
|
+
|
|
|
+type DropfileConfig struct {
|
|
|
+ comm_type int
|
|
|
+ comm_handle int
|
|
|
+ baudrate int
|
|
|
+ BBSID string
|
|
|
+ user_number int
|
|
|
+ real_name string
|
|
|
+ handle string
|
|
|
+ security_level int
|
|
|
+ time_left int
|
|
|
+ emulation int
|
|
|
+ node_number int
|
|
|
+}
|
|
|
+
|
|
|
+type Door struct {
|
|
|
+ config DropfileConfig
|
|
|
+ READFD int
|
|
|
+ WRITEFD int
|
|
|
+}
|
|
|
+
|
|
|
+func (d *Door) ReadDropfile(filename string) {
|
|
|
+ file, err := os.Open(filename)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Printf("Open(%s): %s\n", filename, err)
|
|
|
+ os.Exit(2)
|
|
|
+ }
|
|
|
+
|
|
|
+ defer file.Close()
|
|
|
+
|
|
|
+ var lines []string
|
|
|
+ // read line by line
|
|
|
+
|
|
|
+ // The scanner handles DOS and linux file endings.
|
|
|
+
|
|
|
+ scanner := bufio.NewScanner(file)
|
|
|
+ for scanner.Scan() {
|
|
|
+ line := scanner.Text()
|
|
|
+ lines = append(lines, line)
|
|
|
+ // fmt.Printf("[%s]\n", line)
|
|
|
+ }
|
|
|
+
|
|
|
+ d.config.comm_type, err = strconv.Atoi(lines[0])
|
|
|
+ d.config.comm_handle, err = strconv.Atoi(lines[1])
|
|
|
+ d.config.baudrate, err = strconv.Atoi(lines[2])
|
|
|
+ d.config.BBSID = lines[3]
|
|
|
+ d.config.user_number, err = strconv.Atoi(lines[4])
|
|
|
+ d.config.real_name = lines[5]
|
|
|
+ d.config.handle = lines[6]
|
|
|
+ d.config.security_level, err = strconv.Atoi(lines[7])
|
|
|
+ d.config.time_left, err = strconv.Atoi(lines[8])
|
|
|
+ d.config.emulation, err = strconv.Atoi(lines[9])
|
|
|
+ d.config.node_number, err = strconv.Atoi(lines[10])
|
|
|
+ d.READFD = d.config.comm_handle
|
|
|
+ //if d.READFD == 0 {
|
|
|
+ // d.WRITEFD = 1
|
|
|
+ //} else {
|
|
|
+ d.WRITEFD = d.config.comm_handle
|
|
|
+ //}
|
|
|
+}
|
|
|
+
|
|
|
+func (d *Door) HasKey() bool {
|
|
|
+ var fdsetRead = syscall.FdSet{}
|
|
|
+ clearAll(&fdsetRead)
|
|
|
+ set(&fdsetRead, d.READFD)
|
|
|
+ timeout := syscall.Timeval{Sec: 0, Usec: 1}
|
|
|
+ v, _ := syscall.Select(d.READFD+1, &fdsetRead, nil, nil, &timeout)
|
|
|
+ if v == -1 {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if v == 0 {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+func (d *Door) detect() {
|
|
|
+ // if d.config.comm_handle == 0 {
|
|
|
+ // d.Write("\377\375\042\377\373\001") // fix telnet client
|
|
|
+ // }
|
|
|
+ d.Write("\x1b[0;30;40m\x1b[2J\x1b[H") // black on black, clrscr, go home
|
|
|
+ d.Write("\x03\x04\x1b[6n") // hearts and diamonds does CP437 work?
|
|
|
+
|
|
|
+ d.Write("\n\r" + "\u2615\x1b[6n")
|
|
|
+ d.Write("\x1b[999C\x1b[999B\x1b[6n" + Reset + "\x1b[2J\x1b[H") // goto end of screen + cursor pos
|
|
|
+ // time.Sleep(50 * time.Millisecond)
|
|
|
+ time.Sleep(250 * time.Millisecond)
|
|
|
+ // read everything
|
|
|
+ // telnet term isn't in RAW mode, so keys are buffer until <CR>
|
|
|
+
|
|
|
+ if true { // d.HasKey() {
|
|
|
+ buffer := make([]byte, 100)
|
|
|
+ r, err := syscall.Read(d.READFD, buffer)
|
|
|
+ results := string(buffer[:r])
|
|
|
+ results = strings.Replace(results, "\x1b", "^", -1)
|
|
|
+ fmt.Println("DETECT:", r, err, results)
|
|
|
+ } else {
|
|
|
+ // local telnet echos the reply :()
|
|
|
+ fmt.Println("DETECT: Nothing received.")
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+func (d *Door) Init() {
|
|
|
+ var dropfile string
|
|
|
+
|
|
|
+ flag.StringVar(&dropfile, "d", "", "Path to dropfile")
|
|
|
+ flag.Parse()
|
|
|
+ if len(dropfile) == 0 {
|
|
|
+ flag.PrintDefaults()
|
|
|
+ os.Exit(2)
|
|
|
+ }
|
|
|
+ fmt.Printf("Loading: %s\n", dropfile)
|
|
|
+
|
|
|
+ d.ReadDropfile(dropfile)
|
|
|
+
|
|
|
+ fmt.Printf("BBS %s, User %s / Handle %s / File %d\n", d.config.BBSID, d.config.real_name, d.config.handle, d.config.comm_handle)
|
|
|
+ // putting the linux terminal into raw mode ...
|
|
|
+ // requires golang.org/x/sys/unix unix.Ioctlgetermios, etc.
|
|
|
+ d.detect()
|
|
|
+}
|
|
|
+
|
|
|
+func (d *Door) Write(output string) {
|
|
|
+ buffer := []byte(output)
|
|
|
+ n, err := syscall.Write(d.WRITEFD, buffer)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("Write error/HANGUP?", n)
|
|
|
+ }
|
|
|
+ // No, this isn't it. The # of bytes in buffer == bytes written.
|
|
|
+ if n != len(buffer) {
|
|
|
+ fmt.Printf("Write fail: %d != %d\n", len(buffer), n)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+func write(output string, config *DropfileConfig) {
|
|
|
+ buffer := []byte(output)
|
|
|
+ n, err := syscall.Write(config.comm_handle, buffer)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("Write error/HANGUP?", n)
|
|
|
+ }
|
|
|
+}
|
|
|
+*/
|
|
|
+
|
|
|
+// from: https://github.com/yubo/dea_ng
|
|
|
+// https://github.com/yubo/dea_ng/blob/master/go/src/directoryserver/streaming.go
|
|
|
+
|
|
|
+func set(fdSetPtr *syscall.FdSet, fd int) {
|
|
|
+ (*fdSetPtr).Bits[fd/64] |= 1 << uint64(fd%64)
|
|
|
+}
|
|
|
+
|
|
|
+func isSet(fdSetPtr *syscall.FdSet, fd int) bool {
|
|
|
+ return ((*fdSetPtr).Bits[fd/64] & (1 << uint64(fd%64))) != 0
|
|
|
+}
|
|
|
+
|
|
|
+func clearAll(fdSetPtr *syscall.FdSet) {
|
|
|
+ for index, _ := range (*fdSetPtr).Bits {
|
|
|
+ (*fdSetPtr).Bits[index] = 0
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (d *Door) SleepKey(sleep int64) int {
|
|
|
+ // var fdsetRead, fdsetWrite, fdsete syscall.FdSet
|
|
|
+ var fdsetRead syscall.FdSet
|
|
|
+ // fdsetWrite := syscall.FdSet
|
|
|
+ clearAll(&fdsetRead)
|
|
|
+ // clearAll(&fdsetWrite)
|
|
|
+ // clearAll(&fdsete)
|
|
|
+ set(&fdsetRead, d.READFD)
|
|
|
+ // timeout := syscall.Timeval{Sec: 0, Usec: 100}
|
|
|
+ timeout := syscall.Timeval{Sec: sleep, Usec: 0}
|
|
|
+ v, err := syscall.Select(d.READFD+1, &fdsetRead, nil, nil, &timeout)
|
|
|
+ if v == -1 {
|
|
|
+ fmt.Println("-1 : ", err)
|
|
|
+ // hangup ?!
|
|
|
+ return -2
|
|
|
+ }
|
|
|
+ if v == 0 {
|
|
|
+ // timeout
|
|
|
+ return -1
|
|
|
+ }
|
|
|
+ // var buffer []byte -- 0 byte buffer. doh!
|
|
|
+ buffer := make([]byte, 1)
|
|
|
+ r, err := syscall.Read(d.READFD, buffer)
|
|
|
+ if r != 1 {
|
|
|
+ fmt.Printf("Read said ready, but didn't read a character %d %v.", r, err)
|
|
|
+ // hangup
|
|
|
+ return -2
|
|
|
+ }
|
|
|
+ return int(buffer[0])
|
|
|
+}
|
|
|
+
|
|
|
+func (d *Door) Getch() int {
|
|
|
+ // var fdsetRead, fdsetWrite, fdsete syscall.FdSet
|
|
|
+ var fdsetRead syscall.FdSet
|
|
|
+ // fdsetWrite := syscall.FdSet
|
|
|
+ clearAll(&fdsetRead)
|
|
|
+ // clearAll(&fdsetWrite)
|
|
|
+ // clearAll(&fdsete)
|
|
|
+ set(&fdsetRead, d.READFD)
|
|
|
+ // timeout := syscall.Timeval{Sec: 0, Usec: 100}
|
|
|
+ timeout := syscall.Timeval{Sec: 120, Usec: 0}
|
|
|
+ v, err := syscall.Select(d.READFD+1, &fdsetRead, nil, nil, &timeout)
|
|
|
+ if v == -1 {
|
|
|
+ fmt.Println("-1 : ", err)
|
|
|
+ // hangup ?!
|
|
|
+ return -2
|
|
|
+ }
|
|
|
+ if v == 0 {
|
|
|
+ // timeout
|
|
|
+ return -1
|
|
|
+ }
|
|
|
+ // var buffer []byte -- 0 byte buffer. doh!
|
|
|
+ buffer := make([]byte, 1)
|
|
|
+ r, err := syscall.Read(d.READFD, buffer)
|
|
|
+ if r != 1 {
|
|
|
+ fmt.Printf("Read said ready, but didn't read a character %d %v.", r, err)
|
|
|
+ // hangup
|
|
|
+ return -2
|
|
|
+ }
|
|
|
+ return int(buffer[0])
|
|
|
+}
|
|
|
+
|
|
|
+func sleep_key(config *DropfileConfig, secs int) int {
|
|
|
+ // var fdsetRead, fdsetWrite, fdsete syscall.FdSet
|
|
|
+ var fdsetRead = syscall.FdSet{}
|
|
|
+ // fdsetWrite := syscall.FdSet
|
|
|
+ clearAll(&fdsetRead)
|
|
|
+ // clearAll(&fdsetWrite)
|
|
|
+ // clearAll(&fdsete)
|
|
|
+ set(&fdsetRead, config.comm_handle)
|
|
|
+ timeout := syscall.Timeval{Sec: int64(secs), Usec: 0}
|
|
|
+ // v, err := syscall.Select(config.comm_handle+1, &fdsetRead, &fdsetWrite, &fdsete, &timeout)
|
|
|
+ v, err := syscall.Select(config.comm_handle+1, &fdsetRead, nil, nil, &timeout)
|
|
|
+ fmt.Println("v:", v, "err:", err)
|
|
|
+ if v == -1 {
|
|
|
+ fmt.Println("-1 : ", err)
|
|
|
+ // hangup ?!
|
|
|
+ return -2
|
|
|
+ }
|
|
|
+ if v == 0 {
|
|
|
+ // timeout
|
|
|
+ return -1
|
|
|
+ }
|
|
|
+ // var buffer []byte
|
|
|
+ buffer := make([]byte, 1)
|
|
|
+ // var buffer [1]byte
|
|
|
+
|
|
|
+ r, err := syscall.Read(config.comm_handle, buffer)
|
|
|
+ if r != 1 {
|
|
|
+ fmt.Printf("Read said ready, but didn't read a character %d %v ?\n", r, err)
|
|
|
+ // hangup
|
|
|
+ return -2
|
|
|
+ }
|
|
|
+ return int(buffer[0])
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+func main() {
|
|
|
+ fmt.Println("doorgo")
|
|
|
+ var dropfile string
|
|
|
+
|
|
|
+ flag.StringVar(&dropfile, "dropfile", "", "Dropfile to use")
|
|
|
+ flag.Parse()
|
|
|
+
|
|
|
+ if len(dropfile) == 0 {
|
|
|
+ flag.PrintDefaults()
|
|
|
+ os.Exit(2)
|
|
|
+ }
|
|
|
+ fmt.Printf("Loading: %s\n", dropfile)
|
|
|
+
|
|
|
+ var config DropfileConfig
|
|
|
+ read_dropfile(dropfile, &config)
|
|
|
+
|
|
|
+ fmt.Printf("BBS %s, User %s / Handle %s\n", config.BBSID, config.real_name, config.handle)
|
|
|
+ message := "Welcome BBS User!\n\r"
|
|
|
+ // buffer := []byte(message)
|
|
|
+ // n, err := syscall.Write(config.comm_handle, buffer)
|
|
|
+ write(message, &config)
|
|
|
+
|
|
|
+ write("Press a key...", &config)
|
|
|
+ key := sleep_key(&config, 20)
|
|
|
+ write("\n\r", &config)
|
|
|
+ message = fmt.Sprintf("Key %d / %x\n\r", key, key)
|
|
|
+ write(message, &config)
|
|
|
+
|
|
|
+ write("\n\rReturning to BBS.\n\r", &config)
|
|
|
+ fmt.Println("Done.")
|
|
|
+ // fmt.Println(n, err)
|
|
|
+}
|
|
|
+*/
|