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