irc_chan_on_KICK
authorTero Marttila <terom@fixme.fi>
Mon, 30 Mar 2009 14:45:14 +0300
changeset 89 68345a9b99a3
parent 88 233916a00429
child 90 9d489b1039b2
irc_chan_on_KICK
TODO
src/irc_chan.c
src/irc_chan.h
src/test.c
--- a/TODO	Mon Mar 30 01:47:44 2009 +0300
+++ b/TODO	Mon Mar 30 14:45:14 2009 +0300
@@ -4,7 +4,6 @@
  * tests...
 
 irc_conn:
- * support for CTCP messages, e.g. ACTION
  * ratelimit queue for outgoing messages
 
 irc_net:
--- a/src/irc_chan.c	Mon Mar 30 01:47:44 2009 +0300
+++ b/src/irc_chan.c	Mon Mar 30 14:45:14 2009 +0300
@@ -105,42 +105,6 @@
 }
 
 /**
- * Someone, or us ourselves, left a channel
- *
- * :nm PART <channel> [<message>]
- */
-static void irc_chan_on_PART (const struct irc_line *line, void *arg)
-{
-    struct irc_chan *chan = arg;
-
-    const char *msg = line->args[1];
-
-    // us?
-    if (irc_cmp_nick(line->source->nickname, chan->net->conn->nickname) == 0) {
-        // twiddle state
-        chan->joined = false;
-        chan->parted = true;
-
-        // invoke callback
-        IRC_CHAN_INVOKE_CALLBACK(chan, on_self_part);
-
-    } else {
-        // someone else
-        struct irc_chan_user *chan_user;
-        
-        // invoke callback (source, msg)
-        IRC_CHAN_INVOKE_CALLBACK(chan, on_part, line->source, msg);
-
-        // look up the irc_chan_user
-        if ((chan_user = irc_chan_get_user(chan, line->source->nickname)) == NULL)
-            return log_warn("PART'd user not on channel: %s, %s", irc_chan_name(chan), line->source->nickname);
-
-        // remove them
-        irc_chan_remove_user(chan, chan_user);
-    }
-}
-
-/**
  * :nm PRIVMSG <channel> <message>
  */
 static void irc_chan_on_PRIVMSG (const struct irc_line *line, void *arg)
@@ -202,6 +166,81 @@
 }
 
 /**
+ * Someone, or us ourselves, left a channel
+ *
+ * :nm PART <channel> [<message>]
+ */
+static void irc_chan_on_PART (const struct irc_line *line, void *arg)
+{
+    struct irc_chan *chan = arg;
+
+    const char *msg = line->args[1];
+
+    // us?
+    if (irc_cmp_nick(line->source->nickname, chan->net->conn->nickname) == 0) {
+        // twiddle state
+        chan->joined = false;
+        chan->parted = true;
+
+        // invoke callback
+        IRC_CHAN_INVOKE_CALLBACK(chan, on_self_part);
+        
+        // XXX: cleanup
+
+    } else {
+        // someone else
+        struct irc_chan_user *chan_user;
+        
+        // invoke callback (source, msg)
+        IRC_CHAN_INVOKE_CALLBACK(chan, on_part, line->source, msg);
+
+        // look up the irc_chan_user
+        if ((chan_user = irc_chan_get_user(chan, line->source->nickname)) == NULL)
+            return log_warn("PART'd user not on channel: %s, %s", irc_chan_name(chan), line->source->nickname);
+
+        // remove them
+        irc_chan_remove_user(chan, chan_user);
+    }
+}
+
+/**
+ * :nm KICK <channel> <target> [<reason>]
+ *
+ * User kicked some other user, might be us
+ */
+static void irc_chan_on_KICK (const struct irc_line *line, void *arg)
+{
+    struct irc_chan *chan = arg;
+    struct irc_chan_user *target_user;
+
+    const char *target = line->args[1];
+    const char *msg = line->args[2];
+
+    // us?
+    if (irc_cmp_nick(target, chan->net->conn->nickname) == 0) {
+        // twiddle state
+        chan->joined = false;
+        chan->kicked = true;
+
+        // invoke callback (source, msg)
+        IRC_CHAN_INVOKE_CALLBACK(chan, on_self_kicked, line->source, msg);
+
+        // XXX: cleanup
+
+    } else {
+        // look up the target irc_chan_user
+        if ((target_user = irc_chan_get_user(chan, target)) == NULL)
+            return log_warn("KICK'd user not on channel: %s, %s", irc_chan_name(chan), target);
+        
+        // invoke callback (source, target_user, msg)
+        IRC_CHAN_INVOKE_CALLBACK(chan, on_kick, line->source, target_user, msg);
+
+        // remove them
+        irc_chan_remove_user(chan, target_user);
+    }
+}
+
+/**
  * :nm QUIT [<message>]
  *
  * User quit, so remove them from our users list
@@ -233,6 +272,7 @@
     {   IRC_RPL_ENDOFNAMES, &irc_chan_on_RPL_ENDOFNAMES },
     {   "PRIVMSG",          &irc_chan_on_PRIVMSG        },
     {   "PART",             &irc_chan_on_PART           },
+    {   "KICK",             &irc_chan_on_KICK           },
     {   "QUIT",             &irc_chan_on_QUIT           },
     {   NULL,       NULL                                }
 };
--- a/src/irc_chan.h	Mon Mar 30 01:47:44 2009 +0300
+++ b/src/irc_chan.h	Mon Mar 30 14:45:14 2009 +0300
@@ -26,6 +26,19 @@
 };
 
 /**
+ * Per-channel-user state. This is used to store the list of irc_user's on an irc_chan.
+ *
+ * The nickname is accessible via user->nickname.
+ */
+struct irc_chan_user {
+    /** The per-network user info */
+    struct irc_user *user;
+
+    /** The irc_chan list */
+    LIST_ENTRY(irc_chan_user) chan_users;
+};
+
+/**
  * High-level IRC channel callbacks for convenience.
  *
  * These are based on the normal irc_chan::handlers interface, and you can use both freely.
@@ -42,12 +55,18 @@
     /** We parted the channel */
     void (*on_self_part) (struct irc_chan *chan, void *arg);
 
+    /** We were kicked from the channel */
+    void (*on_self_kicked) (struct irc_chan *chan, const struct irc_nm *source, const char *msg, void *arg);
+
     /** Someone joined the channel */
     void (*on_join) (struct irc_chan *chan, const struct irc_nm *source, void *arg);
 
     /** Someone parted the channel. The irc_chan_user is still present */
     void (*on_part) (struct irc_chan *chan, const struct irc_nm *source, const char *msg, void *arg);
 
+    /** Someone was kicked from the channel. The irc_chan_user is still present */
+    void (*on_kick)  (struct irc_chan *chan, const struct irc_nm *source, struct irc_chan_user *target, const char *msg, void *arg);
+
     /** Someone quit the channel. The irc_chan_user is still present */
     void (*on_quit) (struct irc_chan *chan, const struct irc_nm *source, const char *msg, void *arg);
 
@@ -56,19 +75,6 @@
 };
 
 /**
- * Per-channel-user state. This is used to store the list of irc_user's on an irc_chan.
- *
- * The nickname is accessible via user->nickname.
- */
-struct irc_chan_user {
-    /** The per-network user info */
-    struct irc_user *user;
-
-    /** The irc_chan list */
-    LIST_ENTRY(irc_chan_user) chan_users;
-};
-
-/**
  * Persistent IRC channel state, part of irc_net.
  *
  * This stores the channel's info, status flags, users list, and handlers/callbacks.
@@ -98,6 +104,9 @@
     /** We PART'd the channel */
     bool parted;
 
+    /** We were KICK'd from the channel */
+    bool kicked;
+
     // @}
     
     /** List of users on channel */
--- a/src/test.c	Mon Mar 30 01:47:44 2009 +0300
+++ b/src/test.c	Mon Mar 30 14:45:14 2009 +0300
@@ -878,6 +878,40 @@
     irc_net_destroy(net);
 }
 
+void test_irc_chan_user_kick (void)
+{
+    struct test_chan_ctx ctx;
+    struct sock_test *sock = setup_sock_test();
+    struct irc_net *net = setup_irc_net(sock);
+    struct irc_chan *chan = setup_irc_chan(sock, net, "#test", &ctx);
+
+    // kick a user
+    log_info("test irc_chan_on_KICK (other)");
+    test_sock_push(sock, ":userA!someone@somewhere KICK %s userB\r\n", "#test");
+    check_chan_user(chan, "userA", true);
+    check_chan_user(chan, "userB", false);
+
+    // cleanup
+    irc_net_destroy(net);
+}
+
+void test_irc_chan_self_kick (void)
+{
+    struct test_chan_ctx ctx;
+    struct sock_test *sock = setup_sock_test();
+    struct irc_net *net = setup_irc_net(sock);
+    struct irc_chan *chan = setup_irc_chan(sock, net, "#test", &ctx);
+
+    // kick a user
+    log_info("test irc_chan_on_KICK (self)");
+    test_sock_push(sock, ":userA!someone@somewhere KICK %s mynick foobar\r\n", "#test");
+    assert(!chan->joined);
+    assert(chan->kicked);
+
+    // cleanup
+    irc_net_destroy(net);
+}
+
 void test_irc_chan_user_nick (void)
 {
     struct test_chan_ctx ctx;
@@ -968,6 +1002,8 @@
     {   "irc_chan_namreply",    &test_irc_chan_namreply     },
     {   "irc_chan_user_join",   &test_irc_chan_user_join    },
     {   "irc_chan_user_part",   &test_irc_chan_user_part    },
+    {   "irc_chan_user_kick",   &test_irc_chan_user_kick    },
+    {   "irc_chan_self_kick",   &test_irc_chan_self_kick    },
     {   "irc_chan_user_nick",   &test_irc_chan_user_nick    },
     {   "irc_chan_user_quit",   &test_irc_chan_user_quit    },
     {   "irc_chan_CTCP_ACTION", &test_irc_chan_CTCP_ACTION  },