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