+#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;
+}