door.go 9.7 KB

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