Ticket #1335: twisted-words-ctcp-quoting.2.diff

File twisted-words-ctcp-quoting.2.diff, 8.0 KB (added by nullie, 6 years ago)

New view on this.

  • D:/work/eclipse-workspace/twisted/twisted/words/test/test_irc.py

     
    2020    "xargs%(NUL)smight%(NUL)slike%(NUL)sthis" % {'NUL': irc.NUL }, 
    2121    "embedded%(CR)snewline%(CR)s%(NL)sFUN%(NL)s" % {'CR': irc.CR, 
    2222                                                    'NL': irc.NL}, 
    23     "escape!%(X)s escape!%(M)s %(X)s%(X)sa %(M)s0" % {'X': irc.X_QUOTE, 
    24                                                       'M': irc.M_QUOTE} 
     23    "escape!escape!%(M)s %(M)s0" % {'M': irc.M_QUOTE} 
    2524    ] 
    2625 
    2726 
     
    3130        for s in stringSubjects: 
    3231            self.failUnlessEqual(s, irc.lowDequote(irc.lowQuote(s))) 
    3332 
    34     def test_ctcpquoteSanity(self): 
    35         """Testing CTCP message level quote/dequote""" 
    36         for s in stringSubjects: 
    37             self.failUnlessEqual(s, irc.ctcpDequote(irc.ctcpQuote(s))) 
    3833 
    39  
    4034class IRCClientWithoutLogin(irc.IRCClient): 
    4135    performLogin = 0 
    4236 
     
    297291                             user="sender!ident@host", 
    298292                             channel="recipient", 
    299293                             message=msg) 
     294         
     295    def test_ACTION(self): 
     296        """Testing CTCP ACTION. 
     297         
     298        This imitates behavior of wide-spread IRC clients for ACTION CTCP 
     299        query. 
     300        """ 
     301         
     302        actionQuery = (r":nick!guy@over.there PRIVMSG #theChan :" 
     303                       "%(X)cACTION \o/%(X)c%(EOL)s" 
     304                       % {'X': irc.X_DELIM, 
     305                       'EOL': irc.CR + irc.LF}) 
     306         
     307        self.client.dataReceived(actionQuery) 
     308        self.assertEquals(self.client.calls, 
     309                          [("action", dict(user="nick!guy@over.there", 
     310                                           channel="#theChan", 
     311                                           data=r"\o/"))]) 
    300312 
    301313class BasicServerFunctionalityTestCase(unittest.TestCase): 
    302314    def setUp(self): 
  • D:/work/eclipse-workspace/twisted/twisted/words/protocols/irc.py

     
    10281028 
    10291029        if not message: return # don't raise an exception if some idiot sends us a blank message 
    10301030 
     1031        # If message starts with X_DELIM, it's CTCP message. 
    10311032        if message[0]==X_DELIM: 
    1032             m = ctcpExtract(message) 
    1033             if m['extended']: 
    1034                 self.ctcpQuery(user, channel, m['extended']) 
     1033            # Trailing X_DELIM is optional. 
     1034            tag, data = ctcpParse(message) 
     1035            self.ctcpQuery(user, channel, tag, data) 
     1036            return 
    10351037 
    1036             if not m['normal']: 
    1037                 return 
    1038  
    1039             message = string.join(m['normal'], ' ') 
    1040  
    10411038        self.privmsg(user, channel, message) 
    10421039 
    10431040    def irc_NOTICE(self, prefix, params): 
     
    10451042        channel = params[0] 
    10461043        message = params[-1] 
    10471044 
     1045        # If message starts with X_DELIM, it's CTCP message. 
    10481046        if message[0]==X_DELIM: 
    1049             m = ctcpExtract(message) 
    1050             if m['extended']: 
    1051                 self.ctcpReply(user, channel, m['extended']) 
     1047            # Trailing X_DELIM is optional. 
     1048            tag, data = ctcpParse(message) 
     1049            self.ctcpReply(user, channel, tag, data) 
     1050            return 
    10521051 
    1053             if not m['normal']: 
    1054                 return 
    1055  
    1056             message = string.join(m['normal'], ' ') 
    1057  
    10581052        self.noticed(user, channel, message) 
    10591053 
    10601054    def irc_NICK(self, prefix, params): 
     
    11551149    ### Receiving a CTCP query from another party 
    11561150    ### It is safe to leave these alone. 
    11571151 
    1158     def ctcpQuery(self, user, channel, messages): 
     1152    def ctcpQuery(self, user, channel, tag, data): 
    11591153        """Dispatch method for any CTCP queries received. 
    11601154        """ 
    1161         for m in messages: 
    1162             method = getattr(self, "ctcpQuery_%s" % m[0], None) 
    1163             if method: 
    1164                 method(user, channel, m[1]) 
    1165             else: 
    1166                 self.ctcpUnknownQuery(user, channel, m[0], m[1]) 
     1155        method = getattr(self, "ctcpQuery_%s" % tag, None) 
     1156        if method: 
     1157            method(user, channel, data) 
     1158        else: 
     1159            self.ctcpUnknownQuery(user, channel, tag, data) 
    11671160 
    11681161    def ctcpQuery_ACTION(self, user, channel, data): 
    11691162        self.action(user, channel, data) 
     
    14191412    ### Receiving a response to a CTCP query (presumably to one we made) 
    14201413    ### You may want to add methods here, or override UnknownReply. 
    14211414 
    1422     def ctcpReply(self, user, channel, messages): 
     1415    def ctcpReply(self, user, channel, tag, data): 
    14231416        """Dispatch method for any CTCP replies received. 
    14241417        """ 
    1425         for m in messages: 
    1426             method = getattr(self, "ctcpReply_%s" % m[0], None) 
    1427             if method: 
    1428                 method(user, channel, m[1]) 
    1429             else: 
    1430                 self.ctcpUnknownReply(user, channel, m[0], m[1]) 
    14311418 
     1419        method = getattr(self, "ctcpReply_%s" % tag, None) 
     1420        if method: 
     1421            method(user, channel, data) 
     1422        else: 
     1423            self.ctcpUnknownReply(user, channel, tag, data) 
     1424 
    14321425    def ctcpReply_PING(self, user, channel, data): 
    14331426        nick = user.split('!', 1)[0] 
    14341427        if (not self._pings) or (not self._pings.has_key((nick, data))): 
     
    19081901 
    19091902X_DELIM = chr(001) 
    19101903 
    1911 def ctcpExtract(message): 
    1912     """Extract CTCP data from a string. 
     1904def ctcpParse(message): 
     1905    """Basic CTCP message parsing, data decoding is done by handlers""" 
    19131906 
    1914     Returns a dictionary with two items: 
     1907    # Trailing X_DELIM is optional. 
     1908    if message[-1] == X_DELIM: 
     1909        message = message[1:-1] 
     1910    else: 
     1911        message = message[1:] 
     1912     
     1913    tag, data = message.split(" ", 1) 
     1914    return (tag, data) 
    19151915 
    1916        - C{'extended'}: a list of CTCP (tag, data) tuples 
    1917        - C{'normal'}: a list of strings which were not inside a CTCP delimeter 
    1918     """ 
    1919  
    1920     extended_messages = [] 
    1921     normal_messages = [] 
    1922     retval = {'extended': extended_messages, 
    1923               'normal': normal_messages } 
    1924  
    1925     messages = string.split(message, X_DELIM) 
    1926     odd = 0 
    1927  
    1928     # X1 extended data X2 nomal data X3 extended data X4 normal... 
    1929     while messages: 
    1930         if odd: 
    1931             extended_messages.append(messages.pop(0)) 
    1932         else: 
    1933             normal_messages.append(messages.pop(0)) 
    1934         odd = not odd 
    1935  
    1936     extended_messages[:] = filter(None, extended_messages) 
    1937     normal_messages[:] = filter(None, normal_messages) 
    1938  
    1939     extended_messages[:] = map(ctcpDequote, extended_messages) 
    1940     for i in xrange(len(extended_messages)): 
    1941         m = string.split(extended_messages[i], SPC, 1) 
    1942         tag = m[0] 
    1943         if len(m) > 1: 
    1944             data = m[1] 
    1945         else: 
    1946             data = None 
    1947  
    1948         extended_messages[i] = (tag, data) 
    1949  
    1950     return retval 
    1951  
    19521916# CTCP escaping 
    19531917 
    19541918M_QUOTE= chr(020) 
     
    19831947 
    19841948    return mEscape_re.sub(sub, s) 
    19851949 
    1986 X_QUOTE = '\\' 
    1987  
    1988 xQuoteTable = { 
    1989     X_DELIM: X_QUOTE + 'a', 
    1990     X_QUOTE: X_QUOTE + X_QUOTE 
    1991     } 
    1992  
    1993 xDequoteTable = {} 
    1994  
    1995 for k, v in xQuoteTable.items(): 
    1996     xDequoteTable[v[-1]] = k 
    1997  
    1998 xEscape_re = re.compile('%s.' % (re.escape(X_QUOTE),), re.DOTALL) 
    1999  
    2000 def ctcpQuote(s): 
    2001     for c in (X_QUOTE, X_DELIM): 
    2002         s = string.replace(s, c, xQuoteTable[c]) 
    2003     return s 
    2004  
    2005 def ctcpDequote(s): 
    2006     def sub(matchobj, xDequoteTable=xDequoteTable): 
    2007         s = matchobj.group()[1] 
    2008         try: 
    2009             s = xDequoteTable[s] 
    2010         except KeyError: 
    2011             s = s 
    2012         return s 
    2013  
    2014     return xEscape_re.sub(sub, s) 
    2015  
    20161950def ctcpStringify(messages): 
    20171951    """ 
    20181952    @type messages: a list of extended messages.  An extended 
     
    20341968            m = "%s %s" % (tag, data) 
    20351969        else: 
    20361970            m = str(tag) 
    2037         m = ctcpQuote(m) 
     1971 
    20381972        m = "%s%s%s" % (X_DELIM, m, X_DELIM) 
    20391973        coded_messages.append(m) 
    20401974