door.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. package door
  2. import (
  3. "bufio"
  4. "flag"
  5. "fmt"
  6. "os"
  7. "strconv"
  8. "strings"
  9. "syscall"
  10. "time"
  11. )
  12. /*
  13. door32.sys:
  14. 0 Line 1 : Comm type (0=local, 1=serial, 2=telnet)
  15. 0 Line 2 : Comm or socket handle
  16. 38400 Line 3 : Baud rate
  17. Mystic 1.07 Line 4 : BBSID (software name and version)
  18. 1 Line 5 : User record position (1-based)
  19. James Coyle Line 6 : User's real name
  20. g00r00 Line 7 : User's handle/alias
  21. 255 Line 8 : User's security level
  22. 58 Line 9 : User's time left (in minutes)
  23. 1 Line 10: Emulation *See Below
  24. 1 Line 11: Current node number
  25. */
  26. func Color(arg ...int) string {
  27. var result string = "\x1b["
  28. for i := range arg {
  29. result += fmt.Sprintf("%d;", arg[i])
  30. }
  31. result += "m"
  32. return result
  33. }
  34. func ColorText(color string) string {
  35. // split on spaces, uppercase, match first 3 letter
  36. var result []int
  37. var bg bool
  38. result = append(result, 0)
  39. parts := strings.Fields(strings.ToUpper(color))
  40. for _, part := range parts {
  41. switch part {
  42. case "BLACK", "BLA":
  43. if bg {
  44. result = append(result, 40)
  45. } else {
  46. result = append(result, 30)
  47. }
  48. case "RED":
  49. if bg {
  50. result = append(result, 41)
  51. } else {
  52. result = append(result, 31)
  53. }
  54. case "GREEN", "GRE":
  55. if bg {
  56. result = append(result, 42)
  57. } else {
  58. result = append(result, 32)
  59. }
  60. case "BROWN", "BRO":
  61. if bg {
  62. result = append(result, 43)
  63. } else {
  64. result = append(result, 33)
  65. }
  66. case "YELLOW", "YEL":
  67. if bg {
  68. result = append(result, 43)
  69. } else {
  70. result = append(result, 33)
  71. }
  72. case "BLUE", "BLU":
  73. if bg {
  74. result = append(result, 44)
  75. } else {
  76. result = append(result, 34)
  77. }
  78. case "MAGENTA", "MAG":
  79. if bg {
  80. result = append(result, 45)
  81. } else {
  82. result = append(result, 35)
  83. }
  84. case "CYAN", "CYA":
  85. if bg {
  86. result = append(result, 46)
  87. } else {
  88. result = append(result, 36)
  89. }
  90. case "WHITE", "WHI":
  91. if bg {
  92. result = append(result, 47)
  93. } else {
  94. result = append(result, 37)
  95. }
  96. case "BOLD", "BOL", "BRIGHT", "BRI":
  97. result = append(result, 1)
  98. case "ON":
  99. bg = true
  100. case "BLINK", "BLI":
  101. result = append(result, 5)
  102. case "INVERT", "INVERSE", "INV":
  103. result = append(result, 7)
  104. default:
  105. fmt.Println("ColorText Unknown:", part)
  106. }
  107. }
  108. // fmt.Println("ColorText:", result)
  109. return Color(result...)
  110. }
  111. var Reset string = Color(0)
  112. var READFD int
  113. var WRITEFD int
  114. type DropfileConfig struct {
  115. comm_type int
  116. comm_handle int
  117. baudrate int
  118. BBSID string
  119. user_number int
  120. real_name string
  121. handle string
  122. security_level int
  123. time_left int
  124. emulation int
  125. node_number int
  126. }
  127. type Door struct {
  128. config DropfileConfig
  129. READFD int
  130. WRITEFD int
  131. }
  132. func (d *Door) ReadDropfile(filename string) {
  133. file, err := os.Open(filename)
  134. if err != nil {
  135. fmt.Printf("Open(%s): %s\n", filename, err)
  136. os.Exit(2)
  137. }
  138. defer file.Close()
  139. var lines []string
  140. // read line by line
  141. // The scanner handles DOS and linux file endings.
  142. scanner := bufio.NewScanner(file)
  143. for scanner.Scan() {
  144. line := scanner.Text()
  145. lines = append(lines, line)
  146. // fmt.Printf("[%s]\n", line)
  147. }
  148. d.config.comm_type, err = strconv.Atoi(lines[0])
  149. d.config.comm_handle, err = strconv.Atoi(lines[1])
  150. d.config.baudrate, err = strconv.Atoi(lines[2])
  151. d.config.BBSID = lines[3]
  152. d.config.user_number, err = strconv.Atoi(lines[4])
  153. d.config.real_name = lines[5]
  154. d.config.handle = lines[6]
  155. d.config.security_level, err = strconv.Atoi(lines[7])
  156. d.config.time_left, err = strconv.Atoi(lines[8])
  157. d.config.emulation, err = strconv.Atoi(lines[9])
  158. d.config.node_number, err = strconv.Atoi(lines[10])
  159. d.READFD = d.config.comm_handle
  160. //if d.READFD == 0 {
  161. // d.WRITEFD = 1
  162. //} else {
  163. d.WRITEFD = d.config.comm_handle
  164. //}
  165. }
  166. func (d *Door) HasKey() bool {
  167. var fdsetRead = syscall.FdSet{}
  168. clearAll(&fdsetRead)
  169. set(&fdsetRead, d.READFD)
  170. timeout := syscall.Timeval{Sec: 0, Usec: 1}
  171. v, _ := syscall.Select(d.READFD+1, &fdsetRead, nil, nil, &timeout)
  172. if v == -1 {
  173. return false
  174. }
  175. if v == 0 {
  176. return false
  177. }
  178. return true
  179. }
  180. func (d *Door) detect() {
  181. // if d.config.comm_handle == 0 {
  182. // d.Write("\377\375\042\377\373\001") // fix telnet client
  183. // }
  184. d.Write("\x1b[0;30;40m\x1b[2J\x1b[H") // black on black, clrscr, go home
  185. d.Write("\x03\x04\x1b[6n") // hearts and diamonds does CP437 work?
  186. d.Write("\n\r" + "\u2615\x1b[6n")
  187. d.Write("\x1b[999C\x1b[999B\x1b[6n" + Reset + "\x1b[2J\x1b[H") // goto end of screen + cursor pos
  188. // time.Sleep(50 * time.Millisecond)
  189. time.Sleep(250 * time.Millisecond)
  190. // read everything
  191. // telnet term isn't in RAW mode, so keys are buffer until <CR>
  192. if true { // d.HasKey() {
  193. buffer := make([]byte, 100)
  194. r, err := syscall.Read(d.READFD, buffer)
  195. results := string(buffer[:r])
  196. results = strings.Replace(results, "\x1b", "^", -1)
  197. fmt.Println("DETECT:", r, err, results)
  198. } else {
  199. // local telnet echos the reply :()
  200. fmt.Println("DETECT: Nothing received.")
  201. }
  202. }
  203. func (d *Door) Init() {
  204. var dropfile string
  205. flag.StringVar(&dropfile, "d", "", "Path to dropfile")
  206. flag.Parse()
  207. if len(dropfile) == 0 {
  208. flag.PrintDefaults()
  209. os.Exit(2)
  210. }
  211. fmt.Printf("Loading: %s\n", dropfile)
  212. d.ReadDropfile(dropfile)
  213. 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)
  214. // putting the linux terminal into raw mode ...
  215. // requires golang.org/x/sys/unix unix.Ioctlgetermios, etc.
  216. d.detect()
  217. }
  218. func (d *Door) Write(output string) {
  219. buffer := []byte(output)
  220. n, err := syscall.Write(d.WRITEFD, buffer)
  221. if err != nil {
  222. fmt.Println("Write error/HANGUP?", n)
  223. }
  224. // No, this isn't it. The # of bytes in buffer == bytes written.
  225. if n != len(buffer) {
  226. fmt.Printf("Write fail: %d != %d\n", len(buffer), n)
  227. }
  228. }
  229. /*
  230. func write(output string, config *DropfileConfig) {
  231. buffer := []byte(output)
  232. n, err := syscall.Write(config.comm_handle, buffer)
  233. if err != nil {
  234. fmt.Println("Write error/HANGUP?", n)
  235. }
  236. }
  237. */
  238. // from: https://github.com/yubo/dea_ng
  239. // https://github.com/yubo/dea_ng/blob/master/go/src/directoryserver/streaming.go
  240. func set(fdSetPtr *syscall.FdSet, fd int) {
  241. (*fdSetPtr).Bits[fd/64] |= 1 << uint64(fd%64)
  242. }
  243. func isSet(fdSetPtr *syscall.FdSet, fd int) bool {
  244. return ((*fdSetPtr).Bits[fd/64] & (1 << uint64(fd%64))) != 0
  245. }
  246. func clearAll(fdSetPtr *syscall.FdSet) {
  247. for index, _ := range (*fdSetPtr).Bits {
  248. (*fdSetPtr).Bits[index] = 0
  249. }
  250. }
  251. func (d *Door) SleepKey(sleep int64) int {
  252. // var fdsetRead, fdsetWrite, fdsete syscall.FdSet
  253. var fdsetRead syscall.FdSet
  254. // fdsetWrite := syscall.FdSet
  255. clearAll(&fdsetRead)
  256. // clearAll(&fdsetWrite)
  257. // clearAll(&fdsete)
  258. set(&fdsetRead, d.READFD)
  259. // timeout := syscall.Timeval{Sec: 0, Usec: 100}
  260. timeout := syscall.Timeval{Sec: sleep, Usec: 0}
  261. v, err := syscall.Select(d.READFD+1, &fdsetRead, nil, nil, &timeout)
  262. if v == -1 {
  263. fmt.Println("-1 : ", err)
  264. // hangup ?!
  265. return -2
  266. }
  267. if v == 0 {
  268. // timeout
  269. return -1
  270. }
  271. // var buffer []byte -- 0 byte buffer. doh!
  272. buffer := make([]byte, 1)
  273. r, err := syscall.Read(d.READFD, buffer)
  274. if r != 1 {
  275. fmt.Printf("Read said ready, but didn't read a character %d %v.", r, err)
  276. // hangup
  277. return -2
  278. }
  279. return int(buffer[0])
  280. }
  281. func (d *Door) Getch() int {
  282. // var fdsetRead, fdsetWrite, fdsete syscall.FdSet
  283. var fdsetRead syscall.FdSet
  284. // fdsetWrite := syscall.FdSet
  285. clearAll(&fdsetRead)
  286. // clearAll(&fdsetWrite)
  287. // clearAll(&fdsete)
  288. set(&fdsetRead, d.READFD)
  289. // timeout := syscall.Timeval{Sec: 0, Usec: 100}
  290. timeout := syscall.Timeval{Sec: 120, Usec: 0}
  291. v, err := syscall.Select(d.READFD+1, &fdsetRead, nil, nil, &timeout)
  292. if v == -1 {
  293. fmt.Println("-1 : ", err)
  294. // hangup ?!
  295. return -2
  296. }
  297. if v == 0 {
  298. // timeout
  299. return -1
  300. }
  301. // var buffer []byte -- 0 byte buffer. doh!
  302. buffer := make([]byte, 1)
  303. r, err := syscall.Read(d.READFD, buffer)
  304. if r != 1 {
  305. fmt.Printf("Read said ready, but didn't read a character %d %v.", r, err)
  306. // hangup
  307. return -2
  308. }
  309. return int(buffer[0])
  310. }
  311. func sleep_key(config *DropfileConfig, secs int) int {
  312. // var fdsetRead, fdsetWrite, fdsete syscall.FdSet
  313. var fdsetRead = syscall.FdSet{}
  314. // fdsetWrite := syscall.FdSet
  315. clearAll(&fdsetRead)
  316. // clearAll(&fdsetWrite)
  317. // clearAll(&fdsete)
  318. set(&fdsetRead, config.comm_handle)
  319. timeout := syscall.Timeval{Sec: int64(secs), Usec: 0}
  320. // v, err := syscall.Select(config.comm_handle+1, &fdsetRead, &fdsetWrite, &fdsete, &timeout)
  321. v, err := syscall.Select(config.comm_handle+1, &fdsetRead, nil, nil, &timeout)
  322. fmt.Println("v:", v, "err:", err)
  323. if v == -1 {
  324. fmt.Println("-1 : ", err)
  325. // hangup ?!
  326. return -2
  327. }
  328. if v == 0 {
  329. // timeout
  330. return -1
  331. }
  332. // var buffer []byte
  333. buffer := make([]byte, 1)
  334. // var buffer [1]byte
  335. r, err := syscall.Read(config.comm_handle, buffer)
  336. if r != 1 {
  337. fmt.Printf("Read said ready, but didn't read a character %d %v ?\n", r, err)
  338. // hangup
  339. return -2
  340. }
  341. return int(buffer[0])
  342. }
  343. /*
  344. func main() {
  345. fmt.Println("doorgo")
  346. var dropfile string
  347. flag.StringVar(&dropfile, "dropfile", "", "Dropfile to use")
  348. flag.Parse()
  349. if len(dropfile) == 0 {
  350. flag.PrintDefaults()
  351. os.Exit(2)
  352. }
  353. fmt.Printf("Loading: %s\n", dropfile)
  354. var config DropfileConfig
  355. read_dropfile(dropfile, &config)
  356. fmt.Printf("BBS %s, User %s / Handle %s\n", config.BBSID, config.real_name, config.handle)
  357. message := "Welcome BBS User!\n\r"
  358. // buffer := []byte(message)
  359. // n, err := syscall.Write(config.comm_handle, buffer)
  360. write(message, &config)
  361. write("Press a key...", &config)
  362. key := sleep_key(&config, 20)
  363. write("\n\r", &config)
  364. message = fmt.Sprintf("Key %d / %x\n\r", key, key)
  365. write(message, &config)
  366. write("\n\rReturning to BBS.\n\r", &config)
  367. fmt.Println("Done.")
  368. // fmt.Println(n, err)
  369. }
  370. */