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