class ModeChange(object): booleanModes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" oneValModes = "" multiValModes = "" def __init__(self, modeString): self.items = [] self.update(modeString) def update(self, modeString): if not isinstance(modeString, str): raise ValueError, "string expected, %s given" % type(modeString) if not modeString: # empty string; this is valid but we assume at least one mode return args = modeString.split() modeString = args.pop(0) sign = None if not modeString[0] in "+-": raise ValueError, "mode must start with a sign (+ or -)" for char in modeString: if char in "+-": sign = (char == "+") elif char in self.booleanModes: self.items.append((sign, char, sign)) elif char in self.oneValModes or char in self.multiValModes: self.items.append((sign, char, args.pop(0))) else: raise ValueError, "unrecognized mode %r" % char return self def __str__(self): mode = [] values = [] sign = None for (newsign, char, value) in self.items: if newsign != sign: sign = newsign if sign: mode.append('+') else: mode.append('-') mode.append(char) if isinstance(value, basestring): values.append(value) return ' '.join([''.join(mode)] + values) def __repr__(self): return "%s(%r)" % (self.__class__.__name__, str(self)) class Mode(object): modeChangeClass = ModeChange def __init__(self, mode): self.modes = {} self.update(mode) def update(self, modeChange): if not isinstance(modeChange, self.modeChangeClass): modeChange = self.modeChangeClass(modeChange) for (sign, char, value) in modeChange.items: if char in self.modeChangeClass.multiValModes: if not char in self.modes: self.modes[char] = [] if sign: self.modes[char].append(value) else: try: self.modes[char].remove(value) except ValueError: # value doesn't exist; ignore pass if len(self.modes[char]) == 0: del self.modes[char] elif sign: self.modes[char] = value elif char in self.modes: del self.modes[char] return self def __str__(self): if len(self.modes) == 0: return "" else: modes = ['+'] values = [] for (char, value) in self.modes.items(): if char in self.modeChangeClass.multiValModes: modes.append(char * len(value)) values.extend(value) else: modes.append(char) if isinstance(value, basestring): values.append(value) return ' '.join([''.join(modes)] + values) def __repr__(self): return "%s(%r)" % (self.__class__.__name__, str(self)) def get(self, mode): assert len(mode) == 1, "%r is not a mode" % mode if mode in self.modes: return self.modes[mode] return None def __getattr__(self, attr): if len(attr) == 1: return self.get(attr) else: raise AttributeError # the following classes assume bahamut class ChannelModeChange(ModeChange): booleanModes = 'ciILmMnOprRst' oneValModes = 'l' multiValModes = 'bekov' class UserModeChange(ModeChange): booleanModes = 'aAbcdefghiIjkKmnoOrRswxXy' oneValModes = '' multiValModes = '' class ChannelMode(Mode): modeChangeClass = ChannelModeChange class UserMode(Mode): modeChangeClass = UserModeChange