]> jfr.im git - irc/quakenet/newserv.git/blame - lua/luacommands.c
|# HG changeset patch
[irc/quakenet/newserv.git] / lua / luacommands.c
CommitLineData
8e965b0c 1/* Copyright (C) Chris Porter 2005-2007 */
2da56f0d
CP
2/* ALL RIGHTS RESERVED. */
3/* Don't put this into the SVN repo. */
4
d0d1e2a3
CP
5/*
6 @todo
7 - Write a nick printf type thing for pcalled functions.
8 - Make commands register as apposed to blinding calling.
9 - Use numerics instead of huge structures, and add lookup functions.
10*/
11
2da56f0d
CP
12#include "../channel/channel.h"
13#include "../control/control.h"
14#include "../nick/nick.h"
15#include "../localuser/localuser.h"
16#include "../localuser/localuserchannel.h"
17#include "../lib/irc_string.h"
8e965b0c 18#include "../lib/flags.h"
d4a44e80 19#include "../authext/authext.h"
2da56f0d
CP
20
21#include "lua.h"
22#include "luabot.h"
23
24#include <stdarg.h>
30a59b87 25#include <stddef.h>
2da56f0d 26
ec91b2e4
CP
27#define MAX_PUSHER 50
28
2da56f0d
CP
29static int lua_smsg(lua_State *ps);
30static int lua_skill(lua_State *ps);
31
ec91b2e4 32typedef struct lua_pusher {
30a59b87
CP
33 short argtype;
34 short offset;
35 const char *structname;
ec91b2e4
CP
36} lua_pusher;
37
38struct lua_pusher nickpusher[MAX_PUSHER];
39struct lua_pusher chanpusher[MAX_PUSHER];
ebdfcaa9 40int nickpushercount, chanpushercount;
ec91b2e4 41
4f556cb0
CP
42void lua_setuppusher(struct lua_pusher *pusherlist, lua_State *l, int index, struct lua_pusher **lp, int max, int pcount);
43int lua_usepusher(lua_State *l, struct lua_pusher **lp, void *np);
ec91b2e4 44
ebdfcaa9 45void lua_initnickpusher(void);
ec91b2e4 46void lua_initchanpusher(void);
ec91b2e4 47
ebdfcaa9
CP
48#define lua_setupnickpusher(L2, I2, P2, M2) lua_setuppusher(&nickpusher[0], L2, I2, P2, M2, nickpushercount)
49#define lua_setupchanpusher(L2, I2, P2, M2) lua_setuppusher(&chanpusher[0], L2, I2, P2, M2, chanpushercount)
30a59b87 50
bb4b25ee
CP
51int lua_cmsg(char *channell, char *message, ...) __attribute__ ((format (printf, 2, 3)));
52
2da56f0d
CP
53int lua_cmsg(char *channell, char *message, ...) {
54 char buf[512];
55 va_list va;
56 channel *cp;
57
58 va_start(va, message);
59 vsnprintf(buf, sizeof(buf), message, va);
60 va_end(va);
61
62 cp = findchannel(channell);
63 if(!cp)
64 return LUA_FAIL;
65
66 if(!lua_lineok(buf))
67 return LUA_FAIL;
68
69 lua_channelmessage(cp, "%s", buf);
70
71 return LUA_OK;
72}
73
74static int lua_chanmsg(lua_State *ps) {
75 if(!lua_isstring(ps, 1))
76 LUA_RETURN(ps, LUA_FAIL);
77
78 LUA_RETURN(ps, lua_cmsg(LUA_PUKECHAN, "lua: %s", lua_tostring(ps, 1)));
79}
80
2da56f0d
CP
81static int lua_ctcp(lua_State *ps) {
82 const char *n, *msg;
83 nick *np;
84
85 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
86 LUA_RETURN(ps, LUA_FAIL);
87
88 n = lua_tostring(ps, 1);
89 msg = lua_tostring(ps, 2);
90
91 np = getnickbynick(n);
92 if(!np || !lua_lineok(msg))
93 LUA_RETURN(ps, LUA_FAIL);
94
95 lua_message(np, "\001%s\001", msg);
96
97 LUA_RETURN(ps, lua_cmsg(LUA_PUKECHAN, "lua-ctcp: %s (%s)", np->nick, msg));
98}
99
100static int lua_noticecmd(lua_State *ps) {
101 const char *n, *msg;
102 nick *np;
103
104 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
105 LUA_RETURN(ps, LUA_FAIL);
106
107 n = lua_tostring(ps, 1);
108 msg = lua_tostring(ps, 2);
109
110 np = getnickbynick(n);
111 if(!np || !lua_lineok(msg))
112 LUA_RETURN(ps, LUA_FAIL);
113
114 lua_notice(np, "%s", msg);
115
116 LUA_RETURN(ps, LUA_OK);
117}
118
47990928
CP
119static int lua_privmsgcmd(lua_State *ps) {
120 const char *n, *msg;
121 nick *np;
122
123 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
124 LUA_RETURN(ps, LUA_FAIL);
125
126 n = lua_tostring(ps, 1);
127 msg = lua_tostring(ps, 2);
128
129 np = getnickbynick(n);
130 if(!np || !lua_lineok(msg))
131 LUA_RETURN(ps, LUA_FAIL);
132
133 lua_message(np, "%s", msg);
134
135 LUA_RETURN(ps, LUA_OK);
136}
137
2da56f0d
CP
138static int lua_kill(lua_State *ps) {
139 const char *n, *msg;
140 nick *np;
141
142 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
143 LUA_RETURN(ps, LUA_FAIL);
144
145 n = lua_tostring(ps, 1);
146 msg = lua_tostring(ps, 2);
147
148 np = getnickbynick(n);
149 if(!np)
150 LUA_RETURN(ps, LUA_FAIL);
151
152 if(IsOper(np) || IsService(np) || IsXOper(np))
153 LUA_RETURN(ps, LUA_FAIL);
154
155 if(!lua_lineok(msg))
156 LUA_RETURN(ps, LUA_FAIL);
157
158 killuser(lua_nick, np, "%s", msg);
159
160 LUA_RETURN(ps, lua_cmsg(LUA_PUKECHAN, "lua-KILL: %s (%s)", np->nick, msg));
161}
162
511316a4
CP
163static int lua_kick(lua_State *ps) {
164 const char *n, *msg, *chan;
165 nick *np;
166 channel *cp;
46751959 167 int dochecks = 1;
511316a4
CP
168
169 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2) || !lua_isstring(ps, 3))
170 LUA_RETURN(ps, LUA_FAIL);
171
172 chan = lua_tostring(ps, 1);
173 n = lua_tostring(ps, 2);
174 msg = lua_tostring(ps, 3);
175
46751959
CP
176 if(lua_isboolean(ps, 4) && !lua_toboolean(ps, 4))
177 dochecks = 0;
178
511316a4
CP
179 np = getnickbynick(n);
180 if(!np)
181 LUA_RETURN(ps, LUA_FAIL);
182
46751959
CP
183 if(dochecks && (IsOper(np) || IsXOper(np) || IsService(np)))
184 LUA_RETURN(ps, LUA_FAIL);
185
511316a4
CP
186 cp = findchannel((char *)chan);
187 if(!cp)
188 LUA_RETURN(ps, LUA_FAIL);
189
190 if(!lua_lineok(msg))
191 LUA_RETURN(ps, LUA_FAIL);
192
193 localkickuser(lua_nick, cp, np, msg);
194
195 LUA_RETURN(ps, LUA_OK);
196}
197
198static int lua_invite(lua_State *ps) {
199 nick *np;
200 channel *cp;
201
202 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
203 LUA_RETURN(ps, LUA_FAIL);
204
205 np = getnickbynick((char *)lua_tostring(ps, 1));
206 if(!np)
207 LUA_RETURN(ps, LUA_FAIL);
208
209 cp = findchannel((char *)lua_tostring(ps, 2));
210 if(!cp)
211 LUA_RETURN(ps, LUA_FAIL);
212
213 localinvite(lua_nick, cp, np);
214
215 LUA_RETURN(ps, LUA_OK);
216}
217
2da56f0d
CP
218static int lua_gline(lua_State *ps) {
219 const char *reason;
220 nick *target;
221 char mask[512];
222 int duration, usercount = 0;
223 host *hp;
224
225 if(!lua_isstring(ps, 1) || !lua_isint(ps, 2) || !lua_isstring(ps, 3))
226 LUA_RETURN(ps, LUA_FAIL);
227
228 duration = lua_toint(ps, 2);
79e512d7 229 if((duration < 1) || (duration > 31 * 86400))
2da56f0d
CP
230 LUA_RETURN(ps, LUA_FAIL);
231
232 reason = lua_tostring(ps, 3);
233 if(!lua_lineok(reason) || !reason)
234 LUA_RETURN(ps, LUA_FAIL);
235
236 target = getnickbynick(lua_tostring(ps, 1));
237 if(!target || (IsOper(target) || IsXOper(target) || IsService(target)))
238 LUA_RETURN(ps, LUA_FAIL);
239
240 hp = target->host;
241 if(!hp)
242 LUA_RETURN(ps, LUA_FAIL);
243
244 usercount = hp->clonecount;
245 if(usercount > 10) { /* (decent) trusted host */
246 int j;
247 nick *np;
248
249 usercount = 0;
250
251 for (j=0;j<NICKHASHSIZE;j++)
252 for (np=nicktable[j];np;np=np->next)
253 if (np && (np->host == hp) && (!ircd_strcmp(np->ident, target->ident)))
254 usercount++;
255
256 if(usercount > 50)
257 LUA_RETURN(ps, LUA_FAIL);
258
526e7c1d 259 snprintf(mask, sizeof(mask), "*%s@%s", target->ident, IPtostr(target->p_ipaddr));
2da56f0d 260 } else {
526e7c1d 261 snprintf(mask, sizeof(mask), "*@%s", IPtostr(target->p_ipaddr));
2da56f0d
CP
262 }
263
68e41288 264 irc_send("%s GL * +%s %d %jd :%s", mynumeric->content, mask, duration, (intmax_t)getnettime(), reason);
2da56f0d
CP
265 LUA_RETURN(ps, lua_cmsg(LUA_PUKECHAN, "lua-GLINE: %s (%d users, %d seconds -- %s)", mask, usercount, duration, reason));
266}
267
8566a7ed
CP
268static int lua_fastgetchaninfo(lua_State *ps) {
269 static struct lua_pusher *ourpusher[MAX_PUSHER];
2da56f0d
CP
270 channel *cp;
271
272 if(!lua_isstring(ps, 1))
273 return 0;
274
275 cp = findchannel((char *)lua_tostring(ps, 1));
989bcbf5 276 if(!cp || cp->index->channel != cp)
2da56f0d
CP
277 return 0;
278
8566a7ed 279 lua_setupchanpusher(ps, 2, ourpusher, MAX_PUSHER);
0bb2fe5e 280 return lua_usepusher(ps, ourpusher, cp->index);
2da56f0d
CP
281}
282
283static int lua_opchan(lua_State *ps) {
284 channel *cp;
285 nick *np;
286
287 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
288 LUA_RETURN(ps, LUA_FAIL);
289
290 cp = findchannel((char *)lua_tostring(ps, 1));
291 if(!cp)
292 LUA_RETURN(ps, LUA_FAIL);
293
294 np = getnickbynick((char *)lua_tostring(ps, 2));
295 if(!np)
296 LUA_RETURN(ps, LUA_FAIL);
297
298 localsetmodes(lua_nick, cp, np, MC_OP);
299 LUA_RETURN(ps, LUA_OK);
300}
301
d6998bd1
CP
302static int lua_deopchan(lua_State *ps) {
303 channel *cp;
304 nick *np;
305
306 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
307 LUA_RETURN(ps, LUA_FAIL);
308
309 cp = findchannel((char *)lua_tostring(ps, 1));
310 if(!cp)
311 LUA_RETURN(ps, LUA_FAIL);
312
313 np = getnickbynick((char *)lua_tostring(ps, 2));
314 if(!np)
315 LUA_RETURN(ps, LUA_FAIL);
316
317 localsetmodes(lua_nick, cp, np, MC_DEOP);
318 LUA_RETURN(ps, LUA_OK);
319}
320
2da56f0d
CP
321static int lua_voicechan(lua_State *ps) {
322 channel *cp;
323 nick *np;
324
325 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
326 LUA_RETURN(ps, LUA_FAIL);
327
328 cp = findchannel((char *)lua_tostring(ps, 1));
329 if(!cp)
330 LUA_RETURN(ps, LUA_FAIL);
331
332 np = getnickbynick((char *)lua_tostring(ps, 2));
333 if(!np)
334 LUA_RETURN(ps, LUA_FAIL);
335
336 localsetmodes(lua_nick, cp, np, MC_VOICE);
337 LUA_RETURN(ps, LUA_OK);
338}
339
340static int lua_counthost(lua_State *ps) {
341 long numeric;
342 nick *np;
343
344 if(!lua_islong(ps, 1))
345 return 0;
346
347 numeric = lua_tolong(ps, 1);
348
349 np = getnickbynumeric(numeric);
350 if(!np)
351 return 0;
352
353 lua_pushint(ps, np->host->clonecount);
354 return 1;
355}
356
357static int lua_versioninfo(lua_State *ps) {
358 lua_pushstring(ps, LUA_VERSION);
359 lua_pushstring(ps, LUA_BOTVERSION);
360 lua_pushstring(ps, __DATE__);
361 lua_pushstring(ps, __TIME__);
362
0225bed3 363 lua_pushstring(ps, LUA_AUXVERSION);
6269435f
CP
364
365 return 5;
366}
367
368static int lua_basepath(lua_State *ps) {
369 lua_pushfstring(ps, "%s/", cpath->content);
370
371 return 1;
2da56f0d
CP
372}
373
d324e17b
CP
374static int lua_botnick(lua_State *ps) {
375 lua_pushstring(ps, luabotnick->content);
376
377 return 1;
378}
379
2da56f0d 380static int lua_getuserbyauth(lua_State *l) {
2da56f0d 381 nick *np;
d4a44e80
CP
382 int found = 0;
383 authname *au;
2da56f0d
CP
384
385 if(!lua_isstring(l, 1))
386 return 0;
387
d4a44e80
CP
388 au = getauthbyname(lua_tostring(l, 1));
389 if(!au)
390 return 0;
1fbb1306 391
d4a44e80
CP
392 for(np=au->nicks;np;np=np->nextbyauthname) {
393 lua_pushnumeric(l, np->numeric);
394 found++;
2da56f0d
CP
395 }
396
397 return found;
398}
399
400static int lua_getnickchans(lua_State *l) {
401 nick *np;
402 int i;
403 channel **channels;
404
405 if(!lua_islong(l, 1))
406 return 0;
407
408 np = getnickbynumeric(lua_tolong(l, 1));
409 if(!np)
410 return 0;
411
412 channels = (channel **)np->channels->content;
413 for(i=0;i<np->channels->cursi;i++)
414 lua_pushstring(l, channels[i]->index->name->content);
415
416 return np->channels->cursi;
417}
418
4561a594
CP
419static int lua_getnickchanindex(lua_State *l) {
420 nick *np;
421 int offset;
422
423 if(!lua_islong(l, 1) || !lua_isint(l, 2))
424 return 0;
425
426 np = getnickbynumeric(lua_tolong(l, 1));
427 if(!np)
428 return 0;
429
430 offset = lua_toint(l, 2);
431 if((offset < 0) || (offset >= np->channels->cursi))
432 return 0;
433
434 lua_pushstring(l, ((channel **)np->channels->content)[offset]->index->name->content);
435
436 return 1;
437}
438
c5706d5b
CP
439int hashindex;
440nick *lasthashnick;
f6a3d1f7 441static int geoipext;
c5706d5b 442
ec91b2e4 443struct lua_pusher *nickhashpusher[MAX_PUSHER];
30a59b87 444
c5706d5b
CP
445static int lua_getnextnick(lua_State *l) {
446 if(!lasthashnick && (hashindex != -1))
447 return 0;
448
449 do {
450 if(!lasthashnick) {
451 hashindex++;
452 if(hashindex >= NICKHASHSIZE)
453 return 0;
454 lasthashnick = nicktable[hashindex];
455 } else {
456 lasthashnick = lasthashnick->next;
457 }
458 } while(!lasthashnick);
459
ec91b2e4 460 return lua_usepusher(l, nickhashpusher, lasthashnick);
c5706d5b
CP
461}
462
463static int lua_getfirstnick(lua_State *l) {
c5706d5b
CP
464 hashindex = -1;
465 lasthashnick = NULL;
466
ec91b2e4 467 lua_setupnickpusher(l, 1, nickhashpusher, MAX_PUSHER);
f6a3d1f7 468 geoipext = findnickext("geoip");
30a59b87 469
c5706d5b
CP
470 return lua_getnextnick(l);
471}
472
ec91b2e4
CP
473int chanhashindex;
474chanindex *lasthashchan;
475
476struct lua_pusher *chanhashpusher[MAX_PUSHER];
477
478static int lua_getnextchan(lua_State *l) {
479 if(!lasthashchan && (chanhashindex != -1))
480 return 0;
481
482 do {
483 if(!lasthashchan) {
484 chanhashindex++;
485 if(chanhashindex >= CHANNELHASHSIZE)
486 return 0;
487 lasthashchan = chantable[chanhashindex];
488 } else {
489 lasthashchan = lasthashchan->next;
490 }
491 } while(!lasthashchan || !lasthashchan->channel);
492
493 return lua_usepusher(l, chanhashpusher, lasthashchan);
494}
495
496static int lua_getfirstchan(lua_State *l) {
497 chanhashindex = -1;
498 lasthashchan = NULL;
499
500 lua_setupchanpusher(l, 1, chanhashpusher, MAX_PUSHER);
501
502 return lua_getnextchan(l);
503}
504
8ac8cd09
CP
505static int lua_getnickchancount(lua_State *l) {
506 nick *np;
507
508 if(!lua_islong(l, 1))
509 return 0;
510
511 np = getnickbynumeric(lua_tolong(l, 1));
512 if(!np)
513 return 0;
514
515 lua_pushint(l, np->channels->cursi);
516
517 return 1;
518}
519
2da56f0d
CP
520static int lua_gethostusers(lua_State *l) {
521 nick *np;
522 int count;
523
524 if(!lua_islong(l, 1))
525 return 0;
526
527 np = getnickbynumeric(lua_tolong(l, 1));
528 if(!np || !np->host || !np->host->nicks)
529 return 0;
530
531 np = np->host->nicks;
532 count = np->host->clonecount;
533
534 do {
0bb2fe5e 535 lua_pushnumeric(l, np->numeric);
2da56f0d
CP
536 np = np->nextbyhost;
537 } while(np);
538
539 return count;
540}
541
46751959
CP
542static int lua_getnickcountry(lua_State *l) {
543 nick *np;
544 int ext;
545
546 ext = findnickext("geoip");
547 if(ext == -1)
548 return 0;
549
550 if(!lua_islong(l, 1))
551 return 0;
552
553 np = getnickbynumeric(lua_tolong(l, 1));
554 if(!np)
555 return 0;
556
abc75f54 557 lua_pushint(l, (long)np->exts[ext]);
46751959
CP
558 return 1;
559}
560
ebe20bb8
CP
561static int lua_chanfix(lua_State *ps) {
562 channel *cp;
563 nick *np;
564
565 if(!lua_isstring(ps, 1))
566 LUA_RETURN(ps, LUA_FAIL);
567
568 cp = findchannel((char *)lua_tostring(ps, 1));
1f57d0e2 569 if(!cp || !cp->index)
ebe20bb8
CP
570 LUA_RETURN(ps, LUA_FAIL);
571
572 np = getnickbynick(LUA_CHANFIXBOT);
573 if(!np)
574 LUA_RETURN(ps, LUA_FAIL);
575
576 lua_message(np, "chanfix %s", cp->index->name->content);
577
578 LUA_RETURN(ps, LUA_OK);
579}
580
581static int lua_clearmode(lua_State *ps) {
582 channel *cp;
583 int i;
584 nick *np;
585 unsigned long *lp;
586 modechanges changes;
587
588 if(!lua_isstring(ps, 1))
589 LUA_RETURN(ps, LUA_FAIL);
590
591 cp = findchannel((char *)lua_tostring(ps, 1));
1f57d0e2 592 if(!cp || !cp->users)
ebe20bb8
CP
593 LUA_RETURN(ps, LUA_FAIL);
594
595 localsetmodeinit(&changes, cp, lua_nick);
596
597 localdosetmode_key(&changes, NULL, MCB_DEL);
598 localdosetmode_simple(&changes, 0, CHANMODE_INVITEONLY | CHANMODE_LIMIT);
599
600 while(cp->bans)
601 localdosetmode_ban(&changes, bantostring(cp->bans), MCB_DEL);
602
603 for(i=0,lp=cp->users->content;i<cp->users->hashsize;i++,lp++)
604 if((*lp != nouser) && (*lp & CUMODE_OP)) {
605 np = getnickbynumeric(*lp);
606 if(np && !IsService(np))
607 localdosetmode_nick(&changes, np, MC_DEOP);
608 }
609
610 localsetmodeflush(&changes, 1);
611
612 LUA_RETURN(ps, LUA_OK);
613}
614
46751959
CP
615static int lua_ban(lua_State *ps) {
616 channel *cp;
617 const char *mask;
618 modechanges changes;
619 int dir = MCB_ADD;
620
621 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
622 LUA_RETURN(ps, LUA_FAIL);
623
624 if(lua_isboolean(ps, 3) && lua_toboolean(ps, 3))
625 dir = MCB_DEL;
626
627 cp = findchannel((char *)lua_tostring(ps, 1));
628 if(!cp)
629 LUA_RETURN(ps, LUA_FAIL);
630
631 mask = lua_tostring(ps, 2);
632 if(!mask || !mask[0] || !lua_lineok(mask))
633 LUA_RETURN(ps, LUA_FAIL);
634
635 localsetmodeinit(&changes, cp, lua_nick);
636 localdosetmode_ban(&changes, mask, dir);
637 localsetmodeflush(&changes, 1);
638
639 LUA_RETURN(ps, LUA_OK);
640}
641
d0d1e2a3
CP
642static int lua_topic(lua_State *ps) {
643 channel *cp;
644 char *topic;
645
646 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
647 LUA_RETURN(ps, LUA_FAIL);
648
649 cp = findchannel((char *)lua_tostring(ps, 1));
650 if(!cp)
651 LUA_RETURN(ps, LUA_FAIL);
652
653 topic = (char *)lua_tostring(ps, 2);
654 if(!topic || !lua_lineok(topic))
655 LUA_RETURN(ps, LUA_FAIL);
656
657 localsettopic(lua_nick, cp, topic);
658
659 LUA_RETURN(ps, LUA_OK);
660}
661
662static int lua_getuserchanmodes(lua_State *l) {
663 nick *np;
664 channel *cp;
665 unsigned long *lp;
666
667 if(!lua_islong(l, 1) || !lua_isstring(l, 2))
668 return 0;
669
670 np = getnickbynumeric(lua_tolong(l, 1));
671 if(!np)
672 return 0;
673
674 cp = findchannel((char *)lua_tostring(l, 2));
1f57d0e2 675 if(!cp || !cp->users)
d0d1e2a3
CP
676 return 0;
677
678 lp = getnumerichandlefromchanhash(cp->users, np->numeric);
679 if(!lp)
680 return 0;
681
682 LUA_PUSHNICKCHANMODES(l, lp);
683 return 1;
684}
685
c0d574fa
CP
686static int lua_getusermodes(lua_State *l) {
687 nick *np;
688
689 if(!lua_islong(l, 1))
690 return 0;
691
692 np = getnickbynumeric(lua_tolong(l, 1));
693 if(!np)
694 return 0;
695
696 lua_pushstring(l, printflags(np->umodes, umodeflags));
697 return 1;
698}
699
8566a7ed
CP
700static int lua_fastgetnickbynumeric(lua_State *l) {
701 static struct lua_pusher *ourpusher[MAX_PUSHER];
d4aef858
CP
702 nick *np;
703
704 if(!lua_islong(l, 1))
705 return 0;
706
707 np = getnickbynumeric(lua_tolong(l, 1));
708 if(!np)
709 return 0;
710
8566a7ed
CP
711 lua_setupnickpusher(l, 2, ourpusher, MAX_PUSHER);
712 return lua_usepusher(l, ourpusher, np);
d4aef858
CP
713}
714
8566a7ed 715static int lua_fastgetnickbynick(lua_State *l) {
1f57d0e2
CP
716 static struct lua_pusher *ourpusher[MAX_PUSHER];
717 nick *np;
718
8566a7ed 719 if(!lua_isstring(l, 1))
1f57d0e2
CP
720 return 0;
721
8566a7ed 722 np = getnickbynick((char *)lua_tostring(l, 1));
1f57d0e2
CP
723 if(!np)
724 return 0;
725
726 lua_setupnickpusher(l, 2, ourpusher, MAX_PUSHER);
727 return lua_usepusher(l, ourpusher, np);
728}
729
c0e81f9a
CP
730int channelnicklistindex, channelnicklistcount = -1;
731channel *channelnicklist;
732
733struct lua_pusher *channelnickpusher[MAX_PUSHER];
734
735static int lua_getnextchannick(lua_State *l) {
736 nick *np;
737
738 do {
739 channelnicklistindex++;
740
741 if(channelnicklistindex >= channelnicklistcount)
742 return 0;
743 } while((channelnicklist->users->content[channelnicklistindex] == nouser) || !(np = getnickbynumeric(channelnicklist->users->content[channelnicklistindex])));
744
745 return lua_usepusher(l, channelnickpusher, np);
746}
747
748static int lua_getfirstchannick(lua_State *l) {
749 if(!lua_isstring(l, 1))
750 return 0;
751
752 channelnicklist = findchannel((char *)lua_tostring(l, 1));
753 if(!channelnicklist|| !channelnicklist->users)
754 return 0;
755
756 channelnicklistindex = -1;
757 channelnicklistcount = channelnicklist->users->hashsize;
758
759 lua_setupnickpusher(l, 2, channelnickpusher, MAX_PUSHER);
760
761 return lua_getnextchannick(l);
762}
763
1f57d0e2
CP
764static int lua_nickonchan(lua_State *l) {
765 int success = 0;
766 if(lua_islong(l, 1) && lua_isstring(l, 2)) {
767 channel *cp = findchannel((char *)lua_tostring(l, 2));
768 if(cp && cp->users) {
769 unsigned long *lp = getnumerichandlefromchanhash(cp->users, lua_tolong(l, 1));
770 if(lp)
771 success = 1;
772 }
773 }
774
775 lua_pushboolean(l, success);
776 return 1;
777}
778
8e965b0c
CP
779static int lua_simplechanmode(lua_State *ps) {
780 channel *cp;
781 char *modes;
782 flag_t add = 0, del = ~add;
95c92529 783 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;
8e965b0c
CP
784 modechanges changes;
785
786 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
787 LUA_RETURN(ps, LUA_FAIL);
788
789 cp = findchannel((char *)lua_tostring(ps, 1));
790 if(!cp)
791 LUA_RETURN(ps, LUA_FAIL);
792
793 modes = (char *)lua_tostring(ps, 2);
794 if(!modes)
795 LUA_RETURN(ps, LUA_FAIL);
796
797 if(setflags(&add, permitted, modes, cmodeflags, REJECT_DISALLOWED|REJECT_UNKNOWN) != REJECT_NONE)
798 LUA_RETURN(ps, LUA_FAIL);
799
800 if(setflags(&del, permitted, modes, cmodeflags, REJECT_DISALLOWED|REJECT_UNKNOWN) != REJECT_NONE)
801 LUA_RETURN(ps, LUA_FAIL);
802
803 localsetmodeinit(&changes, cp, lua_nick);
804 localdosetmode_simple(&changes, add, ~del);
805 localsetmodeflush(&changes, 1);
806
807 LUA_RETURN(ps, LUA_OK);
808}
809
524fb1bd
CP
810static int lua_sethost(lua_State *ps) {
811 char *ident, *host;
812 nick *np;
813
814 if(!lua_islong(ps, 1) || !lua_isstring(ps, 2) || !lua_isstring(ps, 3))
815 LUA_RETURN(ps, LUA_FAIL);
816
817 np = getnickbynumeric(lua_tolong(ps, 1));
818 if(!np)
819 LUA_RETURN(ps, LUA_FAIL);
820
821 ident = (char *)lua_tostring(ps, 2);
822 host = (char *)lua_tostring(ps, 3);
823 if(!lua_lineok(ident) || !lua_lineok(host))
824 LUA_RETURN(ps, LUA_FAIL);
825
826 sethostuser(np, ident, host);
827
828 LUA_RETURN(ps, LUA_OK);
829}
830
8e8b814d
CP
831static int lua_getvisiblehostmask(lua_State *l) {
832 nick *np;
833 char buf[HOSTLEN+USERLEN+NICKLEN+REALLEN+10];
834
835 if(!lua_islong(l, 1))
836 return 0;
837
838 np = getnickbynumeric(lua_tolong(l, 1));
839 if(!np)
840 return 0;
841
842 lua_pushstring(l, visiblehostmask(np, buf));
843 return 1;
844}
845
2da56f0d
CP
846void lua_registercommands(lua_State *l) {
847 lua_register(l, "irc_smsg", lua_smsg);
848 lua_register(l, "irc_skill", lua_skill);
849
850 lua_register(l, "chanmsg", lua_chanmsg);
2da56f0d 851 lua_register(l, "versioninfo", lua_versioninfo);
6269435f 852 lua_register(l, "basepath", lua_basepath);
d324e17b 853 lua_register(l, "botnick", lua_botnick);
2da56f0d
CP
854
855 lua_register(l, "irc_report", lua_chanmsg);
856 lua_register(l, "irc_ctcp", lua_ctcp);
857 lua_register(l, "irc_kill", lua_kill);
511316a4
CP
858 lua_register(l, "irc_kick", lua_kick);
859 lua_register(l, "irc_invite", lua_invite);
2da56f0d 860 lua_register(l, "irc_gline", lua_gline);
2da56f0d
CP
861 lua_register(l, "irc_counthost", lua_counthost);
862 lua_register(l, "irc_getuserbyauth", lua_getuserbyauth);
863 lua_register(l, "irc_notice", lua_noticecmd);
47990928 864 lua_register(l, "irc_privmsg", lua_privmsgcmd);
2da56f0d
CP
865 lua_register(l, "irc_opchan", lua_opchan);
866 lua_register(l, "irc_voicechan", lua_voicechan);
ebe20bb8
CP
867 lua_register(l, "irc_chanfix", lua_chanfix);
868 lua_register(l, "irc_clearmode", lua_clearmode);
46751959 869 lua_register(l, "irc_ban", lua_ban);
d6998bd1 870 lua_register(l, "irc_deopchan", lua_deopchan);
d0d1e2a3
CP
871 lua_register(l, "irc_topic", lua_topic);
872
d0d1e2a3
CP
873 lua_register(l, "irc_getfirstnick", lua_getfirstnick);
874 lua_register(l, "irc_getnextnick", lua_getnextnick);
2da56f0d
CP
875
876 lua_register(l, "irc_getnickchans", lua_getnickchans);
4561a594 877 lua_register(l, "irc_getnickchanindex", lua_getnickchanindex);
8ac8cd09 878 lua_register(l, "irc_getnickchancount", lua_getnickchancount);
c5706d5b 879
d0d1e2a3
CP
880 lua_register(l, "irc_getuserchanmodes", lua_getuserchanmodes);
881
c0e81f9a
CP
882 lua_register(l, "irc_getfirstchannick", lua_getfirstchannick);
883 lua_register(l, "irc_getnextchannick", lua_getnextchannick);
c5706d5b 884
2da56f0d 885 lua_register(l, "irc_gethostusers", lua_gethostusers);
46751959 886 lua_register(l, "irc_getnickcountry", lua_getnickcountry);
ec91b2e4
CP
887
888 lua_register(l, "irc_getfirstchan", lua_getfirstchan);
889 lua_register(l, "irc_getnextchan", lua_getnextchan);
c0d574fa 890 lua_register(l, "irc_getusermodes", lua_getusermodes);
1f57d0e2
CP
891 lua_register(l, "irc_nickonchan", lua_nickonchan);
892
893 lua_register(l, "irc_fastgetnickbynumeric", lua_fastgetnickbynumeric);
8566a7ed
CP
894 lua_register(l, "irc_fastgetnickbynick", lua_fastgetnickbynick);
895 lua_register(l, "irc_fastgetchaninfo", lua_fastgetchaninfo);
8e965b0c 896
8e8b814d
CP
897 lua_register(l, "irc_getvisiblehostmask", lua_getvisiblehostmask);
898
8e965b0c 899 lua_register(l, "irc_simplechanmode", lua_simplechanmode);
524fb1bd 900 lua_register(l, "irc_sethost", lua_sethost);
2da56f0d
CP
901}
902
903/* --- */
904
905static int lua_smsg(lua_State *ps) {
906 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
907 LUA_RETURN(ps, LUA_FAIL);
908
909 LUA_RETURN(ps, lua_cmsg((char *)lua_tostring(ps, 2), "%s", lua_tostring(ps, 1)));
910}
911
912static int lua_skill(lua_State *ps) {
913 const char *n, *msg;
914 nick *np;
915
916 if(!lua_isstring(ps, 1) || !lua_isstring(ps, 2))
917 LUA_RETURN(ps, LUA_FAIL);
918
919 n = lua_tostring(ps, 1);
920 msg = lua_tostring(ps, 2);
921
922 np = getnickbynick(n);
923 if(!np)
924 LUA_RETURN(ps, LUA_FAIL);
925
926 if(IsOper(np) || IsService(np) || IsXOper(np))
927 LUA_RETURN(ps, LUA_FAIL);
928
929 if(!lua_lineok(msg))
930 LUA_RETURN(ps, LUA_FAIL);
931
932 killuser(lua_nick, np, "%s", msg);
933
934 LUA_RETURN(ps, LUA_OK);
935}
936
30a59b87 937#define PUSHER_STRING 1
eebdff1f 938#define PUSHER_REALNAME 2
30a59b87
CP
939#define PUSHER_IP 3
940#define PUSHER_LONG 4
eebdff1f
CP
941#define PUSHER_HOSTNAME 5
942#define PUSHER_SSTRING 6
ec91b2e4
CP
943#define PUSHER_TOTALUSERS 7
944#define PUSHER_TOPIC 8
de2bb012 945#define PUSHER_UMODES 9
f6a3d1f7 946#define PUSHER_COUNTRY 10
8566a7ed
CP
947#define PUSHER_REALUSERS 11
948#define PUSHER_CHANMODES 12
949#define PUSHER_TIMESTAMP 13
e0a5b7b5 950#define PUSHER_STRING_INDIRECT 14
30a59b87
CP
951
952void lua_initnickpusher(void) {
953 int i = 0;
954
955#define PUSH_NICKPUSHER(F2, O2) nickpusher[i].argtype = F2; nickpusher[i].structname = #O2; nickpusher[i].offset = offsetof(nick, O2); i++;
f6a3d1f7 956#define PUSH_NICKPUSHER_CUSTOM(F2, custom) nickpusher[i].argtype = F2; nickpusher[i].structname = custom; nickpusher[i].offset = 0; i++;
30a59b87
CP
957
958 PUSH_NICKPUSHER(PUSHER_STRING, nick);
959 PUSH_NICKPUSHER(PUSHER_STRING, ident);
eebdff1f
CP
960 PUSH_NICKPUSHER(PUSHER_HOSTNAME, host);
961 PUSH_NICKPUSHER(PUSHER_REALNAME, realname);
e0a5b7b5 962 PUSH_NICKPUSHER(PUSHER_STRING_INDIRECT, authname);
526e7c1d 963 PUSH_NICKPUSHER(PUSHER_IP, ipnode);
30a59b87 964 PUSH_NICKPUSHER(PUSHER_LONG, numeric);
de2bb012
CP
965 PUSH_NICKPUSHER(PUSHER_LONG, timestamp);
966 PUSH_NICKPUSHER(PUSHER_LONG, accountts);
967 PUSH_NICKPUSHER(PUSHER_UMODES, umodes);
f6a3d1f7 968 PUSH_NICKPUSHER_CUSTOM(PUSHER_COUNTRY, "country");
30a59b87 969
ebdfcaa9 970 nickpushercount = i;
30a59b87
CP
971 nickpusher[i].argtype = 0;
972}
973
4f556cb0 974void lua_setuppusher(struct lua_pusher *pusherlist, lua_State *l, int index, struct lua_pusher **lp, int max, int pcount) {
30a59b87 975 int current = 0;
30a59b87
CP
976
977 if(max > 0)
978 lp[0] = NULL;
979
533af02d 980 if(!lua_istable(l, index) || (max < 2))
30a59b87
CP
981 return;
982
983 lua_pushnil(l);
984
985 max--;
986
533af02d 987 while(lua_next(l, index)) {
ebdfcaa9
CP
988 if(lua_isint(l, -1)) {
989 int index = lua_toint(l, -1);
990 if((index >= 0) && (index < pcount))
991 lp[current++] = &pusherlist[index];
30a59b87
CP
992 }
993
994 lua_pop(l, 1);
995
996 if(current == max)
997 break;
998 }
999
1000 lp[current] = NULL;
1001}
1002
4f556cb0 1003int lua_usepusher(lua_State *l, struct lua_pusher **lp, void *np) {
1f38b1d7
CP
1004 int i = 0;
1005
30a59b87
CP
1006 while(*lp) {
1007 void *offset = (void *)np + (*lp)->offset;
1008
30a59b87
CP
1009 switch((*lp)->argtype) {
1010 case PUSHER_STRING:
1011 lua_pushstring(l, (char *)offset);
1012 break;
e0a5b7b5
CP
1013 case PUSHER_STRING_INDIRECT:
1014 lua_pushstring(l, *(char **)offset);
1015 break;
eebdff1f
CP
1016 case PUSHER_HOSTNAME:
1017 lua_pushstring(l, (*(host **)offset)->name->content);
1018 break;
1019 case PUSHER_REALNAME:
1020 lua_pushstring(l, (*(realname **)offset)->name->content);
1021 break;
30a59b87 1022 case PUSHER_SSTRING:
ec91b2e4 1023 lua_pushstring(l, (*((sstring **)offset))->content);
30a59b87
CP
1024 break;
1025 case PUSHER_LONG:
1026 lua_pushlong(l, *((long *)offset));
1027 break;
8566a7ed
CP
1028 case PUSHER_TIMESTAMP:
1029 lua_pushlong(l, (*((channel **)offset))->timestamp);
1030 break;
30a59b87 1031 case PUSHER_IP:
1c7f0e03 1032 lua_pushstring(l, IPtostr((*((patricia_node_t **)offset))->prefix->sin));
30a59b87 1033 break;
ec91b2e4
CP
1034 case PUSHER_TOTALUSERS:
1035 lua_pushint(l, (*((channel **)offset))->users->totalusers);
1036 break;
8566a7ed
CP
1037 case PUSHER_CHANMODES:
1038 lua_pushstring(l, printallmodes(*((channel **)offset)));
1039 break;
1040 case PUSHER_REALUSERS:
1041 {
1042 channel *cp = *((channel **)offset);
1043 nick *np2;
1044 int i, currentusers = countuniquehosts(cp);
1045 for(i=0;i<cp->users->hashsize;i++) {
1046 if(cp->users->content[i]==nouser)
1047 continue;
1048
1049 if((np2=getnickbynumeric(cp->users->content[i]))==NULL) {
16739dbe 1050 Error("lua", ERR_ERROR, "Found unknown numeric %lu on channel %s", cp->users->content[i], cp->index->name->content);
8566a7ed
CP
1051 continue;
1052 }
1053
1054 if (IsXOper(np2) || IsService(np2))
1055 currentusers--;
1056 }
1057 lua_pushint(l, currentusers);
1058 }
1059 break;
de2bb012
CP
1060 case PUSHER_UMODES:
1061 lua_pushstring(l, printflags(*((flag_t *)offset), umodeflags));
1062 break;
ec91b2e4
CP
1063 case PUSHER_TOPIC:
1064 if((*((channel **)offset))->topic) {
1065 lua_pushstring(l, (*((channel **)offset))->topic->content);
1066 } else {
1067 lua_pushnil(l);
1068 }
1069 break;
f6a3d1f7
CP
1070 case PUSHER_COUNTRY:
1071 if(geoipext < 0) {
1072 lua_pushint(l, -1);
1073 } else {
1074 lua_pushint(l, (long)((nick *)offset)->exts[geoipext]);
1075 }
1076 break;
30a59b87
CP
1077 }
1078
1f38b1d7 1079 i++;
30a59b87
CP
1080 lp++;
1081 }
1f38b1d7
CP
1082
1083 return i;
30a59b87 1084}
24da5817 1085
ec91b2e4
CP
1086void lua_initchanpusher(void) {
1087 int i = 0;
1088
1089#define PUSH_CHANPUSHER(F2, O2, N2) chanpusher[i].argtype = F2; chanpusher[i].structname = N2; chanpusher[i].offset = offsetof(chanindex, O2); i++;
1090
1091 PUSH_CHANPUSHER(PUSHER_SSTRING, name, "name");
1092 PUSH_CHANPUSHER(PUSHER_TOTALUSERS, channel, "totalusers");
1093 PUSH_CHANPUSHER(PUSHER_TOPIC, channel, "topic");
8566a7ed
CP
1094 PUSH_CHANPUSHER(PUSHER_REALUSERS, channel, "realusers");
1095 PUSH_CHANPUSHER(PUSHER_TIMESTAMP, channel, "timestamp");
1096 PUSH_CHANPUSHER(PUSHER_CHANMODES, channel, "modes");
ec91b2e4 1097
ebdfcaa9 1098 chanpushercount = i;
ec91b2e4
CP
1099 chanpusher[i].argtype = 0;
1100}