From b2fbbef1973b094d799e8ecd02967ba791db1a08 Mon Sep 17 00:00:00 2001 From: Jeremy Fincher Date: Sat, 9 Oct 2004 04:57:16 +0000 Subject: [PATCH] Fixed bug with duplicate hostmasks. --- src/ircdb.py | 77 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/src/ircdb.py b/src/ircdb.py index 7ee963d73..25839d72b 100644 --- a/src/ircdb.py +++ b/src/ircdb.py @@ -464,44 +464,50 @@ class IrcUserCreator(Creator): raise ValueError, 'Unexpected user command on line %s.' % lineno IrcUserCreator.id = int(rest) - def name(self, rest, lineno): + def _checkId(self): if self.id is None: - raise ValueError, 'Unexpected user description without id.' + raise ValueError, 'Unexpected user description without user.' + + def name(self, rest, lineno): + self._checkId() self.u.name = rest def ignore(self, rest, lineno): - if self.id is None: - raise ValueError, 'Unexpected user description without id.' + self._checkId() self.u.ignore = bool(eval(rest)) def secure(self, rest, lineno): - if self.id is None: - raise ValueError, 'Unexpected user description without id.' + self._checkId() self.u.secure = bool(eval(rest)) def hashed(self, rest, lineno): - if self.id is None: - raise ValueError, 'Unexpected user description without id.' + self._checkId() self.u.hashed = bool(eval(rest)) def password(self, rest, lineno): - if self.id is None: - raise ValueError, 'Unexpected user description without id.' + self._checkId() self.u.password = rest def hostmask(self, rest, lineno): - if self.id is None: - raise ValueError, 'Unexpected user description without id.' + self._checkId() self.u.hostmasks.append(rest) def capability(self, rest, lineno): - if self.id is None: - raise ValueError, 'Unexpected user description without id.' + self._checkId() self.u.capabilities.add(rest) def finish(self): if self.u.name: - self.users.setUser(self.id, self.u) + try: + self.users.setUser(self.id, self.u) + except DuplicateHostmask: + log.error('Hostmasks for %s collided with another user\'s. ' + 'Resetting hostmasks for %s.', self.u.name) + # Some might argue that this is arbitrary, and perhaps it is. + # But we've got to do *something*, so we'll show some deference + # to our lower-numbered users. + self.u.hostmasks[:] = [] + self.users.setUser(self.id, self.u) IrcUserCreator.id = None class IrcChannelCreator(Creator): @@ -516,30 +522,29 @@ class IrcChannelCreator(Creator): raise ValueError, 'Unexpected channel command on line %s' % lineno IrcChannelCreator.name = rest - def lobotomized(self, rest, lineno): + def _checkId(self): if self.name is None: raise ValueError, 'Unexpected channel description without channel.' + + def lobotomized(self, rest, lineno): + self._checkId() self.c.lobotomized = bool(eval(rest)) def defaultallow(self, rest, lineno): - if self.name is None: - raise ValueError, 'Unexpected channel description without channel.' + self._checkId() self.c.defaultAllow = bool(eval(rest)) def capability(self, rest, lineno): - if self.name is None: - raise ValueError, 'Unexpected channel description without channel.' + self._checkId() self.c.capabilities.add(rest) def ban(self, rest, lineno): - if self.name is None: - raise ValueError, 'Unexpected channel description without channel.' + self._checkId() (pattern, expiration) = rest self.c.bans[pattern] = int(float(expiration)) def ignore(self, rest, lineno): - if self.name is None: - raise ValueError, 'Unexpected channel description without channel.' + self._checkId() (pattern, expiration) = rest.split() self.c.ignores[pattern] = int(float(expiration)) @@ -549,6 +554,9 @@ class IrcChannelCreator(Creator): IrcChannelCreator.name = None +class DuplicateHostmask(ValueError): + pass + class UsersDictionary(utils.IterableMap): """A simple serialized-to-file User Database.""" def __init__(self): @@ -644,7 +652,7 @@ class UsersDictionary(utils.IterableMap): for (id, hostmask) in ids.iteritems(): log.error('Removing %r from user %s.', hostmask, id) self.users[id].removeHostmask(hostmask) - raise ValueError, 'Ids %r matched.' % ids + raise DuplicateHostmask, 'Ids %r matched.' % ids else: # Not a hostmask, must be a name. s = s.lower() try: @@ -664,6 +672,9 @@ class UsersDictionary(utils.IterableMap): # Must be a string. Get the UserId first. id = self.getUserId(id) u = self.users[id] + while isinstance(u, int): + id = u + u = self.users[id] u.id = id return u @@ -703,8 +714,7 @@ class UsersDictionary(utils.IterableMap): self.nextId = max(self.nextId, id) try: if self.getUserId(user.name) != id: - s = '%s is someone else\'s hostmask.' % user.name - raise ValueError, s + raise DuplicateHostmask, hostmask except KeyError: pass for hostmask in user.hostmasks: @@ -712,14 +722,15 @@ class UsersDictionary(utils.IterableMap): if i == id: continue elif u.checkHostmask(hostmask): - s = '%s is someone else\'s hostmask.' % hostmask - user.removeHostmask(hostmask) - raise ValueError, s + # We used to remove the hostmask here, but it's not + # appropriate for us both to remove the hostmask and to + # raise an exception. So instead, we'll raise an + # exception, but be nice and give the offending hostmask + # back at the same time. + raise DuplicateHostmask, hostmask for otherHostmask in u.hostmasks: if ircutils.hostmaskPatternEqual(hostmask, otherHostmask): - user.removeHostmask(hostmask) - s = '%s is someone else\'s hostmask.' % hostmask - raise ValueError, s + raise DuplicateHostmask, hostmask self.invalidateCache(id) self.users[id] = user self.flush()