Index: twisted/words/test/test_irc_service.py =================================================================== --- twisted/words/test/test_irc_service.py (revision 27352) +++ twisted/words/test/test_irc_service.py (working copy) @@ -21,15 +21,23 @@ Sets up a Realm, Portal, Factory, IRCUser, Transport, and Connection for our tests. """ - self.wordsRealm = InMemoryWordsRealm("example.com") + self.hostname = 'example.com' + self.wordsRealm = InMemoryWordsRealm(self.hostname) self.portal = portal.Portal(self.wordsRealm, - [checkers.InMemoryUsernamePasswordDatabaseDontUse(john="pass")]) + [checkers.InMemoryUsernamePasswordDatabaseDontUse( + john="pass", + jane="pass")]) self.factory = IRCFactory(self.wordsRealm, self.portal) + self.ircUser = self.factory.buildProtocol(None) self.stringTransport = proto_helpers.StringTransport() self.ircUser.makeConnection(self.stringTransport) + self.ircUser2 = self.factory.buildProtocol(None) + self.stringTransport2 = proto_helpers.StringTransport() + self.ircUser2.makeConnection(self.stringTransport2) + def test_sendMessage(self): """ Sending a message to a user after they have sent NICK, but before they @@ -38,16 +46,16 @@ self.ircUser.irc_NICK("", ["mynick"]) self.stringTransport.clear() self.ircUser.sendMessage("foo") - self.assertEquals(":example.com foo mynick\r\n", + self.assertEquals(":%s foo mynick\r\n" % self.hostname, self.stringTransport.value()) - def response(self): + def response(self, ircUser): """ Grabs our responses and then clears the transport """ - response = self.ircUser.transport.value().splitlines() - self.ircUser.transport.clear() + response = ircUser.transport.value().splitlines() + ircUser.transport.clear() return map(irc.parsemsg, response) @@ -74,13 +82,13 @@ Pidgin) before a connection is considered to be fully established. """ self.ircUser.irc_NICK("", ["mynick"]) - response = self.response() + response = self.response(self.ircUser) start = list(self.scanResponse(response, irc.RPL_MOTDSTART)) end = list(self.scanResponse(response, irc.RPL_ENDOFMOTD)) self.assertEquals(start, - [(0, ('example.com', '375', ['mynick', '- example.com Message of the Day - ']))]) + [(0, (self.hostname, '375', ['mynick', '- example.com Message of the Day - ']))]) self.assertEquals(end, - [(1, ('example.com', '376', ['mynick', 'End of /MOTD command.']))]) + [(1, (self.hostname, '376', ['mynick', 'End of /MOTD command.']))]) def test_fullLogin(self): @@ -92,19 +100,75 @@ self.ircUser.irc_PASS("", ["pass"]) self.ircUser.irc_NICK("", ["john"]) - version = ('Your host is example.com, running version %s' % - (self.factory._serverInfo["serviceVersion"],)) + version = ('Your host is %s, running version %s' % + (self.hostname, self.factory._serverInfo["serviceVersion"],)) creation = ('This server was created on %s' % (self.factory._serverInfo["creationDate"],)) - self.assertEquals(self.response(), - [('example.com', '375', + self.assertEquals(self.response(self.ircUser), + [(self.hostname, '375', ['john', '- example.com Message of the Day - ']), - ('example.com', '376', ['john', 'End of /MOTD command.']), - ('example.com', '001', ['john', 'connected to Twisted IRC']), - ('example.com', '002', ['john', version]), - ('example.com', '003', ['john', creation]), - ('example.com', '004', - ['john', 'example.com', self.factory._serverInfo["serviceVersion"], + (self.hostname, '376', ['john', 'End of /MOTD command.']), + (self.hostname, '001', ['john', 'connected to Twisted IRC']), + (self.hostname, '002', ['john', version]), + (self.hostname, '003', ['john', creation]), + (self.hostname, '004', + ['john', self.hostname, self.factory._serverInfo["serviceVersion"], 'w', 'n'])]) + + + def test_awayMessage(self): + ''' + Receiving AWAY should put the user into the AWAY state. + PRIVMSG commands directed at that user should not be delivered; instead, + a RPL_AWAY response with the message should be returned. Also check for + RPL_NOWAWAY and RPL_UNAWAY responses. + ''' + + # First, login both clients + self.ircUser.irc_USER('', ['john doe']) + self.ircUser.irc_PASS('', ['pass']) + self.ircUser.irc_NICK('', ['john']) + self.response(self.ircUser) # just dump these responses + + self.ircUser2.irc_USER('', ['jane doe']) + self.ircUser2.irc_PASS('', ['pass']) + self.ircUser2.irc_NICK('', ['jane']) + self.response(self.ircUser2) # just dump these responses + + # user2 tries to msg user1 + self.ircUser2.irc_PRIVMSG('', ['john', 'Are you there?']) + self.assertEquals(self.response(self.ircUser2), []) + + # user1 gets the message + self.assertEquals(self.response(self.ircUser), + [('jane!jane@%s' % self.hostname, 'PRIVMSG', + ['john', 'Are you there?'])]) + + # set user1 away + self.ircUser.irc_AWAY('', ['I am away.']) + self.assertEquals(self.response(self.ircUser), + [(self.hostname, irc.RPL_NOWAWAY, + ['john', 'You have been marked as being away'])]) + + # user2 tries to msg user1 + self.ircUser2.irc_PRIVMSG('', ['john', 'Are you there?']) + self.assertEquals(self.response(self.ircUser2), + [(self.hostname, irc.RPL_AWAY, + ['jane', 'I am away.'])]) + + # user1 comes back + self.ircUser.irc_AWAY('', []) + self.assertEquals(self.response(self.ircUser), + [(self.hostname, irc.RPL_UNAWAY, + ['john', 'You are no longer marked as being away'])]) + + # user2 tries to msg user1 + self.ircUser2.irc_PRIVMSG('', ['john', 'Are you there?']) + self.assertEquals(self.response(self.ircUser2), []) + + # user1 gets the message + self.assertEquals(self.response(self.ircUser), + [('jane!jane@%s' % self.hostname, 'PRIVMSG', + ['john', 'Are you there?'])]) Index: twisted/words/service.py =================================================================== --- twisted/words/service.py (revision 27352) +++ twisted/words/service.py (working copy) @@ -138,6 +138,7 @@ self.name = name self.groups = [] self.lastMessage = time() + self.awayMessage = None def loggedIn(self, realm, mind): @@ -165,6 +166,14 @@ return recipient.receive(self.mind, recipient, message) + def setAway(self, message): + self.awayMessage = message + + + def getAway(self): + return self.awayMessage + + def itergroups(self): return iter(self.groups) @@ -247,11 +256,15 @@ recipientName = recipient.name text = message.get('text', '') - for L in text.splitlines(): - self.privmsg( - '%s!%s@%s' % (sender.name, sender.name, self.hostname), - recipientName, - L) + away = recipient.avatar.getAway() + if away: + sender.sendMessage(irc.RPL_AWAY, ':' + away) + else: + for L in text.splitlines(): + self.privmsg( + '%s!%s@%s' % (sender.name, sender.name, self.hostname), + recipientName, + L) def groupMetaUpdate(self, group, meta): @@ -860,6 +873,21 @@ self.realm.lookupUser(user).addCallbacks(cbUser, ebUser) + def irc_AWAY(self, prefix, params): + """Away status + + Parameters: [ ] + """ + if len(params) > 0: + self.avatar.setAway(params[-1]) + self.sendMessage(irc.RPL_NOWAWAY, + ':You have been marked as being away') + else: + self.avatar.setAway(None) + self.sendMessage(irc.RPL_UNAWAY, + ':You are no longer marked as being away') + + # Unsupported commands, here for legacy compatibility def irc_OPER(self, prefix, params): """Oper message