diff -r 549913bbe0d2 -r e8018446b336 src/irc_net.c --- a/src/irc_net.c Thu Apr 23 21:05:27 2009 +0300 +++ b/src/irc_net.c Thu Apr 23 21:05:52 2009 +0300 @@ -218,6 +218,25 @@ } /** + * :nm MODE [ [ ... ]] + * + * If target is ourselves, handle as a private umode, otherwise, propagate to channel + */ +static void irc_net_on_MODE (const struct irc_line *line, void *arg) +{ + struct irc_net *net = arg; + + if (irc_conn_self(net->conn, line->args[0])) + // don't really care about our umode... + log_info("mode set: %s -> %s %s %s...", line->source->nickname, line->args[1], line->args[2], line->args[3]); + + else + // it's a channel mode + irc_net_propagate_chan(net, line, line->args[0]); + +} + +/** * Our irc_cmd handler list */ static struct irc_cmd_handler _cmd_handlers[] = { @@ -225,7 +244,7 @@ { "QUIT", &irc_net_on_chanuser }, { "JOIN", &irc_net_on_chan0 }, { "PART", &irc_net_on_chan0 }, - { "MODE", &irc_net_on_chan0 }, + { "MODE", &irc_net_on_MODE }, { "TOPIC", &irc_net_on_chan0 }, { "KICK", &irc_net_on_chan0 }, { IRC_RPL_NAMREPLY, &irc_net_on_chan2 }, @@ -242,26 +261,45 @@ }; /** - * The given socket is now connected, so create the irc_conn and bind it in to us + * The given socket is now connected, so create the irc_conn and bind it in to us. + * + * If this fails, this will clean up any partial state, including sock. */ static err_t irc_net_connected (struct irc_net *net, struct sock_stream *sock, struct error_info *err) { // create the irc connection state if (irc_conn_create(&net->conn, sock, &_conn_callbacks, net, err)) - return ERROR_CODE(err); + goto error; // add our command handlers if ((ERROR_CODE(err) = irc_conn_add_cmd_handlers (net->conn, _cmd_handlers, net))) - return ERROR_CODE(err); + goto error; // register if ((ERROR_CODE(err) = irc_conn_register(net->conn, &net->info.register_info))) - return ERROR_CODE(err); + goto error; // ok return SUCCESS; + +error: + if (!net->conn) { + // cleanup sock ourselves + sock_stream_release(sock); + + } else { + // cleanup the partial stuff + irc_conn_destroy(net->conn); + + net->conn = NULL; + } + + return ERROR_CODE(err); } +/** + * Our sock_*_connect_async callback + */ static void irc_net_on_connect (struct sock_stream *sock, struct error_info *conn_err, void *arg) { struct irc_net *net = arg; @@ -280,21 +318,18 @@ // XXX: cleanup } -err_t irc_net_create (struct irc_net **net_ptr, const struct irc_net_info *info, struct error_info *err) +/** + * Connect and create a new irc_conn based on our irc_net_info. + */ +static err_t irc_net_connect (struct irc_net *net, struct error_info *err) { - struct irc_net *net; + struct irc_net_info *info = &net->info; struct sock_stream *sock = NULL; - - // allocate - if ((net = calloc(1, sizeof(*net))) == NULL) - return SET_ERROR(err, ERR_CALLOC); - // initialize - // XXX: info shouldn't be copied directly - net->info = *info; - TAILQ_INIT(&net->channels); - LIST_INIT(&net->users); + // sanity check + assert(!net->conn); + // connect based on what's known if (info->raw_sock) { log_debug("connected using raw socket: %p", info->raw_sock); @@ -308,12 +343,12 @@ } else if (info->ssl_cred) { // aquire a ref // NOTE: before any error handling - sock_ssl_client_cred_get(net->info.ssl_cred); + sock_ssl_client_cred_get(info->ssl_cred); log_debug("connecting to [%s]:%s using SSL", info->hostname, info->service); // connect - if (sock_ssl_connect_async(&sock, info->hostname, info->service, net->info.ssl_cred, &irc_net_on_connect, net, err)) + if (sock_ssl_connect_async(&sock, info->hostname, info->service, info->ssl_cred, &irc_net_on_connect, net, err)) goto error; } else { @@ -326,15 +361,36 @@ } // ok + return SUCCESS; + +error: + return ERROR_CODE(err); +} + +err_t irc_net_create (struct irc_net **net_ptr, const struct irc_net_info *info, struct error_info *err) +{ + struct irc_net *net; + + // allocate + if ((net = calloc(1, sizeof(*net))) == NULL) + return SET_ERROR(err, ERR_CALLOC); + + // initialize + // XXX: we need to copy *info's fields + net->info = *info; + TAILQ_INIT(&net->channels); + LIST_INIT(&net->users); + + // initial connect + if (irc_net_connect(net, err)) + goto error; + + // ok *net_ptr = net; return SUCCESS; error: - if (sock && !net->conn) - // we need to clean up the socket ourself - sock_stream_release(sock); - // cleanup main irc_net_destroy(net);