From 41d266f207a55a13210d05f88149aab2adf7eae7 Mon Sep 17 00:00:00 2001 From: Jeremy Fincher Date: Fri, 12 Sep 2003 20:06:58 +0000 Subject: [PATCH] Updated ircdb to have persistent user ids. --- plugins/ChannelDB.py | 18 +-- plugins/Factoids.py | 3 +- plugins/FunDB.py | 6 +- plugins/Topic.py | 6 +- scripts/setup.py | 8 +- src/AdminCommands.py | 14 ++- src/ChannelCommands.py | 14 ++- src/UserCommands.py | 64 ++++++----- src/asyncoreDrivers.py | 3 +- src/ircdb.py | 256 ++++++++++++++++++++++------------------- src/irclib.py | 31 +++-- src/twistedDrivers.py | 3 +- test/test_ircdb.py | 72 ++++++------ 13 files changed, 261 insertions(+), 237 deletions(-) diff --git a/plugins/ChannelDB.py b/plugins/ChannelDB.py index ccb0944b0..709ed4e33 100644 --- a/plugins/ChannelDB.py +++ b/plugins/ChannelDB.py @@ -148,7 +148,7 @@ class ChannelDB(callbacks.PrivmsgCommandAndRegexp, ChannelDBHandler): actions=actions+%s""", smileys, frowns, chars, words, int(isAction)) try: - name = ircdb.users.getUserName(msg.prefix) + name = ircdb.users.getUser(msg.prefix).name except KeyError: return cursor.execute("""SELECT COUNT(*) @@ -181,7 +181,7 @@ class ChannelDB(callbacks.PrivmsgCommandAndRegexp, ChannelDBHandler): cursor.execute("""UPDATE channel_stats SET joins=joins+1""") try: if ircutils.isUserHostmask(msg.prefix): - name = ircdb.users.getUserName(msg.prefix) + name = ircdb.users.getUser(msg.prefix).name else: name = msg.prefix cursor.execute("""UPDATE user_stats @@ -198,7 +198,7 @@ class ChannelDB(callbacks.PrivmsgCommandAndRegexp, ChannelDBHandler): cursor.execute("""UPDATE channel_stats SET parts=parts+1""") try: if ircutils.isUserHostmask(msg.prefix): - name = ircdb.users.getUserName(msg.prefix) + name = ircdb.users.getUser(msg.prefix).name else: name = msg.prefix cursor.execute("UPDATE user_stats SET parts=parts+1 WHERE name=%s", @@ -214,7 +214,7 @@ class ChannelDB(callbacks.PrivmsgCommandAndRegexp, ChannelDBHandler): cursor.execute("""UPDATE channel_stats SET topics=topics+1""") try: if ircutils.isUserHostmask(msg.prefix): - name = ircdb.users.getUserName(msg.prefix) + name = ircdb.users.getUser(msg.prefix).name else: name = msg.prefix cursor.execute("""UPDATE user_stats @@ -231,7 +231,7 @@ class ChannelDB(callbacks.PrivmsgCommandAndRegexp, ChannelDBHandler): cursor.execute("""UPDATE channel_stats SET modes=modes+1""") try: if ircutils.isUserHostmask(msg.prefix): - name = ircdb.users.getUserName(msg.prefix) + name = ircdb.users.getUser(msg.prefix).name else: name = msg.prefix cursor.execute("""UPDATE user_stats @@ -248,7 +248,7 @@ class ChannelDB(callbacks.PrivmsgCommandAndRegexp, ChannelDBHandler): cursor.execute("""UPDATE channel_stats SET kicks=kicks+1""") try: if ircutils.isUserHostmask(msg.prefix): - name = ircdb.users.getUserName(msg.prefix) + name = ircdb.users.getUser(msg.prefix).name else: name = msg.prefix cursor.execute("""UPDATE user_stats @@ -258,7 +258,7 @@ class ChannelDB(callbacks.PrivmsgCommandAndRegexp, ChannelDBHandler): pass try: kicked = msg.args[1] - name = ircdb.users.getUserName(irc.state.nickToHostmask(kicked)) + name = ircdb.users.getUser(irc.state.nickToHostmask(kicked)).name cursor.execute("""UPDATE user_stats SET kicked=kicked+1 WHERE name=%s""", name) @@ -278,7 +278,7 @@ class ChannelDB(callbacks.PrivmsgCommandAndRegexp, ChannelDBHandler): if not ircdb.users.hasUser(name): try: hostmask = irc.state.nickToHostmask(name) - name = ircdb.users.getUserName(hostmask) + name = ircdb.users.getUser(hostmask).name except KeyError: irc.error(msg, conf.replyNoUser) return @@ -369,7 +369,7 @@ class ChannelDB(callbacks.PrivmsgCommandAndRegexp, ChannelDBHandler): if not ircdb.users.hasUser(name): hostmask = irc.state.nickToHostmask(name) try: - name = ircdb.users.getUserName(hostmask) + name = ircdb.users.getUser(hostmask).name except KeyError: irc.error(msg, conf.replyNoUser) return diff --git a/plugins/Factoids.py b/plugins/Factoids.py index 7748d278c..cadfa07c9 100644 --- a/plugins/Factoids.py +++ b/plugins/Factoids.py @@ -144,7 +144,7 @@ class Factoids(ChannelDBHandler, callbacks.Privmsg): irc.error(msg, conf.replyNoCapability % capability) return if ircdb.users.hasUser(msg.prefix): - name = ircdb.users.getUserName(msg.prefix) + name = ircdb.users.getUser(msg.prefix).name else: name = msg.nick cursor.execute("""INSERT INTO factoids VALUES @@ -364,6 +364,7 @@ class Factoids(ChannelDBHandler, callbacks.Privmsg): utils.nItems(cursor.rowcount, 'key')) else: irc.reply(msg, s) + Class = Factoids # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/plugins/FunDB.py b/plugins/FunDB.py index 1ecb439e5..3e2b92f83 100755 --- a/plugins/FunDB.py +++ b/plugins/FunDB.py @@ -262,7 +262,7 @@ class FunDB(callbacks.Privmsg): (table, s) = privmsgs.getArgs(args, needed=2) table = table.lower() try: - name = ircdb.users.getUserName(msg.prefix) + name = ircdb.users.getUser(msg.prefix).name except KeyError: irc.error(msg, conf.replyNotRegistered) return @@ -295,7 +295,7 @@ class FunDB(callbacks.Privmsg): (table, id) = privmsgs.getArgs(args, needed=2) table = table.lower() try: - ircdb.users.getUserName(msg.prefix) + ircdb.users.getUser(msg.prefix).name except KeyError: irc.error(msg, conf.replyNotRegistered) return @@ -464,7 +464,7 @@ class FunDB(callbacks.Privmsg): irc.queueMsg(ircmsgs.action(channel, '%s for %s (#%s)' %\ (praise, reason, id))) else: - irc.queueMsg(ircmsgs.action(channel, '%s (#%s)' % (praise, id))) + irc.queueMsg(ircmsgs.action(channel, '%s (#%s)' %(praise, id))) raise callbacks.CannotNest def addword(self, irc, msg, args): diff --git a/plugins/Topic.py b/plugins/Topic.py index 73d488a9b..b2f69cc95 100644 --- a/plugins/Topic.py +++ b/plugins/Topic.py @@ -84,7 +84,7 @@ class Topic(callbacks.Privmsg): return currentTopic = irc.state.getTopic(channel) try: - name = ircdb.users.getUserName(msg.prefix) + name = ircdb.users.getUser(msg.prefix).name except KeyError: name = msg.nick formattedTopic = self.topicFormatter % (topic, name) @@ -166,7 +166,7 @@ class Topic(callbacks.Privmsg): else: (topic, name) = match.groups() try: - senderName = ircdb.users.getUserName(msg.prefix) + senderName = ircdb.users.getUser(msg.prefix).name except KeyError: irc.error(msg, conf.replyNoUser) return @@ -208,7 +208,7 @@ class Topic(callbacks.Privmsg): else: (topic, name) = match.groups() try: - username = ircdb.users.getUserName(msg.prefix) + username = ircdb.users.getUser(msg.prefix).name except KeyError: username = msg.nick if name and name != username and \ diff --git a/scripts/setup.py b/scripts/setup.py index 2e0c28356..676ecdef5 100644 --- a/scripts/setup.py +++ b/scripts/setup.py @@ -130,8 +130,7 @@ if __name__ == '__main__': filenames.extend(os.listdir(dir)) plugins = [] for filename in filenames: - if filename.endswith('.py') and \ - filename.lower() != filename: + if filename.endswith('.py') and filename[0].isupper(): plugins.append(os.path.splitext(filename)[0]) plugins.sort() if yn('Would you like to see a list of the available modules?') == 'y': @@ -201,12 +200,13 @@ if __name__ == '__main__': if yn('Would you like to add an owner user?') == 'y': owner = something('What should the owner\'s username be?') password = something('What should the owner\'s password be?') - user = ircdb.IrcUser() + (id, user) = ircdb.users.newUser() user.setPassword(password) + user.names.add(owner) user.addCapability('owner') while yn('Would you like to add a hostmask for the owner?') == 'y': user.addHostmask(something('What hostmask?')) - ircdb.users.setUser(owner, user) + ircdb.users.setUser(id, user) ### # Configuration variables in conf.py. diff --git a/src/AdminCommands.py b/src/AdminCommands.py index db9e229b0..181d107e0 100755 --- a/src/AdminCommands.py +++ b/src/AdminCommands.py @@ -136,9 +136,10 @@ class AdminCommands(privmsgs.CapabilityCheckingPrivmsg): if ircdb.checkCapability(msg.prefix, capability) or \ '!' in capability: try: - u = ircdb.users.getUser(name) - u.addCapability(capability) - ircdb.users.setUser(name, u) + id = ircdb.users.getUserId(name) + user = ircdb.users.getUser(id) + user.addCapability(capability) + ircdb.users.setUser(id, user) irc.reply(msg, conf.replySuccess) except KeyError: irc.error(msg, conf.replyNoUser) @@ -156,9 +157,10 @@ class AdminCommands(privmsgs.CapabilityCheckingPrivmsg): if ircdb.checkCapability(msg.prefix, capability) or \ '!' in capability: try: - u = ircdb.users.getUser(name) - u.addCapability(capability) - ircdb.users.setUser(name, u) + id = ircdb.users.getUserId(name) + user = ircdb.users.getUser(id) + user.addCapability(capability) + ircdb.users.setUser(id, user) irc.reply(msg, conf.replySuccess) except KeyError: irc.error(msg, conf.replyNoUser) diff --git a/src/ChannelCommands.py b/src/ChannelCommands.py index 27a33d2aa..64ca9d81d 100755 --- a/src/ChannelCommands.py +++ b/src/ChannelCommands.py @@ -256,9 +256,10 @@ class ChannelCommands(callbacks.Privmsg): capability = ircdb.makeChannelCapability(channel, capability) if ircdb.checkCapability(msg.prefix, neededcapability): try: - u = ircdb.users.getUser(name) - u.addCapability(capability) - ircdb.users.setUser(name, u) + id = ircdb.users.getUserId(name) + user = ircdb.users.getUser(id) + user.addCapability(capability) + ircdb.users.setUser(id, user) irc.reply(msg, conf.replySuccess) except KeyError: irc.error(msg, conf.replyNoUser) @@ -280,9 +281,10 @@ class ChannelCommands(callbacks.Privmsg): capability = ircdb.makeChannelCapability(channel, capability) if ircdb.checkCapability(msg.prefix, neededcapability): try: - u = ircdb.users.getUser(name) - u.removeCapability(capability) - ircdb.users.setUser(name, u) + id = ircdb.users.getUser(name) + user = ircdb.users.getUser(id) + user.removeCapability(capability) + ircdb.users.setUser(id, user) irc.reply(msg, conf.replySuccess) except KeyError: irc.error(msg, conf.replyNoUser) diff --git a/src/UserCommands.py b/src/UserCommands.py index 8ad90128a..a32e3a202 100755 --- a/src/UserCommands.py +++ b/src/UserCommands.py @@ -36,6 +36,7 @@ Provides commands useful to users in general. This plugin is loaded by default. import string import conf +import utils import ircdb import ircutils import privmsgs @@ -61,16 +62,20 @@ class UserCommands(callbacks.Privmsg): if ircutils.isChannel(msg.args[0]): irc.error(msg, conf.replyRequiresPrivacy) return - if ircdb.users.hasUser(name): - irc.error(msg, 'That name is already registered.') + try: + ircdb.users.getUserId(name) + irc.error(msg, 'That name is alrady assigned to someone.') return + except KeyError: + pass if ircutils.isUserHostmask(name): irc.error(msg, 'Hostmasks aren\'t valid usernames.') return - user = ircdb.IrcUser() + (id, user) = ircdb.users.newUser() + user.name = name user.setPassword(password) user.addHostmask(msg.prefix) - ircdb.users.setUser(name, user) + ircdb.users.setUser(id, user) irc.reply(msg, conf.replySuccess) def addhostmask(self, irc, msg, args): @@ -92,20 +97,20 @@ class UserCommands(callbacks.Privmsg): irc.error(msg, s) return try: - user = ircdb.users.getUser(name) + id = ircdb.users.getUserId(name) + user = ircdb.users.getUser(id) except KeyError: irc.error(msg, conf.replyNoUser) return try: - name = ircdb.users.getUserName(hostmask) - s = 'That hostmask is already registered to %s.' % name - irc.error(msg, s) + _ = ircdb.users.getUserId(hostmask) + irc.error(msg, 'That hostmask is already registered.') return except KeyError: pass if user.checkHostmask(msg.prefix) or user.checkPassword(password): user.addHostmask(hostmask) - ircdb.users.setUser(name, user) + ircdb.users.setUser(id, user) irc.reply(msg, conf.replySuccess) else: irc.error(msg, conf.replyIncorrectAuth) @@ -122,13 +127,14 @@ class UserCommands(callbacks.Privmsg): if not self._checkNotChannel(irc, msg, password): return try: - user = ircdb.users.getUser(name) + id = ircdb.users.getUserId(name) + user = ircdb.users.getUser(id) except KeyError: irc.error(msg, conf.replyNoUser) return if user.checkHostmask(msg.prefix) or user.checkPassword(password): user.removeHostmask(hostmask) - ircdb.users.setUser(name, user) + ircdb.users.setUser(id, user) irc.reply(msg, conf.replySuccess) else: irc.error(msg, conf.replyIncorrectAuth) @@ -144,13 +150,14 @@ class UserCommands(callbacks.Privmsg): if not self._checkNotChannel(irc, msg, oldpassword+newpassword): return try: - user = ircdb.users.getUser(name) + id = ircdb.users.getUserId(name) + user = ircdb.users.getUser(id) except KeyError: irc.error(msg, conf.replyNoUser) return if user.checkPassword(oldpassword): user.setPassword(newpassword) - ircdb.users.setUser(name, user) + ircdb.users.setUser(id, user) irc.reply(msg, conf.replySuccess) else: irc.error(msg, conf.replyIncorrectAuth) @@ -169,8 +176,8 @@ class UserCommands(callbacks.Privmsg): irc.error(msg, conf.replyNoUser) return try: - name = ircdb.users.getUserName(hostmask) - irc.reply(msg, name) + user = ircdb.users.getUser(hostmask) + irc.reply(msg, user.name) except KeyError: irc.error(msg, conf.replyNoUser) @@ -197,11 +204,7 @@ class UserCommands(callbacks.Privmsg): isn't specified, returns the hostmasks of the user calling the command. """ if not args: - try: - name = ircdb.users.getUserName(msg.prefix) - except KeyError: - irc.error(msg, conf.replyNoUser) - return + name = msg.prefix else: name = privmsgs.getArgs(args) try: @@ -219,13 +222,14 @@ class UserCommands(callbacks.Privmsg): if not self._checkNotChannel(irc, msg): return try: - u = ircdb.users.getUser(name) + id = ircdb.users.getUserId(name) + user = ircdb.users.getUser(id) except KeyError: irc.error(msg, conf.replyNoUser) return - if u.checkPassword(password): - u.setAuth(msg.prefix) - ircdb.users.setUser(name, u) + if user.checkPassword(password): + user.setAuth(msg.prefix) + ircdb.users.setUser(id, user) irc.reply(msg, conf.replySuccess) else: irc.error(msg, conf.replyIncorrectAuth) @@ -236,13 +240,13 @@ class UserCommands(callbacks.Privmsg): Un-identifies the user. """ try: - u = ircdb.users.getUser(msg.prefix) - name = ircdb.users.getUserName(msg.prefix) + id = ircdb.users.getUserId(msg.prefix) + user = ircdb.users.getUser(id) except KeyError: irc.error(msg, conf.replyNoUser) return - u.unsetAuth() - ircdb.users.setUser(name, u) + user.unsetAuth() + ircdb.users.setUser(id, user) irc.reply(msg, conf.replySuccess) def whoami(self, irc, msg, args): @@ -251,8 +255,8 @@ class UserCommands(callbacks.Privmsg): Returns the name of the user calling the command. """ try: - name = ircdb.users.getUserName(msg.prefix) - irc.reply(msg, name) + user = ircdb.users.getUser(msg.prefix) + irc.reply(msg, user.name) except KeyError: irc.error(msg, conf.replyNotRegistered) diff --git a/src/asyncoreDrivers.py b/src/asyncoreDrivers.py index 2c2fa66f2..28601eedd 100644 --- a/src/asyncoreDrivers.py +++ b/src/asyncoreDrivers.py @@ -182,7 +182,8 @@ Name: """ % (world.version, sys.version.translate(string.ascii, '\r\n')) try: name = self.buffer self.buffer = '' - self.u = ircdb.users.getUser(name) + id = ircdb.users.getUserId(name) + self.u = ircdb.users.getUser(id) self.prompt = 'Password: ' except KeyError: self.push('Unknown user.\n') diff --git a/src/ircdb.py b/src/ircdb.py index 544078ec8..4e4b9aba0 100644 --- a/src/ircdb.py +++ b/src/ircdb.py @@ -34,11 +34,11 @@ from fix import * import os import sets import time -import atexit import string import conf import debug +import utils import world import ircutils @@ -158,9 +158,10 @@ class UserCapabilitySet(CapabilitySet): class IrcUser(object): """This class holds the capabilities and authentications for a user. """ - def __init__(self, ignore=False, password='', auth=None, + def __init__(self, ignore=False, password='', name='', capabilities=(), hostmasks=None): - self.auth = auth # The (time, hostmask) a user authenticated under. + self.auth = None # The (time, hostmask) a user authenticated under + self.name = name # The name of the user. self.ignore = ignore # A boolean deciding if the person is ignored. self.password = password # password (plaintext? hashed?) self.capabilities = UserCapabilitySet() @@ -172,10 +173,10 @@ class IrcUser(object): self.hostmasks = hostmasks def __repr__(self): - return '%s(ignore=%s, auth=%r, password=%r, '\ + return '%s(ignore=%s, password=%r, name=%r, '\ 'capabilities=%r, hostmasks=%r)\n' %\ - (self.__class__.__name__, self.ignore, self.auth, - self.password, self.capabilities, self.hostmasks) + (self.__class__.__name__, self.ignore, self.password, + self.name, self.capabilities, self.hostmasks) def addCapability(self, capability): self.capabilities.add(capability) @@ -315,103 +316,139 @@ class IrcChannel(object): return True return False - -class UsersDictionary(object): +class UsersDB(object): def __init__(self, filename): self.filename = filename - fd = file(filename, 'r') - s = fd.read() - fd.close() - Set = sets.Set - ignore(Set) # Make PyChecker happy. - self.dict = eval(normalize(s)) - self.cache = {} # hostmasks to nicks. - self.revcache = ircutils.IrcDict() # nicks to hostmasks. - - def resetCache(self, s): - if s in self.cache: - # it's a hostmask. - name = self.cache[s] - del self.cache[s] + if os.path.exists(filename): + fd = file(filename, 'r') + s = fd.read() + fd.close() + IrcSet = ircutils.IrcSet + (self.nextId, self.users) = eval(normalize(s)) else: - # it's already a name. - name = s - # name should always be in self.revcache, this should never KeyError. - if name in self.revcache: - for hostmask in self.revcache[name]: - del self.cache[hostmask] - del self.revcache[name] - - def setCache(self, hostmask, name): - self.cache[hostmask] = name - self.revcache.setdefault(name, []).append(hostmask) - - def getUser(self, s): - if ircutils.isUserHostmask(s): - name = self.getUserName(s) - else: - name = s - return self.dict[name] - - def setUser(self, s, u): - # First, invalidate the cache for this user. - self.resetCache(s) - if ircutils.isUserHostmask(s): - name = self.getUserName(s) - else: - name = s - for hostmask in u.hostmasks: - try: - username = self.getUserName(hostmask) - if username != name: - raise ValueError, 'User has hostmasks already matching ' \ - 'another user\'s hostmasks.' - except KeyError: - pass - self.dict[name] = u - - def hasUser(self, s): - return (s in self.dict) - - def delUser(self, s): - if ircutils.isUserHostmask(s): - name = self.getUserName(s) - else: - name = s - self.resetCache(name) - try: - del self.dict[name] - except KeyError: - pass - - def getUserName(self, s): - assert ircutils.isUserHostmask(s), 'string must be a hostmask' - if s in self.cache: - return self.cache[s] - else: - for (name, user) in self.dict.iteritems(): - if user.checkHostmask(s): - self.cache[s] = name - self.revcache.setdefault(name,[]).append(s) - return name - raise KeyError, s - - def flush(self): - fd = file(self.filename, 'w') - fd.write(repr(self.dict)) - fd.close() + self.nextId = 1 + self.users = [IrcUser(capabilities=['owner'], + password=utils.mktemp())] + self._nameCache = {} + self._hostmaskCache = {} def reload(self): self.__init__(self.filename) + def flush(self): + fd = file(self.filename, 'w') + fd.write(repr((self.nextId, self.users))) + fd.close() + + def getUserId(self, s): + if ircutils.isUserHostmask(s): + try: + return self._hostmaskCache[s] + except KeyError: + ids = [] + for (id, user) in enumerate(self.users): + if user is None: + continue + if user.checkHostmask(s): + ids.append(id) + if len(ids) == 1: + id = ids[0] + self._hostmaskCache[s] = id + self._hostmaskCache.setdefault(id, sets.Set()).add(s) + return id + elif len(ids) == 0: + raise KeyError, s + else: + raise ValueError, 'Ids %r matched.' % ids + else: # Not a hostmask, must be a name. + try: + return self._nameCache[s] + except KeyError: + for (id, user) in enumerate(self.users): + if user is None: + continue + if s == user.name: + self._nameCache[s] = id + self._nameCache.setdefault(id, sets.Set()).add(s) + return id + else: + raise KeyError, s + + def getUser(self, id): + if not isinstance(id, int): + # Must be a string. Get the UserId first. + id = self.getUserId(id) + try: + ret = self.users[id] + if ret is None: + raise KeyError, id + return ret + except IndexError: + raise KeyError, id + + def hasUser(self, id): + try: + self.getUser(id) + return True + except KeyError: + return False + + def setUser(self, id, user): + assert isinstance(id, int), 'setUser takes an integer userId.' + if not 0 <= id < len(self.users) or self.users[id] is None: + raise KeyError, id + try: + if self.getUserId(user.name) != id: + raise ValueError, \ + '%s is already registered to someone else.' % user.name + except KeyError: + pass + for hostmask in user.hostmasks: + try: + if self.getUserId(hostmask) != id: + raise ValueError, \ + '%s is already registered to someone else.'% hostmask + except KeyError: + continue + if id in self._nameCache: + for name in self._nameCache[id]: + del self._nameCache[name] + del self._nameCache[id] + if id in self._hostmaskCache: + for hostmask in self._hostmaskCache[id]: + del self._hostmaskCache[hostmask] + del self._hostmaskCache[id] + ### FIXME: what if the new hostmasks overlap with another hostmask? + self.users[id] = user + + def delUser(self, id): + if not 0 <= id < len(self.users) or self.users[id] is None: + raise KeyError, id + self.users[id] = None + for name in self._nameCache.get(id, []): + del self._nameCache[name] + for hostmask in self._hostmaskCache.get(id, []): + del self._hostmaskCache[hostmask] + + def newUser(self): + user = IrcUser() + id = self.nextId + self.nextId += 1 + self.users.append(user) + return (id, user) + + class ChannelsDictionary(object): def __init__(self, filename): self.filename = filename - fd = file(filename, 'r') - s = fd.read() - fd.close() - Set = sets.Set - self.dict = eval(normalize(s)) + if os.path.exists(filename): + fd = file(filename, 'r') + s = fd.read() + fd.close() + Set = sets.Set + self.dict = eval(normalize(s)) + else: + self.dict = {} def getChannel(self, channel): channel = channel.lower() @@ -438,26 +475,9 @@ class ChannelsDictionary(object): ### # Later, I might add some special handling for botnet. ### -if not os.path.exists(conf.userfile): - fd = open(conf.userfile, 'w') - fd.write('{}') - fd.close() -users = UsersDictionary(conf.userfile) - -if not os.path.exists(conf.channelfile): - fd = file(conf.channelfile, 'w') - fd.write('{}') - fd.close() +users = UsersDB(conf.userfile) channels = ChannelsDictionary(conf.channelfile) -def flushUsers(): - for (name, u) in users.dict.iteritems(): - u.unsetAuth() - users.flush() - -atexit.register(flushUsers) -atexit.register(channels.flush) - world.flushers.append(users.flush) world.flushers.append(channels.flush) @@ -473,7 +493,8 @@ def checkIgnored(hostmask, recipient='', users=users, channels=channels): if ircutils.hostmaskPatternEqual(ignore, hostmask): return True try: - user = users.getUser(hostmask) + id = users.getUserId(hostmask) + user = users.getUser(id) except KeyError: # If there's no user... if ircutils.isChannel(recipient): @@ -507,7 +528,8 @@ def checkCapability(hostmask, capability, users=users, channels=channels): #debug.printf('world.startup is active.') return _x(capability, True) try: - u = users.getUser(hostmask) + id = users.getUserId(hostmask) + u = users.getUser(id) except KeyError: #debug.printf('user could not be found.') if isChannelCapability(capability): @@ -582,13 +604,5 @@ def checkCapabilities(hostmask, capabilities, requireAll=False): else: return False -def getUser(irc, s): - if ircutils.isUserHostmask(s): - return users.getUserName(s) - else: - if users.hasUser(s): - return s - else: - return users.getUserName(irc.state.nickToHostmask(s)) # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/src/irclib.py b/src/irclib.py index f40249e81..c70ea171f 100644 --- a/src/irclib.py +++ b/src/irclib.py @@ -438,8 +438,10 @@ class Irc(object): # it to abuse our 'owner' power we give to ourselves. Ergo, on # outgoing messages that change our nick, we pre-emptively # delete the 'owner' user we setup for ourselves. - if ircdb.users.hasUser(self.nick): - ircdb.users.delUser(self.nick) + user = ircdb.users.getUser(0) + user.unsetAuth() + user.hostmasks = [] + ircdb.users.setUser(0, user) return msg else: return None @@ -455,10 +457,10 @@ class Irc(object): args=msg.args) # First, make sure self.nick is always consistent with the server. if msg.command == 'NICK' and msg.nick == self.nick: - if ircdb.users.hasUser(self.nick): - ircdb.users.delUser(self.nick) - if ircdb.users.hasUser(self.prefix): - ircdb.users.delUser(self.prefix) + user = ircdb.users.getUser(0) + user.unsetAuth() + user.hostmasks = [] + ircdb.users.setUser(0, user) self.nick = msg.args[0] (nick, user, domain) = ircutils.splitHostmask(msg.prefix) self.prefix = '%s!%s@%s' % (self.nick, user, domain) @@ -472,17 +474,12 @@ class Irc(object): self.sendMsg(ircmsgs.nick(self._nickmods.pop(0) % self.nick)) if msg.nick == self.nick: self.prefix = msg.prefix - if ircdb.users.hasUser(self.nick): - u = ircdb.users.getUser(self.nick) - if not u.hasHostmask(msg.prefix): - u.addHostmask(msg.prefix) - ircdb.users.setUser(self.nick, u) - else: - u = ircdb.IrcUser(capabilities=['owner'], - password=utils.mktemp(), - hostmasks=[msg.prefix]) - ircdb.users.setUser(self.nick, u) - atexit.register(lambda: catch(ircdb.users.delUser(self.nick))) + user = ircdb.users.getUser(0) + user.hostmasks = [] + user.name = self.nick + user.addHostmask(msg.prefix) + user.setPassword(utils.mktemp()) + ircdb.users.setUser(0, user) if msg.command == 'ERROR': if msg.args[0].startswith('Closing Link'): if hasattr(self.driver, 'scheduleReconnect'): diff --git a/src/twistedDrivers.py b/src/twistedDrivers.py index acaca3f6b..a9d76e069 100644 --- a/src/twistedDrivers.py +++ b/src/twistedDrivers.py @@ -103,7 +103,8 @@ class MyShell(Shell): debug.printf(repr(username)) debug.printf(repr(password)) try: - u = ircdb.users.getUser(username) + id = ircdb.users.getUserId(username) + u = ircdb.users.getUser(id) debug.printf(u) if u.checkPassword(password) and u.checkCapability('owner'): debug.printf('returning True') diff --git a/test/test_ircdb.py b/test/test_ircdb.py index bbd69a7e7..c31e36f1f 100644 --- a/test/test_ircdb.py +++ b/test/test_ircdb.py @@ -255,34 +255,32 @@ class IrcChannelTestCase(unittest.TestCase): c.removeBan(banmask) self.failIf(c.checkIgnored(prefix)) -class UsersDictionaryTestCase(unittest.TestCase): - filename = 'UsersDictionaryTestCase.conf' +class UsersDBTestCase(unittest.TestCase): + filename = 'UsersDBTestCase.conf' def setUp(self): - fd = file(self.filename, 'w') - fd.write('{}\n') - fd.close() - self.users = ircdb.UsersDictionary(self.filename) - - def tearDown(self): - os.remove(self.filename) + try: + os.remove(self.filename) + except: + pass + self.users = ircdb.UsersDB(self.filename) def testGetSetDelUser(self): self.assertRaises(KeyError, self.users.getUser, 'foo') self.assertRaises(KeyError, self.users.getUser, 'foo!bar@baz') - u = ircdb.IrcUser() + (id, u) = self.users.newUser() hostmask = 'foo!bar@baz' banmask = ircutils.banmask(hostmask) u.addHostmask(banmask) - self.users.setUser('foo', u) + u.name = 'foo' + self.users.setUser(id, u) self.assertEqual(self.users.getUser('foo'), u) self.assertEqual(self.users.getUser(hostmask), u) self.assertEqual(self.users.getUser(banmask), u) - # The UsersDictionary shouldn't allow users to be added whose hostmasks + # The UsersDB shouldn't allow users to be added whose hostmasks # match another user's already in the database. - self.assertRaises(ValueError, self.users.setUser, 'bar', u) - u.removeHostmask(banmask) - u.addHostmask('*!*@*') - self.assertRaises(ValueError, self.users.setUser, 'biff', u) + (id, u2) = self.users.newUser() + u2.addHostmask('*!*@*') + self.assertRaises(ValueError, self.users.setUser, id, u2) class CheckCapabilityTestCase(unittest.TestCase): @@ -304,40 +302,44 @@ class CheckCapabilityTestCase(unittest.TestCase): channelanticap = ircdb.IrcChannel() channelanticap.addCapability(anticap) def setUp(self): - fd = file(self.filename, 'w') - fd.write('{}\n') - fd.close() - self.users = ircdb.UsersDictionary(self.filename) + try: + os.remove(self.filename) + except: + pass + self.users = ircdb.UsersDB(self.filename) self.channels = ircdb.ChannelsDictionary(self.filename) - owner = ircdb.IrcUser() + (id, owner) = self.users.newUser() + owner.name = 'owner' owner.addCapability('owner') owner.addHostmask(self.owner) - self.users.setUser('owner', owner) - nothing = ircdb.IrcUser() + self.users.setUser(id, owner) + (id, nothing) = self.users.newUser() + nothing.name = 'nothing' nothing.addHostmask(self.nothing) - self.users.setUser('nothing', nothing) - justfoo = ircdb.IrcUser() + self.users.setUser(id, nothing) + (id, justfoo) = self.users.newUser() + justfoo.name = 'justfoo' justfoo.addCapability(self.cap) justfoo.addHostmask(self.justfoo) - self.users.setUser('justfoo', justfoo) - antifoo = ircdb.IrcUser() + self.users.setUser(id, justfoo) + (id, antifoo) = self.users.newUser() + antifoo.name = 'antifoo' antifoo.addCapability(self.anticap) antifoo.addHostmask(self.antifoo) - self.users.setUser('antifoo', antifoo) - justchanfoo = ircdb.IrcUser() + self.users.setUser(id, antifoo) + (id, justchanfoo) = self.users.newUser() + justchanfoo.name = 'justchanfoo' justchanfoo.addCapability(self.chancap) justchanfoo.addHostmask(self.justchanfoo) - self.users.setUser('justchanfoo', justchanfoo) - antichanfoo = ircdb.IrcUser() + self.users.setUser(id, justchanfoo) + (id, antichanfoo) = self.users.newUser() + antichanfoo.name = 'antichanfoo' antichanfoo.addCapability(self.antichancap) antichanfoo.addHostmask(self.antichanfoo) - self.users.setUser('antichanfoo', antichanfoo) + self.users.setUser(id, antichanfoo) channel = ircdb.IrcChannel() self.channels.setChannel(self.channel, channel) - def tearDown(self): - os.remove(self.filename) - def checkCapability(self, hostmask, capability): return ircdb.checkCapability(hostmask, capability, self.users, self.channels)