src/irc_net.c
changeset 150 e8018446b336
parent 147 fd97eb3c183a
child 153 d35e7cb3a489
equal deleted inserted replaced
149:549913bbe0d2 150:e8018446b336
   216         
   216         
   217     }
   217     }
   218 }
   218 }
   219 
   219 
   220 /**
   220 /**
       
   221  * :nm MODE <target> [<stuff> [ ... ]]
       
   222  *
       
   223  * If target is ourselves, handle as a private umode, otherwise, propagate to channel
       
   224  */
       
   225 static void irc_net_on_MODE (const struct irc_line *line, void *arg)
       
   226 {
       
   227     struct irc_net *net = arg;
       
   228 
       
   229     if (irc_conn_self(net->conn, line->args[0]))
       
   230         // don't really care about our umode...
       
   231         log_info("mode set: %s -> %s %s %s...", line->source->nickname, line->args[1], line->args[2], line->args[3]);
       
   232 
       
   233     else
       
   234         // it's a channel mode
       
   235         irc_net_propagate_chan(net, line, line->args[0]);
       
   236 
       
   237 }
       
   238 
       
   239 /**
   221  * Our irc_cmd handler list
   240  * Our irc_cmd handler list
   222  */
   241  */
   223 static struct irc_cmd_handler _cmd_handlers[] = {
   242 static struct irc_cmd_handler _cmd_handlers[] = {
   224     // propagate certain messages to the appropriate channel
   243     // propagate certain messages to the appropriate channel
   225     {   "QUIT",             &irc_net_on_chanuser    },
   244     {   "QUIT",             &irc_net_on_chanuser    },
   226     {   "JOIN",             &irc_net_on_chan0       },
   245     {   "JOIN",             &irc_net_on_chan0       },
   227     {   "PART",             &irc_net_on_chan0       },
   246     {   "PART",             &irc_net_on_chan0       },
   228     {   "MODE",             &irc_net_on_chan0       },
   247     {   "MODE",             &irc_net_on_MODE        },
   229     {   "TOPIC",            &irc_net_on_chan0       },
   248     {   "TOPIC",            &irc_net_on_chan0       },
   230     {   "KICK",             &irc_net_on_chan0       },
   249     {   "KICK",             &irc_net_on_chan0       },
   231     {   IRC_RPL_NAMREPLY,   &irc_net_on_chan2       },
   250     {   IRC_RPL_NAMREPLY,   &irc_net_on_chan2       },
   232     {   IRC_RPL_ENDOFNAMES, &irc_net_on_chan1       },
   251     {   IRC_RPL_ENDOFNAMES, &irc_net_on_chan1       },
   233     {   "CTCP ACTION",      &irc_net_on_chan0       },
   252     {   "CTCP ACTION",      &irc_net_on_chan0       },
   240     
   259     
   241     {   NULL,               NULL                    }
   260     {   NULL,               NULL                    }
   242 };
   261 };
   243 
   262 
   244 /**
   263 /**
   245  * The given socket is now connected, so create the irc_conn and bind it in to us
   264  * The given socket is now connected, so create the irc_conn and bind it in to us.
       
   265  *
       
   266  * If this fails, this will clean up any partial state, including sock.
   246  */
   267  */
   247 static err_t irc_net_connected (struct irc_net *net, struct sock_stream *sock, struct error_info *err)
   268 static err_t irc_net_connected (struct irc_net *net, struct sock_stream *sock, struct error_info *err)
   248 {
   269 {
   249     // create the irc connection state
   270     // create the irc connection state
   250     if (irc_conn_create(&net->conn, sock, &_conn_callbacks, net, err))
   271     if (irc_conn_create(&net->conn, sock, &_conn_callbacks, net, err))
   251         return ERROR_CODE(err);
   272         goto error;
   252 
   273 
   253     // add our command handlers
   274     // add our command handlers
   254     if ((ERROR_CODE(err) = irc_conn_add_cmd_handlers (net->conn, _cmd_handlers, net)))
   275     if ((ERROR_CODE(err) = irc_conn_add_cmd_handlers (net->conn, _cmd_handlers, net)))
   255         return ERROR_CODE(err);
   276         goto error;
   256 
   277 
   257     // register
   278     // register
   258     if ((ERROR_CODE(err) = irc_conn_register(net->conn, &net->info.register_info)))
   279     if ((ERROR_CODE(err) = irc_conn_register(net->conn, &net->info.register_info)))
   259         return ERROR_CODE(err);
   280         goto error;
   260 
   281 
   261     // ok
   282     // ok
   262     return SUCCESS;
   283     return SUCCESS;
   263 }
   284 
   264 
   285 error:
       
   286     if (!net->conn) {
       
   287         // cleanup sock ourselves
       
   288         sock_stream_release(sock);
       
   289 
       
   290     } else {
       
   291         // cleanup the partial stuff
       
   292         irc_conn_destroy(net->conn);
       
   293 
       
   294         net->conn = NULL;
       
   295     }
       
   296 
       
   297     return ERROR_CODE(err);
       
   298 }
       
   299 
       
   300 /**
       
   301  * Our sock_*_connect_async callback
       
   302  */
   265 static void irc_net_on_connect (struct sock_stream *sock, struct error_info *conn_err, void *arg)
   303 static void irc_net_on_connect (struct sock_stream *sock, struct error_info *conn_err, void *arg)
   266 {
   304 {
   267     struct irc_net *net = arg;
   305     struct irc_net *net = arg;
   268     struct error_info err;
   306     struct error_info err;
   269 
   307 
   278         FATAL_ERROR(&err, "irc_net_connected failed");
   316         FATAL_ERROR(&err, "irc_net_connected failed");
   279 
   317 
   280     // XXX: cleanup
   318     // XXX: cleanup
   281 }
   319 }
   282 
   320 
   283 err_t irc_net_create (struct irc_net **net_ptr, const struct irc_net_info *info, struct error_info *err)
   321 /**
   284 {
   322  * Connect and create a new irc_conn based on our irc_net_info.
   285     struct irc_net *net;
   323  */
       
   324 static err_t irc_net_connect (struct irc_net *net, struct error_info *err)
       
   325 {
       
   326     struct irc_net_info *info = &net->info;
   286     struct sock_stream *sock = NULL;
   327     struct sock_stream *sock = NULL;
   287     
   328 
   288     // allocate
   329     // sanity check
   289     if ((net = calloc(1, sizeof(*net))) == NULL)
   330     assert(!net->conn);
   290         return SET_ERROR(err, ERR_CALLOC);
   331 
   291 
   332     // connect based on what's known
   292     // initialize
       
   293     // XXX: info shouldn't be copied directly
       
   294     net->info = *info;
       
   295     TAILQ_INIT(&net->channels);
       
   296     LIST_INIT(&net->users);
       
   297 
       
   298     if (info->raw_sock) {
   333     if (info->raw_sock) {
   299         log_debug("connected using raw socket: %p", info->raw_sock);
   334         log_debug("connected using raw socket: %p", info->raw_sock);
   300 
   335 
   301         // direct sock_stream connection
   336         // direct sock_stream connection
   302         sock = info->raw_sock;
   337         sock = info->raw_sock;
   306             goto error;
   341             goto error;
   307 
   342 
   308     } else if (info->ssl_cred) {
   343     } else if (info->ssl_cred) {
   309         // aquire a ref
   344         // aquire a ref
   310         // NOTE: before any error handling
   345         // NOTE: before any error handling
   311         sock_ssl_client_cred_get(net->info.ssl_cred);
   346         sock_ssl_client_cred_get(info->ssl_cred);
   312         
   347         
   313         log_debug("connecting to [%s]:%s using SSL", info->hostname, info->service);
   348         log_debug("connecting to [%s]:%s using SSL", info->hostname, info->service);
   314 
   349 
   315         // connect
   350         // connect
   316         if (sock_ssl_connect_async(&sock, info->hostname, info->service, net->info.ssl_cred, &irc_net_on_connect, net, err))
   351         if (sock_ssl_connect_async(&sock, info->hostname, info->service, info->ssl_cred, &irc_net_on_connect, net, err))
   317             goto error;
   352             goto error;
   318 
   353 
   319     } else {
   354     } else {
   320         log_debug("connecting to [%s]:%s", info->hostname, info->service);
   355         log_debug("connecting to [%s]:%s", info->hostname, info->service);
   321             
   356             
   324             goto error;
   359             goto error;
   325         
   360         
   326     }
   361     }
   327 
   362 
   328     // ok
   363     // ok
       
   364     return SUCCESS;
       
   365 
       
   366 error:
       
   367     return ERROR_CODE(err);    
       
   368 }
       
   369 
       
   370 err_t irc_net_create (struct irc_net **net_ptr, const struct irc_net_info *info, struct error_info *err)
       
   371 {
       
   372     struct irc_net *net;
       
   373     
       
   374     // allocate
       
   375     if ((net = calloc(1, sizeof(*net))) == NULL)
       
   376         return SET_ERROR(err, ERR_CALLOC);
       
   377 
       
   378     // initialize
       
   379     // XXX: we need to copy *info's fields
       
   380     net->info = *info;
       
   381     TAILQ_INIT(&net->channels);
       
   382     LIST_INIT(&net->users);
       
   383 
       
   384     // initial connect
       
   385     if (irc_net_connect(net, err))
       
   386         goto error;
       
   387 
       
   388     // ok
   329     *net_ptr = net;
   389     *net_ptr = net;
   330 
   390 
   331     return SUCCESS;
   391     return SUCCESS;
   332 
   392 
   333 error:
   393 error:
   334     if (sock && !net->conn)
       
   335         // we need to clean up the socket ourself
       
   336         sock_stream_release(sock);
       
   337     
       
   338     // cleanup main
   394     // cleanup main
   339     irc_net_destroy(net);
   395     irc_net_destroy(net);
   340 
   396 
   341     return ERROR_CODE(err);
   397     return ERROR_CODE(err);
   342 }
   398 }