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