-/* Copyright (C) Chris Porter 2005 */
+/* Copyright (C) Chris Porter 2005-2007 */
/* ALL RIGHTS RESERVED. */
/* Don't put this into the SVN repo. */
+/*
+ @todo
+ - Write a nick printf type thing for pcalled functions.
+ - Make commands register as apposed to blinding calling.
+ - Use numerics instead of huge structures, and add lookup functions.
+*/
+
#include "../channel/channel.h"
#include "../control/control.h"
#include "../nick/nick.h"
#include "../localuser/localuser.h"
#include "../localuser/localuserchannel.h"
#include "../lib/irc_string.h"
+#include "../lib/flags.h"
#include "lua.h"
#include "luabot.h"
#include <stdarg.h>
+#include <stddef.h>
+
+#define MAX_PUSHER 50
static int lua_smsg(lua_State *ps);
static int lua_skill(lua_State *ps);
-int lua_lineok(const char *data) {
- if(strchr(data, '\r') || strchr(data, '\n'))
- return 0;
- return 1;
-}
+typedef struct lua_pusher {
+ short argtype;
+ short offset;
+ const char *structname;
+} lua_pusher;
+
+struct lua_pusher nickpusher[MAX_PUSHER];
+struct lua_pusher chanpusher[MAX_PUSHER];
+int nickpushercount, chanpushercount;
+
+void lua_setuppusher(struct lua_pusher *pusherlist, lua_State *l, int index, struct lua_pusher **lp, int max, int pcount);
+int lua_usepusher(lua_State *l, struct lua_pusher **lp, void *np);
+
+void lua_initnickpusher(void);
+void lua_initchanpusher(void);
+
+#define lua_setupnickpusher(L2, I2, P2, M2) lua_setuppusher(&nickpusher[0], L2, I2, P2, M2, nickpushercount)
+#define lua_setupchanpusher(L2, I2, P2, M2) lua_setuppusher(&chanpusher[0], L2, I2, P2, M2, chanpushercount)
+
+int lua_cmsg(char *channell, char *message, ...) __attribute__ ((format (printf, 2, 3)));
int lua_cmsg(char *channell, char *message, ...) {
char buf[512];
LUA_RETURN(ps, lua_cmsg(LUA_PUKECHAN, "lua: %s", lua_tostring(ps, 1)));
}
-static int lua_scripterror(lua_State *ps) {
- if(!lua_isstring(ps, 1))
- LUA_RETURN(ps, LUA_FAIL);
-
- LUA_RETURN(ps, lua_cmsg(LUA_PUKECHAN, "lua-error: %s", lua_tostring(ps, 1)));
-}
-
static int lua_ctcp(lua_State *ps) {
const char *n, *msg;
nick *np;
LUA_RETURN(ps, LUA_OK);
}
+static int lua_privmsgcmd(lua_State *ps) {
+ const char *n, *msg;
+ nick *np;
+
+ if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
+ LUA_RETURN(ps, LUA_FAIL);
+
+ n = lua_tostring(ps, 1);
+ msg = lua_tostring(ps, 2);
+
+ np = getnickbynick(n);
+ if(!np || !lua_lineok(msg))
+ LUA_RETURN(ps, LUA_FAIL);
+
+ lua_message(np, "%s", msg);
+
+ LUA_RETURN(ps, LUA_OK);
+}
+
static int lua_kill(lua_State *ps) {
const char *n, *msg;
nick *np;
const char *n, *msg, *chan;
nick *np;
channel *cp;
+ int dochecks = 1;
if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2) || !lua_isstring(ps, 3))
LUA_RETURN(ps, LUA_FAIL);
n = lua_tostring(ps, 2);
msg = lua_tostring(ps, 3);
+ if(lua_isboolean(ps, 4) && !lua_toboolean(ps, 4))
+ dochecks = 0;
+
np = getnickbynick(n);
if(!np)
LUA_RETURN(ps, LUA_FAIL);
+ if(dochecks && (IsOper(np) || IsXOper(np) || IsService(np)))
+ LUA_RETURN(ps, LUA_FAIL);
+
cp = findchannel((char *)chan);
if(!cp)
LUA_RETURN(ps, LUA_FAIL);
LUA_RETURN(ps, LUA_FAIL);
duration = lua_toint(ps, 2);
- if((duration < 1) || (duration > 86400))
+ if((duration < 1) || (duration > 31 * 86400))
LUA_RETURN(ps, LUA_FAIL);
reason = lua_tostring(ps, 3);
if(usercount > 50)
LUA_RETURN(ps, LUA_FAIL);
- snprintf(mask, sizeof(mask), "*%s@%s", target->ident, IPtostr(target->ipaddress));
+ snprintf(mask, sizeof(mask), "*%s@%s", target->ident, IPtostr(target->p_ipaddr));
} else {
- snprintf(mask, sizeof(mask), "*@%s", IPtostr(target->ipaddress));
+ snprintf(mask, sizeof(mask), "*@%s", IPtostr(target->p_ipaddr));
}
- irc_send("%s GL * +%s %d :%s", mynumeric->content, mask, duration, reason);
+ irc_send("%s GL * +%s %d %jd :%s", mynumeric->content, mask, duration, (intmax_t)getnettime(), reason);
LUA_RETURN(ps, lua_cmsg(LUA_PUKECHAN, "lua-GLINE: %s (%d users, %d seconds -- %s)", mask, usercount, duration, reason));
}
-static int lua_getchaninfo(lua_State *ps) {
+static int lua_fastgetchaninfo(lua_State *ps) {
+ static struct lua_pusher *ourpusher[MAX_PUSHER];
channel *cp;
if(!lua_isstring(ps, 1))
return 0;
cp = findchannel((char *)lua_tostring(ps, 1));
- if(!cp)
+ if(!cp || cp->index->channel != cp)
return 0;
- LUA_PUSHCHAN(ps, cp);
-
- return 1;
+ lua_setupchanpusher(ps, 2, ourpusher, MAX_PUSHER);
+ return lua_usepusher(ps, ourpusher, cp->index);
}
static int lua_opchan(lua_State *ps) {
LUA_RETURN(ps, LUA_OK);
}
+static int lua_deopchan(lua_State *ps) {
+ channel *cp;
+ nick *np;
+
+ if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
+ LUA_RETURN(ps, LUA_FAIL);
+
+ cp = findchannel((char *)lua_tostring(ps, 1));
+ if(!cp)
+ LUA_RETURN(ps, LUA_FAIL);
+
+ np = getnickbynick((char *)lua_tostring(ps, 2));
+ if(!np)
+ LUA_RETURN(ps, LUA_FAIL);
+
+ localsetmodes(lua_nick, cp, np, MC_DEOP);
+ LUA_RETURN(ps, LUA_OK);
+}
+
static int lua_voicechan(lua_State *ps) {
channel *cp;
nick *np;
lua_pushstring(ps, __DATE__);
lua_pushstring(ps, __TIME__);
- return 4;
+ lua_pushstring(ps, LUA_AUXVERSION);
+
+ return 5;
+}
+
+static int lua_basepath(lua_State *ps) {
+ lua_pushfstring(ps, "%s/", cpath->content);
+
+ return 1;
+}
+
+static int lua_botnick(lua_State *ps) {
+ lua_pushstring(ps, luabotnick->content);
+
+ return 1;
}
/* O(n) */
if(!lua_isstring(l, 1))
return 0;
+ acc = lua_tostring(l, 1);
+
for(i=0;i<NICKHASHSIZE;i++) {
for(np=nicktable[i];np;np=np->next) {
- if(np && np->authname && !ircd_strcmp(np->authname, acc)) {
- LUA_PUSHNICK(l, np);
+ if(np && np->authname[0] && !ircd_strcmp(np->authname, acc)) {
+ lua_pushnumeric(l, np->numeric);
found++;
}
}
return np->channels->cursi;
}
+static int lua_getnickchanindex(lua_State *l) {
+ nick *np;
+ int offset;
+
+ if(!lua_islong(l, 1) || !lua_isint(l, 2))
+ return 0;
+
+ np = getnickbynumeric(lua_tolong(l, 1));
+ if(!np)
+ return 0;
+
+ offset = lua_toint(l, 2);
+ if((offset < 0) || (offset >= np->channels->cursi))
+ return 0;
+
+ lua_pushstring(l, ((channel **)np->channels->content)[offset]->index->name->content);
+
+ return 1;
+}
+
+int hashindex;
+nick *lasthashnick;
+static int geoipext;
+
+struct lua_pusher *nickhashpusher[MAX_PUSHER];
+
+static int lua_getnextnick(lua_State *l) {
+ if(!lasthashnick && (hashindex != -1))
+ return 0;
+
+ do {
+ if(!lasthashnick) {
+ hashindex++;
+ if(hashindex >= NICKHASHSIZE)
+ return 0;
+ lasthashnick = nicktable[hashindex];
+ } else {
+ lasthashnick = lasthashnick->next;
+ }
+ } while(!lasthashnick);
+
+ return lua_usepusher(l, nickhashpusher, lasthashnick);
+}
+
+static int lua_getfirstnick(lua_State *l) {
+ hashindex = -1;
+ lasthashnick = NULL;
+
+ lua_setupnickpusher(l, 1, nickhashpusher, MAX_PUSHER);
+ geoipext = findnickext("geoip");
+
+ return lua_getnextnick(l);
+}
+
+int chanhashindex;
+chanindex *lasthashchan;
+
+struct lua_pusher *chanhashpusher[MAX_PUSHER];
+
+static int lua_getnextchan(lua_State *l) {
+ if(!lasthashchan && (chanhashindex != -1))
+ return 0;
+
+ do {
+ if(!lasthashchan) {
+ chanhashindex++;
+ if(chanhashindex >= CHANNELHASHSIZE)
+ return 0;
+ lasthashchan = chantable[chanhashindex];
+ } else {
+ lasthashchan = lasthashchan->next;
+ }
+ } while(!lasthashchan || !lasthashchan->channel);
+
+ return lua_usepusher(l, chanhashpusher, lasthashchan);
+}
+
+static int lua_getfirstchan(lua_State *l) {
+ chanhashindex = -1;
+ lasthashchan = NULL;
+
+ lua_setupchanpusher(l, 1, chanhashpusher, MAX_PUSHER);
+
+ return lua_getnextchan(l);
+}
+
+static int lua_getnickchancount(lua_State *l) {
+ nick *np;
+
+ if(!lua_islong(l, 1))
+ return 0;
+
+ np = getnickbynumeric(lua_tolong(l, 1));
+ if(!np)
+ return 0;
+
+ lua_pushint(l, np->channels->cursi);
+
+ return 1;
+}
+
static int lua_gethostusers(lua_State *l) {
nick *np;
int count;
count = np->host->clonecount;
do {
- LUA_PUSHNICK(l, np);
+ lua_pushnumeric(l, np->numeric);
np = np->nextbyhost;
} while(np);
return count;
}
-/*
-static int lua_iteratenickhash(lua_State *l) {
+static int lua_getnickcountry(lua_State *l) {
nick *np;
- int i, top;
- void *fp;
+ int ext;
- if(!lua_isfunction(l, 1))
- LUA_RETURN(LUA_FAIL);
-
- fp = lua_touserdata(l, 1);
- if(!fp)
- LUA_RETURN(LUA_FAIL);
-
- for(i=0;i<NICKHASHSIZE;i++) {
- for(np=nicktable[i];np;np=np->next) {
- if(np) {
- top = lua_gettop(l);
-
- lua_getglobal(l, "scripterror");
- lua_insert
+ ext = findnickext("geoip");
+ if(ext == -1)
+ return 0;
- LUA_PUSHNICK(l, np);
- lua_pcall(l, 1, 0, top + 1);
+ if(!lua_islong(l, 1))
+ return 0;
- lua_settop(l, top);
- }
- }
- }
+ np = getnickbynumeric(lua_tolong(l, 1));
+ if(!np)
+ return 0;
- LUA_RETURN(LUA_OK);
+ lua_pushint(l, (long)np->exts[ext]);
+ return 1;
}
-*/
static int lua_chanfix(lua_State *ps) {
channel *cp;
LUA_RETURN(ps, LUA_FAIL);
cp = findchannel((char *)lua_tostring(ps, 1));
- if(!cp)
+ if(!cp || !cp->index)
LUA_RETURN(ps, LUA_FAIL);
np = getnickbynick(LUA_CHANFIXBOT);
LUA_RETURN(ps, LUA_FAIL);
cp = findchannel((char *)lua_tostring(ps, 1));
- if(!cp)
+ if(!cp || !cp->users)
LUA_RETURN(ps, LUA_FAIL);
localsetmodeinit(&changes, cp, lua_nick);
LUA_RETURN(ps, LUA_OK);
}
+static int lua_ban(lua_State *ps) {
+ channel *cp;
+ const char *mask;
+ modechanges changes;
+ int dir = MCB_ADD;
+
+ if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
+ LUA_RETURN(ps, LUA_FAIL);
+
+ if(lua_isboolean(ps, 3) && lua_toboolean(ps, 3))
+ dir = MCB_DEL;
+
+ cp = findchannel((char *)lua_tostring(ps, 1));
+ if(!cp)
+ LUA_RETURN(ps, LUA_FAIL);
+
+ mask = lua_tostring(ps, 2);
+ if(!mask || !mask[0] || !lua_lineok(mask))
+ LUA_RETURN(ps, LUA_FAIL);
+
+ localsetmodeinit(&changes, cp, lua_nick);
+ localdosetmode_ban(&changes, mask, dir);
+ localsetmodeflush(&changes, 1);
+
+ LUA_RETURN(ps, LUA_OK);
+}
+
+static int lua_topic(lua_State *ps) {
+ channel *cp;
+ char *topic;
+
+ if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
+ LUA_RETURN(ps, LUA_FAIL);
+
+ cp = findchannel((char *)lua_tostring(ps, 1));
+ if(!cp)
+ LUA_RETURN(ps, LUA_FAIL);
+
+ topic = (char *)lua_tostring(ps, 2);
+ if(!topic || !lua_lineok(topic))
+ LUA_RETURN(ps, LUA_FAIL);
+
+ localsettopic(lua_nick, cp, topic);
+
+ LUA_RETURN(ps, LUA_OK);
+}
+
+static int lua_getuserchanmodes(lua_State *l) {
+ nick *np;
+ channel *cp;
+ unsigned long *lp;
+
+ if(!lua_islong(l, 1) || !lua_isstring(l, 2))
+ return 0;
+
+ np = getnickbynumeric(lua_tolong(l, 1));
+ if(!np)
+ return 0;
+
+ cp = findchannel((char *)lua_tostring(l, 2));
+ if(!cp || !cp->users)
+ return 0;
+
+ lp = getnumerichandlefromchanhash(cp->users, np->numeric);
+ if(!lp)
+ return 0;
+
+ LUA_PUSHNICKCHANMODES(l, lp);
+ return 1;
+}
+
+static int lua_getusermodes(lua_State *l) {
+ nick *np;
+
+ if(!lua_islong(l, 1))
+ return 0;
+
+ np = getnickbynumeric(lua_tolong(l, 1));
+ if(!np)
+ return 0;
+
+ lua_pushstring(l, printflags(np->umodes, umodeflags));
+ return 1;
+}
+
+static int lua_fastgetnickbynumeric(lua_State *l) {
+ static struct lua_pusher *ourpusher[MAX_PUSHER];
+ nick *np;
+
+ if(!lua_islong(l, 1))
+ return 0;
+
+ np = getnickbynumeric(lua_tolong(l, 1));
+ if(!np)
+ return 0;
+
+ lua_setupnickpusher(l, 2, ourpusher, MAX_PUSHER);
+ return lua_usepusher(l, ourpusher, np);
+}
+
+static int lua_fastgetnickbynick(lua_State *l) {
+ static struct lua_pusher *ourpusher[MAX_PUSHER];
+ nick *np;
+
+ if(!lua_isstring(l, 1))
+ return 0;
+
+ np = getnickbynick((char *)lua_tostring(l, 1));
+ if(!np)
+ return 0;
+
+ lua_setupnickpusher(l, 2, ourpusher, MAX_PUSHER);
+ return lua_usepusher(l, ourpusher, np);
+}
+
+int channelnicklistindex, channelnicklistcount = -1;
+channel *channelnicklist;
+
+struct lua_pusher *channelnickpusher[MAX_PUSHER];
+
+static int lua_getnextchannick(lua_State *l) {
+ nick *np;
+
+ do {
+ channelnicklistindex++;
+
+ if(channelnicklistindex >= channelnicklistcount)
+ return 0;
+ } while((channelnicklist->users->content[channelnicklistindex] == nouser) || !(np = getnickbynumeric(channelnicklist->users->content[channelnicklistindex])));
+
+ return lua_usepusher(l, channelnickpusher, np);
+}
+
+static int lua_getfirstchannick(lua_State *l) {
+ if(!lua_isstring(l, 1))
+ return 0;
+
+ channelnicklist = findchannel((char *)lua_tostring(l, 1));
+ if(!channelnicklist|| !channelnicklist->users)
+ return 0;
+
+ channelnicklistindex = -1;
+ channelnicklistcount = channelnicklist->users->hashsize;
+
+ lua_setupnickpusher(l, 2, channelnickpusher, MAX_PUSHER);
+
+ return lua_getnextchannick(l);
+}
+
+static int lua_nickonchan(lua_State *l) {
+ int success = 0;
+ if(lua_islong(l, 1) && lua_isstring(l, 2)) {
+ channel *cp = findchannel((char *)lua_tostring(l, 2));
+ if(cp && cp->users) {
+ unsigned long *lp = getnumerichandlefromchanhash(cp->users, lua_tolong(l, 1));
+ if(lp)
+ success = 1;
+ }
+ }
+
+ lua_pushboolean(l, success);
+ return 1;
+}
+
+static int lua_simplechanmode(lua_State *ps) {
+ channel *cp;
+ char *modes;
+ flag_t add = 0, del = ~add;
+ flag_t permitted = CHANMODE_NOEXTMSG | CHANMODE_TOPICLIMIT | CHANMODE_SECRET | CHANMODE_PRIVATE | CHANMODE_INVITEONLY | CHANMODE_MODERATE | CHANMODE_NOCOLOUR | CHANMODE_NOCTCP | CHANMODE_REGONLY | CHANMODE_DELJOINS | CHANMODE_NOQUITMSG | CHANMODE_NONOTICE | CHANMODE_MODNOAUTH | CHANMODE_SINGLETARG;
+ modechanges changes;
+
+ if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
+ LUA_RETURN(ps, LUA_FAIL);
+
+ cp = findchannel((char *)lua_tostring(ps, 1));
+ if(!cp)
+ LUA_RETURN(ps, LUA_FAIL);
+
+ modes = (char *)lua_tostring(ps, 2);
+ if(!modes)
+ LUA_RETURN(ps, LUA_FAIL);
+
+ if(setflags(&add, permitted, modes, cmodeflags, REJECT_DISALLOWED|REJECT_UNKNOWN) != REJECT_NONE)
+ LUA_RETURN(ps, LUA_FAIL);
+
+ if(setflags(&del, permitted, modes, cmodeflags, REJECT_DISALLOWED|REJECT_UNKNOWN) != REJECT_NONE)
+ LUA_RETURN(ps, LUA_FAIL);
+
+ localsetmodeinit(&changes, cp, lua_nick);
+ localdosetmode_simple(&changes, add, ~del);
+ localsetmodeflush(&changes, 1);
+
+ LUA_RETURN(ps, LUA_OK);
+}
+
+static int lua_sethost(lua_State *ps) {
+ char *ident, *host;
+ nick *np;
+
+ if(!lua_islong(ps, 1) || !lua_isstring(ps, 2) || !lua_isstring(ps, 3))
+ LUA_RETURN(ps, LUA_FAIL);
+
+ np = getnickbynumeric(lua_tolong(ps, 1));
+ if(!np)
+ LUA_RETURN(ps, LUA_FAIL);
+
+ ident = (char *)lua_tostring(ps, 2);
+ host = (char *)lua_tostring(ps, 3);
+ if(!lua_lineok(ident) || !lua_lineok(host))
+ LUA_RETURN(ps, LUA_FAIL);
+
+ sethostuser(np, ident, host);
+
+ LUA_RETURN(ps, LUA_OK);
+}
+
+static int lua_getvisiblehostmask(lua_State *l) {
+ nick *np;
+ char buf[HOSTLEN+USERLEN+NICKLEN+REALLEN+10];
+
+ if(!lua_islong(l, 1))
+ return 0;
+
+ np = getnickbynumeric(lua_tolong(l, 1));
+ if(!np)
+ return 0;
+
+ lua_pushstring(l, visiblehostmask(np, buf));
+ return 1;
+}
+
void lua_registercommands(lua_State *l) {
lua_register(l, "irc_smsg", lua_smsg);
lua_register(l, "irc_skill", lua_skill);
lua_register(l, "chanmsg", lua_chanmsg);
- lua_register(l, "scripterror", lua_scripterror);
lua_register(l, "versioninfo", lua_versioninfo);
+ lua_register(l, "basepath", lua_basepath);
+ lua_register(l, "botnick", lua_botnick);
lua_register(l, "irc_report", lua_chanmsg);
lua_register(l, "irc_ctcp", lua_ctcp);
lua_register(l, "irc_kick", lua_kick);
lua_register(l, "irc_invite", lua_invite);
lua_register(l, "irc_gline", lua_gline);
- lua_register(l, "irc_getchaninfo", lua_getchaninfo);
lua_register(l, "irc_counthost", lua_counthost);
lua_register(l, "irc_getuserbyauth", lua_getuserbyauth);
lua_register(l, "irc_notice", lua_noticecmd);
+ lua_register(l, "irc_privmsg", lua_privmsgcmd);
lua_register(l, "irc_opchan", lua_opchan);
lua_register(l, "irc_voicechan", lua_voicechan);
lua_register(l, "irc_chanfix", lua_chanfix);
lua_register(l, "irc_clearmode", lua_clearmode);
+ lua_register(l, "irc_ban", lua_ban);
+ lua_register(l, "irc_deopchan", lua_deopchan);
+ lua_register(l, "irc_topic", lua_topic);
+
+ lua_register(l, "irc_getfirstnick", lua_getfirstnick);
+ lua_register(l, "irc_getnextnick", lua_getnextnick);
lua_register(l, "irc_getnickchans", lua_getnickchans);
+ lua_register(l, "irc_getnickchanindex", lua_getnickchanindex);
+ lua_register(l, "irc_getnickchancount", lua_getnickchancount);
+
+ lua_register(l, "irc_getuserchanmodes", lua_getuserchanmodes);
+
+ lua_register(l, "irc_getfirstchannick", lua_getfirstchannick);
+ lua_register(l, "irc_getnextchannick", lua_getnextchannick);
+
lua_register(l, "irc_gethostusers", lua_gethostusers);
+ lua_register(l, "irc_getnickcountry", lua_getnickcountry);
+
+ lua_register(l, "irc_getfirstchan", lua_getfirstchan);
+ lua_register(l, "irc_getnextchan", lua_getnextchan);
+ lua_register(l, "irc_getusermodes", lua_getusermodes);
+ lua_register(l, "irc_nickonchan", lua_nickonchan);
-/* lua_register(l, "irc_iteratenickhash", lua_iteratenickhash); */
+ lua_register(l, "irc_fastgetnickbynumeric", lua_fastgetnickbynumeric);
+ lua_register(l, "irc_fastgetnickbynick", lua_fastgetnickbynick);
+ lua_register(l, "irc_fastgetchaninfo", lua_fastgetchaninfo);
+
+ lua_register(l, "irc_getvisiblehostmask", lua_getvisiblehostmask);
+
+ lua_register(l, "irc_simplechanmode", lua_simplechanmode);
+ lua_register(l, "irc_sethost", lua_sethost);
}
/* --- */
LUA_RETURN(ps, LUA_OK);
}
+#define PUSHER_STRING 1
+#define PUSHER_REALNAME 2
+#define PUSHER_IP 3
+#define PUSHER_LONG 4
+#define PUSHER_HOSTNAME 5
+#define PUSHER_SSTRING 6
+#define PUSHER_TOTALUSERS 7
+#define PUSHER_TOPIC 8
+#define PUSHER_UMODES 9
+#define PUSHER_COUNTRY 10
+#define PUSHER_REALUSERS 11
+#define PUSHER_CHANMODES 12
+#define PUSHER_TIMESTAMP 13
+#define PUSHER_STRING_INDIRECT 14
+
+void lua_initnickpusher(void) {
+ int i = 0;
+
+#define PUSH_NICKPUSHER(F2, O2) nickpusher[i].argtype = F2; nickpusher[i].structname = #O2; nickpusher[i].offset = offsetof(nick, O2); i++;
+#define PUSH_NICKPUSHER_CUSTOM(F2, custom) nickpusher[i].argtype = F2; nickpusher[i].structname = custom; nickpusher[i].offset = 0; i++;
+
+ PUSH_NICKPUSHER(PUSHER_STRING, nick);
+ PUSH_NICKPUSHER(PUSHER_STRING, ident);
+ PUSH_NICKPUSHER(PUSHER_HOSTNAME, host);
+ PUSH_NICKPUSHER(PUSHER_REALNAME, realname);
+ PUSH_NICKPUSHER(PUSHER_STRING_INDIRECT, authname);
+ PUSH_NICKPUSHER(PUSHER_IP, ipnode);
+ PUSH_NICKPUSHER(PUSHER_LONG, numeric);
+ PUSH_NICKPUSHER(PUSHER_LONG, timestamp);
+ PUSH_NICKPUSHER(PUSHER_LONG, accountts);
+ PUSH_NICKPUSHER(PUSHER_UMODES, umodes);
+ PUSH_NICKPUSHER_CUSTOM(PUSHER_COUNTRY, "country");
+
+ nickpushercount = i;
+ nickpusher[i].argtype = 0;
+}
+
+void lua_setuppusher(struct lua_pusher *pusherlist, lua_State *l, int index, struct lua_pusher **lp, int max, int pcount) {
+ int current = 0;
+
+ if(max > 0)
+ lp[0] = NULL;
+
+ if(!lua_istable(l, index) || (max < 2))
+ return;
+
+ lua_pushnil(l);
+
+ max--;
+
+ while(lua_next(l, index)) {
+ if(lua_isint(l, -1)) {
+ int index = lua_toint(l, -1);
+ if((index >= 0) && (index < pcount))
+ lp[current++] = &pusherlist[index];
+ }
+
+ lua_pop(l, 1);
+
+ if(current == max)
+ break;
+ }
+
+ lp[current] = NULL;
+}
+
+int lua_usepusher(lua_State *l, struct lua_pusher **lp, void *np) {
+ int i = 0;
+
+ while(*lp) {
+ void *offset = (void *)np + (*lp)->offset;
+
+ switch((*lp)->argtype) {
+ case PUSHER_STRING:
+ lua_pushstring(l, (char *)offset);
+ break;
+ case PUSHER_STRING_INDIRECT:
+ lua_pushstring(l, *(char **)offset);
+ break;
+ case PUSHER_HOSTNAME:
+ lua_pushstring(l, (*(host **)offset)->name->content);
+ break;
+ case PUSHER_REALNAME:
+ lua_pushstring(l, (*(realname **)offset)->name->content);
+ break;
+ case PUSHER_SSTRING:
+ lua_pushstring(l, (*((sstring **)offset))->content);
+ break;
+ case PUSHER_LONG:
+ lua_pushlong(l, *((long *)offset));
+ break;
+ case PUSHER_TIMESTAMP:
+ lua_pushlong(l, (*((channel **)offset))->timestamp);
+ break;
+ case PUSHER_IP:
+ lua_pushstring(l, IPtostr((*((patricia_node_t **)offset))->prefix->sin));
+ break;
+ case PUSHER_TOTALUSERS:
+ lua_pushint(l, (*((channel **)offset))->users->totalusers);
+ break;
+ case PUSHER_CHANMODES:
+ lua_pushstring(l, printallmodes(*((channel **)offset)));
+ break;
+ case PUSHER_REALUSERS:
+ {
+ channel *cp = *((channel **)offset);
+ nick *np2;
+ int i, currentusers = countuniquehosts(cp);
+ for(i=0;i<cp->users->hashsize;i++) {
+ if(cp->users->content[i]==nouser)
+ continue;
+
+ if((np2=getnickbynumeric(cp->users->content[i]))==NULL) {
+ Error("lua", ERR_ERROR, "Found unknown numeric %lu on channel %s", cp->users->content[i], cp->index->name->content);
+ continue;
+ }
+
+ if (IsXOper(np2) || IsService(np2))
+ currentusers--;
+ }
+ lua_pushint(l, currentusers);
+ }
+ break;
+ case PUSHER_UMODES:
+ lua_pushstring(l, printflags(*((flag_t *)offset), umodeflags));
+ break;
+ case PUSHER_TOPIC:
+ if((*((channel **)offset))->topic) {
+ lua_pushstring(l, (*((channel **)offset))->topic->content);
+ } else {
+ lua_pushnil(l);
+ }
+ break;
+ case PUSHER_COUNTRY:
+ if(geoipext < 0) {
+ lua_pushint(l, -1);
+ } else {
+ lua_pushint(l, (long)((nick *)offset)->exts[geoipext]);
+ }
+ break;
+ }
+
+ i++;
+ lp++;
+ }
+
+ return i;
+}
+
+void lua_initchanpusher(void) {
+ int i = 0;
+
+#define PUSH_CHANPUSHER(F2, O2, N2) chanpusher[i].argtype = F2; chanpusher[i].structname = N2; chanpusher[i].offset = offsetof(chanindex, O2); i++;
+
+ PUSH_CHANPUSHER(PUSHER_SSTRING, name, "name");
+ PUSH_CHANPUSHER(PUSHER_TOTALUSERS, channel, "totalusers");
+ PUSH_CHANPUSHER(PUSHER_TOPIC, channel, "topic");
+ PUSH_CHANPUSHER(PUSHER_REALUSERS, channel, "realusers");
+ PUSH_CHANPUSHER(PUSHER_TIMESTAMP, channel, "timestamp");
+ PUSH_CHANPUSHER(PUSHER_CHANMODES, channel, "modes");
+
+ chanpushercount = i;
+ chanpusher[i].argtype = 0;
+}