Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

added plugin ircutil.Names, used by admin.OpProvider

Now if OpProvider doesn't know if it has OP or not, it will issue a
NAMES to the server to see.
  • Loading branch information...
commit f623c6518e59387620e2029c56455cdbd2bdb70b 1 parent 4e2bffa
@brownan authored
View
36 abbott/plugins/admin.py
@@ -63,7 +63,7 @@ def start(self):
# Maps channel names to a boolean indicating whether we currently hold
# op there or not
- self.have_op = defaultdict(bool)
+ self.have_op = {}
# Maps channel names to a set of (deferred, IDelayedCall) tuples where
# deferred is to be called when we get op, and the delayed call will
@@ -115,6 +115,28 @@ def stop(self):
for delayedcall in self.op_timeout_event.itervalues():
delayedcall.cancel()
+ @defer.inlineCallbacks
+ def _has_op(self, channel):
+ """Returns a deferred that fires with True if we have op on the
+ channel, or False if we don't or it can't be determined.
+
+ If there is no entry in have_op, we do a NAMES lookup on the channel to
+ try and determine if we are OP or not.
+
+ """
+ try:
+ defer.returnValue( self.have_op[channel] )
+ except KeyError:
+ # determine if we have OP
+ names_list = (yield self.transport.issue_request("irc.names",channel))
+
+ nick = (yield self.transport.issue_request("irc.getnick"))
+
+ has_op = "@"+nick in names_list
+ self.have_op[channel] = has_op
+ defer.returnValue(has_op)
+
+
def _set_op_timeout(self, channel):
"""Sets the op timeout for the given channel. If there is not currently
an op timeout, makes one. If there is currently a timeout set, resets
@@ -180,7 +202,7 @@ def on_request_ircadmin_opself(self, channel):
configured.
"""
- if self.have_op[channel]:
+ if (yield self._has_op(channel)):
# Already has op. Reset the timeout timer and return success
self._set_op_timeout(channel)
defer.returnValue(channel)
@@ -313,8 +335,9 @@ def set_op_mode(self, event, match):
### Handlers for op and deop requests for arbitrary users from other
### plugins
+ @defer.inlineCallbacks
def on_request_ircadmin_op(self, channel, nick):
- if self.have_op[channel]:
+ if (yield self._has_op(channel)):
self._set_op_timeout(channel)
self.transport.send_event(Event("irc.do_mode",
channel=channel,
@@ -324,9 +347,10 @@ def on_request_ircadmin_op(self, channel, nick):
))
else:
self._do_op(channel, nick, True)
- return defer.succeed(None)
+ return
+ @defer.inlineCallbacks
def on_request_ircadmin_deop(self, channel, nick):
- if self.have_op[channel]:
+ if (yield self._has_op(channel)):
self._set_op_timeout(channel)
self.transport.send_event(Event("irc.do_mode",
channel=channel,
@@ -336,7 +360,7 @@ def on_request_ircadmin_deop(self, channel, nick):
))
else:
self._do_op(channel, nick, False)
- return defer.succeed(None)
+ return
def _do_op(self, channel, nick, opset):
"""Issues an op request with a method appropriate for the given
View
5 abbott/plugins/irc.py
@@ -40,7 +40,9 @@ def lineReceived(self, line):
def sendLine(self, line):
"""Overrides IRCClient.sendLine to encode outgoing lines with UTF-8.
- Also implements some rate-limiting logic
+ Also implements some rate-limiting logic.
+
+ This method is also exported to other plugins as the irc.do_raw event.
"""
if isinstance(line, str):
@@ -305,6 +307,7 @@ def received_event(self, event):
'irc.do_whois': ('whois', ('nickname', 'server')),
'irc.do_setnick': ('setNick', ('nickname',)),
'irc.do_quit': ('quit', ('message',)),
+ 'irc.do_raw': ('sendLine',('line',)),
}
methodname, methodargs = events[event.eventtype]
View
66 abbott/plugins/ircutil.py
@@ -132,6 +132,72 @@ def do_whois(self, event, match):
event.reply("Whois info for %s:" % nick)
for command, params in info.iteritems():
event.reply("%s: %s" % (command, params))
+
+class Names(CommandPluginSuperclass):
+ """Provides a NAMES request for other plugins and a !names command"""
+ def start(self):
+ super(Names, self).start()
+
+ self.provides_request("irc.names")
+
+ self.listen_for_event("irc.on_unknown")
+
+ self.install_command(
+ cmdname="names",
+ argmatch=r"(?P<channel>\S+)?$",
+ cmdusage="[channel]",
+ callback=self.do_names,
+ helptext="Does an IRC NAMES command and replies with the result",
+ permission="irc.names",
+ )
+
+ self.currentinfo = []
+ self.pendingwhoises = defaultdict(set)
+
+ @defer.inlineCallbacks
+ def on_request_irc_names(self, channel):
+ self.transport.send_event(Event("irc.do_raw",
+ line="NAMES " + channel))
+ log.msg("NAMES line sent for channel %s. Awaiting reply..." % channel)
+
+ d = defer.Deferred()
+ self.pendingwhoises[channel].add(d)
+
+ names = (yield d)
+
+ defer.returnValue(names)
+
+ def on_event_irc_on_unknown(self, event):
+ command = event.command
+
+ if command == "RPL_NAMREPLY":
+ channel = event.params[2]
+ names = event.params[3]
+ self.currentinfo.append(names)
+
+ elif command == "RPL_ENDOFNAMES":
+ channel = event.params[1]
+ names = " ".join(self.currentinfo)
+ self.currentinfo = []
+ for d in self.pendingwhoises.pop(channel):
+ d.callback(names)
+
+
+ @defer.inlineCallbacks
+ def do_names(self, event, match):
+ gd = match.groupdict()
+ channel = gd['channel']
+
+ if not channel:
+ if event.direct:
+ event.reply("on what channel?")
+ return
+ channel = event.channel
+
+ info = (yield self.transport.issue_request("irc.names", channel))
+
+ event.reply("NAMES info for {0}: {1}".format(channel, info))
+
class ReplyInserter(CommandPluginSuperclass):
"""This plugin's function is to insert a reply() function to each incoming
Please sign in to comment.
Something went wrong with that request. Please try again.