2 * This is the first client module for newserv :)
4 * A very simple bot which should give people some ideas for how to
5 * implement stuff on this thing
8 #include "../irc/irc_config.h"
9 #include "../parser/parser.h"
10 #include "../localuser/localuser.h"
11 #include "../localuser/localuserchannel.h"
12 #include "../nick/nick.h"
13 #include "../lib/sstring.h"
14 #include "../core/config.h"
15 #include "../irc/irc.h"
16 #include "../lib/splitline.h"
17 #include "../channel/channel.h"
18 #include "../lib/flags.h"
19 #include "../core/schedule.h"
20 #include "../lib/base64.h"
21 #include "../core/modules.h"
22 #include "../lib/version.h"
23 #include "../lib/irc_string.h"
36 CommandTree
*controlcmds
;
37 ControlMsg controlreply
;
38 ControlWall controlwall
;
39 ControlPermitted controlpermitted
;
40 DestroyExt controldestroyext
;
42 void controldestroycmdext(void *ext
);
43 void handlemessages(nick
*target
, int messagetype
, void **args
);
44 int controlstatus(void *sender
, int cargc
, char **cargv
);
45 void controlconnect(void *arg
);
46 int controlwhois(void *sender
, int cargc
, char **cargv
);
47 int controlchannel(void *sender
, int cargc
, char **cargv
);
48 int relink(void *sender
, int cargc
, char **cargv
);
49 int die(void *sender
, int cargc
, char **cargv
);
50 int controlinsmod(void *sender
, int cargc
, char **cargv
);
51 int controllsmod(void *sender
, int cargc
, char **cargv
);
52 int controlrehash(void *sender
, int cargc
, char **cargv
);
53 int controlreload(void *sender
, int cargc
, char **cargv
);
54 int controlhelpcmd(void *sender
, int cargc
, char **cargv
);
55 void controlnoticeopers(flag_t permissionlevel
, flag_t noticelevel
, char *format
, ...) __attribute__ ((format (printf
, 3, 4)));
56 void controlnoticeopers(flag_t permissionlevel
, flag_t noticelevel
, char *format
, ...);
57 int controlcheckpermitted(flag_t level
, nick
*user
);
58 void handlesignal(int hooknum
, void *arg
);
61 controlcmds
=newcommandtree();
62 controlreply
=&controlmessage
;
63 controlwall
=&controlnoticeopers
;
64 controlpermitted
=&controlcheckpermitted
;
65 controldestroyext
=&controldestroycmdext
;
67 registercontrolhelpcmd("status",NO_DEVELOPER
,1,&controlstatus
,"Usage: status ?level?\nDisplays status information, increasing level gives more verbose information.");
68 registercontrolhelpcmd("whois",NO_OPERED
,1,&controlwhois
,"Usage: whois <nickname|#numeric>\nDisplays lots of information about the specified nickname or numeric.");
69 registercontrolhelpcmd("channel",NO_OPER
,1,&controlchannel
,"Usage: channel <#channel>\nDisplays channel information.");
70 registercontrolhelpcmd("relink",NO_DEVELOPER
,1,&relink
,"Usage: relink\nRelinks service to the network.");
71 registercontrolhelpcmd("die",NO_DEVELOPER
,1,&die
,"Usage: die <reason>\nTerminates the service.");
72 registercontrolhelpcmd("insmod",NO_DEVELOPER
,1,&controlinsmod
,"Usage: insmod <module>\nAdds a module to the running instance.");
73 registercontrolhelpcmd("rmmod",NO_DEVELOPER
,1,&controlrmmod
,"Usage: rmmod <module>\nRemoves a module from the running instance.");
74 registercontrolhelpcmd("lsmod",NO_OPER
,0,&controllsmod
,"Usage: lsmod\nLists currently running modules.");
75 registercontrolhelpcmd("rehash",NO_DEVELOPER
,1,&controlrehash
,"Usage: rehash\nReloads configuration file.");
76 registercontrolhelpcmd("showcommands",NO_ACCOUNT
,0,&controlshowcommands
,"Usage: showcommands\nShows all registered commands.");
77 registercontrolhelpcmd("reload",NO_DEVELOPER
,1,&controlreload
,"Usage: reload <module>\nReloads specified module.");
78 registercontrolhelpcmd("help",NO_ANYONE
,1,&controlhelpcmd
,"Usage: help <command>\nShows help for specified command.");
80 registerhook(HOOK_CORE_REHASH
, &handlesignal
);
81 registerhook(HOOK_CORE_SIGINT
, &handlesignal
);
82 scheduleoneshot(time(NULL
)+1,&controlconnect
,NULL
);
86 deleteallschedules(&controlconnect
);
88 deregisterlocaluser(mynick
,"Leaving");
91 deregistercontrolcmd("status",&controlstatus
);
92 deregistercontrolcmd("whois",&controlwhois
);
93 deregistercontrolcmd("channel",&controlchannel
);
94 deregistercontrolcmd("relink",&relink
);
95 deregistercontrolcmd("die",&die
);
96 deregistercontrolcmd("insmod",&controlinsmod
);
97 deregistercontrolcmd("rmmod",&controlrmmod
);
98 deregistercontrolcmd("lsmod",&controllsmod
);
99 deregistercontrolcmd("rehash",&controlrehash
);
100 deregistercontrolcmd("showcommands",&controlshowcommands
);
101 deregistercontrolcmd("reload",&controlreload
);
102 deregistercontrolcmd("help",&controlhelpcmd
);
104 destroycommandtree(controlcmds
);
106 deregisterhook(HOOK_CORE_REHASH
, &handlesignal
);
107 deregisterhook(HOOK_CORE_SIGINT
, &handlesignal
);
110 void registercontrolhelpcmd(const char *name
, int level
, int maxparams
, CommandHandler handler
, char *helpstr
) {
114 newcmd
= addcommandtotree(controlcmds
,name
,level
,maxparams
,handler
);
117 /* Allocate a help record */
118 help
=(cmdhelp
*)malloc(sizeof(cmdhelp
));
120 Error("control",ERR_ERROR
,"Malloc failed: registercontrolhelpcmd");
123 memset((void *)help
,0,sizeof(cmdhelp
));
125 /* this isn't an sstring atm, as sstring has a max length (512) */
126 int len
=strlen(helpstr
);
127 help
->helpstr
=(char *)malloc(len
+1);
129 strncpy(help
->helpstr
, helpstr
, len
);
130 help
->helpstr
[len
] = '\0';
132 newcmd
->ext
=(void *)help
;
133 newcmd
->destroyext
=controldestroyext
;
137 void registercontrolhelpfunccmd(const char *name
, int level
, int maxparams
, CommandHandler handler
, CommandHelp helpcmd
) {
141 /* Allocate a help record */
142 help
=(cmdhelp
*)malloc(sizeof(cmdhelp
));
144 Error("control",ERR_ERROR
,"Malloc failed: registercontrolhelpfunccmd");
147 memset((void *)help
,0,sizeof(cmdhelp
));
149 help
->helpcmd
=helpcmd
;
151 newcmd
= addcommandexttotree(controlcmds
,name
,level
,maxparams
,handler
, (void *)help
);
152 newcmd
->destroyext
=controldestroyext
;
156 int deregistercontrolcmd(const char *name
, CommandHandler handler
) {
157 return deletecommandfromtree(controlcmds
, name
, handler
);
160 void controlconnect(void *arg
) {
161 sstring
*cnick
, *myident
, *myhost
, *myrealname
, *myauthname
;
164 cnick
=getcopyconfigitem("control","nick","C",NICKLEN
);
165 myident
=getcopyconfigitem("control","ident","control",NICKLEN
);
166 myhost
=getcopyconfigitem("control","hostname",myserver
->content
,HOSTLEN
);
167 myrealname
=getcopyconfigitem("control","realname","NewServ Control Service",REALLEN
);
168 myauthname
=getcopyconfigitem("control","authname","C",ACCOUNTLEN
);
170 mynick
=registerlocaluser(cnick
->content
,myident
->content
,myhost
->content
,myrealname
->content
,myauthname
->content
,UMODE_SERVICE
|UMODE_DEAF
|UMODE_OPER
|UMODE_ACCOUNT
|UMODE_INV
,&handlemessages
);
171 triggerhook(HOOK_CONTROL_REGISTERED
, mynick
);
172 cp
=findchannel("#twilightzone");
174 localcreatechannel(mynick
,"#twilightzone");
176 localjoinchannel(mynick
,cp
);
177 localgetops(mynick
,cp
);
181 freesstring(myident
);
183 freesstring(myrealname
);
184 freesstring(myauthname
);
187 void handlestats(int hooknum
, void *arg
) {
188 controlreply(hooknick
,"%s",(char *)arg
);
191 int controlstatus(void *sender
, int cargc
, char **cargv
) {
192 unsigned long level
=999;
193 hooknick
=(nick
*)sender
;
196 level
=strtoul(cargv
[0],NULL
,10);
199 registerhook(HOOK_CORE_STATSREPLY
,&handlestats
);
201 triggerhook(HOOK_CORE_STATSREQUEST
,(void *)level
);
202 deregisterhook(HOOK_CORE_STATSREPLY
,&handlestats
);
206 int controlrehash(void *sender
, int cargc
, char **cargv
) {
207 nick
*np
=(nick
*)sender
;
209 controlreply(np
,"Rehashing the config file.");
212 triggerhook(HOOK_CORE_REHASH
,(void *)0);
216 void handlewhois(int hooknum
, void *arg
) {
217 controlreply(hooknick
,"%s",(char *)arg
);
220 int controlwhois(void *sender
, int cargc
, char **cargv
) {
229 if (cargv
[0][0]=='#') {
230 if (!(target
=getnickbynumericstr(cargv
[0]+1))) {
231 controlreply(sender
,"Sorry, couldn't find numeric %s",cargv
[0]+1);
235 if ((target
=getnickbynick(cargv
[0]))==NULL
) {
236 controlreply((nick
*)sender
,"Sorry, couldn't find that user");
241 controlreply((nick
*)sender
,"Nick : %s",target
->nick
);
242 controlreply((nick
*)sender
,"Numeric : %s",longtonumeric(target
->numeric
,5));
243 controlreply((nick
*)sender
,"User@Host : %s@%s (%d user(s) on this host)",target
->ident
,target
->host
->name
->content
,target
->host
->clonecount
);
244 if (IsSetHost(target
)) {
245 if (target
->shident
) {
246 controlreply((nick
*)sender
,"Fakehost : %s@%s",target
->shident
->content
, target
->sethost
->content
);
248 controlreply((nick
*)sender
,"Fakehost : %s",target
->sethost
->content
);
251 controlreply((nick
*)sender
,"Timestamp : %lu",target
->timestamp
);
255 int ext
= findnickext("signontracker");
258 time_t signedon
= (time_t)(target
->exts
[ext
]);
260 controlreply((nick
*)sender
,"Signed on : %lu",signedon
);
262 controlreply((nick
*)sender
,"Signed on : ???");
266 controlreply((nick
*)sender
,"IP address: %s",IPtostr(target
->p_ipaddr
));
267 controlreply((nick
*)sender
,"Realname : %s (%d user(s) have this realname)",target
->realname
->name
->content
,target
->realname
->usercount
);
268 if (target
->umodes
) {
269 controlreply((nick
*)sender
,"Umode(s) : %s",printflags(target
->umodes
,umodeflags
));
271 if (IsOper(target
) && target
->opername
)
272 controlreply((nick
*)sender
,"Opered as : %s",target
->opername
->content
);
273 if (IsAccount(target
)) {
274 controlreply((nick
*)sender
,"Account : %s",target
->authname
);
275 if (target
->accountts
)
276 controlreply((nick
*)sender
,"AccountTS : %ld",target
->accountts
);
278 controlreply((nick
*)sender
,"UserID : %ld",target
->auth
->userid
);
279 if (target
->auth
->flags
)
280 controlreply((nick
*)sender
,"AccFlags : %s",printflags(target
->auth
->flags
,accountflags
));
285 controlreply((nick
*)sender
, "Away : %s",target
->away
->content
);
288 hooknick
=(nick
*)sender
;
289 registerhook(HOOK_CONTROL_WHOISREPLY
,&handlewhois
);
290 triggerhook(HOOK_CONTROL_WHOISREQUEST
,target
);
291 deregisterhook(HOOK_CONTROL_WHOISREPLY
,&handlewhois
);
293 if (target
->channels
->cursi
==0) {
294 controlreply((nick
*)sender
,"Channels : none");
295 } else if (target
->channels
->cursi
>50) {
296 controlreply((nick
*)sender
,"Channels : - (total: %d)",target
->channels
->cursi
);
299 channels
=(channel
**)target
->channels
->content
;
300 for (i
=0;i
<=target
->channels
->cursi
;i
++) {
301 if (!((i
==target
->channels
->cursi
) || ((70-strlen(buf
))<channels
[i
]->index
->name
->length
&& strlen(buf
)>0))) {
302 strcat(buf
,channels
[i
]->index
->name
->content
);
305 if (strlen(buf
)==0) {
308 controlreply((nick
*)sender
,"Channels : %s",buf
);
319 int controlinsmod(void *sender
, int cargc
, char **cargv
) {
323 switch(insmod(cargv
[0])) {
325 controlreply((nick
*)sender
,"Unable to load module %s",cargv
[0]);
329 controlreply((nick
*)sender
,"Module %s already loaded, or name not valid",cargv
[0]);
333 controlreply((nick
*)sender
,"Module %s loaded.",cargv
[0]);
337 controlreply((nick
*)sender
,"An unknown error occured.");
342 int controlrmmod(void *sender
, int cargc
, char **cargv
) {
346 switch(rmmod(cargv
[0])) {
348 controlreply((nick
*)sender
,"Module %s is not loaded.",cargv
[0]);
352 controlreply((nick
*)sender
,"Module %s unloaded.",cargv
[0]);
356 controlreply((nick
*)sender
,"An unknown error occured.");
361 int controllsmod(void *sender
, int cargc
, char **cargv
) {
365 if (cargc
< 1) { /* list all loaded modules */
366 const char *ver
, *buildid
;
367 time_t t
, t2
= time(NULL
);
368 ptr
= lsmod(i
, &ver
, &buildid
, &t
);
370 /* 9999d 24h 59m 59s fbf2a4a69ee1-tip */
371 controlreply((nick
*)sender
,"Module Loaded for Version Build id");
372 while (ptr
!= NULL
) {
373 controlreply((nick
*)sender
," %-40s %-17s %-30s %s", ptr
, longtoduration(t2
-t
, 2), ver
?ver
:"", buildid
?buildid
:"");
374 ptr
= lsmod(++i
, &ver
, &buildid
, &t
);
377 ptr
= lsmod(getindex(cargv
[0]), NULL
, NULL
, NULL
);
378 controlreply((nick
*)sender
,"Module \"%s\" %s", cargv
[0], (ptr
? "is loaded." : "is NOT loaded."));
383 int controlreload(void *sender
, int cargc
, char **cargv
) {
387 controlreply((nick
*)sender
,"Imma gonna try and reload %s",cargv
[0]);
389 safereload(cargv
[0]);
394 int relink(void *sender
, int cargc
, char **cargv
) {
396 controlreply((nick
*)sender
,"You must give a reason.");
400 irc_send("%s SQ %s 0 :%s",mynumeric
->content
,myserver
->content
,cargv
[0]);
406 int die(void *sender
, int cargc
, char **cargv
) {
407 if (cargc
<1 || (strlen(cargv
[0]) < 10)) {
408 controlreply((nick
*)sender
,"You must give a reason.");
412 controlwall(NO_OPER
,NL_OPERATIONS
,"DIE from %s: %s",((nick
*)sender
)->nick
, cargv
[0]);
414 newserv_shutdown_pending
=1;
419 int controlchannel(void *sender
, int cargc
, char **cargv
) {
425 int i
,j
, ops
=0, voice
=0;
431 if ((cp
=findchannel(cargv
[0]))==NULL
) {
432 controlreply((nick
*)sender
,"Couldn't find channel: %s",cargv
[0]);
437 sprintf(buf2
,"%d",cp
->limit
);
440 controlreply((nick
*)sender
,"Channel : %s",cp
->index
->name
->content
);
441 strftime(timebuf
, 30, "%d/%m/%y %H:%M", localtime(&(cp
->timestamp
)));
442 controlreply((nick
*)sender
,"C-time : %ld [%s]",cp
->timestamp
,timebuf
);
444 controlreply((nick
*)sender
,"Topic : %s",cp
->topic
->content
);
445 strftime(timebuf
, 30, "%d/%m/%y %H:%M", localtime(&(cp
->topictime
)));
446 controlreply((nick
*)sender
,"T-time : %ld [%s]",cp
->topictime
,timebuf
);
448 controlreply((nick
*)sender
,"Topic : (none)");
450 controlreply((nick
*)sender
,"Mode(s) : %s %s%s%s",printflags(cp
->flags
,cmodeflags
),IsLimit(cp
)?buf2
:"",
451 IsLimit(cp
)?" ":"",IsKey(cp
)?cp
->key
->content
:"");
452 controlreply((nick
*)sender
,"Users : %d (hash size %d, utilisation %.1f%%); %d unique hosts",
453 cp
->users
->totalusers
,cp
->users
->hashsize
,((float)(100*cp
->users
->totalusers
)/cp
->users
->hashsize
),
454 countuniquehosts(cp
));
458 for (j
=0;j
<=cp
->users
->hashsize
;j
++) {
459 if (i
==4 || j
==cp
->users
->hashsize
) {
461 controlreply((nick
*)sender
,"Users : %s",buf
);
465 if (j
==cp
->users
->hashsize
)
468 if (cp
->users
->content
[j
]!=nouser
) {
469 if (cp
->users
->content
[j
]&CUMODE_OP
)
471 else if (cp
->users
->content
[j
]&CUMODE_VOICE
)
473 np
=getnickbynumeric(cp
->users
->content
[j
]);
474 sprintf(&buf
[i
*18],"%c%c%-15s ",cp
->users
->content
[j
]&CUMODE_VOICE
?'+':' ',
475 cp
->users
->content
[j
]&CUMODE_OP
?'@':' ', np
?np
->nick
:"!BUG-NONICK!");
481 controlreply((nick
*)sender
, "Users : Opped: %d, Voiced: %d", ops
,voice
);
482 for (cbp
=cp
->bans
;cbp
;cbp
=cbp
->next
) {
483 controlreply((nick
*)sender
,"Ban : %s",bantostringdebug(cbp
));
488 int controlshowcommands(void *sender
, int cargc
, char **cargv
) {
489 nick
*np
=(nick
*)sender
;
490 Command
*cmdlist
[100];
493 n
=getcommandlist(controlcmds
,cmdlist
,100);
495 controlreply(np
,"The following commands are registered at present:");
498 controlreply(np
,"%s",cmdlist
[i
]->command
->content
);
501 controlreply(np
,"End of list.");
505 void handlemessages(nick
*target
, int messagetype
, void **args
) {
511 switch(messagetype
) {
514 /* If it's a message, first arg is nick and second is message */
515 sender
=(nick
*)args
[0];
517 Error("control",ERR_INFO
,"From: %s!%s@%s: %s",sender
->nick
,sender
->ident
,sender
->host
->name
->content
, (char *)args
[1]);
519 /* Split the line into params */
520 cargc
=splitline((char *)args
[1],cargv
,50,0);
527 cmd
=findcommandintree(controlcmds
,cargv
[0],1);
529 controlreply(sender
,"Unknown command.");
533 if (cmd
->level
>0 && !IsOper(sender
)) {
534 controlreply(sender
,"You need to be opered to use this command.");
538 /* If we were doing "authed user tracking" here we'd put a check in for authlevel */
540 /* Check the maxargs */
541 if (cmd
->maxparams
<(cargc
-1)) {
542 /* We need to do some rejoining */
543 rejoinline(cargv
[cmd
->maxparams
],cargc
-(cmd
->maxparams
));
544 cargc
=(cmd
->maxparams
)+1;
547 if((cmd
->handler
)((void *)sender
,cargc
-1,&(cargv
[1])) == CMD_USAGE
)
548 controlhelp(sender
, cmd
);
552 /* someone killed me? Bastards */
553 scheduleoneshot(time(NULL
)+1,&controlconnect
,NULL
);
555 triggerhook(HOOK_CONTROL_REGISTERED
, NULL
);
563 void controlmessage(nick
*target
, char *message
, ... ) {
571 va_start(va
,message
);
572 vsnprintf(buf
,512,message
,va
);
575 sendmessagetouser(mynick
,target
,"%s",buf
);
578 void controlchanmsg(channel
*cp
, char *message
, ...) {
586 va_start(va
,message
);
587 vsnprintf(buf
,512,message
,va
);
590 sendmessagetochannel(mynick
,cp
,"%s",buf
);
593 void controlnotice(nick
*target
, char *message
, ... ) {
601 va_start(va
,message
);
602 vsnprintf(buf
,512,message
,va
);
605 sendnoticetouser(mynick
,target
,"%s",buf
);
608 void controlspecialrmmod(void *arg
) {
609 struct specialsched
*a
= (struct specialsched
*)arg
;
610 sstring
*froo
= a
->modulename
;
614 rmmod(froo
->content
);
618 void controlspecialreloadmod(void *arg
) {
619 struct specialsched
*a
= (struct specialsched
*)arg
;
620 sstring
*froo
= a
->modulename
;
624 safereload(froo
->content
);
628 void controlhelp(nick
*np
, Command
*cmd
) {
631 cmdhelp
*help
=(cmdhelp
*)cmd
->ext
;
634 controlreply(np
, "Sorry, no help for this command.");
637 if ( help
->helpcmd
) {
638 (help
->helpcmd
)(np
, cmd
);
642 controlreply(np
, "Sorry, no help for this command.");
648 if(*cp
== '\0' || *cp
== '\n') {
656 controlreply(np
, "%s", sp
);
670 int controlhelpcmd(void *sender
, int cargc
, char **cargv
) {
672 nick
*np
= (nick
*)sender
;
677 cmd
=findcommandintree(controlcmds
,cargv
[0],1);
679 controlreply(np
,"Unknown command.");
683 controlhelp(np
, cmd
);
687 void controlnoticeopers(flag_t permissionlevel
, flag_t noticelevel
, char *format
, ...) {
693 va_start(va
, format
);
694 vsnprintf(broadcast
, sizeof(broadcast
), format
, va
);
697 for(i
=0;i
<NICKHASHSIZE
;i
++)
698 for(np
=nicktable
[i
];np
;np
=np
->next
)
700 controlnotice(np
, "%s", broadcast
);
703 void controlnswall(int noticelevel
, char *format
, ...) {
707 va_start(va
, format
);
708 vsnprintf(broadcast
, sizeof(broadcast
), format
, va
);
711 controlwall(NO_OPER
, noticelevel
, "%s", broadcast
);
714 int controlcheckpermitted(flag_t level
, nick
*user
) {
718 void handlesignal(int hooknum
, void *arg
) {
719 char *signal
, *action
;
721 if(hooknum
== HOOK_CORE_SIGINT
) {
723 action
= "terminating";
725 long hupped
= (long)arg
;
730 action
= "rehashing";
733 controlwall(NO_OPER
, NL_OPERATIONS
, "SIG%s received, %s...", signal
, action
);
736 void controldestroycmdext(void *ext
) {
737 if ( ((cmdhelp
*)ext
)->helpstr
)
738 free( ((cmdhelp
*)ext
)->helpstr
);
742 char *controlid(nick
*np
) {
743 static char buf
[512];
745 snprintf(buf
, sizeof(buf
), "%s!%s@%s/%s", np
->nick
, np
->ident
, np
->host
->name
->content
, np
->authname
);