Ticket #1685: words_irc_unicode.patch

File words_irc_unicode.patch, 32.2 KB (added by Yury Yurevich, 13 years ago)

unicode patch for words.irc and words.service

  • protocols/irc.py

    diff -urN words.trunk/protocols/irc.py words.current/protocols/irc.py
    old new  
    4444import random
    4545import re
    4646import stat
    47 import string
    4847import struct
    4948import sys
    5049import time
    51 import types
    5250import traceback
    5351import socket
    5452
    5553from os import path
     54from string import letters, digits, punctuation
    5655
    5756NUL = chr(0)
    5857CR = chr(015)
     
    6867class IRCPasswordMismatch(Exception):
    6968    pass
    7069
    71 def parsemsg(s):
     70def parsemsg(s, encoding='utf-8'):
    7271    """Breaks a message from an IRC server into its prefix, command, and arguments.
    7372    """
    7473    prefix = ''
    7574    trailing = []
     75    if encoding is None:
     76        encoding = 'utf-8'
    7677    if not s:
    77         raise IRCBadMessage("Empty line.")
     78        raise IRCBadMessage(u"Empty line.")
    7879    if s[0] == ':':
    7980        prefix, s = s[1:].split(' ', 1)
    8081    if s.find(' :') != -1:
     
    8485    else:
    8586        args = s.split()
    8687    command = args.pop(0)
     88   
     89    try:
     90        prefix = prefix.decode(encoding)
     91        command = command.decode(encoding)
     92        args = map(lambda x: x.decode(encoding), args)
     93    except UnicodeDecodeError:
     94        raise IRCBadMessage(u"Couldn't decode your %s-string: %s" % (encoding, repr(s)))
     95    log.msg("irc: parsemsg: prefix=%s, command=%s, args=%s" % (repr(prefix), repr(command), repr(args)), debug=True)
    8796    return prefix, command, args
    8897
    8998
     
    125134
    126135
    127136    def sendLine(self, line):
     137        log.msg("irc: IRC.sendLine %s" % repr(line), debug=True)
    128138        if self.encoding is not None:
    129139            if isinstance(line, unicode):
    130140                line = line.encode(self.encoding)
     
    147157            # sanity checking to catch likely dumb mistakes.
    148158            raise ValueError, "Somebody screwed up, 'cuz this doesn't" \
    149159                  " look like a command to me: %s" % command
    150 
    151         line = string.join([command] + list(parameter_list))
     160        log.msg("irc: IRC.sendMessage: command=%s parameter_list=%s prefix=%s" % (repr(command), repr(parameter_list), repr(prefix)), debug=True)
     161        line = ' '.join([command] + list(parameter_list))
    152162        if prefix.has_key('prefix'):
    153163            line = ":%s %s" % (prefix['prefix'], line)
    154164        self.sendLine(line)
     
    164174        of LineReceiver to turn "line mode" on and off was not
    165175        required.)
    166176        """
    167         lines = (self.buffer + data).split(LF)
     177        self.buffer = self.buffer + data
     178        lines = self.buffer.split(LF)
    168179        # Put the (possibly empty) element after the last LF back in the
    169180        # buffer
    170181        self.buffer = lines.pop()
     
    175186                continue
    176187            if line[-1] == CR:
    177188                line = line[:-1]
    178             prefix, command, params = parsemsg(line)
     189            try:
     190                prefix, command, params = parsemsg(line, self.encoding)
     191            except IRCBadMessage, msg:
     192                self.sendMessage(str(ERR_UNKNOWNCOMMAND), str(msg))
     193                break
    179194            # mIRC is a big pile of doo-doo
    180195            command = command.upper()
    181196            # DEBUG: log.msg( "%s %s %s" % (prefix, command, params))
     
    187202        """Determine the function to call for the given command and call
    188203        it with the given arguments.
    189204        """
    190         method = getattr(self, "irc_%s" % command, None)
     205        try:
     206            method = getattr(self, "irc_%s" % command, None)
     207        except UnicodeEncodeError:
     208            method = None
    191209        try:
    192210            if method is not None:
    193211                method(prefix, params)
     
    531549        C{None}, no delay will be imposed.
    532550    @type lineRate: Number of Seconds.
    533551    """
     552    encoding = None
    534553
    535554    motd = ""
    536555    nickname = 'irc'
     
    928947            self._pings = {}
    929948
    930949        if text is None:
    931             chars = string.letters + string.digits + string.punctuation
     950            chars = letters + digits + punctuation
    932951            key = ''.join([random.choice(chars) for i in range(12)])
    933952        else:
    934953            key = str(text)
     
    944963                del self._pings[byValue[i][1]]
    945964
    946965    def dccSend(self, user, file):
    947         if type(file) == types.StringType:
     966        if isinstance(file, basestring):
    948967            file = open(file, 'r')
    949968
    950969        size = fileSize(file)
     
    965984        if not (size is None):
    966985            args.append(size)
    967986
    968         args = string.join(args, ' ')
     987        args = ' '.join(args)
    969988
    970989        self.ctcpMakeQuery(user, [('DCC', args)])
    971990
     
    9941013        self.signedOn()
    9951014
    9961015    def irc_JOIN(self, prefix, params):
    997         nick = string.split(prefix,'!')[0]
     1016        nick = prefix.split('!')[0]
    9981017        channel = params[-1]
    9991018        if nick == self.nickname:
    10001019            self.joined(channel)
     
    10021021            self.userJoined(nick, channel)
    10031022
    10041023    def irc_PART(self, prefix, params):
    1005         nick = string.split(prefix,'!')[0]
     1024        nick = prefix.split('!')[0]
    10061025        channel = params[0]
    10071026        if nick == self.nickname:
    10081027            self.left(channel)
     
    10101029            self.userLeft(nick, channel)
    10111030
    10121031    def irc_QUIT(self, prefix, params):
    1013         nick = string.split(prefix,'!')[0]
     1032        nick = prefix.split('!')[0]
    10141033        self.userQuit(nick, params[0])
    10151034
    10161035    def irc_MODE(self, prefix, params):
     
    10381057            if not m['normal']:
    10391058                return
    10401059
    1041             message = string.join(m['normal'], ' ')
     1060            message = ' '.join(m['normal'])
    10421061
    10431062        self.privmsg(user, channel, message)
    10441063
     
    10551074            if not m['normal']:
    10561075                return
    10571076
    1058             message = string.join(m['normal'], ' ')
     1077            message = ' '.join(m['normal'])
    10591078
    10601079        self.noticed(user, channel, message)
    10611080
    10621081    def irc_NICK(self, prefix, params):
    1063         nick = string.split(prefix,'!', 1)[0]
     1082        nick = prefix.split('!', 1)[0]
    10641083        if nick == self.nickname:
    10651084            self.nickChanged(params[0])
    10661085        else:
     
    10691088    def irc_KICK(self, prefix, params):
    10701089        """Kicked?  Who?  Not me, I hope.
    10711090        """
    1072         kicker = string.split(prefix,'!')[0]
     1091        kicker = prefix.split('!')[0]
    10731092        channel = params[0]
    10741093        kicked = params[1]
    10751094        message = params[-1]
    1076         if string.lower(kicked) == string.lower(self.nickname):
     1095        if kicked.lower() == self.nickname.lower():
    10771096            # Yikes!
    10781097            self.kickedFrom(channel, kicker, message)
    10791098        else:
     
    10821101    def irc_TOPIC(self, prefix, params):
    10831102        """Someone in the channel set the topic.
    10841103        """
    1085         user = string.split(prefix, '!')[0]
     1104        user = prefix.split('!')[0]
    10861105        channel = params[0]
    10871106        newtopic = params[1]
    10881107        self.topicUpdated(user, channel, newtopic)
     
    10901109    def irc_RPL_TOPIC(self, prefix, params):
    10911110        """I just joined the channel, and the server is telling me the current topic.
    10921111        """
    1093         user = string.split(prefix, '!')[0]
     1112        user = prefix.split('!')[0]
    10941113        channel = params[1]
    10951114        newtopic = params[2]
    10961115        self.topicUpdated(user, channel, newtopic)
    10971116
    10981117    def irc_RPL_NOTOPIC(self, prefix, params):
    1099         user = string.split(prefix, '!')[0]
     1118        user = prefix.split('!')[0]
    11001119        channel = params[1]
    11011120        newtopic = ""
    11021121        self.topicUpdated(user, channel, newtopic)
     
    11711190        self.action(user, channel, data)
    11721191
    11731192    def ctcpQuery_PING(self, user, channel, data):
    1174         nick = string.split(user,"!")[0]
     1193        nick = user.split("!")[0]
    11751194        self.ctcpMakeReply(nick, [("PING", data)])
    11761195
    11771196    def ctcpQuery_FINGER(self, user, channel, data):
     
    11861205        else:
    11871206            reply = str(self.fingerReply)
    11881207
    1189         nick = string.split(user,"!")[0]
     1208        nick = user.split("!")[0]
    11901209        self.ctcpMakeReply(nick, [('FINGER', reply)])
    11911210
    11921211    def ctcpQuery_VERSION(self, user, channel, data):
     
    11951214                               % (user, data))
    11961215
    11971216        if self.versionName:
    1198             nick = string.split(user,"!")[0]
     1217            nick = user.split("!")[0]
    11991218            self.ctcpMakeReply(nick, [('VERSION', '%s:%s:%s' %
    12001219                                       (self.versionName,
    12011220                                        self.versionNum,
     
    12061225            self.quirkyMessage("Why did %s send '%s' with a SOURCE query?"
    12071226                               % (user, data))
    12081227        if self.sourceURL:
    1209             nick = string.split(user,"!")[0]
     1228            nick = user.split("!")[0]
    12101229            # The CTCP document (Zeuge, Rollo, Mesander 1994) says that SOURCE
    12111230            # replies should be responded to with the location of an anonymous
    12121231            # FTP server in host:directory:file format.  I'm taking the liberty
     
    12191238            self.quirkyMessage("Why did %s send '%s' with a USERINFO query?"
    12201239                               % (user, data))
    12211240        if self.userinfo:
    1222             nick = string.split(user,"!")[0]
     1241            nick = user.split("!")[0]
    12231242            self.ctcpMakeReply(nick, [('USERINFO', self.userinfo)])
    12241243
    12251244    def ctcpQuery_CLIENTINFO(self, user, channel, data):
     
    12301249        the usage of that tag.
    12311250        """
    12321251
    1233         nick = string.split(user,"!")[0]
     1252        nick = user.split("!")[0]
    12341253        if not data:
    12351254            # XXX: prefixedMethodNames gets methods from my *class*,
    12361255            # but it's entirely possible that this *instance* has more
     
    12391258                                                'ctcpQuery_')
    12401259
    12411260            self.ctcpMakeReply(nick, [('CLIENTINFO',
    1242                                        string.join(names, ' '))])
     1261                                       ' '.join(names))])
    12431262        else:
    1244             args = string.split(data)
     1263            args = data.split()
    12451264            method = getattr(self, 'ctcpQuery_%s' % (args[0],), None)
    12461265            if not method:
    12471266                self.ctcpMakeReply(nick, [('ERRMSG',
     
    12561275    def ctcpQuery_ERRMSG(self, user, channel, data):
    12571276        # Yeah, this seems strange, but that's what the spec says to do
    12581277        # when faced with an ERRMSG query (not a reply).
    1259         nick = string.split(user,"!")[0]
     1278        nick = user.split("!")[0]
    12601279        self.ctcpMakeReply(nick, [('ERRMSG',
    12611280                                   "%s :No error has occoured." % data)])
    12621281
     
    12641283        if data is not None:
    12651284            self.quirkyMessage("Why did %s send '%s' with a TIME query?"
    12661285                               % (user, data))
    1267         nick = string.split(user,"!")[0]
     1286        nick = user.split("!")[0]
    12681287        self.ctcpMakeReply(nick,
    12691288                           [('TIME', ':%s' %
    12701289                             time.asctime(time.localtime(time.time())))])
     
    12821301            data = data[len(dcctype)+1:]
    12831302            handler(user, channel, data)
    12841303        else:
    1285             nick = string.split(user,"!")[0]
     1304            nick = user.split("!")[0]
    12861305            self.ctcpMakeReply(nick, [('ERRMSG',
    12871306                                       "DCC %s :Unknown DCC type '%s'"
    12881307                                       % (data, dcctype))])
     
    13921411    #    raise NotImplementedError
    13931412
    13941413    def ctcpUnknownQuery(self, user, channel, tag, data):
    1395         nick = string.split(user,"!")[0]
     1414        nick = user.split("!")[0]
    13961415        self.ctcpMakeReply(nick, [('ERRMSG',
    13971416                                   "%s %s: Unknown query '%s'"
    13981417                                   % (tag, data, tag))])
     
    14571476        """When I get a message that's so broken I can't use it.
    14581477        """
    14591478        log.msg(line)
    1460         log.msg(string.join(traceback.format_exception(excType,
     1479        log.msg(''.join(traceback.format_exception(excType,
    14611480                                                        excValue,
    1462                                                         tb),''))
     1481                                                        tb)))
    14631482
    14641483    def quirkyMessage(self, s):
    14651484        """This is called when I receive a message which is peculiar,
     
    14801499    def lineReceived(self, line):
    14811500        line = lowDequote(line)
    14821501        try:
    1483             prefix, command, params = parsemsg(line)
     1502            prefix, command, params = parsemsg(line, self.encoding)
    14841503            if numeric_to_symbolic.has_key(command):
    14851504                command = numeric_to_symbolic[command]
    14861505            self.handleCommand(command, prefix, params)
     
    15641583    connected = 0
    15651584
    15661585    def __init__(self, file):
    1567         if type(file) is types.StringType:
     1586        if isinstance(file, basestring):
    15681587            self.file = open(file, 'r')
    15691588
    15701589    def connectionMade(self):
     
    16911710
    16921711    def dataReceived(self, data):
    16931712        self.buffer = self.buffer + data
    1694         lines = string.split(self.buffer, LF)
     1713        lines = self.buffer.split(LF)
    16951714        # Put the (possibly empty) element after the last LF back in the
    16961715        # buffer
    16971716        self.buffer = lines.pop()
     
    17301749    """
    17311750
    17321751    orig_data = data
    1733     data = string.split(data)
     1752    data = data.split()
    17341753    if len(data) < 4:
    17351754        return orig_data
    17361755
     
    17521771                )
    17531772            # The mapping to 'int' is to get rid of those accursed
    17541773            # "L"s which python 1.5.2 puts on the end of longs.
    1755             address = string.join(map(str,map(int,address)), ".")
     1774            address = '.'.join(map(str,map(int,address)))
    17561775
    17571776    if dcctype == 'SEND':
    17581777        filename = arg
     
    19241943    retval = {'extended': extended_messages,
    19251944              'normal': normal_messages }
    19261945
    1927     messages = string.split(message, X_DELIM)
     1946    messages = message.split(X_DELIM)
    19281947    odd = 0
    19291948
    19301949    # X1 extended data X2 nomal data X3 extended data X4 normal...
     
    19401959
    19411960    extended_messages[:] = map(ctcpDequote, extended_messages)
    19421961    for i in xrange(len(extended_messages)):
    1943         m = string.split(extended_messages[i], SPC, 1)
     1962        m = extended_messages[i].split(SPC, 1)
    19441963        tag = m[0]
    19451964        if len(m) > 1:
    19461965            data = m[1]
     
    19711990
    19721991def lowQuote(s):
    19731992    for c in (M_QUOTE, NUL, NL, CR):
    1974         s = string.replace(s, c, mQuoteTable[c])
     1993        s = s.replace(c, mQuoteTable[c])
    19751994    return s
    19761995
    19771996def lowDequote(s):
     
    20012020
    20022021def ctcpQuote(s):
    20032022    for c in (X_QUOTE, X_DELIM):
    2004         s = string.replace(s, c, xQuoteTable[c])
     2023        s = s.replace(c, xQuoteTable[c])
    20052024    return s
    20062025
    20072026def ctcpDequote(s):
     
    20262045    coded_messages = []
    20272046    for (tag, data) in messages:
    20282047        if data:
    2029             if not isinstance(data, types.StringType):
     2048            if not isinstance(data, basestring):
    20302049                try:
    20312050                    # data as list-of-strings
    20322051                    data = " ".join(map(str, data))
     
    20402059        m = "%s%s%s" % (X_DELIM, m, X_DELIM)
    20412060        coded_messages.append(m)
    20422061
    2043     line = string.join(coded_messages, '')
     2062    line = ''.join(coded_messages)
    20442063    return line
    20452064
    20462065
  • service.py

    diff -urN words.trunk/service.py words.current/service.py
    old new  
    210210        if not kw.has_key('prefix'):
    211211            kw['prefix'] = self.hostname
    212212        if not kw.has_key('to'):
    213             kw['to'] = self.name.encode(self.encoding)
     213            kw['to'] = self.name
    214214
    215215        arglist = [self, command, kw['to']] + list(parameter_list)
    216216        irc.IRC.sendMessage(*arglist, **kw)
     
    219219    # IChatClient implementation
    220220    def userJoined(self, group, user):
    221221        self.join(
    222             "%s!%s@%s" % (user.name, user.name, self.hostname),
    223             '#' + group.name)
     222            u"%s!%s@%s" % (user.name, user.name, self.hostname),
     223            u'#' + group.name)
    224224
    225225
    226226    def userLeft(self, group, user, reason=None):
    227227        assert reason is None or isinstance(reason, unicode)
    228228        self.part(
    229             "%s!%s@%s" % (user.name, user.name, self.hostname),
    230             '#' + group.name,
    231             (reason or u"leaving").encode(self.encoding, 'replace'))
     229            u"%s!%s@%s" % (user.name, user.name, self.hostname),
     230            u'#' + group.name,
     231            (reason or u"leaving"))
    232232
    233233
    234234    def receive(self, sender, recipient, message):
     
    236236
    237237        # omg???????????
    238238        if iwords.IGroup.providedBy(recipient):
    239             recipientName = '#' + recipient.name
     239            recipientName = u'#' + recipient.name
    240240        else:
    241241            recipientName = recipient.name
    242242
    243243        text = message.get('text', '<an unrepresentable message>')
    244244        for L in text.splitlines():
    245245            self.privmsg(
    246                 '%s!%s@%s' % (sender.name, sender.name, self.hostname),
     246                u'%s!%s@%s' % (sender.name, sender.name, self.hostname),
    247247                recipientName,
    248248                L)
    249249
     
    254254            author = meta.get('topic_author', '')
    255255            self.topic(
    256256                self.name,
    257                 '#' + group.name,
     257                u'#' + group.name,
    258258                topic,
    259                 '%s!%s@%s' % (author, author, self.hostname)
     259                u'%s!%s@%s' % (author, author, self.hostname)
    260260                )
    261261
    262262    # irc.IRC callbacks - starting with login related stuff.
     
    283283
    284284        [REQUIRED]
    285285        """
    286         try:
    287             nickname = params[0].decode(self.encoding)
    288         except UnicodeDecodeError:
    289             self.privmsg(
    290                 NICKSERV,
    291                 nickname,
    292                 'Your nickname is cannot be decoded.  Please use ASCII or UTF-8.')
    293             self.transport.loseConnection()
    294             return
     286        nickname = params[0]
     287        assert isinstance(nickname, unicode)
    295288
    296289        if self.password is None:
    297290            self.nickname = nickname
     
    339332
    340333
    341334    def logInAs(self, nickname, password):
     335        log.msg("service: IRCUser.logInAs nick=%s" % repr(nickname), debug=True)
    342336        d = self.factory.portal.login(
    343337            credentials.UsernamePassword(nickname, password),
    344338            self,
     
    348342
    349343    _welcomeMessages = [
    350344        (irc.RPL_WELCOME,
    351          ":connected to Twisted IRC"),
     345         u":connected to Twisted IRC"),
    352346        (irc.RPL_YOURHOST,
    353          ":Your host is %(serviceName)s, running version %(serviceVersion)s"),
     347         u":Your host is %(serviceName)s, running version %(serviceVersion)s"),
    354348        (irc.RPL_CREATED,
    355          ":This server was created on %(creationDate)s"),
     349         u":This server was created on %(creationDate)s"),
    356350
    357351        # "Bummer.  This server returned a worthless 004 numeric.
    358352        #  I'll have to guess at all the values"
     
    360354        (irc.RPL_MYINFO,
    361355         # w and n are the currently supported channel and user modes
    362356         # -- specify this better
    363          "%(serviceName)s %(serviceVersion)s w n"),
     357         u"%(serviceName)s %(serviceVersion)s w n"),
    364358        ]
    365359
    366360
     
    413407        Parameters: <server1> [ <server2> ]
    414408        """
    415409        if self.realm is not None:
    416             self.sendMessage('PONG', self.hostname)
     410            self.sendMessage(u'PONG', self.hostname)
    417411
    418412
    419413    def irc_QUIT(self, prefix, params):
     
    428422        if modes:
    429423            self.sendMessage(
    430424                irc.ERR_UNKNOWNMODE,
    431                 ":Unknown MODE flag.")
     425                u":Unknown MODE flag.")
    432426        else:
    433427            self.channelMode(self.name, '#' + group.name, '+')
    434428
     
    437431        if modes:
    438432            self.sendMessage(
    439433                irc.ERR_UNKNOWNMODE,
    440                 ":Unknown MODE flag.")
     434                u":Unknown MODE flag.")
    441435        elif user is self.avatar:
    442436            self.sendMessage(
    443437                irc.RPL_UMODEIS,
    444                 "+")
     438                u"+")
    445439        else:
    446440            self.sendMessage(
    447441                irc.ERR_USERSDONTMATCH,
    448                 ":You can't look at someone else's modes.")
     442                u":You can't look at someone else's modes.")
    449443
    450444
    451445    def irc_MODE(self, prefix, params):
     
    455449        *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
    456450
    457451        """
    458         try:
    459             channelOrUser = params[0].decode(self.encoding)
    460         except UnicodeDecodeError:
    461             self.sendMessage(
    462                 irc.ERR_NOSUCHNICK, params[0],
    463                 ":No such nickname (could not decode your unicode!)")
    464             return
     452        channelOrUser = params[0]
     453        assert(channelOrUser, unicode)
    465454
    466455        if channelOrUser.startswith('#'):
    467456            def ebGroup(err):
    468457                err.trap(ewords.NoSuchGroup)
    469458                self.sendMessage(
    470459                    irc.ERR_NOSUCHCHANNEL, params[0],
    471                     ":That channel doesn't exist.")
     460                    u":That channel doesn't exist.")
    472461            d = self.realm.lookupGroup(channelOrUser[1:])
    473462            d.addCallbacks(
    474463                self._channelMode,
     
    478467            def ebUser(err):
    479468                self.sendMessage(
    480469                    irc.ERR_NOSUCHNICK,
    481                     ":No such nickname.")
     470                    u":No such nickname.")
    482471
    483472            d = self.realm.lookupUser(channelOrUser)
    484473            d.addCallbacks(
     
    502491
    503492        Parameters: <msgtarget> <text to be sent>
    504493        """
    505         try:
    506             targetName = params[0].decode(self.encoding)
    507         except UnicodeDecodeError:
    508             self.sendMessage(
    509                 irc.ERR_NOSUCHNICK, targetName,
    510                 ":No such nick/channel (could not decode your unicode!)")
    511             return
     494        targetName = params[0]
     495        assert isinstance(targetName, unicode)
    512496
    513497        messageText = params[-1]
    514498        if targetName.startswith('#'):
     
    523507        def ebTarget(err):
    524508            self.sendMessage(
    525509                irc.ERR_NOSUCHNICK, targetName,
    526                 ":No such nick/channel.")
     510                u":No such nick/channel.")
    527511
    528512        target.addCallbacks(cbTarget, ebTarget)
    529513
     
    533517
    534518        Parameters: ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] )
    535519        """
    536         try:
    537             groupName = params[0].decode(self.encoding)
    538         except UnicodeDecodeError:
    539             self.sendMessage(
    540                 irc.IRC_NOSUCHCHANNEL, params[0],
    541                 ":No such channel (could not decode your unicode!)")
    542             return
     520        groupName = params[0]
     521        assert isinstance(groupName, unicode)
    543522
    544523        if groupName.startswith('#'):
    545524            groupName = groupName[1:]
     
    549528                self.userJoined(group, self)
    550529                self.names(
    551530                    self.name,
    552                     '#' + group.name,
     531                    u'#' + group.name,
    553532                    [user.name for user in group.iterusers()])
    554533                self._sendTopic(group)
    555534            return self.avatar.join(group).addCallback(cbJoin)
    556535
    557536        def ebGroup(err):
    558537            self.sendMessage(
    559                 irc.ERR_NOSUCHCHANNEL, '#' + groupName,
    560                 ":No such channel.")
     538                irc.ERR_NOSUCHCHANNEL, u'#' + groupName,
     539                u":No such channel.")
    561540
    562541        self.realm.getGroup(groupName).addCallbacks(cbGroup, ebGroup)
    563542
     
    567546
    568547        Parameters: <channel> *( "," <channel> ) [ <Part Message> ]
    569548        """
    570         try:
    571             groupName = params[0].decode(self.encoding)
    572         except UnicodeDecodeError:
    573             self.sendMessage(
    574                 irc.ERR_NOTONCHANNEL, params[0],
    575                 ":Could not decode your unicode!")
    576             return
     549        groupName = params[0]
     550        assert isinstance(groupName, unicode)
    577551
    578552        if groupName.startswith('#'):
    579553            groupName = groupName[1:]
    580554
    581555        if len(params) > 1:
    582             reason = params[1].decode('utf-8')
     556            reason = params[1]
     557            assert isinstance(reason, unicode)
    583558        else:
    584559            reason = None
    585560
     
    592567            err.trap(ewords.NoSuchGroup)
    593568            self.sendMessage(
    594569                irc.ERR_NOTONCHANNEL,
    595                 '#' + groupName,
    596                 ":" + err.getErrorMessage())
     570                u'#' + groupName,
     571                u":" + err.getErrorMessage())
    597572
    598573        self.realm.lookupGroup(groupName).addCallbacks(cbGroup, ebGroup)
    599574
     
    606581        #<< NAMES #python
    607582        #>> :benford.openprojects.net 353 glyph = #python :Orban ... @glyph ... Zymurgy skreech
    608583        #>> :benford.openprojects.net 366 glyph #python :End of /NAMES list.
    609         try:
    610             channel = params[-1].decode(self.encoding)
    611         except UnicodeDecodeError:
    612             self.sendMessage(
    613                 irc.ERR_NOSUCHCHANNEL, params[-1],
    614                 ":No such channel (could not decode your unicode!)")
    615             return
     584        channel = params[-1]
     585        assert isinstance(channel, unicode)
    616586
    617587        if channel.startswith('#'):
    618588            channel = channel[1:]
     
    620590        def cbGroup(group):
    621591            self.names(
    622592                self.name,
    623                 '#' + group.name,
     593                u'#' + group.name,
    624594                [user.name for user in group.iterusers()])
    625595
    626596        def ebGroup(err):
     
    628598            # No group?  Fine, no names!
    629599            self.names(
    630600                self.name,
    631                 '#' + group.name,
     601                u'#' + group.name,
    632602                [])
    633603
    634604        self.realm.lookupGroup(channel).addCallbacks(cbGroup, ebGroup)
     
    639609
    640610        Parameters: <channel> [ <topic> ]
    641611        """
    642         try:
    643             channel = params[0].decode(self.encoding)
    644         except UnicodeDecodeError:
    645             self.sendMessage(
    646                 irc.ERR_NOSUCHCHANNEL,
    647                 ":That channel doesn't exist (could not decode your unicode!)")
    648             return
     612        channel = params[0]
     613        assert isinstance(channel, unicode)
    649614
    650615        if channel.startswith('#'):
    651616            channel = channel[1:]
     
    660625        topic = group.meta.get("topic")
    661626        author = group.meta.get("topic_author") or "<noone>"
    662627        date = group.meta.get("topic_date", 0)
    663         self.topic(self.name, '#' + group.name, topic)
    664         self.topicAuthor(self.name, '#' + group.name, author, date)
     628        self.topic(self.name, u'#' + group.name, topic)
     629        self.topicAuthor(self.name, u'#' + group.name, author, date)
    665630
    666631
    667632    def _getTopic(self, channel):
     
    672637            err.trap(ewords.NoSuchGroup)
    673638            self.sendMessage(
    674639                irc.ERR_NOSUCHCHANNEL, '=', channel,
    675                 ":That channel doesn't exist.")
     640                u":That channel doesn't exist.")
    676641
    677642        self.realm.lookupGroup(channel).addCallbacks(self._sendTopic, ebGroup)
    678643
     
    690655            def ebSet(err):
    691656                self.sendMessage(
    692657                    ERR_CHANOPRIVSNEEDED,
    693                     "#" + group.name,
    694                     ":You need to be a channel operator to do that.")
     658                    u"#" + group.name,
     659                    u":You need to be a channel operator to do that.")
    695660
    696661            return group.setMetadata(newMeta).addErrback(ebSet)
    697662
     
    699664            err.trap(ewords.NoSuchGroup)
    700665            self.sendMessage(
    701666                irc.ERR_NOSUCHCHANNEL, '=', channel,
    702                 ":That channel doesn't exist.")
     667                u":That channel doesn't exist.")
    703668
    704669        self.realm.lookupGroup(channel).addCallbacks(cbGroup, ebGroup)
    705670
     
    713678        """
    714679        for (name, size, topic) in channels:
    715680            self.sendMessage(irc.RPL_LIST, name, str(size), ":" + topic)
    716         self.sendMessage(irc.RPL_LISTEND, ":End of /LIST")
     681        self.sendMessage(irc.RPL_LISTEND, u":End of /LIST")
    717682
    718683
    719684    def irc_LIST(self, prefix, params):
     
    730695        #>> :orwell.freenode.net 323 exarkun :End of /LIST
    731696        if params:
    732697            # Return information about indicated channels
    733             try:
    734                 channels = params[0].decode(self.encoding).split(',')
    735             except UnicodeDecodeError:
    736                 self.sendMessage(
    737                     irc.ERR_NOSUCHCHANNEL, params[0],
    738                     ":No such channel (could not decode your unicode!)")
    739                 return
    740 
     698            channels_list = params[0]
     699            assert isinstance(channels_list, unicode)
     700            channels = channels_list.split(',')
    741701            groups = []
    742702            for ch in channels:
     703                ch = ch.strip()
    743704                if ch.startswith('#'):
    744705                    ch = ch[1:]
    745706                groups.append(self.realm.lookupGroup(ch))
     
    767728
    768729    def _userWho(self, user):
    769730        self.sendMessage(irc.RPL_ENDOFWHO,
    770                          ":User /WHO not implemented")
     731                         u":User /WHO not implemented")
    771732
    772733
    773734    def irc_WHO(self, prefix, params):
     
    785746        #>> :x.opn 352 glyph #python glyph adsl-64-123-27-108.dsl.austtx.swbell.net x.opn glyph H :0 glyph
    786747        #>> :x.opn 315 glyph glyph :End of /WHO list.
    787748        if not params:
    788             self.sendMessage(irc.RPL_ENDOFWHO, ":/WHO not supported.")
    789             return
    790 
    791         try:
    792             channelOrUser = params[0].decode(self.encoding)
    793         except UnicodeDecodeError:
    794             self.sendMessage(
    795                 irc.RPL_ENDOFWHO, params[0],
    796                 ":End of /WHO list (could not decode your unicode!)")
     749            self.sendMessage(irc.RPL_ENDOFWHO, u":/WHO not supported.")
    797750            return
     751       
     752        channelOrUser = params[0]
     753        assert isinstance(channelOrUser, unicode)
    798754
    799755        if channelOrUser.startswith('#'):
    800756            def ebGroup(err):
    801757                err.trap(ewords.NoSuchGroup)
    802758                self.sendMessage(
    803759                    irc.RPL_ENDOFWHO, channelOrUser,
    804                     ":End of /WHO list.")
     760                    u":End of /WHO list.")
    805761            d = self.realm.lookupGroup(channelOrUser[1:])
    806762            d.addCallbacks(self._channelWho, ebGroup)
    807763        else:
     
    809765                err.trap(ewords.NoSuchUser)
    810766                self.sendMessage(
    811767                    irc.RPL_ENDOFWHO, channelOrUser,
    812                     ":End of /WHO list.")
     768                    u":End of /WHO list.")
    813769            d = self.realm.lookupUser(channelOrUser)
    814770            d.addCallbacks(self._userWho, ebUser)
    815771
     
    833789            self.sendMessage(
    834790                irc.ERR_NOSUCHNICK,
    835791                params[0],
    836                 ":No such nick/channel")
    837 
    838         try:
    839             user = params[0].decode(self.encoding)
    840         except UnicodeDecodeError:
    841             self.sendMessage(
    842                 irc.ERR_NOSUCHNICK,
    843                 params[0],
    844                 ":No such nick/channel")
    845             return
     792                u":No such nick/channel")
     793        user = params[0]
     794        assert isinstance(user, unicode)
    846795
    847796        self.realm.lookupUser(user).addCallbacks(cbUser, ebUser)
    848797
     
    853802
    854803        Parameters: <name> <password>
    855804        """
    856         self.sendMessage(irc.ERR_NOOPERHOST, ":O-lines not applicable")
     805        self.sendMessage(irc.ERR_NOOPERHOST, u":O-lines not applicable")
    857806
    858807
    859808class IRCFactory(protocol.ServerFactory):
     
    932881
    933882
    934883    def jellyFor(self, jellier):
     884        #### FIXME why explicit encoding?
    935885        return reflect.qual(self.__class__), self.group.name.encode('utf-8'), jellier.invoker.registerReference(self)
    936886
    937887
     
    948898
    949899    def unjellyFor(self, unjellier, unjellyList):
    950900        clsName, name, ref = unjellyList
     901        #### FIXME why explicit encoding? why not unicode?
    951902        self.name = name.decode('utf-8')
    952903        return pb.RemoteReference.unjellyFor(self, unjellier, [clsName, ref])
    953904
     
    11041055
    11051056
    11061057    def getUser(self, name):
    1107         assert isinstance(name, unicode)
     1058        assert isinstance(name, basestring)
     1059        # fixup for doing all tests done. update tests??
     1060        if isinstance(name, str):
     1061            # FIXME why str? must be unicode!
     1062            warnings.warn("Why name in WordsRealm.getUser is str? it must be unicode!", DeprecationWarning, stacklevel=2)
     1063            name = name.decode(self._encoding)
    11081064        if self.createUserOnRequest:
    11091065            def ebUser(err):
    11101066                err.trap(ewords.DuplicateUser)