home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / var / lib / python-support / python2.6 / glchess / ggz / client.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  25.9 KB  |  735 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. import os
  5. import protocol
  6. import xml.sax.saxutils as xml
  7. import gettext
  8. _ = gettext.gettext
  9.  
  10. class Channel:
  11.     '''
  12.     '''
  13.     
  14.     def logXML(self, text):
  15.         pass
  16.  
  17.     
  18.     def logBinary(self, data):
  19.         pass
  20.  
  21.     
  22.     def connect(self, host, port):
  23.         pass
  24.  
  25.     
  26.     def send(self, data, isBinary = False):
  27.         pass
  28.  
  29.     
  30.     def close(self):
  31.         pass
  32.  
  33.  
  34.  
  35. class ChannelFeedback:
  36.     '''
  37.     '''
  38.     
  39.     def registerIncomingData(self, data):
  40.         pass
  41.  
  42.     
  43.     def onSessionEnded(self):
  44.         pass
  45.  
  46.     
  47.     def closed(self, errno = 0):
  48.         pass
  49.  
  50.  
  51.  
  52. class ClientFeedback:
  53.     
  54.     def setBusy(self, isBusy):
  55.         '''Called when the client is busy (unable to take requests)'''
  56.         pass
  57.  
  58.     
  59.     def onConnected(self):
  60.         pass
  61.  
  62.     
  63.     def onDisconnected(self, reason):
  64.         pass
  65.  
  66.     
  67.     def openChannel(self, feedback):
  68.         """Open a channel to the GGZ server.
  69.         
  70.         'feedback' is the object to notify data received on this channel.
  71.         """
  72.         pass
  73.  
  74.     
  75.     def getLogin(self):
  76.         '''Called when the login credentials are required.
  77.         
  78.         Returns the username and password to log in with.
  79.         If the password is None then log in as guest.
  80.         '''
  81.         return ('test', None)
  82.  
  83.     
  84.     def getPassword(self, username):
  85.         """Called when a password is required.
  86.         
  87.         'username' is the username the password is required for.
  88.         """
  89.         pass
  90.  
  91.     
  92.     def onMOTD(self, motd):
  93.         """Called when the message of the day is received.
  94.         
  95.         'motd' is the message received.
  96.         """
  97.         pass
  98.  
  99.     
  100.     def roomAdded(self, room):
  101.         """Called when a room is added.
  102.         
  103.         'room' the new room.
  104.         """
  105.         pass
  106.  
  107.     
  108.     def roomUpdated(self, room):
  109.         pass
  110.  
  111.     
  112.     def roomJoined(self, room):
  113.         pass
  114.  
  115.     
  116.     def tableAdded(self, table):
  117.         pass
  118.  
  119.     
  120.     def tableUpdated(self, table):
  121.         pass
  122.  
  123.     
  124.     def tableRemoved(self, table):
  125.         pass
  126.  
  127.     
  128.     def playerAdded(self, player):
  129.         pass
  130.  
  131.     
  132.     def playerRemoved(self, player):
  133.         pass
  134.  
  135.     
  136.     def onChat(self, chatType, sender, text):
  137.         pass
  138.  
  139.  
  140.  
  141. class Game:
  142.     id = ''
  143.     name = ''
  144.     version = ''
  145.     protocol_engine = ''
  146.     protocol_version = ''
  147.     nPlayers = 0
  148.     author = ''
  149.     url = ''
  150.  
  151.  
  152. class Room:
  153.     id = ''
  154.     game = None
  155.     nPlayers = 0
  156.  
  157.  
  158. class Table:
  159.     id = ''
  160.     room = ''
  161.     game = None
  162.     status = ''
  163.     description = ''
  164.     
  165.     def __init__(self, nSeats):
  166.         self.seats = []
  167.         for i in xrange(nSeats):
  168.             seat = Seat()
  169.             self.seats.append(seat)
  170.         
  171.  
  172.  
  173.  
  174. class Seat:
  175.     type = ''
  176.     user = ''
  177.  
  178.  
  179. class Player:
  180.     name = ''
  181.     type = ''
  182.     table = None
  183.     perms = 0
  184.     lag = 0
  185.     room = None
  186.     lastRoom = None
  187.  
  188.  
  189. class MainChannel(ChannelFeedback, protocol.ParserFeedback):
  190.     
  191.     def __init__(self, client):
  192.         self.client = client
  193.         self.decoder = protocol.Decoder(self)
  194.  
  195.     
  196.     def registerIncomingData(self, data):
  197.         self.controller.logXML(data)
  198.         while len(data) > 0:
  199.             data = self.decoder.feed(data)
  200.  
  201.     
  202.     def send(self, data, isBinary = False):
  203.         self.controller.send(data, isBinary)
  204.  
  205.     
  206.     def onConnected(self):
  207.         if not self.client.state is self.client.STATE_DISCONNECTED:
  208.             raise AssertionError
  209.         self.client.feedback.onConnected()
  210.         self.client.setState(self.client.STATE_START_SESSION)
  211.         
  212.         try:
  213.             language = os.environ['LANG']
  214.         except KeyError:
  215.             self.client.state is self.client.STATE_DISCONNECTED
  216.             self.client.state is self.client.STATE_DISCONNECTED
  217.             language = 'C'
  218.         except:
  219.             self.client.state is self.client.STATE_DISCONNECTED
  220.  
  221.         self.send("<?xml version='1.0' encoding='UTF-8'?>\n")
  222.         self.send('<SESSION>\n')
  223.         self.send('<LANGUAGE>%s</LANGUAGE>\n' % xml.sax.saxutils.escape(language))
  224.         (self.client.username, self.client.password) = self.client.feedback.getLogin()
  225.         if self.client.password is None:
  226.             self.client._loginGuest(self.client.username)
  227.         else:
  228.             self.client._login(self.client.username, self.client.password)
  229.  
  230.     
  231.     def onResult(self, action, code):
  232.         if action == 'login':
  233.             if code == 'ok':
  234.                 self.client.setState(self.client.STATE_LIST_GAMES)
  235.             elif code == 'usr lookup':
  236.                 self.client.close(_('Incorrect password'))
  237.             elif code == 'already logged in':
  238.                 self.client.close(_('Account in use'))
  239.             elif code == 'wrong login type':
  240.                 self.client.setState(self.client.STATE_GET_PASSWORD)
  241.             else:
  242.                 self.client.close(code)
  243.         elif action == 'enter':
  244.             if code != 'ok':
  245.                 print 'Failed to enter room'
  246.                 self.client.setState(self.client.STATE_READY)
  247.                 return None
  248.             room = self.client.enteringRoom
  249.             self.client.room = room
  250.             self.client.players = { }
  251.             self.client.tables = { }
  252.             room.nPlayers = 0
  253.             self.client.setState(self.client.STATE_LIST_TABLES)
  254.         elif action == 'list':
  255.             if self.client.state is self.client.STATE_LIST_GAMES:
  256.                 self.client.setState(self.client.STATE_LIST_ROOMS)
  257.             elif self.client.state is self.client.STATE_LIST_ROOMS:
  258.                 for room in self.client.rooms.itervalues():
  259.                     if room.game is None:
  260.                         break
  261.                         continue
  262.                 
  263.                 self.client.setState(self.client.STATE_ENTERING_ROOM)
  264.                 self.client.enteringRoom = room
  265.                 self.send("<ENTER ROOM='%s'/>\n" % room.id)
  266.             elif self.client.state is self.client.STATE_LIST_TABLES:
  267.                 self.client.setState(self.client.STATE_LIST_PLAYERS)
  268.             elif self.client.state is self.client.STATE_LIST_PLAYERS:
  269.                 self.client.setState(self.client.STATE_READY)
  270.                 self.client.feedback.roomEntered(self.client.enteringRoom)
  271.             
  272.         elif action == 'chat':
  273.             pass
  274.         elif action == 'launch':
  275.             self.client.setState(self.client.STATE_READY)
  276.         elif action == 'join':
  277.             if code == 'ok':
  278.                 self.client.setState(self.client.STATE_AT_TABLE)
  279.             elif code == 'table full':
  280.                 print 'Failed to join table: table full'
  281.                 self.client.setState(self.client.STATE_READY)
  282.             else:
  283.                 print 'Unknown join result: %s' % action
  284.         elif action == 'leave':
  285.             if code == 'ok':
  286.                 self.client.setState(self.client.STATE_READY)
  287.             else:
  288.                 print 'Unknown leave result: %s' % action
  289.         else:
  290.             print 'Unknown result: %s %s' % (action, code)
  291.  
  292.     
  293.     def onMOTD(self, motd):
  294.         self.client.feedback.onMOTD(motd)
  295.  
  296.     
  297.     def onChat(self, chatType, sender, text):
  298.         self.client.feedback.onChat(chatType, sender, text)
  299.  
  300.     
  301.     def onJoin(self, tableId, isSpectator):
  302.         
  303.         try:
  304.             table = self._getTable(tableId)
  305.         except KeyError:
  306.             print "Unknown JOIN with TABLE='%s'" % tableId
  307.             return None
  308.  
  309.         self.client.setState(self.client.STATE_AT_TABLE)
  310.         g = self.client.feedback.onJoin(table, isSpectator, self.client.channel)
  311.         self.client.channel.setGame(g)
  312.  
  313.     
  314.     def onLeave(self, reason):
  315.         self.client.feedback.onLeave(reason)
  316.  
  317.     
  318.     def gameAdded(self, gameId, name, version, author, url, numPlayers, protocol_engine, protocol_version):
  319.         game = Game()
  320.         game.id = gameId
  321.         game.name = name
  322.         game.version = version
  323.         game.author = author
  324.         game.url = url
  325.         game.numPlayers = numPlayers
  326.         game.protocol_engine = protocol_engine
  327.         game.protocol_version = protocol_version
  328.         self.client.games[gameId] = game
  329.  
  330.     
  331.     def roomAdded(self, roomId, gameId, name, description, nPlayers):
  332.         
  333.         try:
  334.             game = self._getGame(gameId, optional = True)
  335.         except KeyError:
  336.             print "Unknown ROOM ADD with GAME='%s'" % gameId
  337.             return None
  338.  
  339.         room = Room()
  340.         room.id = roomId
  341.         room.game = game
  342.         room.name = name
  343.         room.description = description
  344.         room.nPlayers = int(nPlayers)
  345.         self.client.rooms[roomId] = room
  346.         self.client.feedback.roomAdded(room)
  347.  
  348.     
  349.     def roomPlayersUpdate(self, roomId, nPlayers):
  350.         
  351.         try:
  352.             room = self._getRoom(roomId)
  353.         except KeyError:
  354.             print "Unknown ROOM PLAYER UPDATE with ROOM='%s'" % roomId
  355.             return None
  356.  
  357.         room.nPlayers = int(nPlayers)
  358.         self.client.feedback.roomUpdated(room)
  359.  
  360.     
  361.     def tableAdded(self, roomId, tableId, gameId, status, nSeats, description):
  362.         
  363.         try:
  364.             room = self._getRoom(roomId)
  365.             game = self._getGame(gameId)
  366.         except KeyError:
  367.             print "Unknown TABLE ADD with ROOM='%s' GAME='%s'" % (roomId, gameId)
  368.             return None
  369.  
  370.         table = Table(int(nSeats))
  371.         table.id = tableId
  372.         table.room = room
  373.         table.game = game
  374.         table.status = status
  375.         table.description = description
  376.         self.client.tables[tableId] = table
  377.         self.client.feedback.tableAdded(table)
  378.  
  379.     
  380.     def tableStatusChanged(self, tableId, status):
  381.         
  382.         try:
  383.             table = self._getTable(tableId)
  384.         except KeyError:
  385.             print "Unknown TABLE STATUS with TABLE='%s'" % tableId
  386.             return None
  387.  
  388.         table.status = status
  389.         self.client.feedback.tableUpdated(table)
  390.  
  391.     
  392.     def seatChanged(self, roomId, tableId, seatId, seatType, user):
  393.         
  394.         try:
  395.             table = self._getTable(tableId)
  396.         except KeyError:
  397.             print "Unknown SEAT CHANGE with TABLE='%s'" % tableId
  398.             return None
  399.  
  400.         if table.room.id != roomId:
  401.             return None
  402.         seat = table.seats[int(seatId)]
  403.         seat.type = seatType
  404.         seat.user = user
  405.         self.client.feedback.tableUpdated(table)
  406.  
  407.     
  408.     def tableRemoved(self, tableId):
  409.         
  410.         try:
  411.             table = self.client.tables.pop(tableId)
  412.         except KeyError:
  413.             print "Unknown TABLE REMOVE with TABLE='%s'" % tableId
  414.             return None
  415.  
  416.         self.client.feedback.tableRemoved(table)
  417.  
  418.     
  419.     def onPlayerList(self, roomId, players):
  420.         
  421.         try:
  422.             room = self._getRoom(roomId)
  423.             for p in players:
  424.                 _ = self._getTable(p.tableId, optional = True)
  425.         except KeyError:
  426.             print "Unknown PLAYER LIST with ROOM='%s'" % roomId
  427.             return None
  428.  
  429.         self.client.players = { }
  430.         for p in players:
  431.             player = Player()
  432.             player.name = p.name
  433.             player.type = p.type
  434.             player.table = self._getTable(p.tableId, optional = True)
  435.             player.perms = p.perms
  436.             player.lag = p.lag
  437.             player.room = room
  438.             self.client.players[player.name] = player
  439.         
  440.         room.nPlayers = len(players)
  441.         self.client.feedback.roomUpdated(room)
  442.  
  443.     
  444.     def playerAdded(self, name, playerType, tableId, perms, lag, roomId, fromRoomId):
  445.         
  446.         try:
  447.             room = self._getRoom(roomId, optional = True)
  448.             lastRoom = self.client.rooms[fromRoomId]
  449.             table = self._getTable(tableId, optional = True)
  450.         except KeyError:
  451.             print "Unknown PLAYER ADD with ROOM='%s' LASTROOM='%s' TABLE='%s'" % (roomId, fromRoomId, tableId)
  452.             return None
  453.  
  454.         player = Player()
  455.         player.name = name
  456.         player.type = playerType
  457.         player.table = table
  458.         player.perms = perms
  459.         player.lag = lag
  460.         player.room = room
  461.         player.lastRoom = lastRoom
  462.         self.client.players[player.name] = player
  463.         if player.lastRoom is not None:
  464.             player.lastRoom.nPlayers -= 1
  465.             self.client.feedback.roomUpdated(player.lastRoom)
  466.         
  467.         if player.room is not None:
  468.             player.room.nPlayers += 1
  469.             self.client.feedback.roomUpdated(player.room)
  470.         
  471.         self.client.feedback.playerAdded(player)
  472.  
  473.     
  474.     def playerRemoved(self, name, roomId, toRoomId):
  475.         
  476.         try:
  477.             player = self.client.players.pop(name)
  478.             room = self._getRoom(toRoomId, optional = True)
  479.         except KeyError:
  480.             print "Unknown PLAYER REMOVE with NAME='%s' ROOM='%s' TOROOM='%s'" % (name, roomId, toRoomId)
  481.             return None
  482.  
  483.         player.lastRoom = player.room
  484.         player.room = room
  485.         if player.room is not None:
  486.             player.room.nPlayers += 1
  487.             self.client.feedback.roomUpdated(player.room)
  488.         
  489.         if player.lastRoom is not None:
  490.             player.lastRoom.nPlayers -= 1
  491.             self.client.feedback.roomUpdated(player.lastRoom)
  492.         
  493.         self.client.feedback.playerRemoved(player)
  494.  
  495.     
  496.     def closed(self, errno = 0):
  497.         self.client.close(_('Connection closed: %s') % os.strerror(errno))
  498.  
  499.     
  500.     def _getGame(self, gameId, optional = False):
  501.         if optional and gameId == '-1':
  502.             return None
  503.         return self.client.games[gameId]
  504.  
  505.     
  506.     def _getRoom(self, roomId, optional = False):
  507.         if optional and roomId == '-1':
  508.             return None
  509.         return self.client.rooms[roomId]
  510.  
  511.     
  512.     def _getTable(self, tableId, optional = False):
  513.         if optional and tableId == '-1':
  514.             return None
  515.         return self.client.tables[tableId]
  516.  
  517.  
  518.  
  519. class GameChannel(ChannelFeedback, protocol.ParserFeedback):
  520.     
  521.     def __init__(self, client, command):
  522.         self.client = client
  523.         self.command = command
  524.         self.inSession = True
  525.         self.decoder = protocol.Decoder(self)
  526.         self.buffer = ''
  527.         self.game = None
  528.  
  529.     
  530.     def setGame(self, game):
  531.         self.game = game
  532.         if len(self.buffer) > 0:
  533.             self.game.registerIncomingData(self.buffer)
  534.         
  535.         self.buffer = ''
  536.  
  537.     
  538.     def registerIncomingData(self, data):
  539.         while self.inSession and len(data) > 0:
  540.             remainder = self.decoder.feed(data)
  541.             self.controller.logXML(data[:len(data) - len(remainder)])
  542.             data = remainder
  543.         if len(data) == 0:
  544.             return None
  545.         self.controller.logBinary(data)
  546.  
  547.     
  548.     def onDisconnected(self, reason):
  549.         print 'Disconnected: %s' % reason
  550.  
  551.     
  552.     def send(self, data, isBinary = False):
  553.         self.controller.send(data, isBinary)
  554.  
  555.     
  556.     def onConnected(self):
  557.         self.send("<?xml version='1.0' encoding='UTF-8'?>\n")
  558.         self.send('<SESSION>\n')
  559.         self.send('<LANGUAGE>en_NZ.UTF-8</LANGUAGE>\n')
  560.         self.send("<CHANNEL ID='%s' /></SESSION>\n" % self.client.username)
  561.  
  562.     
  563.     def onSessionEnded(self):
  564.         self.inSession = False
  565.         self.client.mainChannel.send(self.command)
  566.  
  567.     
  568.     def closed(self, errno = 0):
  569.         print 'SEVERE: GGZ channel closed'
  570.  
  571.  
  572.  
  573. class Client:
  574.     STATE_DISCONNECTED = 'DISCONNECTED'
  575.     STATE_START_SESSION = 'START_SESSION'
  576.     STATE_LOGIN = 'LOGIN'
  577.     STATE_GET_PASSWORD = 'GET_PASSWORD'
  578.     STATE_LIST_GAMES = 'LIST_GAMES'
  579.     STATE_LIST_ROOMS = 'LIST_ROOMS'
  580.     STATE_READY = 'READY'
  581.     STATE_JOIN_TABLE_CHANNEL = 'JOIN_TABLE_CHANNEL'
  582.     STATE_JOIN_TABLE = 'JOIN_TABLE'
  583.     STATE_START_TABLE_CHANNEL = 'START_TABLE_CHANNEL'
  584.     STATE_START_TABLE = 'START_TABLE'
  585.     STATE_AT_TABLE = 'AT_TABLE'
  586.     STATE_LEAVE_TABLE = 'LEAVE_TABLE'
  587.     STATE_ENTERING_ROOM = 'ENTERING_ROOM'
  588.     STATE_LIST_TABLES = 'LIST_TABLES'
  589.     STATE_LIST_PLAYERS = 'LIST_PLAYERS'
  590.     
  591.     def __init__(self, feedback):
  592.         self.feedback = feedback
  593.         self.commands = []
  594.         self.sending = False
  595.         self.games = { }
  596.         self.rooms = { }
  597.         self.tables = { }
  598.         self.players = { }
  599.         self.room = None
  600.         self.state = self.STATE_DISCONNECTED
  601.  
  602.     
  603.     def isReady(self):
  604.         '''Check if ready for new requests.
  605.         
  606.         Returns True if can make a new request.
  607.         '''
  608.         return self.state is self.STATE_READY
  609.  
  610.     
  611.     def close(self, error):
  612.         self.disconnectionError = error
  613.         self.setState(self.STATE_DISCONNECTED)
  614.  
  615.     
  616.     def isBusy(self):
  617.         if not self.state is self.STATE_READY and self.state is self.STATE_AT_TABLE:
  618.             pass
  619.         return not (self.state is self.STATE_DISCONNECTED)
  620.  
  621.     
  622.     def setState(self, state):
  623.         print 'Changing state from %s to %s' % (self.state, state)
  624.         self.state = state
  625.         self.feedback.setBusy(self.isBusy())
  626.         if state is self.STATE_LIST_GAMES:
  627.             self.mainChannel.send("<LIST TYPE='game' FULL='true'/>\n")
  628.         elif state is self.STATE_LIST_ROOMS:
  629.             self.mainChannel.send("<LIST TYPE='room' FULL='true'/>\n")
  630.         elif state is self.STATE_LIST_TABLES:
  631.             self.mainChannel.send("<LIST TYPE='table'/>\n")
  632.         elif state is self.STATE_LIST_PLAYERS:
  633.             self.mainChannel.send("<LIST TYPE='player'/>\n")
  634.         elif state is self.STATE_GET_PASSWORD:
  635.             self.feedback.getPassword(self.username)
  636.         elif state is self.STATE_DISCONNECTED:
  637.             self.feedback.onDisconnected(self.disconnectionError)
  638.             self.mainChannel.controller.close()
  639.         
  640.  
  641.     
  642.     def start(self):
  643.         if not self.state is self.STATE_DISCONNECTED:
  644.             raise AssertionError
  645.         self.mainChannel = MainChannel(self)
  646.         self.mainChannel.controller = self.feedback.openChannel(self.mainChannel)
  647.  
  648.     
  649.     def setPassword(self, password):
  650.         if not self.state is self.STATE_GET_PASSWORD:
  651.             raise AssertionError
  652.         if password is None:
  653.             self.close(_('A password is required'))
  654.         else:
  655.             self._login(self.username, password)
  656.  
  657.     
  658.     def _login(self, username, password):
  659.         if not self.state is self.STATE_START_SESSION and self.state is self.STATE_GET_PASSWORD:
  660.             raise AssertionError
  661.         self.setState(self.STATE_LOGIN)
  662.         username = xml.sax.saxutils.escape(username)
  663.         password = xml.sax.saxutils.escape(password)
  664.         self.mainChannel.send("<LOGIN TYPE='normal'><NAME>%s</NAME><PASSWORD>%s</PASSWORD></LOGIN>\n" % (username, password))
  665.  
  666.     
  667.     def _loginGuest(self, username):
  668.         if not self.state is self.STATE_START_SESSION:
  669.             raise AssertionError
  670.         self.setState(self.STATE_LOGIN)
  671.         username = xml.sax.saxutils.escape(username)
  672.         self.mainChannel.send("<LOGIN TYPE='guest'><NAME>%s</NAME></LOGIN>\n" % username)
  673.  
  674.     
  675.     def _loginNew(self, username, password, email):
  676.         if not self.state is self.STATE_START_SESSION:
  677.             raise AssertionError
  678.         self.setState(self.STATE_LOGIN)
  679.         username = xml.sax.saxutils.escape(username)
  680.         password = xml.sax.saxutils.escape(password)
  681.         email = xml.sax.saxutils.escape(email)
  682.         self.mainChannel.send("<LOGIN TYPE='first'><NAME>%s</NAME><PASSWORD>%s</PASSWORD><EMAIL>%s</EMAIL></LOGIN>\n" % (username, password, email))
  683.  
  684.     
  685.     def enterRoom(self, room):
  686.         if self.state is self.STATE_AT_TABLE:
  687.             print 'At table'
  688.             return None
  689.         if not self.state is self.STATE_READY:
  690.             raise AssertionError
  691.         self.setState(self.STATE_ENTERING_ROOM)
  692.         self.enteringRoom = room
  693.         self.mainChannel.send("<ENTER ROOM='%s'/>\n" % room.id)
  694.  
  695.     
  696.     def startTable(self, gameId, description, player):
  697.         if self.state is not self.STATE_READY:
  698.             print 'Unable to start table'
  699.             return None
  700.         self.setState(self.STATE_START_TABLE)
  701.         command = '<LAUNCH>\n'
  702.         command += "<TABLE GAME='%s' SEATS='2'>\n" % gameId
  703.         command += '<DESC>%s</DESC>\n' % xml.sax.saxutils.escape(description)
  704.         command += "<SEAT NUM='0' TYPE='reserved'>%s</SEAT>\n" % player
  705.         command += "<SEAT NUM='1' TYPE='open'/>\n"
  706.         command += '</TABLE>\n'
  707.         command += '</LAUNCH>\n'
  708.         self.channel = GameChannel(self, command)
  709.         self.channel.controller = self.feedback.openChannel(self.channel)
  710.  
  711.     
  712.     def joinTable(self, table):
  713.         if self.state is self.STATE_AT_TABLE:
  714.             print 'Already at table'
  715.             return None
  716.         if not self.state is self.STATE_READY:
  717.             raise AssertionError
  718.         self.setState(self.STATE_JOIN_TABLE)
  719.         command = "<JOIN TABLE='%s' SPECTATOR='false'/>\n" % table.id
  720.         self.channel = GameChannel(self, command)
  721.         self.channel.controller = self.feedback.openChannel(self.channel)
  722.  
  723.     
  724.     def leaveTable(self):
  725.         if not self.state is self.STATE_AT_TABLE:
  726.             raise AssertionError
  727.         self.setState(self.STATE_LEAVE_TABLE)
  728.         self.mainChannel.send("<LEAVE FORCE='true'/>\n")
  729.  
  730.     
  731.     def sendChat(self, text):
  732.         self.mainChannel.send("<CHAT TYPE='normal'>%s</CHAT>\n" % xml.sax.saxutils.escape(text))
  733.  
  734.  
  735.