#include "lua_irc.h"
#include "lua_func.h"
#include <stdlib.h>
#include <string.h>
static struct lua_type lua_chan_type = LUA_TYPE("evirc.chan");
/**
* Create a lua_chan userdata from the given irc_chan and leave it on the stack, returning 1
*/
static int lua_chan_create (lua_State *L, struct irc_chan *chan)
{
// create the new obj
struct lua_chan *lua_chan = lua_type_create(L, &lua_chan_type, sizeof(*lua_chan));
// initialize
lua_chan->chan = chan;
// ok
return 1;
}
/**
* Return the channel name as a lua string
*/
static struct lua_func lua_chan__tostring_func = LUA_FUNC(&lua_chan_type, "__tostring",
"format using channel name",
LUA_FUNC_ARG_END
);
static int lua_chan__tostring (lua_State *L)
{
struct lua_chan *lua_chan;
lua_args_parse(L, &lua_chan__tostring_func, (void *) &lua_chan);
lua_pushfstring(L, "<irc_chan %s>", irc_chan_name(lua_chan->chan));
return 1;
}
/**
* Send a PRIVMSG to the channel
*/
static struct lua_func lua_chan_say_func = LUA_FUNC(&lua_chan_type, "evirc.chan.say",
"send a message to a channel",
LUA_FUNC_ARG_STRING("message", LUA_ARG_STRING_REQUIRED )
);
static int lua_chan_say (lua_State *L)
{
struct lua_chan *lua_chan;
err_t err;
const char *message;
// parse args
lua_args_parse(L, &lua_chan_say_func, (void *) &lua_chan,
&message
);
// send
if ((err = irc_chan_PRIVMSG(lua_chan->chan, message)))
return luaL_error(L, "irc_chan_PRIVMSG: '%s': %s", message, error_name(err));
// ok
return 0;
}
static struct lua_method lua_chan_methods[] = LUA_METHODS(
LUA_METHOD("__tostring", lua_chan__tostring, &lua_chan__tostring_func ),
LUA_METHOD("say", lua_chan_say, &lua_chan_say_func )
);
static struct lua_type lua_net_type = LUA_TYPE("evirc.net");
/**
* Create a lua_net userdata from the given irc_net and push it onto the stack, returning 1.
*/
static int lua_net_create (lua_State *L, struct irc_net *net)
{
// create the new obj
struct lua_net *lua_net = lua_type_create(L, &lua_net_type, sizeof(*lua_net));
// initialize
lua_net->net = net;
// ok
return 1;
}
/**
* Return the network name as a lua string
*/
static struct lua_func lua_net__tostring_func = LUA_FUNC(&lua_net_type, "__tostring",
"format using network name",
LUA_FUNC_ARG_END
);
static int lua_net__tostring (lua_State *L)
{
struct lua_net *lua_net;
lua_args_parse(L, &lua_net__tostring_func, (void *) &lua_net);
lua_pushfstring(L, "<irc_net %s>", irc_net_name(lua_net->net));
return 1;
}
/**
* Join a new channel, returning the lua_chan
*/
static struct lua_func lua_net_join_func = LUA_FUNC(&lua_net_type, "join",
"create a new channel and join it",
LUA_FUNC_ARG_STRING("channel", LUA_ARG_STRING_REQUIRED)
);
static int lua_net_join (lua_State *L)
{
struct lua_net *lua_net;
struct irc_chan_info chan_info;
struct irc_chan *chan;
struct error_info err;
// the channel name
lua_args_parse(L, &lua_net_join_func, (void *) &lua_net,
&chan_info.channel
);
// add it
if (irc_net_add_chan(lua_net->net, &chan, &chan_info, &err))
return luaL_error(L, "irc_net_add_chan: %s: %s", chan_info.channel, error_msg(&err));
// return it
return lua_chan_create(L, chan);
}
/**
* Look up a channel by name, returning the lua_chan
*/
static struct lua_func lua_net_get_chan_func = LUA_FUNC(&lua_net_type, "channel",
"look up a channel by name",
LUA_FUNC_ARG_STRING("channel", LUA_ARG_STRING_REQUIRED)
);
static int lua_net_get_chan (lua_State *L)
{
struct lua_net *lua_net;
struct irc_chan *chan;
const char *channel;
// parse args
lua_args_parse(L, &lua_net_get_chan_func, (void *) &lua_net,
&channel
);
// lookup the irc_chan
if ((chan = irc_net_get_chan(lua_net->net, channel)) == NULL)
return luaL_error(L, "irc_net_get_chan: no such channel: %s", channel);
// wrap it
return lua_chan_create(L, chan);
}
static struct lua_func lua_net_channels_func = LUA_FUNC(&lua_net_type, "channels",
"Return an iterater over the network's channels",
LUA_FUNC_ARG_END
);
static int lua_net_channels_iter (lua_State *L)
{
int nargs = lua_gettop(L);
struct lua_net *lua_net = lua_arg_obj(L, nargs, 1, &lua_net_type, false);
struct lua_chan *lua_chan = lua_arg_obj(L, nargs, 2, &lua_chan_type, true);
struct irc_chan *chan_next;
// get next item from current
if (lua_chan)
chan_next = TAILQ_NEXT(lua_chan->chan, net_channels);
else
chan_next = TAILQ_FIRST(&lua_net->net->channels);
// push return value - next item
if (chan_next)
lua_chan_create(L, chan_next);
else
lua_pushnil(L);
return 1;
}
static int lua_net_channels (lua_State *L)
{
struct lua_net *lua_net;
// parse args
lua_args_parse(L, &lua_net_channels_func, (void *) &lua_net);
// push iter func
lua_pushcfunction(L, lua_net_channels_iter);
// push invariant state - the lua_net
lua_pushvalue(L, 1);
// return iter three-tuple
return 2;
}
static struct lua_method lua_net_methods[] = LUA_METHODS(
LUA_METHOD("__tostring", lua_net__tostring, &lua_net__tostring_func ),
LUA_METHOD("join", lua_net_join, &lua_net_join_func ),
LUA_METHOD("channel", lua_net_get_chan, &lua_net_get_chan_func ),
LUA_METHOD("channels", lua_net_channels, &lua_net_channels_func )
);
static struct lua_type lua_client_type = LUA_TYPE("evirc.client");
static struct lua_func lua_client_set_defaults_func = LUA_FUNC(&lua_client_type, "set_defaults",
"set the default settings to use for evirc.client.connect",
LUA_FUNC_ARG_STRING("nickname", LUA_ARG_STRING_REQUIRED ),
LUA_FUNC_ARG_STRING("username", LUA_ARG_STRING_REQUIRED ),
LUA_FUNC_ARG_STRING("realname", LUA_ARG_STRING_REQUIRED ),
LUA_FUNC_ARG_STRING("service", IRC_PORT ),
LUA_FUNC_ARG_STRING("service_ssl", IRC_SSL_PORT )
);
static int lua_client_set_defaults (lua_State *L)
{
struct lua_client *lua_client;
const char *nickname, *username, *realname, *service, *service_ssl;
// parse args
lua_args_parse(L, &lua_client_set_defaults_func, (void *) &lua_client,
&nickname, &username, &realname, &service, &service_ssl
);
// set
struct irc_client_defaults defaults = {
.register_info = {
.nickname = nickname,
.username = username,
.realname = realname
},
.service = service,
.service_ssl = service_ssl
};
// invoke
// XXX: needs to be copied
irc_client_set_defaults(lua_client->client, &defaults);
// ok
return 0;
}
static struct lua_func lua_client_connect_func = LUA_FUNC(&lua_client_type, "connect",
"Create and return a new IRC network",
LUA_FUNC_ARG_STRING("network", LUA_ARG_STRING_REQUIRED ),
LUA_FUNC_ARG_STRING("hostname", LUA_ARG_STRING_REQUIRED ),
LUA_FUNC_ARG_STRING("service", NULL ),
LUA_FUNC_ARG_BOOL( "ssl", false ),
LUA_FUNC_ARG_STRING("ssl_cafile", NULL ),
LUA_FUNC_ARG_BOOL( "ssl_verify", false ),
LUA_FUNC_ARG_STRING("ssl_cert", NULL ),
LUA_FUNC_ARG_STRING("ssl_pkey", NULL )
);
static int lua_client_connect (lua_State *L)
{
struct lua_client *lua_client;
struct irc_net_info net_info;
const char *ssl_cafile = NULL, *ssl_cert = NULL, *ssl_pkey = NULL;
bool use_ssl = false, ssl_verify = false;
struct irc_net *net;
struct error_info err;
// init net_info
memset(&net_info, 0, sizeof(net_info));
// parse args
lua_args_parse(L, &lua_client_connect_func, (void *) &lua_client,
&net_info.network, &net_info.hostname, &net_info.service,
&use_ssl, &ssl_cafile, &ssl_verify, &ssl_cert, &ssl_pkey
);
// SSL?
if (use_ssl || ssl_cafile || ssl_verify || ssl_cert || ssl_pkey) {
// verify
if ((ssl_cert || ssl_pkey) && !(ssl_cert && ssl_pkey))
return luaL_error(L, "must give both ssl_cert and ssl_pkey");
// create
if (ssl_client_cred_create(&net_info.ssl_cred, ssl_cafile, ssl_verify, ssl_cert, ssl_pkey, &err))
return luaL_error(L, "sock_ssl_client_cred_create(ssl_cafile=%s, ssl_verify=%b, ssl_cert=%s, ssl_pkey=%s): %s",
ssl_cafile, ssl_verify, ssl_cert, ssl_pkey, error_msg(&err)
);
}
// 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 struct lua_func lua_client_get_network_func = LUA_FUNC(&lua_client_type, "network",
"Lookup an existing network by name",
LUA_FUNC_ARG_STRING("network", LUA_ARG_STRING_REQUIRED)
);
static int lua_client_get_network (lua_State *L)
{
struct lua_client *lua_client;
struct irc_net *net;
const char *network;
// parse args
lua_args_parse(L, &lua_client_get_network_func, (void *) &lua_client,
&network
);
// lookup the irc_net
if ((net = irc_client_get_net(lua_client->client, network)) == NULL)
return luaL_error(L, "irc_client_get_net: no such network: %s", network);
// wrap it
return lua_net_create(L, net);
}
static struct lua_func lua_client_networks_func = LUA_FUNC(&lua_client_type, "channels",
"Return an iterator over the client's networks",
LUA_FUNC_ARG_END
);
static int lua_client_networks_iter (lua_State *L)
{
int nargs = lua_gettop(L);
struct lua_client *lua_client = lua_arg_obj(L, nargs, 1, &lua_client_type, false);
struct lua_net *lua_net = lua_arg_obj(L, nargs, 2, &lua_net_type, true);
struct irc_net *net_next;
if (lua_net)
// return next
net_next = TAILQ_NEXT(lua_net->net, client_networks);
else
// return first
net_next = TAILQ_FIRST(&lua_client->client->networks);
// build and return next value
if (net_next)
lua_net_create(L, net_next);
else
lua_pushnil(L);
return 1;
}
static int lua_client_networks (lua_State *L)
{
struct lua_client *lua_client;
// parse args
lua_args_parse(L, &lua_client_networks_func, (void *) &lua_client);
// push iter func
lua_pushcfunction(L, lua_client_networks_iter);
// push invariant state - the lua_client
lua_pushvalue(L, 1);
// return three-tuple
return 2;
}
static struct lua_func lua_client_quit_func = LUA_FUNC(&lua_client_type, "quit",
"Disconnect from all networks",
LUA_FUNC_ARG_STRING("message", "Bye")
);
static int lua_client_quit (lua_State *L)
{
struct lua_client *lua_client;
err_t err;
const char *message;
// parse args
lua_args_parse(L, &lua_client_quit_func, (void *) &lua_client,
&message
);
// 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 struct lua_method lua_client_methods[] = LUA_METHODS(
LUA_METHOD("set_defaults", lua_client_set_defaults, &lua_client_set_defaults_func ),
LUA_METHOD("connect", lua_client_connect, &lua_client_connect_func ),
LUA_METHOD("network", lua_client_get_network, &lua_client_get_network_func ),
LUA_METHOD("networks", lua_client_networks, &lua_client_networks_func ),
LUA_METHOD("quit", lua_client_quit, &lua_client_quit_func )
);
void lua_irc_init (struct nexus_lua *lua)
{
// register types
lua_type_register(lua->st, &lua_chan_type, lua_chan_methods);
lua_type_register(lua->st, &lua_net_type, lua_net_methods);
// register the global "client" object
struct lua_client *lua_client = lua_type_register_global(lua->st, &lua_client_type, lua_client_methods, "client", sizeof(*lua_client));
// initialize it
lua_client->client = lua->nexus->client;
}