--- a/src/irc_chan.c Thu Mar 26 22:03:20 2009 +0200
+++ b/src/irc_chan.c Thu Mar 26 22:54:25 2009 +0200
@@ -27,7 +27,7 @@
if (irc_chan_get_user(chan, nickname))
return SUCCESS;
- // lookup/create the irc_user state
+ // lookup/create the irc_user state, incrementing the refcount
if ((err = irc_net_get_user(chan->net, &user, nickname)))
return err;
@@ -48,6 +48,21 @@
}
/**
+ * Remove an irc_chan_user previously added by irc_chan_add_user().
+ */
+static void irc_chan_remove_user (struct irc_chan *chan, struct irc_chan_user *chan_user)
+{
+ // put the irc_user reference back, decrementing refcount
+ irc_net_put_user(chan->net, chan_user->user);
+
+ // remove from list
+ LIST_REMOVE(chan_user, chan_users);
+
+ // free
+ free(chan_user);
+}
+
+/**
* :nm JOIN <channel>
*/
static void irc_chan_on_JOIN (const struct irc_line *line, void *arg)
@@ -82,6 +97,49 @@
}
/**
+ * 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;
+ err_t err;
+
+ const char *msg = line->args[1];
+
+ // us?
+ if (irc_prefix_cmp_nick(line->prefix, 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
+ char prefix_buf[IRC_PREFIX_MAX];
+ struct irc_nm nm;
+ struct irc_chan_user *chan_user;
+
+ // parse the nickname
+ if ((err = irc_nm_parse(&nm, prefix_buf, line->prefix)))
+ return log_warn("invalid prefix: %s", line->prefix);
+
+ // invoke callback (source, msg)
+ IRC_CHAN_INVOKE_CALLBACK(chan, on_part, &nm, msg);
+
+ // look up the irc_chan_user
+ if ((chan_user = irc_chan_get_user(chan, nm.nickname)) == NULL)
+ return log_warn("PART'd user not on channel: %s, %s", irc_chan_name(chan), nm.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)
@@ -156,6 +214,7 @@
*/
struct irc_cmd_handler _cmd_handlers[] = {
{ "JOIN", &irc_chan_on_JOIN },
+ { "PART", &irc_chan_on_PART },
{ "PRIVMSG", &irc_chan_on_PRIVMSG },
{ IRC_RPL_NAMREPLY, &irc_chan_on_RPL_NAMREPLY },
{ IRC_RPL_ENDOFNAMES, &irc_chan_on_RPL_ENDOFNAMES },
@@ -197,7 +256,12 @@
void irc_chan_destroy (struct irc_chan *chan)
{
- // XXX: free chan_users list
+ struct irc_chan_user *chan_user;
+
+ // free users
+ while ((chan_user = LIST_FIRST(&chan->users))) {
+ irc_chan_remove_user(chan, chan_user);
+ }
// free command handlers
irc_cmd_free(&chan->handlers);