Commits

Mike Steder committed d74118f Merge

Merging in latest from home

  • Participants
  • Parent commits 8c5600a, 142ec2a

Comments (0)

Files changed (11)

+------------------------
+Installing NoirChat
+------------------------
+========================
+Dependencies
+========================
+
+To run NoirChat you need to install the following
+packages.
+
+1. libevent
+2. greenlet
+3. argparse
+4. gevent
+5. zope.interface
+
+To test or develop NoirChat you should install
+
+1. unittest2
+2. mock
+
+========================
+setup, build, install
+========================
+
+Each of the above dependencies can be
+found in deps/ directory included with NoirChat's source.
+
+Installation of each package should look like:
+
+ $ tar -zxvf greenlet-0.x.tar.gz
+ $ cd greenlet-0.x
+ $ python setup.py build
+ $ sudo python setup.py install
+
+ 
+ 
         newnick = message.parameters[0]
         if newnick not in db.nicks:
             if not len(newnick) > irc.MAX_NICK_LENGTH:
-                db.nicks.add(newnick)
-                db.nickToUserId[newnick] = userId
-                user.nick = newnick
+                db.setNick(userId, newnick)
                 po.send([userId], ":%s NICK %s"%(user.nick, user.nick))
             else:
                 po.send([userId], irc.ERR_ERRONEUSNICKNAME)
 @registerCommand("USER")
 def user(db, po, userId, message):
     user = db.getUser(userId)
-    if len(message.parameters) == 4 and not user.user:
-        user.user = message.parameters
+    if len(message.parameters) >= 4 and not user.user:
         username = message.parameters[0]
         hostname = message.parameters[1]
         servername = message.parameters[2]
-        realname = message.parameters[3]
+        realname = " ".join(message.parameters[3:])
+        if realname[0] == ":":
+            realname = realname[1:]
+
+        user.user = (username, hostname, servername, realname)
+
         po.send([userId], "NOTICE you are now registered as %s!%s@%s (%s)"%(
             username, hostname, servername, realname))
-    elif len(message.parameters) == 4 and user.user:
+    elif len(message.parameters) >= 4 and user.user:
         po.send([userId], irc.ERR_ALREADYREGISTRED)
     else:
         po.send([userId], irc.ERR_NEEDMOREPARAMS)
     channel = db.joinChannel(channelName)
     channel.join(userId)
     po.send([userId], "%s Topic: %s"%(irc.RPL_TOPIC, channel.topic))
-    po.send([userId], "%s %s"%(irc.RPL_NAMREPLY, " ".join([str(u) for u in channel.users])))
+    users = [db.getUser(u) for u in channel.users]
+    nicks = [u.nick for u in users]
+    po.send([userId], "%s %s"%(irc.RPL_NAMREPLY, " ".join(nicks)))
 
 # PART
 @registerCommand("PART")
 @registerCommand("PRIVMSG")
 def privMsg(db, po, userId, message):
     try:
+        user = db.getUser(userId)
         target = message.parameters[0]
         text = " ".join(message.parameters[1:])
         if target.startswith("#"):
             target = target.upper()
             channel = db.channelByName[target]
-            targetIds = channel.users
+            targetIds = [x for x in channel.users if x != userId]
+        elif "," in target:
+            targets = target.split(",")
+            targetIds = [db.nickToUserId[t] for t in targets]
         else:
             targetIds = [db.nickToUserId[target]]
-        po.send(targetIds, "PRIVMSG %s %s"%(target, text))
+        po.send(targetIds, ":%s PRIVMSG %s %s"%(user.nick, target, text))
     except:
         po.send([userId], irc.ERR_UNKNOWNCOMMAND)
         raise
     def addUser(self, socket, address):
         u = User(socket,
                  address)
+        self.socketToUser[socket] = u
         self.users[u.userId] = u
         return u.userId
 
     def getUser(self, userId):
         return self.users[userId]
 
+    def setNick(self, userId, newnick):
+        self.nicks.add(newnick)
+        self.nickToUserId[newnick] = userId
+        self.users[userId].nick = newnick
+
     def joinChannel(self, channelName):
         channelName = channelName.upper()
         if channelName not in self.channelByName:

noir/test/commands/test_channel.py

 from noir.test import mocks
 
 
+class TestTOPIC(unittest2.TestCase):
+    """TOPIC message is used to change or view the topic of a channel
+
+    to change:
+    TOPIC <channel> [<topic>]
+
+    to view:
+    TOPIC <channel>
+
+    RPL codes:
+
+    ERR_NEEDMOREPARAMS
+    ERR_NOTONCHANNEL
+    RPL_NOTOPIC
+    RPL_TOPIC
+    ERR_CHANOPRIVSNEEDED
+    """
+
+
+class TestNAMES(unittest2.TestCase):
+    """
+    list visible users in channels #a and #b:
+    NAMES #a,#b
+
+    list all visible channels and users:
+    NAMES
+    """
+
+
 class TestJOIN(unittest2.TestCase):
     """at least 9 test cases are in order
     as JOIN can return any of 9 RPL codes:
     """
     
     def setUp(self):
+        self.db = models.DB()
+        socket, address = "Fake", "127.0.0.1"
+        self.u1 = self.db.addUser(socket, address)
+        self.u2 = self.db.addUser(socket, address)
+        self.u3 = self.db.addUser(socket, address)
+        self.po = mocks.MockPo()
+        self.db.setNick(self.u1, "alpha")
+        self.db.setNick(self.u2, "bravo")
+        self.db.setNick(self.u3, "charlie")
         self.command = commands.COMMANDS["JOIN"]
+
+    def tearDown(self):
+        self.po.send.reset_mock()
+
+    def test_join_and_create(self):
+        m = messages.Message(":alpha", "JOIN", ["#alphabet"])
+        self.command(self.db, self.po, self.u1, m)
+        calls = self.po.send.call_args_list
+        self.assertEqual(calls, [
+            (([self.u1], "%s Topic: #ALPHABET"%(irc.RPL_TOPIC,)),
+             {}),
+            (([self.u1], "%s %s"%(irc.RPL_NAMREPLY, "alpha")),
+             {})
+            ])
+
+    def test_join_channel_with_2_users(self):
+        channel = self.db.joinChannel("#ALPHABET")
+        channel.join(self.u1)
+        channel.join(self.u2)
+        m = messages.Message(None, "JOIN", ["#alphabet"])
+        self.command(self.db, self.po, self.u3, m)
+        calls = self.po.send.call_args_list
+        self.assertEqual(calls, [
+            (([self.u3], "%s Topic: #ALPHABET"%(irc.RPL_TOPIC,)),
+             {}),
+            (([self.u3], "%s %s"%(irc.RPL_NAMREPLY, "alpha bravo charlie")),
+             {})
+            ])
+
+
+class TestPART(unittest2.TestCase):
+    """
+    PART <channel>[,<channel2>]
+
+    ERR_NEEDMOREPARAMS, ERR_NOSUCHCHANNEL
+    ERR_NOTONCHANNEL
+    """
+
+
+class TestLIST(unittest2.TestCase):
+    """Lists channels and their topics
+    LIST
+
+    LIST #a,#b
+    """
+
+

noir/test/commands/test_miscellaneous.py

+"""
+Misc commands
+
+PING
+PONG
+"""
+
+

noir/test/commands/test_optional.py

+"""
+Optional commands
+
+AWAY
+REHASH
+RESTART
+SUMMON
+USERS
+OPERWALL
+USERHOST
+ISON
+"""

noir/test/commands/test_registration.py

         self.command(self.db, self.po, self.u, m)
         self.po.send.assert_called_with([self.u], ":bingo NICK bingo")
 
+    def test_set_nick_data(self):
+        """Normal nick message without user prefix
+
+        So we're initially setting the users nick as part
+        of the registration process
+
+        """
+        m = messages.Message(None, "NICK", ["bingo"])
+        self.command(self.db, self.po, self.u, m)
+        user = self.db.getUser(self.u)
+        self.assertEqual(user.nick, "bingo")
+
     def test_set_nick_w_hopcount(self):
         """Hopcount is used to tell servers about nicknames on
         other servers.  The server will ignore the hopcount
         self.po.send.assert_called_with([self.u], irc.ERR_ERRONEUSNICKNAME)
 
 
+class TestUSER(unittest2.TestCase):
+    def setUp(self):
+        self.db = models.DB()
+        socket, address = "Fake", "127.0.0.1"
+        self.u = self.db.addUser(socket, address)
+        self.po = mocks.MockPo()
+        self.command = commands.COMMANDS["USER"]
+
+    def test_needMoreParameters_none(self):
+        m = messages.Message(None, "USER", [])
+        self.command(self.db, self.po, self.u, m)
+        self.po.send.assert_called_with([self.u], irc.ERR_NEEDMOREPARAMS)
+        
+    def test_needMoreParameters_3(self):
+        m = messages.Message(None, "USER", ["a", "b", "c"])
+        self.command(self.db, self.po, self.u, m)
+        self.po.send.assert_called_with([self.u], irc.ERR_NEEDMOREPARAMS)
+
+    def test_register_shortName(self):
+        m = messages.Message(None, "USER", ["guest", "hostname", "servername", "RealName" ])
+        self.command(self.db, self.po, self.u, m)
+        u = self.db.getUser(self.u)
+        self.assertEqual(u.user, ("guest", "hostname", "servername", "RealName"))
+
+    def test_register_alreadyRegistered(self):
+        m = messages.Message(None, "USER", ["guest", "hostname", "servername", "RealName" ])
+        self.command(self.db, self.po, self.u, m)
+        self.po.send.assert_called_with([self.u], "NOTICE you are now registered as %s!%s@%s (%s)"%("guest", "hostname", "servername", "RealName"))
+        self.command(self.db, self.po, self.u, m)
+        self.po.send.assert_called_with([self.u], irc.ERR_ALREADYREGISTRED)
+
+    def test_register_nameWithSpaces(self):
+        m = messages.Message(None, "USER", ["guest", "hostname", "servername", ":My", "Real", "Name", "With", "Spaces"])
+        self.command(self.db, self.po, self.u, m)
+        self.po.send.assert_called_with([self.u], "NOTICE you are now registered as %s!%s@%s (%s)"%("guest", "hostname", "servername", "My Real Name With Spaces"))
+        u = self.db.getUser(self.u)
+        self.assertEqual(u.user, ('guest', 'hostname', 'servername', 'My Real Name With Spaces'))
+

noir/test/commands/test_sending.py

+"""
+"""
+
+
+import unittest2
+
+from noir import commands
+from noir import irc
+from noir import messages
+from noir import models
+from noir.test import mocks
+
+
+class TestPRIVMSG(unittest2.TestCase):
+    """
+    PRIVMSG <receiver>[,<receiver2>] <text to be sent>
+
+    ERR_NORECIPIENT, ERR_NOTEXTTOSEND,
+    ERR_CANNOTSENDTOCHAN, ERR_NOTOPLEVEL,
+    ERR_WILDTOPLEVEL, ERR_TOOMANYTARGETS,
+    ERR_NOSUCHNICK
+    RPL_AWAY
+    """
+    def setUp(self):
+        self.db = models.DB()
+        socket, address = "Fake", "127.0.0.1"
+        self.u1 = self.db.addUser(socket, address)
+        self.u2 = self.db.addUser(socket, address)
+        self.u3 = self.db.addUser(socket, address)
+        self.po = mocks.MockPo()
+        self.command = commands.COMMANDS["PRIVMSG"]
+        self.db.setNick(self.u1, "alpha")
+        self.db.setNick(self.u2, "bravo")
+        self.db.setNick(self.u3, "charlie")
+
+    def test_alpha_to_bravo(self):
+        m = messages.Message(":alpha", "PRIVMSG",
+                             ["bravo", "hello", "how", "are", "you?"])
+        self.command(self.db, self.po, self.u1, m)
+        self.po.send.assert_called_with([self.u2], ":alpha PRIVMSG bravo hello how are you?")
+        
+    def test_bravo_to_alpha(self):
+        m = messages.Message(":bravo", "PRIVMSG",
+                             ["alpha", "hello", "how", "are", "you?"])
+        self.command(self.db, self.po, self.u2, m)
+        self.po.send.assert_called_with([self.u1], ":bravo PRIVMSG alpha hello how are you?")
+
+    def test_alpha_to_charlie_bravo(self):
+        m = messages.Message(":alpha", "PRIVMSG",
+                             ["charlie,bravo", "hello", "how", "are", "you", "guys?"])
+        self.command(self.db, self.po, self.u1, m)
+        self.po.send.assert_called_with([self.u3, self.u2], ":alpha PRIVMSG charlie,bravo hello how are you guys?")
+
+    def test_alpha_to_bravo_charlie(self):
+        m = messages.Message(":alpha", "PRIVMSG",
+                             ["bravo,charlie", "hello", "how", "are", "you", "guys?"])
+        self.command(self.db, self.po, self.u1, m)
+        self.po.send.assert_called_with([self.u2, self.u3], ":alpha PRIVMSG bravo,charlie hello how are you guys?")
+
+    def test_alpha_to_channel_alphabet(self):
+        """#alphabet contains, alpha, bravo, and charlie
+
+        """
+        channel = self.db.joinChannel("#ALPHABET")
+        channel.join(self.u1)
+        channel.join(self.u2)
+        channel.join(self.u3)
+        m = messages.Message(":alpha", "PRIVMSG",
+                             ["#alphabet", "how", "is", "everyone?"])
+        self.command(self.db, self.po, self.u1, m)
+        self.po.send.assert_called_with([self.u2, self.u3], ":alpha PRIVMSG #ALPHABET how is everyone?")
+        
+
+
+class TestNOTICE(unittest2.TestCase):
+    """Duplicate of PRIVMSG essentially except
+    replies must never be sent in response to a notice.
+
+    So basically, this should allow you to send any message
+    you like but you'll receive no reply indicating success
+    or failure of the message.
+
+    """

noir/test/commands/test_server.py

+"""
+"""
+
+
+import unittest2
+
+from noir import commands
+from noir import irc
+from noir import messages
+from noir import models
+from noir.test import mocks
+
+
+class TestVERSION(unittest2.TestCase):
+    """Reports version of the IRC server
+
+    :msteder VERSION  ; returns version of this server
+
+    VERSION irc.freenode.org  ; returns version of irc.freenode.org
+
+    ERR_NOSUCHSERVER, RPL_VERSION
+
+    """
+
+
+class TestTIME(unittest2.TestCase):
+    """Reports local time of server
+
+    TIME
+
+    ERR_NOSUCHSERVER, RPL_TIME
+
+    """
+
+
+class TestADMIN(unittest2.TestCase):
+    """
+    """
+
+
+class TestINFO(unittest2.TestCase):
+    """
+    """

noir/test/commands/test_user.py

+"""
+User commands
+"""
+
+
+import unittest2
+
+from noir import commands
+from noir import irc
+from noir import messages
+from noir import models
+from noir.test import mocks
+
+
+class TestWHO(unittest2.TestCase):
+    """returns users that match query parameter
+
+    WHO [<name> [<o>]]
+
+    WHO *.fi ; list all users that match *.fi
+
+    WHO jto* o ; list all users matching jto* if they are an operator
+    
+    ERR_NOSUCHSERVER,
+    RPL_WHOREPLY,
+    RPL_ENDOFWHO
+
+    """

noir/test/test_models.py

+"""
+"""
+
+
+import unittest2
+
+
+from noir import models
+
+
+class TestAddingUsers(unittest2.TestCase):
+    def setUp(self):
+        self.db = models.DB()
+        self.socket, self.address = "fake socket", "localhost"
+        self.newUserId = self.db.addUser(self.socket, self.address)
+
+    def test_getUser(self):
+        user = self.db.getUser(self.newUserId)
+        self.assertEqual(user.userId, self.newUserId)
+        self.assertEqual(user.socket, "fake socket")
+        self.assertEqual(user.address, "localhost")
+
+    def test_getUserBySocket(self):
+        user = self.db.socketToUser[self.socket]
+        self.assertEqual(user.userId, self.newUserId)
+
+    def test_numberOfUsers(self):
+        self.assertEqual(len(self.db.users), 1)
+
+class TestSetNick(unittest2.TestCase):
+    def setUp(self):
+        self.db = models.DB()
+        self.socket, self.address = "fake socket", "localhost"
+        self.newUserId = self.db.addUser(self.socket, self.address)
+        self.db.setNick(self.newUserId, "bingo")        
+
+    def test_includedInNicksSet(self):
+        self.assertEqual(self.db.nicks, set(["bingo"]))
+
+    def test_mappingToUserId(self):
+        self.assertEqual(self.db.nickToUserId["bingo"], self.newUserId)
+
+    def test_userNick(self):
+        user = self.db.getUser(self.newUserId)
+        self.assertEqual(user.nick, "bingo")