# HG changeset patch # User Tero Marttila # Date 1238526593 -10800 # Node ID f357f835f0d51b652b9c568fb164a16a97f32f06 # Parent d3bc82ee76cb11e3231fdc4c4067268f4e3747eb add irc_client_defaults to apply default values for irc_client_add_net irc_net_info, implement --defaults cmd opt and lua_client_connect diff -r d3bc82ee76cb -r f357f835f0d5 src/error.h --- a/src/error.h Tue Mar 31 20:57:07 2009 +0300 +++ b/src/error.h Tue Mar 31 22:09:53 2009 +0300 @@ -81,6 +81,7 @@ /** irc_net errors */ _ERR_IRC_NET = 0x000900, + ERR_IRC_NET_INFO, ERR_IRC_NET_STATE, /** @see module_error_code */ @@ -94,6 +95,8 @@ _ERR_LUA = 0x000c00, ERR_LUA_MEM, ERR_LUA_SYNTAX, + ERR_LUA_RUN, + ERR_LUA_ERR, /** irc_chan errors */ _ERR_IRC_CHAN = 0x000d00, @@ -102,6 +105,7 @@ /** General errors */ _ERR_GENERAL = 0xffff00, ERR_CMD_OPT, + ERR_UNKNOWN, }; diff -r d3bc82ee76cb -r f357f835f0d5 src/irc_client.c --- a/src/irc_client.c Tue Mar 31 20:57:07 2009 +0300 +++ b/src/irc_client.c Tue Mar 31 22:09:53 2009 +0300 @@ -37,12 +37,42 @@ free(client); } -err_t irc_client_add_net (struct irc_client *client, struct irc_net **net_ptr, struct irc_net_info *net_info, struct error_info *err) +void irc_client_set_defaults (struct irc_client *client, const struct irc_client_defaults *defaults) +{ + client->defaults = *defaults; +} + +#define APPLY_REGISTER_INFO_DEFAULT(out, value, def, _field_) ( \ + ((out)->register_info._field_ = ( \ + (value)->register_info._field_ ? (value)->register_info._field_ : ( \ + (def)->register_info._field_ \ + ) \ + )) == NULL \ + ) + +err_t irc_client_add_net (struct irc_client *client, struct irc_net **net_ptr, const struct irc_net_info *_net_info, struct error_info *err) { struct irc_net *net; + struct irc_net_info net_info = { + .use_ssl = _net_info->use_ssl, + }; + + // combine _net_info and defaults to get net_info + if ( + _net_info->raw_sock + || (net_info.network = _net_info->network) == NULL + || (net_info.hostname = _net_info->hostname) == NULL + || (net_info.service = (_net_info->service ? _net_info->service : ( + _net_info->use_ssl ? client->defaults.service_ssl : client->defaults.service + ))) == NULL + || APPLY_REGISTER_INFO_DEFAULT(&net_info, _net_info, &client->defaults, nickname) + || APPLY_REGISTER_INFO_DEFAULT(&net_info, _net_info, &client->defaults, username) + || APPLY_REGISTER_INFO_DEFAULT(&net_info, _net_info, &client->defaults, realname) + ) + return SET_ERROR(err, ERR_IRC_NET_INFO); // create the new irc_chan struct - if (irc_net_create(&net, net_info, err)) + if (irc_net_create(&net, &net_info, err)) return ERROR_CODE(err); // add to network list diff -r d3bc82ee76cb -r f357f835f0d5 src/irc_client.h --- a/src/irc_client.h Tue Mar 31 20:57:07 2009 +0300 +++ b/src/irc_client.h Tue Mar 31 22:09:53 2009 +0300 @@ -10,9 +10,26 @@ #include /** + * Defaults for irc_client operation, mostly add_net + */ +struct irc_client_defaults { + /** Default nickname/username/etc to use */ + struct irc_conn_register_info register_info; + + /** Default service (port) to use for non-SSL connections */ + const char *service; + + /** Default service (port) to use for SSL connections */ + const char *service_ssl; +}; + +/** * High-level IRC client state, this just means a set of named irc_net's and some common behaviour. */ struct irc_client { + /** Default parameters */ + struct irc_client_defaults defaults; + /** Our set of configured IRC networks */ TAILQ_HEAD(irc_client_networks, irc_net) networks; @@ -34,14 +51,27 @@ void irc_client_destroy (struct irc_client *client); /** - * Add a new IRC network + * Set the default parameters to use for e.g. add_net. + * + * The irc_client_defaults struct itself is copied, but not its contents. + * + * @param client the IRC client + * @param defaults the defaults to use, not copied + */ +void irc_client_set_defaults (struct irc_client *client, const struct irc_client_defaults *defaults); + +/** + * Add a new IRC network, using any default values set using irc_client_set_defaults() to replace NULL values in the + * given \a net_info. + * + * Use of raw_socket is not supported. * * @param client the irc_client state * @param net_ptr used to return the new irc_net if not NULL * @param net_info info required to identify and connect to the network * @param err returned error info */ -err_t irc_client_add_net (struct irc_client *client, struct irc_net **net_ptr, struct irc_net_info *net_info, struct error_info *err); +err_t irc_client_add_net (struct irc_client *client, struct irc_net **net_ptr, const struct irc_net_info *net_info, struct error_info *err); /** * Get a pre-existing IRC network by name diff -r d3bc82ee76cb -r f357f835f0d5 src/irc_net.h --- a/src/irc_net.h Tue Mar 31 20:57:07 2009 +0300 +++ b/src/irc_net.h Tue Mar 31 22:09:53 2009 +0300 @@ -76,6 +76,8 @@ * * Errors are returned via *err, also returning the error code. * + * The irc_net_info struct itself is copied, but the strings contained therein are not... + * * @param net the new irc_net struct is returned via this pointer * @param info network information, used to connect and register * @param err return error info diff -r d3bc82ee76cb -r f357f835f0d5 src/lua_objs.c --- a/src/lua_objs.c Tue Mar 31 20:57:07 2009 +0300 +++ b/src/lua_objs.c Tue Mar 31 22:09:53 2009 +0300 @@ -1,5 +1,7 @@ #include "lua_objs.h" +#include + #include #include #include @@ -218,20 +220,31 @@ struct irc_client *client; }; -static int lua_client_quit (lua_State *L) +static int lua_client_connect (lua_State *L) { struct lua_client *lua_client = lua_obj_get_obj(L, __func__, "evirc.client"); - err_t err; - - // the message - const char *message = luaL_checkstring(L, 2); + struct irc_net_info net_info; + struct irc_net *net; + struct error_info err; - // execute - if ((err = irc_client_quit(lua_client->client, message))) - return luaL_error(L, "irc_client_quit: %s", error_name(err)); + // init net_info + memset(&net_info, 0, sizeof(net_info)); - // ok - return 0; + // the network name + net_info.network = luaL_checkstring(L, 2); + + // the hostname + net_info.hostname = luaL_checkstring(L, 3); + + // service remains default + net_info.service = "6667"; + + // create it + if (irc_client_add_net(lua_client->client, &net, &net_info, &err)) + return luaL_error(L, "irc_client_add_net: %s/%s: %s", net_info.network, net_info.hostname, error_msg(&err)); + + // wrap it + return lua_net_create(L, net); } static int lua_client_get_network (lua_State *L) @@ -250,9 +263,26 @@ return lua_net_create(L, net); } +static int lua_client_quit (lua_State *L) +{ + struct lua_client *lua_client = lua_obj_get_obj(L, __func__, "evirc.client"); + err_t err; + + // the message + const char *message = luaL_checkstring(L, 2); + + // execute + if ((err = irc_client_quit(lua_client->client, message))) + return luaL_error(L, "irc_client_quit: %s", error_name(err)); + + // ok + return 0; +} + static const struct luaL_Reg lua_client_methods[] = { + { "connect", &lua_client_connect }, + { "network", &lua_client_get_network }, { "quit", &lua_client_quit }, - { "network", &lua_client_get_network }, { NULL, NULL } }; @@ -263,7 +293,6 @@ static void lua_client_init (lua_State *L, struct irc_client *client) { // allocate the global "client" object - // XXX: mem errors? struct lua_client *lua_client = lua_newuserdata(L, sizeof(*lua_client)); // create the type metatable @@ -279,12 +308,35 @@ lua_setglobal(L, "client"); } -err_t lua_objs_init (lua_State *L, struct nexus *nexus) +/** + * Set up the lua state in protected mode + */ +static int _lua_objs_init (lua_State *L) { + struct nexus *nexus; + + // read the nexus off the stack + if ((nexus = lua_touserdata(L, 1)) == NULL) + luaL_error(L, "lua_touserdata: NULL"); + // init the various bits lua_client_init(L, nexus->client); lua_net_init(L); lua_chan_init(L); - return SUCCESS; + // nothing + return 0; } + +err_t lua_objs_init (lua_State *L, struct nexus *nexus) +{ + // call in protected mode + switch (lua_cpcall(L, &_lua_objs_init, nexus)) { + case 0: return SUCCESS; + case LUA_ERRRUN: return ERR_LUA_RUN; + case LUA_ERRMEM: return ERR_LUA_MEM; + case LUA_ERRERR: return ERR_LUA_ERR; + default: return ERR_UNKNOWN; + } +} + diff -r d3bc82ee76cb -r f357f835f0d5 src/nexus.c --- a/src/nexus.c Tue Mar 31 20:57:07 2009 +0300 +++ b/src/nexus.c Tue Mar 31 22:09:53 2009 +0300 @@ -18,6 +18,7 @@ */ enum option_code { OPT_HELP = 'h', + OPT_DEFAULTS = 'D', OPT_NETWORK = 'n', OPT_CHANNEL = 'c', OPT_MODULE = 'm', @@ -35,6 +36,7 @@ */ static struct option options[] = { {"help", 0, NULL, OPT_HELP }, + {"defaults", 1, NULL, OPT_DEFAULTS }, {"network", 1, NULL, OPT_NETWORK }, {"channel", 1, NULL, OPT_CHANNEL }, {"module", 1, NULL, OPT_MODULE }, @@ -54,6 +56,7 @@ printf("Usage: %s [OPTIONS]\n", exe); printf("\n"); printf(" --help / -h display this message\n"); + printf(" --defaults / -D set the IRC client default info using '::'\n"); printf(" --network / -n add an IRC network using ':[:[:ssl]]' format\n"); printf(" --channel / -c add an IRC channel using ':' format\n"); printf(" --module / -m add a module using ':' format\n"); @@ -87,21 +90,49 @@ } /** + * Parse and apply a --defaults option, setting the resulting defaults to our irc_client + */ +static err_t apply_defaults (struct nexus *nexus, char *opt, struct error_info *err) +{ + struct irc_client_defaults defaults = { + .register_info = { NULL, NULL, NULL }, + .service = DEFAULT_PORT, + .service_ssl = DEFAULT_PORT_SSL, + }; + + // parse the required fields + if ((defaults.register_info.nickname = strsep(&opt, ":")) == NULL) + RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "missing field for --defaults"); + + if ((defaults.register_info.username = strsep(&opt, ":")) == NULL) + RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "missing field for --defaults"); + + if ((defaults.register_info.realname = strsep(&opt, ":")) == NULL) + RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "missing field for --defaults"); + + // trailing garbage? + if (opt) + RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "trailing values for --channel"); + + // apply them + log_info("using default nick/user/real-name: %s/%s/%s", + defaults.register_info.nickname, defaults.register_info.username, defaults.register_info.realname); + + irc_client_set_defaults(nexus->client, &defaults); + + // ok + return SET_ERROR(err, SUCCESS); +} + +/** * Parse and apply a --network option, adding the given network to our irc_client. */ static err_t apply_network (struct nexus *nexus, char *opt, struct error_info *err) { - struct irc_net_info info = { - .network = NULL, - .hostname = NULL, - .service = DEFAULT_PORT, - .use_ssl = false, - .register_info = { - .nickname = "SpBotDev", - .username = "spbot-dev", - .realname = "SpBot (development version)" - } - }; + struct irc_net_info info; + + // init to zero + memset(&info, 0, sizeof(info)); // parse the required fields if ((info.network = strsep(&opt, ":")) == NULL) @@ -280,6 +311,12 @@ return ERROR_CODE(err); break; + + case OPT_DEFAULTS: + if (apply_defaults(nexus, optarg, err)) + return ERROR_CODE(err); + + break; case OPT_CHANNEL: if (apply_channel(nexus, optarg, err))