add irc_client_defaults to apply default values for irc_client_add_net irc_net_info, implement --defaults cmd opt and lua_client_connect
--- 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,
};
--- 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
--- 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 <sys/queue.h>
/**
+ * 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
--- 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
--- 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 <string.h>
+
#include <lua5.1/lua.h>
#include <lua5.1/lualib.h>
#include <lua5.1/lauxlib.h>
@@ -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;
+ }
+}
+
--- 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 '<nickname>:<username>:<realname>'\n");
printf(" --network / -n add an IRC network using '<name>:<hostname>[:<port>[:ssl]]' format\n");
printf(" --channel / -c add an IRC channel using '<network>:<channel>' format\n");
printf(" --module / -m add a module using '<name>:<path>' 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 <nickname> field for --defaults");
+
+ if ((defaults.register_info.username = strsep(&opt, ":")) == NULL)
+ RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "missing <username> field for --defaults");
+
+ if ((defaults.register_info.realname = strsep(&opt, ":")) == NULL)
+ RETURN_SET_ERROR_STR(err, ERR_CMD_OPT, "missing <realname> 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))