Skip to content
Snippets Groups Projects
Commit 8c6461c5 authored by Ben Kelly's avatar Ben Kelly Committed by Eric S. Raymond
Browse files

Add support for keyed channels. Supports both channel?secret and channel?key=secret.


Signed-off-by: default avatarEric S. Raymond <esr@thyrsus.com>
parent 08d7f63c
No related branches found
No related tags found
No related merge requests found
...@@ -154,20 +154,20 @@ class Connection: ...@@ -154,20 +154,20 @@ class Connection:
% (self.servername, outof)) % (self.servername, outof))
qcopy = [] qcopy = []
while not self.queue.empty(): while not self.queue.empty():
(channel, message) = self.queue.get() (channel, message, key) = self.queue.get()
if channel != outof: if channel != outof:
qcopy.append((channel, message)) qcopy.append((channel, message, key))
for (channel, message) in qcopy: for (channel, message, key) in qcopy:
self.queue.put((channel, message)) self.queue.put((channel, message, key))
self.status = "ready" self.status = "ready"
def enqueue(self, channel, message): def enqueue(self, channel, message, key):
"Enque a message for transmission." "Enque a message for transmission."
if self.thread is None or not self.thread.is_alive(): if self.thread is None or not self.thread.is_alive():
self.status = "unseen" self.status = "unseen"
self.thread = threading.Thread(target=self.dequeue) self.thread = threading.Thread(target=self.dequeue)
self.thread.setDaemon(True) self.thread.setDaemon(True)
self.thread.start() self.thread.start()
self.queue.put((channel, message)) self.queue.put((channel, message, key))
def dequeue(self): def dequeue(self):
"Try to ship pending messages from the queue." "Try to ship pending messages from the queue."
try: try:
...@@ -252,9 +252,9 @@ class Connection: ...@@ -252,9 +252,9 @@ class Connection:
self.status = "expired" self.status = "expired"
break break
elif self.status == "ready": elif self.status == "ready":
(channel, message) = self.queue.get() (channel, message, key) = self.queue.get()
if channel not in self.channels_joined: if channel not in self.channels_joined:
self.connection.join(channel) self.connection.join(channel, key=key)
self.irker.debug(1, "joining %s on %s." % (channel, self.servername)) self.irker.debug(1, "joining %s on %s." % (channel, self.servername))
# An empty message might be used as a keepalive or # An empty message might be used as a keepalive or
# to join a channel for logging, so suppress the # to join a channel for logging, so suppress the
...@@ -339,6 +339,10 @@ class Target(): ...@@ -339,6 +339,10 @@ class Target():
self.channel = self.channel[:-7] self.channel = self.channel[:-7]
if self.channel and not isnick and self.channel[0] not in "#&+": if self.channel and not isnick and self.channel[0] not in "#&+":
self.channel = "#" + self.channel self.channel = "#" + self.channel
# support both channel?secret and channel?key=secret
self.key = None
if parsed.query:
self.key = re.sub("^key=", "", parsed.query)
self.port = int(ircport) self.port = int(ircport)
def valid(self): def valid(self):
"Both components must be present for a valid target." "Both components must be present for a valid target."
...@@ -354,7 +358,7 @@ class Dispatcher: ...@@ -354,7 +358,7 @@ class Dispatcher:
self.servername = servername self.servername = servername
self.port = port self.port = port
self.connections = [] self.connections = []
def dispatch(self, channel, message): def dispatch(self, channel, message, key):
"Dispatch messages for our server-port combination." "Dispatch messages for our server-port combination."
# First, check if there is room for another channel # First, check if there is room for another channel
# on any of our existing connections. # on any of our existing connections.
...@@ -362,7 +366,7 @@ class Dispatcher: ...@@ -362,7 +366,7 @@ class Dispatcher:
eligibles = [x for x in connections if x.joined_to(channel)] \ eligibles = [x for x in connections if x.joined_to(channel)] \
or [x for x in connections if x.accepting(channel)] or [x for x in connections if x.accepting(channel)]
if eligibles: if eligibles:
eligibles[0].enqueue(channel, message) eligibles[0].enqueue(channel, message, key)
return return
# All connections are full up. Look for one old enough to be # All connections are full up. Look for one old enough to be
# scavenged. # scavenged.
...@@ -377,14 +381,14 @@ class Dispatcher: ...@@ -377,14 +381,14 @@ class Dispatcher:
found_connection.part(drop_channel, "scavenged by irkerd") found_connection.part(drop_channel, "scavenged by irkerd")
del found_connection.channels_joined[drop_channel] del found_connection.channels_joined[drop_channel]
#time.sleep(ANTI_FLOOD_DELAY) #time.sleep(ANTI_FLOOD_DELAY)
found_connection.enqueue(channel, message) found_connection.enqueue(channel, message, key)
return return
# Didn't find any channels with no recent activity # Didn't find any channels with no recent activity
newconn = Connection(self.irker, newconn = Connection(self.irker,
self.servername, self.servername,
self.port) self.port)
self.connections.append(newconn) self.connections.append(newconn)
newconn.enqueue(channel, message) newconn.enqueue(channel, message, key)
def live(self): def live(self):
"Does this server-port combination have any live connections?" "Does this server-port combination have any live connections?"
self.connections = [x for x in self.connections if x.live()] self.connections = [x for x in self.connections if x.live()]
...@@ -511,7 +515,7 @@ class Irker: ...@@ -511,7 +515,7 @@ class Irker:
return return
if target.server() not in self.servers: if target.server() not in self.servers:
self.servers[target.server()] = Dispatcher(self, target.servername, target.port) self.servers[target.server()] = Dispatcher(self, target.servername, target.port)
self.servers[target.server()].dispatch(target.channel, message) self.servers[target.server()].dispatch(target.channel, message, target.key)
# GC dispatchers with no active connections # GC dispatchers with no active connections
servernames = self.servers.keys() servernames = self.servers.keys()
for servername in servernames: for servername in servernames:
......
...@@ -45,6 +45,7 @@ Examples: ...@@ -45,6 +45,7 @@ Examples:
{"to":"irc://chat.freenode.net/git-ciabot", "privmsg":"Hello, world!"} {"to":"irc://chat.freenode.net/git-ciabot", "privmsg":"Hello, world!"}
{"to":["irc://chat.freenode.net/#git-ciabot","irc://chat.freenode.net/#gpsd"],"privmsg":"Multichannel test"} {"to":["irc://chat.freenode.net/#git-ciabot","irc://chat.freenode.net/#gpsd"],"privmsg":"Multichannel test"}
{"to":"irc://chat.hypothetical.net:6668/git-ciabot", "privmsg":"Hello, world!"} {"to":"irc://chat.hypothetical.net:6668/git-ciabot", "privmsg":"Hello, world!"}
{"to":"irc://chat.hypothetical.net:6668/git-private?key=topsecret", "privmsg":"Keyed channel test"}
</programlisting></para> </programlisting></para>
<para>If the channel part of the URL does not have one of the prefix <para>If the channel part of the URL does not have one of the prefix
...@@ -58,6 +59,11 @@ colon, as shown in the third example; otherwise ...@@ -58,6 +59,11 @@ colon, as shown in the third example; otherwise
<application>irkerd</application> sends messages to the the default 6667 IRC <application>irkerd</application> sends messages to the the default 6667 IRC
port of each server.</para> port of each server.</para>
<para>To join password-protected (mode +k) channels, the channel part of the
URL may be followed with a query-string indicating the channel key, of the
form <quote>?secret</quote> or <quote>?key=secret</quote>, where
<quote>secret</quote> is the channel key.</para>
<para>An empty message is legal and will cause <para>An empty message is legal and will cause
<application>irkerd</application> to join the target channels without <application>irkerd</application> to join the target channels without
actually emitting a message. This may be useful for advertising that actually emitting a message. This may be useful for advertising that
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment