1 /* Copyright (C) Chris Porter 2005-2006 */
2 /* ALL RIGHTS RESERVED. */
3 /* Don't put this into the SVN repo. */
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.
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"
29 static int lua_smsg(lua_State
*ps
);
30 static int lua_skill(lua_State
*ps
);
32 typedef struct lua_nickpusher
{
35 const char *structname
;
38 void lua_initnickpusher(void);
39 void lua_setupnickpusher(lua_State
*l
, int index
, struct lua_nickpusher
**lp
, int max
);
40 void lua_usenickpusher(lua_State
*l
, struct lua_nickpusher
**lp
, nick
*np
);
42 int lua_lineok(const char *data
) {
43 if(strchr(data
, '\r') || strchr(data
, '\n'))
48 int lua_cmsg(char *channell
, char *message
, ...) {
53 va_start(va
, message
);
54 vsnprintf(buf
, sizeof(buf
), message
, va
);
57 cp
= findchannel(channell
);
64 lua_channelmessage(cp
, "%s", buf
);
69 static int lua_chanmsg(lua_State
*ps
) {
70 if(!lua_isstring(ps
, 1))
71 LUA_RETURN(ps
, LUA_FAIL
);
73 LUA_RETURN(ps
, lua_cmsg(LUA_PUKECHAN
, "lua: %s", lua_tostring(ps
, 1)));
76 static int lua_scripterror(lua_State
*ps
) {
77 if(!lua_isstring(ps
, 1))
78 LUA_RETURN(ps
, LUA_FAIL
);
80 LUA_RETURN(ps
, lua_cmsg(LUA_PUKECHAN
, "lua-error: %s", lua_tostring(ps
, 1)));
83 static int lua_ctcp(lua_State
*ps
) {
87 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2))
88 LUA_RETURN(ps
, LUA_FAIL
);
90 n
= lua_tostring(ps
, 1);
91 msg
= lua_tostring(ps
, 2);
93 np
= getnickbynick(n
);
94 if(!np
|| !lua_lineok(msg
))
95 LUA_RETURN(ps
, LUA_FAIL
);
97 lua_message(np
, "\001%s\001", msg
);
99 LUA_RETURN(ps
, lua_cmsg(LUA_PUKECHAN
, "lua-ctcp: %s (%s)", np
->nick
, msg
));
102 static int lua_noticecmd(lua_State
*ps
) {
106 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2))
107 LUA_RETURN(ps
, LUA_FAIL
);
109 n
= lua_tostring(ps
, 1);
110 msg
= lua_tostring(ps
, 2);
112 np
= getnickbynick(n
);
113 if(!np
|| !lua_lineok(msg
))
114 LUA_RETURN(ps
, LUA_FAIL
);
116 lua_notice(np
, "%s", msg
);
118 LUA_RETURN(ps
, LUA_OK
);
121 static int lua_kill(lua_State
*ps
) {
125 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2))
126 LUA_RETURN(ps
, LUA_FAIL
);
128 n
= lua_tostring(ps
, 1);
129 msg
= lua_tostring(ps
, 2);
131 np
= getnickbynick(n
);
133 LUA_RETURN(ps
, LUA_FAIL
);
135 if(IsOper(np
) || IsService(np
) || IsXOper(np
))
136 LUA_RETURN(ps
, LUA_FAIL
);
139 LUA_RETURN(ps
, LUA_FAIL
);
141 killuser(lua_nick
, np
, "%s", msg
);
143 LUA_RETURN(ps
, lua_cmsg(LUA_PUKECHAN
, "lua-KILL: %s (%s)", np
->nick
, msg
));
146 static int lua_kick(lua_State
*ps
) {
147 const char *n
, *msg
, *chan
;
152 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2) || !lua_isstring(ps
, 3))
153 LUA_RETURN(ps
, LUA_FAIL
);
155 chan
= lua_tostring(ps
, 1);
156 n
= lua_tostring(ps
, 2);
157 msg
= lua_tostring(ps
, 3);
159 if(lua_isboolean(ps
, 4) && !lua_toboolean(ps
, 4))
162 np
= getnickbynick(n
);
164 LUA_RETURN(ps
, LUA_FAIL
);
166 if(dochecks
&& (IsOper(np
) || IsXOper(np
) || IsService(np
)))
167 LUA_RETURN(ps
, LUA_FAIL
);
169 cp
= findchannel((char *)chan
);
171 LUA_RETURN(ps
, LUA_FAIL
);
174 LUA_RETURN(ps
, LUA_FAIL
);
176 localkickuser(lua_nick
, cp
, np
, msg
);
178 LUA_RETURN(ps
, LUA_OK
);
181 static int lua_invite(lua_State
*ps
) {
185 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2))
186 LUA_RETURN(ps
, LUA_FAIL
);
188 np
= getnickbynick((char *)lua_tostring(ps
, 1));
190 LUA_RETURN(ps
, LUA_FAIL
);
192 cp
= findchannel((char *)lua_tostring(ps
, 2));
194 LUA_RETURN(ps
, LUA_FAIL
);
196 localinvite(lua_nick
, cp
, np
);
198 LUA_RETURN(ps
, LUA_OK
);
201 static int lua_gline(lua_State
*ps
) {
205 int duration
, usercount
= 0;
208 if(!lua_isstring(ps
, 1) || !lua_isint(ps
, 2) || !lua_isstring(ps
, 3))
209 LUA_RETURN(ps
, LUA_FAIL
);
211 duration
= lua_toint(ps
, 2);
212 if((duration
< 1) || (duration
> 86400))
213 LUA_RETURN(ps
, LUA_FAIL
);
215 reason
= lua_tostring(ps
, 3);
216 if(!lua_lineok(reason
) || !reason
)
217 LUA_RETURN(ps
, LUA_FAIL
);
219 target
= getnickbynick(lua_tostring(ps
, 1));
220 if(!target
|| (IsOper(target
) || IsXOper(target
) || IsService(target
)))
221 LUA_RETURN(ps
, LUA_FAIL
);
225 LUA_RETURN(ps
, LUA_FAIL
);
227 usercount
= hp
->clonecount
;
228 if(usercount
> 10) { /* (decent) trusted host */
234 for (j
=0;j
<NICKHASHSIZE
;j
++)
235 for (np
=nicktable
[j
];np
;np
=np
->next
)
236 if (np
&& (np
->host
== hp
) && (!ircd_strcmp(np
->ident
, target
->ident
)))
240 LUA_RETURN(ps
, LUA_FAIL
);
242 snprintf(mask
, sizeof(mask
), "*%s@%s", target
->ident
, IPtostr(target
->ipaddress
));
244 snprintf(mask
, sizeof(mask
), "*@%s", IPtostr(target
->ipaddress
));
247 irc_send("%s GL * +%s %d :%s", mynumeric
->content
, mask
, duration
, reason
);
248 LUA_RETURN(ps
, lua_cmsg(LUA_PUKECHAN
, "lua-GLINE: %s (%d users, %d seconds -- %s)", mask
, usercount
, duration
, reason
));
251 static int lua_getchaninfo(lua_State
*ps
) {
254 if(!lua_isstring(ps
, 1))
257 cp
= findchannel((char *)lua_tostring(ps
, 1));
261 LUA_PUSHCHAN(ps
, cp
);
266 static int lua_opchan(lua_State
*ps
) {
270 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2))
271 LUA_RETURN(ps
, LUA_FAIL
);
273 cp
= findchannel((char *)lua_tostring(ps
, 1));
275 LUA_RETURN(ps
, LUA_FAIL
);
277 np
= getnickbynick((char *)lua_tostring(ps
, 2));
279 LUA_RETURN(ps
, LUA_FAIL
);
281 localsetmodes(lua_nick
, cp
, np
, MC_OP
);
282 LUA_RETURN(ps
, LUA_OK
);
285 static int lua_deopchan(lua_State
*ps
) {
289 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2))
290 LUA_RETURN(ps
, LUA_FAIL
);
292 cp
= findchannel((char *)lua_tostring(ps
, 1));
294 LUA_RETURN(ps
, LUA_FAIL
);
296 np
= getnickbynick((char *)lua_tostring(ps
, 2));
298 LUA_RETURN(ps
, LUA_FAIL
);
300 localsetmodes(lua_nick
, cp
, np
, MC_DEOP
);
301 LUA_RETURN(ps
, LUA_OK
);
304 static int lua_voicechan(lua_State
*ps
) {
308 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2))
309 LUA_RETURN(ps
, LUA_FAIL
);
311 cp
= findchannel((char *)lua_tostring(ps
, 1));
313 LUA_RETURN(ps
, LUA_FAIL
);
315 np
= getnickbynick((char *)lua_tostring(ps
, 2));
317 LUA_RETURN(ps
, LUA_FAIL
);
319 localsetmodes(lua_nick
, cp
, np
, MC_VOICE
);
320 LUA_RETURN(ps
, LUA_OK
);
323 static int lua_counthost(lua_State
*ps
) {
327 if(!lua_islong(ps
, 1))
330 numeric
= lua_tolong(ps
, 1);
332 np
= getnickbynumeric(numeric
);
336 lua_pushint(ps
, np
->host
->clonecount
);
340 static int lua_versioninfo(lua_State
*ps
) {
341 lua_pushstring(ps
, LUA_VERSION
);
342 lua_pushstring(ps
, LUA_BOTVERSION
);
343 lua_pushstring(ps
, __DATE__
);
344 lua_pushstring(ps
, __TIME__
);
347 lua_pushstring(ps
, " + " LUAJIT_VERSION
);
349 lua_pushstring(ps
, "");
355 static int lua_basepath(lua_State
*ps
) {
356 lua_pushfstring(ps
, "%s/", cpath
->content
);
362 static int lua_getuserbyauth(lua_State
*l
) {
367 if(!lua_isstring(l
, 1))
370 acc
= lua_tostring(l
, 1);
372 for(i
=0;i
<NICKHASHSIZE
;i
++) {
373 for(np
=nicktable
[i
];np
;np
=np
->next
) {
374 if(np
&& np
->authname
&& !ircd_strcmp(np
->authname
, acc
)) {
384 static int lua_getnickchans(lua_State
*l
) {
389 if(!lua_islong(l
, 1))
392 np
= getnickbynumeric(lua_tolong(l
, 1));
396 channels
= (channel
**)np
->channels
->content
;
397 for(i
=0;i
<np
->channels
->cursi
;i
++)
398 lua_pushstring(l
, channels
[i
]->index
->name
->content
);
400 return np
->channels
->cursi
;
403 static int lua_getnickchanindex(lua_State
*l
) {
407 if(!lua_islong(l
, 1) || !lua_isint(l
, 2))
410 np
= getnickbynumeric(lua_tolong(l
, 1));
414 offset
= lua_toint(l
, 2);
415 if((offset
< 0) || (offset
>= np
->channels
->cursi
))
418 lua_pushstring(l
, ((channel
**)np
->channels
->content
)[offset
]->index
->name
->content
);
426 #define MAX_NICKPUSHER 50
428 struct lua_nickpusher
*nickhashpusher
[MAX_NICKPUSHER
];
430 static int lua_getnextnick(lua_State
*l
) {
431 if(!lasthashnick
&& (hashindex
!= -1))
437 if(hashindex
>= NICKHASHSIZE
)
439 lasthashnick
= nicktable
[hashindex
];
441 lasthashnick
= lasthashnick
->next
;
443 } while(!lasthashnick
);
445 lua_usenickpusher(l
, nickhashpusher
, lasthashnick
);
449 static int lua_getfirstnick(lua_State
*l
) {
453 lua_setupnickpusher(l
, 1, nickhashpusher
, MAX_NICKPUSHER
);
455 return lua_getnextnick(l
);
458 static int lua_getnickchancount(lua_State
*l
) {
461 if(!lua_islong(l
, 1))
464 np
= getnickbynumeric(lua_tolong(l
, 1));
468 lua_pushint(l
, np
->channels
->cursi
);
473 static int lua_gethostusers(lua_State
*l
) {
477 if(!lua_islong(l
, 1))
480 np
= getnickbynumeric(lua_tolong(l
, 1));
481 if(!np
|| !np
->host
|| !np
->host
->nicks
)
484 np
= np
->host
->nicks
;
485 count
= np
->host
->clonecount
;
495 static int lua_getnickcountry(lua_State
*l
) {
499 ext
= findnickext("geoip");
503 if(!lua_islong(l
, 1))
506 np
= getnickbynumeric(lua_tolong(l
, 1));
510 lua_pushint(l
, (int)np
->exts
[ext
]);
514 static int lua_chanfix(lua_State
*ps
) {
518 if(!lua_isstring(ps
, 1))
519 LUA_RETURN(ps
, LUA_FAIL
);
521 cp
= findchannel((char *)lua_tostring(ps
, 1));
523 LUA_RETURN(ps
, LUA_FAIL
);
525 np
= getnickbynick(LUA_CHANFIXBOT
);
527 LUA_RETURN(ps
, LUA_FAIL
);
529 lua_message(np
, "chanfix %s", cp
->index
->name
->content
);
531 LUA_RETURN(ps
, LUA_OK
);
534 static int lua_clearmode(lua_State
*ps
) {
541 if(!lua_isstring(ps
, 1))
542 LUA_RETURN(ps
, LUA_FAIL
);
544 cp
= findchannel((char *)lua_tostring(ps
, 1));
546 LUA_RETURN(ps
, LUA_FAIL
);
548 localsetmodeinit(&changes
, cp
, lua_nick
);
550 localdosetmode_key(&changes
, NULL
, MCB_DEL
);
551 localdosetmode_simple(&changes
, 0, CHANMODE_INVITEONLY
| CHANMODE_LIMIT
);
554 localdosetmode_ban(&changes
, bantostring(cp
->bans
), MCB_DEL
);
556 for(i
=0,lp
=cp
->users
->content
;i
<cp
->users
->hashsize
;i
++,lp
++)
557 if((*lp
!= nouser
) && (*lp
& CUMODE_OP
)) {
558 np
= getnickbynumeric(*lp
);
559 if(np
&& !IsService(np
))
560 localdosetmode_nick(&changes
, np
, MC_DEOP
);
563 localsetmodeflush(&changes
, 1);
565 LUA_RETURN(ps
, LUA_OK
);
568 static int lua_ban(lua_State
*ps
) {
574 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2))
575 LUA_RETURN(ps
, LUA_FAIL
);
577 if(lua_isboolean(ps
, 3) && lua_toboolean(ps
, 3))
580 cp
= findchannel((char *)lua_tostring(ps
, 1));
582 LUA_RETURN(ps
, LUA_FAIL
);
584 mask
= lua_tostring(ps
, 2);
585 if(!mask
|| !mask
[0] || !lua_lineok(mask
))
586 LUA_RETURN(ps
, LUA_FAIL
);
588 localsetmodeinit(&changes
, cp
, lua_nick
);
589 localdosetmode_ban(&changes
, mask
, dir
);
590 localsetmodeflush(&changes
, 1);
592 LUA_RETURN(ps
, LUA_OK
);
595 static int lua_topic(lua_State
*ps
) {
599 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2))
600 LUA_RETURN(ps
, LUA_FAIL
);
602 cp
= findchannel((char *)lua_tostring(ps
, 1));
604 LUA_RETURN(ps
, LUA_FAIL
);
606 topic
= (char *)lua_tostring(ps
, 2);
607 if(!topic
|| !lua_lineok(topic
))
608 LUA_RETURN(ps
, LUA_FAIL
);
610 localsettopic(lua_nick
, cp
, topic
);
612 LUA_RETURN(ps
, LUA_OK
);
615 static int lua_getuserchanmodes(lua_State
*l
) {
620 if(!lua_islong(l
, 1) || !lua_isstring(l
, 2))
623 np
= getnickbynumeric(lua_tolong(l
, 1));
627 cp
= findchannel((char *)lua_tostring(l
, 2));
631 lp
= getnumerichandlefromchanhash(cp
->users
, np
->numeric
);
635 LUA_PUSHNICKCHANMODES(l
, lp
);
639 static int lua_getnickbynick(lua_State
*l
) {
642 if(!lua_isstring(l
, 1))
645 np
= getnickbynick(lua_tostring(l
, 1));
653 static int lua_getnickbynumeric(lua_State
*l
) {
656 if(!lua_islong(l
, 1))
659 np
= getnickbynumeric(lua_tolong(l
, 1));
667 void lua_registercommands(lua_State
*l
) {
668 lua_register(l
, "irc_smsg", lua_smsg
);
669 lua_register(l
, "irc_skill", lua_skill
);
671 lua_register(l
, "chanmsg", lua_chanmsg
);
672 lua_register(l
, "scripterror", lua_scripterror
);
673 lua_register(l
, "versioninfo", lua_versioninfo
);
674 lua_register(l
, "basepath", lua_basepath
);
676 lua_register(l
, "irc_report", lua_chanmsg
);
677 lua_register(l
, "irc_ctcp", lua_ctcp
);
678 lua_register(l
, "irc_kill", lua_kill
);
679 lua_register(l
, "irc_kick", lua_kick
);
680 lua_register(l
, "irc_invite", lua_invite
);
681 lua_register(l
, "irc_gline", lua_gline
);
682 lua_register(l
, "irc_getchaninfo", lua_getchaninfo
);
683 lua_register(l
, "irc_counthost", lua_counthost
);
684 lua_register(l
, "irc_getuserbyauth", lua_getuserbyauth
);
685 lua_register(l
, "irc_notice", lua_noticecmd
);
686 lua_register(l
, "irc_opchan", lua_opchan
);
687 lua_register(l
, "irc_voicechan", lua_voicechan
);
688 lua_register(l
, "irc_chanfix", lua_chanfix
);
689 lua_register(l
, "irc_clearmode", lua_clearmode
);
690 lua_register(l
, "irc_ban", lua_ban
);
691 lua_register(l
, "irc_deopchan", lua_deopchan
);
692 lua_register(l
, "irc_topic", lua_topic
);
694 lua_register(l
, "irc_getnickbynick", lua_getnickbynick
);
695 lua_register(l
, "irc_getnickbynumeric", lua_getnickbynumeric
);
696 lua_register(l
, "irc_getfirstnick", lua_getfirstnick
);
697 lua_register(l
, "irc_getnextnick", lua_getnextnick
);
699 lua_register(l
, "irc_getnickchans", lua_getnickchans
);
700 lua_register(l
, "irc_getnickchanindex", lua_getnickchanindex
);
701 lua_register(l
, "irc_getnickchancount", lua_getnickchancount
);
703 lua_register(l
, "irc_getuserchanmodes", lua_getuserchanmodes
);
706 lua_register(l
, "irc_gethostusers", lua_gethostusers
);
707 lua_register(l
, "irc_getnickcountry", lua_getnickcountry
);
712 static int lua_smsg(lua_State
*ps
) {
713 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2))
714 LUA_RETURN(ps
, LUA_FAIL
);
716 LUA_RETURN(ps
, lua_cmsg((char *)lua_tostring(ps
, 2), "%s", lua_tostring(ps
, 1)));
719 static int lua_skill(lua_State
*ps
) {
723 if(!lua_isstring(ps
, 1) || !lua_isstring(ps
, 2))
724 LUA_RETURN(ps
, LUA_FAIL
);
726 n
= lua_tostring(ps
, 1);
727 msg
= lua_tostring(ps
, 2);
729 np
= getnickbynick(n
);
731 LUA_RETURN(ps
, LUA_FAIL
);
733 if(IsOper(np
) || IsService(np
) || IsXOper(np
))
734 LUA_RETURN(ps
, LUA_FAIL
);
737 LUA_RETURN(ps
, LUA_FAIL
);
739 killuser(lua_nick
, np
, "%s", msg
);
741 LUA_RETURN(ps
, LUA_OK
);
744 struct lua_nickpusher nickpusher
[MAX_NICKPUSHER
];
746 #define PUSHER_STRING 1
747 #define PUSHER_SSTRING 2
749 #define PUSHER_LONG 4
751 void lua_initnickpusher(void) {
754 #define PUSH_NICKPUSHER(F2, O2) nickpusher[i].argtype = F2; nickpusher[i].structname = #O2; nickpusher[i].offset = offsetof(nick, O2); i++;
756 PUSH_NICKPUSHER(PUSHER_STRING
, nick
);
757 PUSH_NICKPUSHER(PUSHER_STRING
, ident
);
758 PUSH_NICKPUSHER(PUSHER_SSTRING
, host
);
759 PUSH_NICKPUSHER(PUSHER_SSTRING
, realname
);
760 PUSH_NICKPUSHER(PUSHER_STRING
, authname
);
761 PUSH_NICKPUSHER(PUSHER_IP
, ipaddress
);
762 PUSH_NICKPUSHER(PUSHER_LONG
, numeric
);
764 nickpusher
[i
].argtype
= 0;
767 void lua_setupnickpusher(lua_State
*l
, int index
, struct lua_nickpusher
**lp
, int max
) {
769 struct lua_nickpusher
*f
;
774 if(!lua_istable(l
, -1) || (max
< 2))
781 while (lua_next(l
, index
)) {
782 if(lua_isstring(l
, -1)) {
783 char *name
= (char *)lua_tostring(l
, -1);
785 for(f
=&nickpusher
[0];f
->argtype
;f
++)
786 if(!strcmp(f
->structname
, name
))
802 void lua_usenickpusher(lua_State
*l
, struct lua_nickpusher
**lp
, nick
*np
) {
806 void *offset
= (void *)np
+ (*lp
)->offset
;
808 lua_pushstring(l
, (*lp
)->structname
);
810 switch((*lp
)->argtype
) {
812 lua_pushstring(l
, (char *)offset
);
815 lua_pushstring(l
, ((sstring
*)offset
)->content
);
818 lua_pushlong(l
, *((long *)offset
));
821 lua_pushstring(l
, IPtostr(*((long *)offset
)));