Fix LIST handling and message parsing
* Always use simple LIST syntax if it succeeded once after a failed complex query * Reject asking for a LIST twice * Quickly discard any ISUPPORT messages that don't contain things we need to use * Detect the server name and drop any messages from the server
This commit is contained in:
parent
f34de8940f
commit
b4fa747853
86
core/bot.py
86
core/bot.py
|
@ -106,22 +106,26 @@ class IRCBot(IRCClient):
|
||||||
self.realname = alias["realname"]
|
self.realname = alias["realname"]
|
||||||
self.username = alias["nick"]+"/"+relay["net"]
|
self.username = alias["nick"]+"/"+relay["net"]
|
||||||
self.password = main.config["Relay"]["Password"]
|
self.password = main.config["Relay"]["Password"]
|
||||||
self.userinfo = None
|
self.userinfo = None #
|
||||||
self.fingerReply = None
|
self.fingerReply = None #
|
||||||
self.versionName = None
|
self.versionName = None # don't tell anyone information about us
|
||||||
self.versionNum = None
|
self.versionNum = None #
|
||||||
self.versionEnv = None
|
self.versionEnv = None #
|
||||||
self.sourceURL = None
|
self.sourceURL = None #
|
||||||
|
|
||||||
self._getWho = {} # LoopingCall objects -- needed to be able to stop them
|
self._getWho = {} # LoopingCall objects -- needed to be able to stop them
|
||||||
|
|
||||||
self._tempWho = {} # Temporary storage for gathering WHO info
|
self._tempWho = {} # temporary storage for gathering WHO info
|
||||||
self._tempNames = {} # Temporary storage for gathering NAMES info
|
self._tempNames = {} # temporary storage for gathering NAMES info
|
||||||
self._tempList = ([], []) # Temporary storage for gathering LIST info
|
self._tempList = ([], []) # temporary storage for gathering LIST info
|
||||||
self.listOngoing = False
|
self.listOngoing = False # we are currently receiving a LIST
|
||||||
self.listRetried = False
|
self.listRetried = False # we asked and got nothing so asked again
|
||||||
|
self.listAttempted = False # we asked for a list
|
||||||
|
self.listSimple = False # after asking again we got the list, so
|
||||||
|
# use the simple syntax from now on
|
||||||
|
|
||||||
self.chanlimit = 0
|
self.chanlimit = 0
|
||||||
|
self.servername = None
|
||||||
|
|
||||||
def joinChannels(self, channels):
|
def joinChannels(self, channels):
|
||||||
sleeptime = 0.0
|
sleeptime = 0.0
|
||||||
|
@ -151,11 +155,13 @@ class IRCBot(IRCClient):
|
||||||
if cast[i] == "": # a dictionary that changes length with each iteration
|
if cast[i] == "": # a dictionary that changes length with each iteration
|
||||||
del cast[i]
|
del cast[i]
|
||||||
if "muser" in cast.keys():
|
if "muser" in cast.keys():
|
||||||
|
if cast["muser"] == self.servername:
|
||||||
|
return
|
||||||
|
if "channel" in cast.keys():
|
||||||
|
if cast["channel"] == "*":
|
||||||
|
return
|
||||||
|
if not {"nick", "ident", "host"}.issubset(set(cast.keys())):
|
||||||
cast["nick"], cast["ident"], cast["host"] = parsen(cast["muser"])
|
cast["nick"], cast["ident"], cast["host"] = parsen(cast["muser"])
|
||||||
# additional checks here to see if it's a server -- irc.example.net
|
|
||||||
# discard if it is
|
|
||||||
#if not cast["type"] in ["nick", "kick", "quit", "part", "join"]:
|
|
||||||
# del cast["muser"]
|
|
||||||
if set(["nick", "ident", "host", "msg"]).issubset(set(cast)):
|
if set(["nick", "ident", "host", "msg"]).issubset(set(cast)):
|
||||||
if "msg" in cast.keys():
|
if "msg" in cast.keys():
|
||||||
if cast["ident"] == "znc" and cast["host"] == "znc.in":
|
if cast["ident"] == "znc" and cast["host"] == "znc.in":
|
||||||
|
@ -166,6 +172,7 @@ class IRCBot(IRCClient):
|
||||||
del cast["host"]
|
del cast["host"]
|
||||||
del cast["channel"]
|
del cast["channel"]
|
||||||
if "Disconnected from IRC" in cast["msg"]:
|
if "Disconnected from IRC" in cast["msg"]:
|
||||||
|
log("ZNC disconnected on %s - %i" (self.net, self.num))
|
||||||
self.connected = False
|
self.connected = False
|
||||||
if not cast["type"] in ["query", "self", "highlight", "znc", "who"]:
|
if not cast["type"] in ["query", "self", "highlight", "znc", "who"]:
|
||||||
if "channel" in cast.keys() and not cast["type"] == "mode": # don't handle modes here
|
if "channel" in cast.keys() and not cast["type"] == "mode": # don't handle modes here
|
||||||
|
@ -323,10 +330,16 @@ class IRCBot(IRCClient):
|
||||||
newNicklist.append(f)
|
newNicklist.append(f)
|
||||||
userinfo.initialNames(self.net, nicklist[0], newNicklist)
|
userinfo.initialNames(self.net, nicklist[0], newNicklist)
|
||||||
|
|
||||||
|
def myInfo(self, servername, version, umodes, cmodes):
|
||||||
|
self.servername = servername
|
||||||
|
|
||||||
def _list(self, noargs):
|
def _list(self, noargs):
|
||||||
d = Deferred()
|
d = Deferred()
|
||||||
self._tempList = ([], [])
|
self._tempList = ([], [])
|
||||||
self._tempList[0].append(d)
|
self._tempList[0].append(d)
|
||||||
|
if self.listSimple:
|
||||||
|
self.sendLine("LIST")
|
||||||
|
return d
|
||||||
if noargs:
|
if noargs:
|
||||||
self.sendLine("LIST")
|
self.sendLine("LIST")
|
||||||
else:
|
else:
|
||||||
|
@ -334,10 +347,19 @@ class IRCBot(IRCClient):
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def list(self, noargs=False):
|
def list(self, noargs=False):
|
||||||
|
if not self.listAttempted:
|
||||||
|
self.listAttempted = True
|
||||||
|
else:
|
||||||
|
debug("List request dropped, already asked for LIST - %s - %i" % (self.net, self.num))
|
||||||
|
return
|
||||||
if not self.listOngoing:
|
if not self.listOngoing:
|
||||||
self._list(noargs).addCallback(self.got_list)
|
self._list(noargs).addCallback(self.got_list)
|
||||||
|
else:
|
||||||
|
debug("List request dropped, already ongoing - %s - %i" % (self.net, self.num))
|
||||||
|
return
|
||||||
|
|
||||||
def irc_RPL_LISTSTART(self, prefix, params):
|
def irc_RPL_LISTSTART(self, prefix, params):
|
||||||
|
self.listAttempted = False
|
||||||
self.listOngoing = True
|
self.listOngoing = True
|
||||||
|
|
||||||
def irc_RPL_LIST(self, prefix, params):
|
def irc_RPL_LIST(self, prefix, params):
|
||||||
|
@ -359,12 +381,16 @@ class IRCBot(IRCClient):
|
||||||
if noResults:
|
if noResults:
|
||||||
if not self.listRetried:
|
if not self.listRetried:
|
||||||
self.list(True)
|
self.list(True)
|
||||||
|
self.listRetried = True
|
||||||
else:
|
else:
|
||||||
warn("List still empty after retry: %s - %i" % (net, num))
|
warn("List still empty after retry: %s - %i" % (net, num))
|
||||||
self.listRetried = False
|
self.listRetried = False
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.listRetried = False
|
if self.listRetried:
|
||||||
|
self.listRetried = False
|
||||||
|
debug("List received after retry - defaulting to simple list syntax")
|
||||||
|
self.listSimple = True
|
||||||
|
|
||||||
def got_list(self, listinfo):
|
def got_list(self, listinfo):
|
||||||
if len(listinfo) == 0: # probably ngircd not supporting LIST >0
|
if len(listinfo) == 0: # probably ngircd not supporting LIST >0
|
||||||
|
@ -372,19 +398,33 @@ class IRCBot(IRCClient):
|
||||||
chankeep.initialList(self.net, self.num, listinfo, self.chanlimit)
|
chankeep.initialList(self.net, self.num, listinfo, self.chanlimit)
|
||||||
|
|
||||||
def isupport(self, options):
|
def isupport(self, options):
|
||||||
for i in options:
|
interested = ("CHANLIMIT", "MAXCHANNELS")
|
||||||
|
if not any((x for x in options if any(y in x for y in interested))):
|
||||||
|
return # check if any of interested is in any of options, some networks
|
||||||
|
chanlimit = None # call isupport() more than once, so discard swiftly anything
|
||||||
|
for i in options: # we don't care about
|
||||||
if i.startswith("CHANLIMIT"):
|
if i.startswith("CHANLIMIT"):
|
||||||
if ":" in i:
|
if ":" in i:
|
||||||
split = i.split(":")
|
split = i.split(":")
|
||||||
if len(split) >= 2:
|
if len(split) >= 2:
|
||||||
chanlimit = split[1]
|
chanlimit = split[1]
|
||||||
try:
|
break
|
||||||
self.chanlimit = int(chanlimit)
|
elif i.startswith("MAXCHANNELS"):
|
||||||
return
|
if "=" in i:
|
||||||
except TypeError:
|
split = i.split("=")
|
||||||
warn("Invalid CHANLIMIT: %s" % i)
|
if len(split) == 2:
|
||||||
|
chanlimit = split[1]
|
||||||
|
break
|
||||||
|
if chanlimit:
|
||||||
|
try:
|
||||||
|
self.chanlimit = int(chanlimit)
|
||||||
|
except TypeError:
|
||||||
|
warn("Invalid chanlimit: %s" % i)
|
||||||
if self.num == 1: # Only one instance should do a list, so
|
if self.num == 1: # Only one instance should do a list, so
|
||||||
self.list() # why not this one? :P
|
if self.chanlimit:
|
||||||
|
self.list() # why not this one? :P
|
||||||
|
else:
|
||||||
|
debug("Aborting LIST due to bad chanlimit")
|
||||||
self.checkChannels()
|
self.checkChannels()
|
||||||
|
|
||||||
#twisted sucks so i have to do this to actually get the user info
|
#twisted sucks so i have to do this to actually get the user info
|
||||||
|
|
|
@ -27,7 +27,6 @@ def getChanFree(net, new):
|
||||||
name = net+str(i)
|
name = net+str(i)
|
||||||
chanfree[i] = main.IRCPool[name].chanlimit-len(main.IRCPool[name].channels)
|
chanfree[i] = main.IRCPool[name].chanlimit-len(main.IRCPool[name].channels)
|
||||||
chanlimits.add(main.IRCPool[name].chanlimit)
|
chanlimits.add(main.IRCPool[name].chanlimit)
|
||||||
|
|
||||||
if not len(chanlimits) == 1:
|
if not len(chanlimits) == 1:
|
||||||
error("Network %s has servers with different CHANMAX values" % net)
|
error("Network %s has servers with different CHANMAX values" % net)
|
||||||
return False
|
return False
|
||||||
|
@ -39,7 +38,6 @@ def emptyChanAllocate(net, flist, relay, new):
|
||||||
return
|
return
|
||||||
for i in new:
|
for i in new:
|
||||||
chanfree[0][i] = chanfree[1]
|
chanfree[0][i] = chanfree[1]
|
||||||
print("chanfree", chanfree)
|
|
||||||
allocated = {}
|
allocated = {}
|
||||||
toalloc = len(flist)
|
toalloc = len(flist)
|
||||||
if toalloc > sum(chanfree[0].values()):
|
if toalloc > sum(chanfree[0].values()):
|
||||||
|
|
|
@ -7,7 +7,7 @@ from utils.logging.debug import debug
|
||||||
from utils.parsing import parsen
|
from utils.parsing import parsen
|
||||||
|
|
||||||
def getWhoSingle(name, query):
|
def getWhoSingle(name, query):
|
||||||
result = main.r.sscan("live.who."+name, 0, query, count=-1)
|
result = main.r.sscan("live.who."+name, 0, query, count=999999)
|
||||||
if result[1] == []:
|
if result[1] == []:
|
||||||
return None
|
return None
|
||||||
return (i.decode() for i in result[1])
|
return (i.decode() for i in result[1])
|
||||||
|
|
Loading…
Reference in New Issue