added remove command ( fpart ), fixed ( i guess ) few bugs related to unability to match affected users by a mode

This commit is contained in:
Nicolas Coevoet 2013-11-29 20:02:07 +01:00
parent 455d955aa7
commit 30ac32bc61

View File

@ -47,6 +47,10 @@ import re
import sqlite3 import sqlite3
import collections import collections
#due to more kind of pattern checked, increase size
ircutils._hostmaskPatternEqualCache = utils.structures.CacheDict(4000)
def matchHostmask (pattern,n): def matchHostmask (pattern,n):
# return the machted pattern for Nick # return the machted pattern for Nick
if n.prefix == None or not ircutils.isUserHostmask(n.prefix): if n.prefix == None or not ircutils.isUserHostmask(n.prefix):
@ -204,7 +208,9 @@ def getBestPattern (n):
ident = ircutils.userFromHostmask(n.prefix) ident = ircutils.userFromHostmask(n.prefix)
if host.find('gateway/') != -1 and host.find('/x-') != -1: if host.find('gateway/') != -1 and host.find('/x-') != -1:
host = '%s/*' % host.split('/x-')[0] host = '%s/*' % host.split('/x-')[0]
results.append('*!%s@%s' % (ident,host)) k = '*!%s@%s' % (ident,host)
if not k in results:
results.append(k)
if n.account: if n.account:
results.append('$a:%s' % n.account) results.append('$a:%s' % n.account)
if n.realname: if n.realname:
@ -299,9 +305,9 @@ class Ircd (object):
object.__init__(self) object.__init__(self)
self.irc = irc self.irc = irc
self.name = irc.network self.name = irc.network
self.channels = {} self.channels = ircutils.IrcDict()
self.nicks = {} self.nicks = ircutils.IrcDict()
self.caps = {} self.caps = ircutils.IrcDict()
# contains IrcMsg, kicks, modes, etc # contains IrcMsg, kicks, modes, etc
self.queue = utils.structures.smallqueue() self.queue = utils.structures.smallqueue()
# contains less important IrcMsgs ( sync, logChannel ) # contains less important IrcMsgs ( sync, logChannel )
@ -750,13 +756,13 @@ class Chan (object):
object.__init__(self) object.__init__(self)
self.ircd = ircd self.ircd = ircd
self.name = name self.name = name
self._lists = {} self._lists = ircutils.IrcDict()
# queue contains (mode,valueOrNone) - ircutils.joinModes # queue contains (mode,valueOrNone) - ircutils.joinModes
self.queue = utils.structures.smallqueue() self.queue = utils.structures.smallqueue()
# contains [modevalue] = [mode,value,seconds,prefix] # contains [modevalue] = [mode,value,seconds,prefix]
self.update = {} self.update = ircutils.IrcDict()
# contains [modevalue] = [mode,value,message,prefix] # contains [modevalue] = [mode,value,message,prefix]
self.mark = {} self.mark = ircutils.IrcDict()
# contains IrcMsg ( mostly kick / fpart ) # contains IrcMsg ( mostly kick / fpart )
self.action = utils.structures.smallqueue() self.action = utils.structures.smallqueue()
# looking for eqIb list ends # looking for eqIb list ends
@ -766,9 +772,9 @@ class Chan (object):
self.deopAsked = False self.deopAsked = False
self.deopPending = False self.deopPending = False
# now stuff here is related to protection # now stuff here is related to protection
self.spam = {} self.spam = ircutils.IrcDict()
self.repeatLogs = {} self.repeatLogs = ircutils.IrcDict()
self.massPattern = {} self.massPattern = ircutils.IrcDict()
def isWrong (self,pattern): def isWrong (self,pattern):
if 'bad' in self.spam: if 'bad' in self.spam:
@ -782,7 +788,7 @@ class Chan (object):
def getItemsFor (self,mode): def getItemsFor (self,mode):
if not mode in self._lists: if not mode in self._lists:
self._lists[mode] = {} self._lists[mode] = ircutils.IrcDict()
return self._lists[mode] return self._lists[mode]
def addItem (self,mode,value,by,when,db): def addItem (self,mode,value,by,when,db):
@ -911,11 +917,11 @@ class Nick (object):
# [float(timestamp),target,message] # [float(timestamp),target,message]
def setPrefix (self,prefix): def setPrefix (self,prefix):
if not prefix == self.prefix: if prefix != None and not prefix == self.prefix:
self.prefix = prefix self.prefix = prefix
if self.prefix: if self.prefix:
# compute ip
matchHostmask(self.prefix,self) matchHostmask(self.prefix,self)
getBestPattern(self)
return self return self
def setIp (self,ip): def setIp (self,ip):
@ -939,13 +945,13 @@ class Nick (object):
def __repr__(self): def __repr__(self):
ip = self.ip ip = self.ip
if ip == None: if ip is None:
ip = '' ip = ''
account = self.account account = self.account
if account == None: if account is None:
account = '' account = ''
realname = self.realname realname = self.realname
if realname == None: if realname is None:
realname = '' realname = ''
return '%s ip:%s $a:%s $r:%s' % (self.prefix,ip,account,realname) return '%s ip:%s $a:%s $r:%s' % (self.prefix,ip,account,realname)
@ -1019,7 +1025,7 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
plugins.ChannelDBHandler.__init__(self) plugins.ChannelDBHandler.__init__(self)
self.lastTickle = time.time()-self.registryValue('pool') self.lastTickle = time.time()-self.registryValue('pool')
self.forceTickle = True self.forceTickle = True
self._ircs = {} self._ircs = ircutils.IrcDict()
self.getIrc(irc) self.getIrc(irc)
self.recaps = re.compile("[A-Z]") self.recaps = re.compile("[A-Z]")
@ -1142,7 +1148,7 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
else: else:
results = i.pending(irc,channel,mode,msg.prefix,pattern,self.getDb(irc.network)) results = i.pending(irc,channel,mode,msg.prefix,pattern,self.getDb(irc.network))
if len(results): if len(results):
irc.reply(', '.join(results), private=True) irc.reply(' '.join(results), private=True)
else: else:
irc.error('no results') irc.error('no results')
pending = wrap(pending,['op',additional('letter'),optional('hostmask')]) pending = wrap(pending,['op',additional('letter'),optional('hostmask')])
@ -1271,6 +1277,19 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
irc.error('unknown patterns, already removed or unsupported mode') irc.error('unknown patterns, already removed or unsupported mode')
ue = wrap(ue,['op',many('something')]) ue = wrap(ue,['op',many('something')])
def remove (self,irc,msg,args,channel,nick,reason):
"""[<channel>] <nick> [<reason>]
force a part on <nick> with <reason> if provided"""
chan = self.getChan(irc,channel)
if not reason:
reason = msg.nick
chan.action.enqueue(ircmsgs.IrcMsg('REMOVE %s %s :%s' % (channel,nick,reason)))
irc.replySuccess()
self.forceTickle = True
self._tickle(irc)
remove = wrap(remove,['op','nickInChannel',additional('text')])
def check (self,irc,msg,args,channel,pattern): def check (self,irc,msg,args,channel,pattern):
"""[<channel>] <pattern> """[<channel>] <pattern>
@ -1283,9 +1302,11 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
n = self.getNick(irc,nick) n = self.getNick(irc,nick)
m = match(pattern,n) m = match(pattern,n)
if m: if m:
results.append(nick) results.append('[%s - %s]' % (nick,m))
else:
log.debug('ChanServ.check unknown %s' % nick)
if len(results): if len(results):
irc.reply(', '.join(results)) irc.reply(' '.join(results))
else: else:
irc.error('nobody will be affected') irc.error('nobody will be affected')
else: else:
@ -1296,10 +1317,9 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
"""<nick|hostmask> """<nick|hostmask>
returns a list of hostmask's pattern, best first, mostly used for debug""" returns a list of hostmask's pattern, best first, mostly used for debug"""
# returns patterns for a given nick
i = self.getIrc(irc) i = self.getIrc(irc)
if prefix in i.nicks: if prefix in i.nicks:
irc.reply(', '.join(getBestPattern(self.getNick(irc,prefix)))) irc.reply(' '.join(getBestPattern(self.getNick(irc,prefix))))
else: else:
n = Nick(0) n = Nick(0)
if prefix.find('#') != -1: if prefix.find('#') != -1:
@ -1311,7 +1331,7 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
else: else:
n.setPrefix(prefix) n.setPrefix(prefix)
if ircutils.isUserHostmask(prefix): if ircutils.isUserHostmask(prefix):
irc.reply(', '.join(getBestPattern(n))) irc.reply(' '.join(getBestPattern(n)))
return return
irc.error('nick not found or wrong hostmask given') irc.error('nick not found or wrong hostmask given')
getmask = wrap(getmask,['owner','text']) getmask = wrap(getmask,['owner','text'])
@ -1412,12 +1432,12 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
def getIrc (self,irc): def getIrc (self,irc):
# init irc db # init irc db
if not irc in self._ircs: if not irc.network in self._ircs:
i = self._ircs[irc] = Ircd (irc,self.registryValue('logsSize')) i = self._ircs[irc.network] = Ircd (irc,self.registryValue('logsSize'))
# restore CAP, if needed, needed to track account (account-notify) ang gecos (extended-join) # restore CAP, if needed, needed to track account (account-notify) ang gecos (extended-join)
# see config of this plugin # see config of this plugin
irc.queueMsg(ircmsgs.IrcMsg('CAP LS')) irc.queueMsg(ircmsgs.IrcMsg('CAP LS'))
return self._ircs[irc] return self._ircs[irc.network]
def getChan (self,irc,channel): def getChan (self,irc,channel):
i = self.getIrc(irc) i = self.getIrc(irc)
@ -1434,15 +1454,12 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
elif len(modesToAsk): elif len(modesToAsk):
i.lowQueue.enqueue(ircmsgs.IrcMsg('MODE %s %s' % (channel,modesToAsk))) i.lowQueue.enqueue(ircmsgs.IrcMsg('MODE %s %s' % (channel,modesToAsk)))
# schedule that for later # schedule that for later
def doLater():
# prevent the bot to disconnect itself is server takes too much time to answer # prevent the bot to disconnect itself is server takes too much time to answer
i.lowQueue.enqueue(ircmsgs.ping(channel)) i.lowQueue.enqueue(ircmsgs.ping(channel))
# loads extended who # loads extended who
i.lowQueue.enqueue(ircmsgs.IrcMsg('WHO ' + channel +' %tnuhiar,42')) # some ircd may not like this i.lowQueue.enqueue(ircmsgs.IrcMsg('WHO ' + channel +' %tnuhiar,42')) # some ircd may not like this
# fallback, TODO maybe uneeded as supybot do it by itself on join, but necessary on plugin reload ... # fallback, TODO maybe uneeded as supybot do it by itself on join, but necessary on plugin reload ...
i.lowQueue.enqueue(ircmsgs.IrcMsg('WHO %s' % channel)) i.lowQueue.enqueue(ircmsgs.IrcMsg('WHO %s' % channel))
schedule.addEvent(doLater,time.time()+30)
return i.getChan (irc,channel) return i.getChan (irc,channel)
def getNick (self,irc,nick): def getNick (self,irc,nick):
@ -1501,9 +1518,6 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
def doPing (self,irc,msg): def doPing (self,irc,msg):
self._tickle(irc) self._tickle(irc)
def die(self):
self._ircs = {}
def _sendModes (self, irc, modes, f): def _sendModes (self, irc, modes, f):
numModes = irc.state.supported.get('modes', 1) numModes = irc.state.supported.get('modes', 1)
ircd = self.getIrc(irc) ircd = self.getIrc(irc)
@ -1613,7 +1627,7 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
index = 0 index = 0
for k in L: for k in L:
(m,value,expire,prefix) = L[index] (m,value,expire,prefix) = L[index]
if expire == -1 or expire == None: if expire == -1 or expire is None:
if overexpire != expire: if overexpire != expire:
chan.update['%s%s' % (m,value)] = [m,value,overexpire,irc.prefix] chan.update['%s%s' % (m,value)] = [m,value,overexpire,irc.prefix]
index = index + 1 index = index + 1
@ -2079,6 +2093,7 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
return return
if targets == irc.nick: if targets == irc.nick:
b = False b = False
# todo keep this code commented until request to implement it
#b = False #b = False
#if text == 'You are not authorized to perform this operation.': #if text == 'You are not authorized to perform this operation.':
#b = True #b = True
@ -2499,7 +2514,7 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
L = [] L = []
for user in irc.state.channels[self.registryValue('logChannel',channel=channel)].users: for user in irc.state.channels[self.registryValue('logChannel',channel=channel)].users:
L.append(user) L.append(user)
self._logChan(irc,channel,'[%s] %s : %s' % (channel,info,', '.join(L))) self._logChan(irc,channel,'[%s] %s : %s' % (channel,info,' '.join(L)))
self._tickle(irc) self._tickle(irc)
# protection features # protection features
@ -2620,8 +2635,16 @@ class ChanTracker(callbacks.Plugin,plugins.ChannelDBHandler):
jacc = n / float(len(sa) + len(sb) - n) jacc = n / float(len(sa) + len(sb) - n)
return jacc return jacc
def die(self):
log.debug('ChanTracker die')
self._ircs = ircutils.IrcDict()
def doError (self,irc,msg): def doError (self,irc,msg):
self._ircs = {} log.debug('ChanTracker doError: %s' % irc.network)
if irc.network in self._ircs:
del self._ircs[irc]
else:
self._ircs = ircutils.IrcDict()
Class = ChanTracker Class = ChanTracker