setuptelnet.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. package server
  2. import "github.com/beoran/woe/monolog"
  3. import t "github.com/beoran/woe/telnet"
  4. import "github.com/beoran/woe/telnet"
  5. import "strings"
  6. import "strconv"
  7. /* This file contains telnet setup helpers for the client. */
  8. // generic negotiation
  9. func (me * Client) SetupNegotiate(millis int, command byte, option byte, yes_event telnet.EventType, no_event telnet.EventType) (bool, telnet.Event) {
  10. me.telnet.TelnetSendNegotiate(command, option)
  11. tev, timeout, close := me.TryReadEvent(millis)
  12. if tev == nil || timeout || close {
  13. monolog.Info("Timeout or close in TryReadEvent")
  14. return false, nil
  15. }
  16. evtype := telnet.EventTypeOf(tev)
  17. if evtype == no_event {
  18. monolog.Info("Negative event no_event %v %v %v", tev, evtype, no_event)
  19. return false, tev
  20. }
  21. if evtype != yes_event {
  22. monolog.Info("Unexpected event yes_event %v %v %v", tev, evtype, yes_event)
  23. return false, tev
  24. }
  25. return true, tev
  26. }
  27. // Negotiate COMPRESS2 support
  28. func (me * Client) SetupCompress2() telnet.Event {
  29. ok, tev := me.SetupNegotiate(1000, t.TELNET_WILL, t.TELNET_TELOPT_COMPRESS2, t.TELNET_DO_EVENT, t.TELNET_DONT_EVENT)
  30. if (!ok) {
  31. return tev
  32. }
  33. me.telnet.TelnetBeginCompress2()
  34. monolog.Info("Client #{@id} started COMPRESS2 compression")
  35. me.info.compress2 = true
  36. return tev
  37. }
  38. // Negotiate NAWS (window size) support
  39. func (me * Client) SetupNAWS() telnet.Event {
  40. ok, tev := me.SetupNegotiate(1000, t.TELNET_DO, t.TELNET_TELOPT_NAWS, t.TELNET_WILL_EVENT, t.TELNET_WONT_EVENT)
  41. if (!ok) {
  42. return tev
  43. }
  44. tev2, _, _ := me.TryReadEvent(1000)
  45. if (tev2 == nil) || (!telnet.IsEventType(tev2, t.TELNET_NAWS_EVENT)) {
  46. return tev2
  47. }
  48. nawsevent, ok := tev2.(*telnet.NAWSEvent)
  49. if ok {
  50. me.info.w = nawsevent.W
  51. me.info.h = nawsevent.H
  52. monolog.Info("Client %d window size #{%d}x#{%d}", me.id, me.info.w, me.info.h)
  53. me.info.naws = true
  54. }
  55. return nil
  56. }
  57. func (me * Client) SetupMSSP() telnet.Event {
  58. ok, tev := me.SetupNegotiate(1000, t.TELNET_WILL, t.TELNET_TELOPT_MSSP, t.TELNET_DO_EVENT, t.TELNET_DONT_EVENT)
  59. if (!ok) {
  60. return tev
  61. }
  62. me.telnet.TelnetSendMSSP(MSSP)
  63. monolog.Info("Client %d accepts MSSP", me.id)
  64. me.info.mssp = true
  65. return nil
  66. }
  67. // Check for MXP (html-like) support (but don't implement it yet)
  68. func (me * Client) SetupMXP() telnet.Event {
  69. ok, tev := me.SetupNegotiate(1000, t.TELNET_DO, t.TELNET_TELOPT_MXP, t.TELNET_WILL_EVENT, t.TELNET_WONT_EVENT)
  70. if (!ok) {
  71. return tev
  72. }
  73. monolog.Info("Client %d accepts MXP", me.id)
  74. me.info.mxp = true
  75. return nil
  76. }
  77. // Check for MSP (sound) support (but don't implement it yet)
  78. func (me * Client) SetupMSP() telnet.Event {
  79. ok, tev := me.SetupNegotiate(1000, t.TELNET_DO, t.TELNET_TELOPT_MSP, t.TELNET_WILL_EVENT, t.TELNET_WONT_EVENT)
  80. if (!ok) {
  81. return tev
  82. }
  83. monolog.Info("Client %d accepts MSP", me.id)
  84. me.info.msp = true
  85. return nil
  86. }
  87. // Check for MSDP (two way MSSP) support (but don't implement it yet)
  88. func (me * Client) SetupMSDP() telnet.Event {
  89. ok, tev := me.SetupNegotiate(1000, t.TELNET_WILL, t.TELNET_TELOPT_MSDP, t.TELNET_DO_EVENT, t.TELNET_DONT_EVENT)
  90. if (!ok) {
  91. return tev
  92. }
  93. monolog.Info("Client %d accepts MSDP", me.id)
  94. me.info.msdp = true
  95. return nil
  96. }
  97. func (me * Client) HasTerminal(name string) bool {
  98. monolog.Debug("Client %d supports terminals? %s %v", me.id, name, me.info.terminals)
  99. for index := range me.info.terminals {
  100. if (me.info.terminals[index] == name) {
  101. return true
  102. }
  103. }
  104. return false
  105. }
  106. // Negotiate MTTS/TTYPE (TERMINAL TYPE) support
  107. func (me * Client) SetupTType() telnet.Event {
  108. me.info.terminals = nil
  109. ok, tev := me.SetupNegotiate(1000, t.TELNET_DO, t.TELNET_TELOPT_TTYPE, t.TELNET_WILL_EVENT, t.TELNET_WONT_EVENT)
  110. if (!ok) {
  111. return tev
  112. }
  113. var last string = "none"
  114. var now string = ""
  115. for last != now {
  116. last = now
  117. me.telnet.TelnetTTypeSend()
  118. var tev2 telnet.Event = nil
  119. // Some clients (like KildClient, but not TinTin or telnet),
  120. // insist on spamming useless NUL characters
  121. // here... So we have to retry a few times to get a ttype_is
  122. // throwing away any undesirable junk in between.
  123. GET_TTYPE: for index := 0 ; index < 3 ; index++ {
  124. tev2, _, _ = me.TryReadEvent(1000)
  125. etyp := telnet.EventTypeOf(tev2)
  126. monolog.Info("Waiting for TTYPE: %T %v %d", tev2, tev2, etyp)
  127. if tev2 != nil && telnet.IsEventType(tev2, t.TELNET_TTYPE_EVENT) {
  128. monolog.Info("TTYPE received: %T %v %d", tev2, tev2, etyp)
  129. break GET_TTYPE
  130. }
  131. }
  132. if tev2 == nil || !telnet.IsEventType(tev2, t.TELNET_TTYPE_EVENT) {
  133. etyp := telnet.EventTypeOf(tev2)
  134. monolog.Warning("Received no TTYPE: %T %v %d", tev2, tev2, etyp)
  135. return tev2
  136. }
  137. ttypeevent := tev2.(*telnet.TTypeEvent)
  138. now = ttypeevent.Name
  139. if (!me.HasTerminal(now)) {
  140. me.info.terminals = append(me.info.terminals, now)
  141. }
  142. me.info.terminal = now
  143. }
  144. monolog.Info("Client %d supports terminals %v", me.id, me.info.terminals)
  145. monolog.Info("Client %d active terminal %v", me.id, me.info.terminal)
  146. // MTTS support
  147. for i := range me.info.terminals {
  148. term := me.info.terminals[i]
  149. monolog.Info("Checking MTTS support: %s", term)
  150. if strings.HasPrefix(term, "MTTS ") {
  151. // it's an mtts terminal
  152. strnum := strings.TrimPrefix(term, "MTTS ")
  153. num, err := strconv.Atoi(strnum)
  154. if err == nil {
  155. me.info.mtts = num
  156. monolog.Info("Client %d supports mtts %d", me.id, me.info.mtts)
  157. } else {
  158. monolog.Warning("Client %d could not parse mtts %s %v", me.id, strnum, err)
  159. }
  160. }
  161. }
  162. me.info.ttype = true
  163. return nil
  164. }
  165. func (me * Client) SetupTelnet() {
  166. for {
  167. tev, _, _ := me.TryReadEvent(500)
  168. if tev != nil {
  169. monolog.Info("Client %d telnet setup received: %v", me.id, tev)
  170. } else {
  171. monolog.Info("Client %d no telnet setup received", me.id)
  172. break
  173. }
  174. }
  175. me.SetupMSSP()
  176. // me.SetupCompress2
  177. me.SetupNAWS()
  178. me.SetupTType()
  179. me.SetupMXP()
  180. me.SetupMSP()
  181. me.SetupMSDP()
  182. // me.ColorTest()
  183. }
  184. /*
  185. # Switches to "password" mode.
  186. def password_mode
  187. # The server sends "IAC WILL ECHO", meaning "I, the server, will do any
  188. # echoing from now on." The client should acknowledge this with an IAC DO
  189. # ECHO, and then stop putting echoed text in the input buffer.
  190. # It should also do whatever is appropriate for password entry to the input
  191. # box thing - for example, it might * it out. Text entered in server-echoes
  192. # mode should also not be placed any command history.
  193. # don't use the Q state machne for echos
  194. @telnet.telnet_send_bytes(TELNET_IAC, TELNET_WILL, TELNET_TELOPT_ECHO)
  195. tev = wait_for_input(0.1)
  196. return tev if tev && tev.type != :do
  197. return nil
  198. end
  199. # Switches to "normal, or non-password mode.
  200. def normal_mode
  201. # When the server wants the client to start local echoing again, it sends
  202. # "IAC WONT ECHO" - the client must respond to this with "IAC DONT ECHO".
  203. # Again don't use Q state machine.
  204. @telnet.telnet_send_bytes(TELNET_IAC, TELNET_WONT, TELNET_TELOPT_ECHO)
  205. tev = wait_for_input(0.1)
  206. return tev if tev && tev.type != :dont
  207. return nil
  208. end
  209. end
  210. def handle_command
  211. order = wait_for_command
  212. case order
  213. when "/quit"
  214. write("Byebye!\r\n")
  215. @busy = false
  216. else
  217. @server.broadcast("#{@account.id} said #{order}\r\n")
  218. end
  219. end
  220. */