setuptelnet.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. package server
  2. import "gitlab.com/beoran/woe/monolog"
  3. import t "gitlab.com/beoran/woe/telnet"
  4. import "gitlab.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. if tev == nil {
  26. return false, tev
  27. }
  28. return true, tev
  29. }
  30. // Negotiate BINARY support, for sending UTF-8. This is largely a courtesy to the cliennt,
  31. // since woe will send UTF-8 anyway.
  32. func (me *Client) SetupBinary() telnet.Event {
  33. ok, tev := me.SetupNegotiate(1000, t.TELNET_WILL, t.TELNET_TELOPT_BINARY, t.TELNET_DO_EVENT, t.TELNET_DONT_EVENT)
  34. if !ok {
  35. me.info.binary = false
  36. return tev
  37. }
  38. monolog.Info("Client #{@id} accepts BINARY")
  39. me.info.binary = true
  40. return tev
  41. }
  42. // negotiate suppress go ahead
  43. func (me *Client) SetupSupressGA() telnet.Event {
  44. ok, tev := me.SetupNegotiate(1000, t.TELNET_WILL, t.TELNET_TELOPT_SGA, t.TELNET_DO_EVENT, t.TELNET_DONT_EVENT)
  45. if !ok {
  46. me.info.binary = false
  47. return tev
  48. }
  49. monolog.Info("Client #{@id} will suppress GA")
  50. me.info.sga = true
  51. return tev
  52. }
  53. // Negotiate COMPRESS2 support
  54. func (me *Client) SetupCompress2() telnet.Event {
  55. ok, tev := me.SetupNegotiate(1000, t.TELNET_WILL, t.TELNET_TELOPT_COMPRESS2, t.TELNET_DO_EVENT, t.TELNET_DONT_EVENT)
  56. if !ok {
  57. return tev
  58. }
  59. me.telnet.TelnetBeginCompress2()
  60. monolog.Info("Client #{@id} started COMPRESS2 compression")
  61. me.info.compress2 = true
  62. return tev
  63. }
  64. // Negotiate NAWS (window size) support
  65. func (me *Client) SetupNAWS() telnet.Event {
  66. ok, tev := me.SetupNegotiate(1000, t.TELNET_DO, t.TELNET_TELOPT_NAWS, t.TELNET_WILL_EVENT, t.TELNET_WONT_EVENT)
  67. if !ok {
  68. return tev
  69. }
  70. tev2, _, _ := me.TryReadEvent(1000)
  71. if (tev2 == nil) || (!telnet.IsEventType(tev2, t.TELNET_NAWS_EVENT)) {
  72. return tev2
  73. }
  74. nawsevent, ok := tev2.(*telnet.NAWSEvent)
  75. if ok {
  76. me.info.w = nawsevent.W
  77. me.info.h = nawsevent.H
  78. monolog.Info("Client %d window size #{%d}x#{%d}", me.id, me.info.w, me.info.h)
  79. me.info.naws = true
  80. }
  81. return nil
  82. }
  83. func (me *Client) SetupMSSP() telnet.Event {
  84. ok, tev := me.SetupNegotiate(1000, t.TELNET_WILL, t.TELNET_TELOPT_MSSP, t.TELNET_DO_EVENT, t.TELNET_DONT_EVENT)
  85. if !ok {
  86. return tev
  87. }
  88. me.telnet.TelnetSendMSSP(MSSP)
  89. monolog.Info("Client %d accepts MSSP", me.id)
  90. me.info.mssp = true
  91. return nil
  92. }
  93. // Check for MXP (html-like) support (but don't implement it yet)
  94. func (me *Client) SetupMXP() telnet.Event {
  95. ok, tev := me.SetupNegotiate(1000, t.TELNET_DO, t.TELNET_TELOPT_MXP, t.TELNET_WILL_EVENT, t.TELNET_WONT_EVENT)
  96. if !ok {
  97. return tev
  98. }
  99. monolog.Info("Client %d accepts MXP", me.id)
  100. me.info.mxp = true
  101. return nil
  102. }
  103. // Check for MSP (sound) support (but don't implement it yet)
  104. func (me *Client) SetupMSP() telnet.Event {
  105. ok, tev := me.SetupNegotiate(1000, t.TELNET_DO, t.TELNET_TELOPT_MSP, t.TELNET_WILL_EVENT, t.TELNET_WONT_EVENT)
  106. if !ok {
  107. return tev
  108. }
  109. monolog.Info("Client %d accepts MSP", me.id)
  110. me.info.msp = true
  111. return nil
  112. }
  113. // Check for MSDP (two way MSSP) support (but don't implement it yet)
  114. func (me *Client) SetupMSDP() telnet.Event {
  115. ok, tev := me.SetupNegotiate(1000, t.TELNET_WILL, t.TELNET_TELOPT_MSDP, t.TELNET_DO_EVENT, t.TELNET_DONT_EVENT)
  116. if !ok {
  117. return tev
  118. }
  119. monolog.Info("Client %d accepts MSDP", me.id)
  120. me.info.msdp = true
  121. return nil
  122. }
  123. func (me *Client) HasTerminal(name string) bool {
  124. monolog.Debug("Client %d supports terminals? %s %v", me.id, name, me.info.terminals)
  125. for index := range me.info.terminals {
  126. if me.info.terminals[index] == name {
  127. return true
  128. }
  129. }
  130. return false
  131. }
  132. // Negotiate MTTS/TTYPE (TERMINAL TYPE) support
  133. func (me *Client) SetupTType() telnet.Event {
  134. me.info.terminals = nil
  135. ok, tev := me.SetupNegotiate(1000, t.TELNET_DO, t.TELNET_TELOPT_TTYPE, t.TELNET_WILL_EVENT, t.TELNET_WONT_EVENT)
  136. if !ok {
  137. return tev
  138. }
  139. var last string = "none"
  140. var now string = ""
  141. for last != now {
  142. last = now
  143. me.telnet.TelnetTTypeSend()
  144. var tev2 telnet.Event = nil
  145. // Some clients (like KildClient, but not TinTin or telnet),
  146. // insist on spamming useless NUL characters
  147. // here... So we have to retry a few times to get a ttype_is
  148. // throwing away any undesirable junk in between.
  149. GET_TTYPE:
  150. for index := 0; index < 3; index++ {
  151. tev2, _, _ = me.TryReadEvent(1000)
  152. if tev2 != nil {
  153. etyp := telnet.EventTypeOf(tev2)
  154. monolog.Info("Waiting for TTYPE: %T %v %d", tev2, tev2, etyp)
  155. if telnet.IsEventType(tev2, t.TELNET_TTYPE_EVENT) {
  156. monolog.Info("TTYPE received: %T %v %d", tev2, tev2, etyp)
  157. break GET_TTYPE
  158. }
  159. } else { // and some clients don't respond, even
  160. monolog.Info("Waiting for TTYPE: %T", tev2)
  161. }
  162. }
  163. if tev2 == nil || !telnet.IsEventType(tev2, t.TELNET_TTYPE_EVENT) {
  164. etyp := telnet.EventTypeOf(tev2)
  165. monolog.Warning("Received no TTYPE: %T %v %d", tev2, tev2, etyp)
  166. return tev2
  167. }
  168. ttypeevent := tev2.(*telnet.TTypeEvent)
  169. now = ttypeevent.Name
  170. if !me.HasTerminal(now) {
  171. me.info.terminals = append(me.info.terminals, now)
  172. }
  173. me.info.terminal = now
  174. }
  175. monolog.Info("Client %d supports terminals %v", me.id, me.info.terminals)
  176. monolog.Info("Client %d active terminal %v", me.id, me.info.terminal)
  177. // MTTS support
  178. for i := range me.info.terminals {
  179. term := me.info.terminals[i]
  180. monolog.Info("Checking MTTS support: %s", term)
  181. if strings.HasPrefix(term, "MTTS ") {
  182. // it's an mtts terminal
  183. strnum := strings.TrimPrefix(term, "MTTS ")
  184. num, err := strconv.Atoi(strnum)
  185. if err == nil {
  186. me.info.mtts = num
  187. monolog.Info("Client %d supports mtts %d", me.id, me.info.mtts)
  188. } else {
  189. monolog.Warning("Client %d could not parse mtts %s %v", me.id, strnum, err)
  190. }
  191. }
  192. }
  193. me.info.ttype = true
  194. return nil
  195. }
  196. /*
  197. Although most clients don't do this, some clients, like tinyfuge actively initiate telnet setup.
  198. Deal with that first, then do our own setup. It seems like tinyfuge is "waiting" for something
  199. before performing the setup, which messes up TryReadEvent...
  200. */
  201. func (me *Client) ReadTelnetSetup() {
  202. /* First send a NOP to prod the client into activity. This shouldn't be neccesary,
  203. but some clients, in particular Tinyfugue waits for server activity before it sends it's own
  204. telnet setup messages. If the NOP is not sent, those setup messages will then end up messing up the
  205. telnet setup the WOE server is trying to do. Arguably this should perhaps be an AYT, but a NOP will
  206. hopefully do the least damage.
  207. */
  208. msg := []byte{telnet.TELNET_IAC, telnet.TELNET_NOP}
  209. me.telnet.SendRaw(msg)
  210. for {
  211. // wait for incoming events.
  212. event, _, _ := me.TryReadEvent(500)
  213. if event == nil {
  214. monolog.Info("Client %d no telnet setup received", me.id)
  215. return
  216. }
  217. monolog.Info("Client %d telnet setup received: %v", me.id, event)
  218. switch event := event.(type) {
  219. case *telnet.DataEvent:
  220. monolog.Info("Unexpected DATA event %T : %d.", event, len(event.Data))
  221. // should do something with the data, maybe?
  222. return
  223. case *telnet.NAWSEvent:
  224. monolog.Info("Received Telnet NAWS event %T.", event)
  225. me.HandleNAWSEvent(event)
  226. case *telnet.WillEvent:
  227. monolog.Info("Received Telnet WILL event %T.", event)
  228. // XXX do something with it!
  229. default:
  230. monolog.Info("Unexpected event in setup phase %T : %v. Ignored for now.", event, event)
  231. }
  232. }
  233. }
  234. func (me *Client) SetupTelnet() {
  235. me.ReadTelnetSetup()
  236. me.SetupSupressGA()
  237. // me.SetupBinary()
  238. me.SetupMSSP()
  239. // me.SetupCompress2
  240. me.SetupNAWS()
  241. me.SetupTType()
  242. me.SetupMXP()
  243. me.SetupMSP()
  244. me.SetupMSDP()
  245. // me.ColorTest()
  246. }