Add support for keyed channels. Supports both channel?secret and channel?key=secret.
authorBen Kelly <bk@ancilla.ca>
Thu, 10 Oct 2013 18:16:41 +0000 (14:16 -0400)
committerEric S. Raymond <esr@thyrsus.com>
Fri, 18 Oct 2013 20:09:46 +0000 (16:09 -0400)
Signed-off-by: Eric S. Raymond <esr@thyrsus.com>
irkerd
irkerd.xml

diff --git a/irkerd b/irkerd
index b2bc9ce9791faeadd20b2e05835fcf197bf04200..c22e942e6033fb65257638cd251995511e113513 100755 (executable)
--- a/irkerd
+++ b/irkerd
@@ -154,20 +154,20 @@ class Connection:
                               % (self.servername, outof))
         qcopy = []
         while not self.queue.empty():
-            (channel, message) = self.queue.get()
+            (channel, message, key) = self.queue.get()
             if channel != outof:
-                qcopy.append((channel, message))
-        for (channel, message) in qcopy:
-            self.queue.put((channel, message))
+                qcopy.append((channel, message, key))
+        for (channel, message, key) in qcopy:
+            self.queue.put((channel, message, key))
         self.status = "ready"
-    def enqueue(self, channel, message):
+    def enqueue(self, channel, message, key):
         "Enque a message for transmission."
         if self.thread is None or not self.thread.is_alive():
             self.status = "unseen"
             self.thread = threading.Thread(target=self.dequeue)
             self.thread.setDaemon(True)
             self.thread.start()
-        self.queue.put((channel, message))
+        self.queue.put((channel, message, key))
     def dequeue(self):
         "Try to ship pending messages from the queue."
         try:
@@ -252,9 +252,9 @@ class Connection:
                     self.status = "expired"
                     break
                 elif self.status == "ready":
-                    (channel, message) = self.queue.get()
+                    (channel, message, key) = self.queue.get()
                     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))
                     # An empty message might be used as a keepalive or
                     # to join a channel for logging, so suppress the
@@ -339,6 +339,10 @@ class Target():
             self.channel = self.channel[:-7]
         if self.channel and not isnick and self.channel[0] not in "#&+":
             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)
     def valid(self):
         "Both components must be present for a valid target."
@@ -354,7 +358,7 @@ class Dispatcher:
         self.servername = servername
         self.port = port
         self.connections = []
-    def dispatch(self, channel, message):
+    def dispatch(self, channel, message, key):
         "Dispatch messages for our server-port combination."
         # First, check if there is room for another channel
         # on any of our existing connections.
@@ -362,7 +366,7 @@ class Dispatcher:
         eligibles = [x for x in connections if x.joined_to(channel)] \
                     or [x for x in connections if x.accepting(channel)]
         if eligibles:
-            eligibles[0].enqueue(channel, message)
+            eligibles[0].enqueue(channel, message, key)
             return
         # All connections are full up. Look for one old enough to be
         # scavenged.
@@ -377,14 +381,14 @@ class Dispatcher:
             found_connection.part(drop_channel, "scavenged by irkerd")
             del found_connection.channels_joined[drop_channel]
             #time.sleep(ANTI_FLOOD_DELAY)
-            found_connection.enqueue(channel, message)
+            found_connection.enqueue(channel, message, key)
             return
         # Didn't find any channels with no recent activity
         newconn = Connection(self.irker,
                              self.servername,
                              self.port)
         self.connections.append(newconn)
-        newconn.enqueue(channel, message)
+        newconn.enqueue(channel, message, key)
     def live(self):
         "Does this server-port combination have any live connections?"
         self.connections = [x for x in self.connections if x.live()]
@@ -511,7 +515,7 @@ class Irker:
                                 return
                             if target.server() not in self.servers:
                                 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
                             servernames = self.servers.keys()
                             for servername in servernames:
index 2af5a337f9353838b74d1173c57281b402671732..9d3907ac6d3f2cf73fdde95cdfa5accb551bce80 100644 (file)
@@ -45,6 +45,7 @@ Examples:
 {"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.hypothetical.net:6668/git-ciabot", "privmsg":"Hello, world!"}
+{"to":"irc://chat.hypothetical.net:6668/git-private?key=topsecret", "privmsg":"Keyed channel test"}
 </programlisting></para>
 
 <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
 <application>irkerd</application> sends messages to the the default 6667 IRC
 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
 <application>irkerd</application> to join the target channels without
 actually emitting a message.  This may be useful for advertising that