home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / python-support / gnome-games-data / glchess / chess / fics / client.py < prev    next >
Encoding:
Python Source  |  2009-04-14  |  16.4 KB  |  492 lines

  1. # -*- coding: utf-8 -*-
  2. import re
  3. import socket
  4. import select
  5.  
  6. import style12
  7. import telnet
  8.  
  9. PROMPT          = 'fics% '
  10. PROMPT_LOGIN    = 'login: '
  11.  
  12. class Player:
  13.     pass
  14.  
  15. class Game:
  16.     pass
  17.  
  18. class Encoder:
  19.     """
  20.     """
  21.  
  22. class TelnetDecoder(telnet.Decoder):
  23.     def __init__(self, decoder):
  24.         self.decoder = decoder
  25.         telnet.Decoder.__init__(self)
  26.  
  27.     def onData(self, data):
  28.         self.decoder._processData(data)
  29.         
  30.     def onEndSubnegotiation(self):
  31.         print 'onEndSubnegotiation()'
  32.         
  33.     def onNoOp(self):
  34.         print 'onNoOp()'
  35.     
  36.     def onDataMark(self):
  37.         print 'onDataMark()'
  38.         
  39.     def onBreak(self):
  40.         print 'onBreak()'
  41.         
  42.     def onInterruptProcess(self):
  43.         print 'onInterruptProcess()'
  44.         
  45.     def onAbortOutput(self):
  46.         print 'onAbortOutput()'
  47.         
  48.     def onAreYouThere(self):
  49.         print 'onAreYouThere()'
  50.         
  51.     def onEraseCharacter(self):
  52.         print 'onEraseCharacter()'
  53.         
  54.     def onEraseLine(self):
  55.         print 'onEraseLine()'
  56.         
  57.     def onGoAhead(self):
  58.         print 'onGoAhead()'
  59.         
  60.     def onStartSubnegotiation(self):
  61.         print 'onStartSubnegotiation()'
  62.     
  63.     def onWill(self, option):
  64.         print 'onWill(%i)' % option
  65.     
  66.     def onWont(self, option):
  67.         print 'onWont(%i)' % option
  68.     
  69.     def onDo(self, option):
  70.         print 'onDo(%i)' % option
  71.         
  72.     def onDont(self, option):
  73.         print 'onDont(%i)' % option
  74.     
  75.     def onUnknownCommand(self, command):
  76.         print 'onUnknownCommand(%i)' % command
  77.     
  78. class Decoder:
  79.     """
  80.     """
  81.     
  82.     buffer = ''
  83.     
  84.     longChat = None
  85.     
  86.     def __init__(self):
  87.         """
  88.         """
  89.         self.telnetDecoder = TelnetDecoder(self)
  90.         
  91.         # Yuck, regular expression is just horrible. I plan to replace this with something readable
  92.         # (that compiles to regexp if regexp is faster)
  93.         
  94.         #Press return to enter the server as "GuestVRDG":
  95.         self.nameAssignPattern = re.compile('Press return to enter the server as "(\S+)":')
  96.                 
  97.         #jibbjibb(U)(53): i like cheese
  98.         self.chatPattern = re.compile('^(\S+)[(](\d+)[)]: (.*)$')
  99.         #GuestTLNX(U) tells you: hello!
  100.         self.tellPattern = re.compile('^(\S+)[(](\S+)[)] tells you: (.*)$')
  101.         #'GuestTLNX(U)[26] says: hello'
  102.         self.sayPattern = re.compile('^(\S+)[(](\S+)[)][[](\d+)[]] says: (.*)$')
  103.  
  104.         #Challenge: GuestKWWN (----) GuestDRJK (----) unrated blitz 2 12.
  105.         self.challengePattern = re.compile('Challenge: (\S+) [(](\S{4})[)] \S+ [(]\S{4}[)] (\w+) (\w+) (\d+) (\d+)[.]$')
  106.         
  107.         # 19  716 milkhope            5  14 unrated blitz                  0-9999 mf
  108.         # 41 1812 CrazyBeukiBot(C)    2  12 unrated blitz                  0-9999 
  109.         # 50 1190 rauschdesign       10   0 unrated blitz      [white]     0-9999 f
  110.         # 70 1157 stshot             12   1 unrated blitz                  0-1300
  111.         self.seekPattern = re.compile('^\s*(\d+)\s+(\S{4}) (\S+)\s+(\d+)\s+(\d+) (\S+) (\S+)\s+(\S*)\s+(\d+)-\s*(\d+)\s*(\S*)$')
  112.         
  113.         #1 ad displayed.
  114.         #9 ads displayed.
  115.         self.endSeekPattern = re.compile('^(\d+) ads? displayed.$')
  116.         
  117.         #GuestJXJT (++++) seeking 0 1 unrated lightning ("play 15" to respond)
  118.         self.announcePattern = re.compile('^(\S+) [(](\S{4})[)] seeking (\d+) (\d+) (\w+) (\w+)(.*) [(]"play (\d+)" to respond[)]$')
  119.  
  120.         #{Game 109 (GuestKSBS vs. GuestXKQX) Creating unrated blitz match.}
  121.         #{Game 109 (GuestKSBS vs. GuestXKQX) GuestXKQX forfeits by disconnection} 1-0
  122.         #{Game 109 (GuestXKQX vs. GuestKSBS) GuestKSBS resigns} 1-0
  123.         self.gameResultPattern = re.compile('^{Game (\d+) [(](\S+) vs. (\S+)[)] (.+)}\s*(.*)$')
  124.  
  125.         # 1 (Exam.    0 Kupreichik     0 talpa     ) [ uu  0   0] W: 22
  126.         # 2 2274 OldManII    ++++ Peshkin    [ bu  2  12]   2:34 -  1:47 (39-39) B:  3
  127.         self.exampleGamePattern = re.compile('\s*(\d+) [(]Exam[.] (\S{4}) (\S+)\s+(\S{4}) (\S+)\s+ [)] [[]\s*(\S+)\s+(\d+)\s+(\d+)[]] ([WB]):\s+(\d+)$')
  128.         self.gamePattern = re.compile('\s*(\d+) (\S{4}) (\S+)\s+(\S{4}) (\S+)\s+[[]\s*(\S+)\s+(\d+)\s+(\d+)[]]\s+(\d+):(\d+) -\s+(\d+):(\d+) [(](\d+)-(\d+)[)] ([WB]):\s+(\d+)$')
  129.         
  130.         #GuestDRJK, whom you were challenging, has departed.
  131.         #Challenge to GuestDRJK withdrawn.
  132.         
  133.         self.patterns = [self.announcePattern, self.nameAssignPattern,
  134.                          self.chatPattern, self.tellPattern, self.sayPattern,
  135.                          self.challengePattern, self.gamePattern, self.exampleGamePattern, self.gameResultPattern,
  136.                          self.seekPattern, self.endSeekPattern]
  137.                          
  138.     def onUnknownLine(self, text):
  139.         """
  140.         """
  141.         pass
  142.  
  143.     def onLogin(self):
  144.         """
  145.         """
  146.         pass
  147.     
  148.     def onPrompt(self):
  149.         """
  150.         """
  151.         pass
  152.     
  153.     def onNameAssign(self, name):
  154.         """
  155.         """
  156.         pass
  157.     
  158.     def onSeekClear(self):
  159.         pass
  160.     def onSeekAdd(self, number, game, player):
  161.         pass
  162.     def onSeekRemove(self, numbers):
  163.         pass
  164.     
  165.     def onAnnounce(self, number, game, player):
  166.         """
  167.         """
  168.         pass
  169.  
  170.     def onEndSeek(self, nSeeks):
  171.         """
  172.         """
  173.         pass
  174.     
  175.     def onDynamicAnnounce(self, number, game, player):
  176.         """
  177.         """
  178.         pass
  179.     
  180.     def onChallenge(self, game, player):
  181.         """
  182.         """
  183.         pass
  184.     
  185.     def onGame(self, game, white, black):
  186.         """
  187.         """
  188.         pass
  189.     
  190.     def onGameResult(self, game, white, black, text):
  191.         """
  192.         """
  193.         pass
  194.                 
  195.     def onChat(self, channel, playerName, text):
  196.         """
  197.         """
  198.         pass
  199.  
  200.     def onMove(self, move):
  201.         """
  202.         """
  203.         pass
  204.     
  205.     def parseLine(self, line):
  206.         """
  207.         """
  208.         # Join continuing chat messages
  209.         if self.longChat != None:
  210.             # Remove leading space ('\   text')
  211.             while line.startswith('\\'):
  212.                 line = line[1:]
  213.             while line.startswith(' '):
  214.                 line = line[1:]
  215.             self.longChat += line
  216.             
  217.             # Continues on the next line too
  218.             if line[-1] == ' ':
  219.                 return (None, None)
  220.             
  221.             text = self.longChat
  222.             self.longChat = None
  223.             return (self.onChat, (self.longChatOptions[0], self.longChatOptions[1], text))
  224.         
  225.         # Look for lines
  226.         for pattern in self.patterns:
  227.             result = pattern.findall(line)
  228.             if len(result) != 0:
  229.                 # Game in progress
  230.                 if pattern is self.gamePattern:
  231.                     white = Player()
  232.                     black = Player()
  233.                     game = Game()
  234.                     (game.number, white.rating, white.name, black.rating, black.name,
  235.                      game.options, game.a, game.b, whiteMin, whiteSec,
  236.                      blackMin, blackSec,
  237.                      white.strength, black.strength,
  238.                      game.colour, game.moveNumber) = result[0]
  239.                     game.isExample = False
  240.                     white.time = int(whiteMin) * 60 + int(whiteSec)
  241.                     black.time = int(blackMin) * 60 + int(blackSec)
  242.                     return (self.onGame, (game, white, black))
  243.                 
  244.                 elif pattern is self.exampleGamePattern:
  245.                     white = Player()
  246.                     black = Player()
  247.                     game = Game()
  248.                     (game.number, white.rating, white.name, black.rating, black.name,
  249.                      game.options, game.a, game.b,
  250.                      game.colour, game.moveNumber) = result[0]
  251.                     game.isExample = True
  252.                     return (self.onGame, (game, white, black))
  253.                 
  254.                 elif pattern is self.nameAssignPattern:
  255.                     name = result
  256.                     return (self.onNameAssign, (name, ))
  257.                 
  258.                 # Requested seek
  259.                 elif pattern is self.seekPattern:
  260.                     player = Player()
  261.                     game = Game()
  262.                     (number,
  263.                      player.rating, player.name,
  264.                      game.a, game.b, game.rating, game.type, game.colour, game.minRating, game.maxRating, game.options) = result[0]
  265.                     return (self.onAnnounce, (number, game, player))
  266.                 elif pattern is self.endSeekPattern:
  267.                     (nSeeks, ) = result
  268.                     return (self.onEndSeek, (int(nSeeks), ))
  269.                 # Dynamic seek
  270.                 if pattern is self.announcePattern:
  271.                     player = Player()
  272.                     game = Game()
  273.                     (player.name, player.rating, game.a, game.b, game.rating, game.type, game.options, number) = result[0]
  274.                     return (self.onDynamicAnnounce, (number, game, player))
  275.                 
  276.                 # Explicit challenge
  277.                 elif pattern is self.challengePattern:
  278.                     player = Player()
  279.                     game = Game()
  280.                     (player.name, player.rating, game.rating, game.type, game.a, game.b) = result[0]
  281.                     return (self.onChallenge, (game, player))
  282.                 
  283.                 # Game result
  284.                 elif pattern is self.gameResultPattern:
  285.                     white = Player()
  286.                     black = Player()
  287.                     game = Game()
  288.                     (game.number, white.name, black.name, text, game.result) = result[0]
  289.                     if game.result == '':
  290.                         game.result = '*'
  291.                     return (self.onGameResult, (game, white, black, text))
  292.                 
  293.                 elif pattern is self.chatPattern:
  294.                     (playerName, channel, text) = result[0]
  295.                     if text[-1] == ' ':
  296.                         self.longChat = text
  297.                         self.longChatOptions = (channel, playerName)
  298.                         return (None, None)
  299.                     else:
  300.                         return (self.onChat, (channel, playerName, text))
  301.                 
  302.                 elif pattern is self.tellPattern:
  303.                     (playerName, rating, text) = result[0]
  304.                     if text[-1] == ' ':
  305.                         self.longChat = text
  306.                         self.longChatOptions = ('', playerName)
  307.                         return (None, None)
  308.                     else:
  309.                         return (self.onChat, ('', playerName, text))
  310.  
  311.                 elif pattern is self.sayPattern:
  312.                     (playerName, rating, game, text) = result[0]
  313.                     if text[-1] == ' ':
  314.                         self.longChat = text
  315.                         self.longChatOptions = ('', playerName)
  316.                         return (None, None)
  317.                     else:
  318.                         return (self.onChat, ('', playerName, text))
  319.  
  320.         # Game move
  321.         if line.startswith('<12> '):
  322.             try:
  323.                 move = style12.decode(line)
  324.             except ValueError, e:
  325.                 print 'Invalid move: %s (%s)' % (line, str(e))
  326.             else:
  327.                 return (self.onMove, (move,))
  328.  
  329.         elif line.startswith('<s> '):
  330.             words = line.split()
  331.             player = Player()
  332.             game = Game()
  333.             try:
  334.                 number = int(words[1])
  335.             except (IndexError, ValueError):
  336.                 return (self.onUnknownLine, (line,))
  337.             
  338.             for word in words[2:]:
  339.                 try:
  340.                     (name, value) = word.split('=', 1)
  341.                 except ValueError:
  342.                     return (self.onUnknownLine, (line,))
  343.                 
  344.                 # FIXME: Accept errors
  345.                 if name == 'w':
  346.                     player.name = value
  347.                 elif name == 'ti':
  348.                     pass
  349.                 elif name == 'rt':
  350.                     while not value[-1].isdigit():
  351.                         value = value[:-1]
  352.                     player.rating = int(value)
  353.                 elif name == 't':
  354.                     game.time = int(value)
  355.                 elif name == 'i':
  356.                     game.inc = int(value)
  357.                 elif name == 'r':
  358.                     game.isRated = value != '0'
  359.                 elif name == 'tp':
  360.                     game.type = value
  361.                 elif name == 'c':
  362.                     game.colour = value
  363.                 elif name == 'rr':
  364.                     (minRating, maxRating) = value.split('-', 1)
  365.                     game.minRating = int(minRating)
  366.                     game.maxRating = int(maxRating)
  367.                 elif name == 'a':
  368.                     game.isAutomatic = value != '0'
  369.                 elif name == 'f':
  370.                     game.formulaCheked = value != '0'
  371.  
  372.             return (self.onSeekAdd, (number, game, player))
  373.             
  374.         elif line.startswith('<sr> '):
  375.             adverts = []
  376.             for word in line.split()[1:]:
  377.                 try:
  378.                     adverts.append(int(word))
  379.                 except ValueError:
  380.                     return (self.onUnknownLine, (line,))
  381.  
  382.             return (self.onSeekRemove, (adverts,))
  383.  
  384.         elif line.startswith('<sc>'):
  385.             return (self.onSeekClear, ())
  386.  
  387.         return (self.onUnknownLine, (line,))
  388.     
  389.     def parsePrompt(self, line):
  390.         """
  391.         """
  392.         if line == PROMPT_LOGIN:
  393.             return (self.onLogin, ())
  394.         elif line == PROMPT:
  395.             return (self.onPrompt, ())
  396.         return (None, None)
  397.     
  398.     def registerIncomingData(self, data):
  399.         """
  400.         """
  401.         self.telnetDecoder.registerIncomingData(data)
  402.         
  403.     def _processData(self, data):
  404.         """
  405.         """
  406.         self.buffer += data
  407.         
  408.         callbacks = []
  409.         while True:
  410.             index = self.buffer.find('\n\r')
  411.             if index < 0:
  412.                 break
  413.             
  414.             line = self.buffer[:index]
  415.             self.buffer = self.buffer[index+2:]
  416.             
  417.             # Strip pesky prompt off the front
  418.             if line.startswith(PROMPT):
  419.                 line = line[len(PROMPT):]
  420.                 callbacks.append((self.onPrompt, ()))
  421.                 if len(line) == 0:
  422.                     continue
  423.  
  424.             (callback, data) = self.parseLine(line)
  425.             if callback is not None:
  426.                 callbacks.append((callback, data))
  427.  
  428.         (callback, data) = self.parsePrompt(self.buffer)
  429.         if callback is not None:
  430.             callbacks.append((callback, data))
  431.             
  432.         for (callback, data) in callbacks:
  433.             callback(*data)
  434.  
  435. if __name__ == '__main__':
  436.     class P(Decoder):
  437.         
  438.         sentStyle = False
  439.     
  440.         def __init__(self):
  441.             Decoder.__init__(self)
  442.             self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  443.             self.s.connect(('freechess.org', 23))
  444.         
  445.         def send(self, data):
  446.             self.s.send(data)
  447.             
  448.         def onLogin(self):
  449.             self.send('guest\n')
  450.             
  451.         def onPrompt(self):
  452.             if not self.sentStyle:
  453.                 self.send('style 12\n')
  454.                 #self.send('set open 0\n') # Don't support being challenged yet
  455.                 self.send('games\n')
  456.                 self.send('sought\n')
  457.                 self.sentStyle = True
  458.                 
  459.         def onNameAssign(self, name):
  460.             print 'Assigned name: %s' % repr(name)
  461.             self.send('\n')
  462.             
  463.         def onAnnounce(self, number, game, player):
  464.             print 'ANNOUNCE: PLAYER=%s (%s)' % (player.name, number)
  465.             
  466.         def onDynamicAnnounce(self, number, game, player):
  467.             print 'ANNOUNCE*: PLAYER=%s (%s)' % (player.name, number)
  468.             
  469.         def onChallenge(self, game, player):
  470.             print 'CHALLENGE: PLAYER=' + player.name
  471.             self.send('accept\n')
  472.         
  473.         def onGame(self, game, white, black):
  474.             print 'GAME: #%s, %s vs %s' % (game.number, white.name, black.name)
  475.                 
  476.         def onGameResult(self, game, white, black, text):
  477.             print 'GAME_RESULT: #%s, %s (%s)' % (game.number, game.result, text)
  478.  
  479.         def onChat(self, channel, playerName, text):
  480.             print 'CHAT: channel=%s name=%s: %s' % (channel, playerName, text)
  481.         
  482.         def onMove(self, move):
  483.             print 'MOVE: ' + str(move)
  484.  
  485.         def run(self):
  486.             while True:
  487.                 (data, address) = self.s.recvfrom(65535)
  488.                 self.registerIncomingData(data)
  489.  
  490.     p = P()
  491.     p.run()
  492.