]> jfr.im git - irc/quakenet/newserv.git/blob - control/control.c
Initial Import
[irc/quakenet/newserv.git] / control / control.c
1 /*
2 * This is the first client module for newserv :)
3 *
4 * A very simple bot which should give people some ideas for how to
5 * implement stuff on this thing
6 */
7
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 "control.h"
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdarg.h>
27
28 nick *mynick;
29
30 nick *statsnick;
31
32 CommandTree *controlcmds;
33
34 void handlemessages(nick *target, int messagetype, void **args);
35 int controlstatus(void *sender, int cargc, char **cargv);
36 void controlconnect(void *arg);
37 int controlwhois(void *sender, int cargc, char **cargv);
38 int controlchannel(void *sender, int cargc, char **cargv);
39 int relink(void *sender, int cargc, char **cargv);
40 int die(void *sender, int cargc, char **cargv);
41 int controlinsmod(void *sender, int cargc, char **cargv);
42 int controlrmmod(void *sender, int cargc, char **cargv);
43 int controlrehash(void *sender, int cargc, char **cargv);
44 int controlshowcommands(void *sender, int cargc, char **cargv);
45 int controlreload(void *sender, int cargc, char **cargv);
46
47 void _init() {
48 controlcmds=newcommandtree();
49
50 addcommandtotree(controlcmds,"status",10,1,&controlstatus);
51 addcommandtotree(controlcmds,"whois",10,1,&controlwhois);
52 addcommandtotree(controlcmds,"channel",10,1,&controlchannel);
53 addcommandtotree(controlcmds,"relink",10,1,&relink);
54 addcommandtotree(controlcmds,"die",10,1,&die);
55 addcommandtotree(controlcmds,"insmod",10,1,&controlinsmod);
56 addcommandtotree(controlcmds,"rmmod",10,1,&controlrmmod);
57 addcommandtotree(controlcmds,"rehash",10,1,&controlrehash);
58 addcommandtotree(controlcmds,"showcommands",10,0,&controlshowcommands);
59 addcommandtotree(controlcmds,"reload",10,1,&controlreload);
60
61 scheduleoneshot(time(NULL)+1,&controlconnect,NULL);
62 }
63
64 void registercontrolcmd(const char *name, int level, int maxparams, CommandHandler handler) {
65 addcommandtotree(controlcmds,name,level,maxparams,handler);
66 }
67
68 int deregistercontrolcmd(const char *name, CommandHandler handler) {
69 return deletecommandfromtree(controlcmds, name, handler);
70 }
71
72 void controlconnect(void *arg) {
73 sstring *cnick, *myident, *myhost, *myrealname, *myauthname;
74 channel *cp;
75
76 cnick=getcopyconfigitem("control","nick","C",NICKLEN);
77 myident=getcopyconfigitem("control","ident","control",NICKLEN);
78 myhost=getcopyconfigitem("control","hostname",myserver->content,HOSTLEN);
79 myrealname=getcopyconfigitem("control","realname","NewServ Control Service",REALLEN);
80 myauthname=getcopyconfigitem("control","authname","C",ACCOUNTLEN);
81
82 mynick=registerlocaluser(cnick->content,myident->content,myhost->content,myrealname->content,myauthname->content,UMODE_SERVICE|UMODE_DEAF|UMODE_OPER|UMODE_ACCOUNT,&handlemessages);
83 cp=findchannel("#twilightzone");
84 if (!cp) {
85 localcreatechannel(mynick,"#twilightzone");
86 } else {
87 localjoinchannel(mynick,cp);
88 localgetops(mynick,cp);
89 }
90
91 freesstring(cnick);
92 freesstring(myident);
93 freesstring(myhost);
94 freesstring(myrealname);
95 freesstring(myauthname);
96 }
97
98 void handlestats(int hooknum, void *arg) {
99 sendmessagetouser(mynick,statsnick,"%s",(char *)arg);
100 }
101
102 int controlstatus(void *sender, int cargc, char **cargv) {
103 unsigned int level=5;
104
105 statsnick=(nick *)sender;
106
107 if (cargc>0) {
108 level=strtoul(cargv[0],NULL,10);
109 }
110
111 registerhook(HOOK_CORE_STATSREPLY,&handlestats);
112 triggerhook(HOOK_CORE_STATSREQUEST,(void *)level);
113 deregisterhook(HOOK_CORE_STATSREPLY,&handlestats);
114 return CMD_OK;
115 }
116
117 int controlrehash(void *sender, int cargc, char **cargv) {
118 nick *np=(nick *)sender;
119
120 controlreply(np,"Rehashing the config file.");
121
122 rehashconfig();
123 triggerhook(HOOK_CORE_REHASH,(void *)0);
124 return CMD_OK;
125 }
126
127 int controlwhois(void *sender, int cargc, char **cargv) {
128 nick *target;
129 channel **channels;
130 char buf[BUFSIZE];
131 int i;
132
133 if (cargc<1) {
134 sendmessagetouser(mynick,(nick *)sender,"Usage: whois <user>");
135 return CMD_ERROR;
136 }
137
138 if (cargv[0][0]=='#') {
139 if (!(target=getnickbynumericstr(cargv[0]+1))) {
140 sendmessagetouser(mynick,sender,"Sorry, couldn't find numeric %s",cargv[0]+1);
141 return CMD_ERROR;
142 }
143 } else {
144 if ((target=getnickbynick(cargv[0]))==NULL) {
145 sendmessagetouser(mynick,(nick *)sender,"Sorry, couldn't find that user");
146 return CMD_ERROR;
147 }
148 }
149
150 sendmessagetouser(mynick,(nick *)sender,"Nick : %s",target->nick);
151 sendmessagetouser(mynick,(nick *)sender,"Numeric : %s",longtonumeric(target->numeric,5));
152 sendmessagetouser(mynick,(nick *)sender,"User@Host : %s@%s (%d user(s) on this host)",target->ident,target->host->name->content,target->host->clonecount);
153 if (IsSetHost(target)) {
154 if (target->shident) {
155 sendmessagetouser(mynick,(nick *)sender,"Fakehost : %s@%s",target->shident->content, target->sethost->content);
156 } else {
157 sendmessagetouser(mynick,(nick *)sender,"Fakehost : %s",target->sethost->content);
158 }
159 }
160 sendmessagetouser(mynick,(nick *)sender,"Timestamp : %lu",target->timestamp);
161 sendmessagetouser(mynick,(nick *)sender,"IP address: %d.%d.%d.%d",(target->ipaddress)>>24,(target->ipaddress>>16)&255, (target->ipaddress>>8)&255,target->ipaddress&255);
162 sendmessagetouser(mynick,(nick *)sender,"Realname : %s (%d user(s) have this realname)",target->realname->name->content,target->realname->usercount);
163 if (target->umodes) {
164 sendmessagetouser(mynick,(nick *)sender,"Umode(s) : %s",printflags(target->umodes,umodeflags));
165 }
166 if (IsAccount(target)) {
167 sendmessagetouser(mynick,(nick *)sender,"Account : %s",target->authname);
168 if (target->accountts)
169 sendmessagetouser(mynick,(nick *)sender,"AccountTS : %ld",target->accountts);
170 }
171 if (target->channels->cursi==0) {
172 sendmessagetouser(mynick,(nick *)sender,"Channels : none");
173 } else if (target->channels->cursi>50) {
174 sendmessagetouser(mynick,(nick *)sender,"Channels : - (total: %d)",target->channels->cursi);
175 } else {
176 buf[0]='\0';
177 channels=(channel **)target->channels->content;
178 for (i=0;i<=target->channels->cursi;i++) {
179 if (!((i==target->channels->cursi) || ((70-strlen(buf))<channels[i]->index->name->length && strlen(buf)>0))) {
180 strcat(buf,channels[i]->index->name->content);
181 strcat(buf," ");
182 } else {
183 if (strlen(buf)==0) {
184 break;
185 } else {
186 sendmessagetouser(mynick,(nick *)sender,"Channels : %s",buf);
187 buf[0]='\0';
188 i--;
189 }
190 }
191 }
192 }
193
194 return CMD_OK;
195 }
196
197 int controlinsmod(void *sender, int cargc, char **cargv) {
198 if (cargc<1) {
199 sendmessagetouser(mynick,(nick *)sender,"Usage: insmod <modulename>");
200 return CMD_ERROR;
201 }
202
203 switch(insmod(cargv[0])) {
204 case -1:
205 sendmessagetouser(mynick,(nick *)sender,"Unable to load module %s",cargv[0]);
206 return CMD_ERROR;
207
208 case 1:
209 sendmessagetouser(mynick,(nick *)sender,"Module %s already loaded, or name not valid",cargv[0]);
210 return CMD_ERROR;
211
212 case 0:
213 sendmessagetouser(mynick,(nick *)sender,"Module %s loaded.",cargv[0]);
214 return CMD_OK;
215
216 default:
217 sendmessagetouser(mynick,(nick *)sender,"An unknown error occured.");
218 return CMD_ERROR;
219 }
220 }
221
222 int controlrmmod(void *sender, int cargc, char **cargv) {
223 if (cargc<1) {
224 sendmessagetouser(mynick,(nick *)sender,"Usage: insmod <modulename>");
225 return CMD_ERROR;
226 }
227
228 switch(rmmod(cargv[0])) {
229 case 1:
230 sendmessagetouser(mynick,(nick *)sender,"Module %s is not loaded.",cargv[0]);
231 return CMD_ERROR;
232
233 case 0:
234 sendmessagetouser(mynick,(nick *)sender,"Module %s unloaded.",cargv[0]);
235 return CMD_OK;
236
237 default:
238 sendmessagetouser(mynick,(nick *)sender,"An unknown error occured.");
239 return CMD_ERROR;
240 }
241 }
242
243 int controlreload(void *sender, int cargc, char **cargv) {
244 if (cargc<1) {
245 sendmessagetouser(mynick,(nick *)sender,"Usage: reload <modulename>");
246 return CMD_ERROR;
247 }
248
249 controlrmmod(sender, cargc, cargv);
250 return controlinsmod(sender, cargc, cargv);
251 }
252
253 int relink(void *sender, int cargc, char **cargv) {
254 if (cargc<1) {
255 sendmessagetouser(mynick,(nick *)sender,"You must give a reason.");
256 return CMD_ERROR;
257 }
258
259 irc_send("%s SQ %s 0 :%s",mynumeric->content,myserver->content,cargv[0]);
260 irc_disconnected();
261
262 return CMD_OK;
263 }
264
265 int die(void *sender, int cargc, char **cargv) {
266 if (cargc<1) {
267 sendmessagetouser(mynick,(nick *)sender,"You must give a reason.");
268 return CMD_ERROR;
269 }
270
271 irc_send("%s SQ %s 0 :%s",mynumeric->content,myserver->content,cargv[0]);
272 irc_disconnected();
273
274 exit(0);
275 }
276
277 int controlchannel(void *sender, int cargc, char **cargv) {
278 channel *cp;
279 nick *np;
280 chanban *cbp;
281 char buf[BUFSIZE];
282 char buf2[12];
283 int i,j;
284
285 if (cargc<1) {
286 sendmessagetouser(mynick,(nick *)sender,"Usage: channel #chan");
287 return CMD_ERROR;
288 }
289
290 if ((cp=findchannel(cargv[0]))==NULL) {
291 sendmessagetouser(mynick,(nick *)sender,"Couldn't find channel: %s",cargv[0]);
292 return CMD_ERROR;
293 }
294
295 if (IsLimit(cp)) {
296 sprintf(buf2,"%d",cp->limit);
297 }
298
299 sendmessagetouser(mynick,(nick *)sender,"Channel : %s",cp->index->name->content);
300 if (cp->topic) {
301 sendmessagetouser(mynick,(nick *)sender,"Topic : %s",cp->topic->content);
302 sendmessagetouser(mynick,(nick *)sender,"T-time : %ld [%s\]",cp->topictime,ctime(&(cp->topictime)));
303 }
304 sendmessagetouser(mynick,(nick *)sender,"Mode(s) : %s %s%s%s",printflags(cp->flags,cmodeflags),IsLimit(cp)?buf2:"",
305 IsLimit(cp)?" ":"",IsKey(cp)?cp->key->content:"");
306 sendmessagetouser(mynick,(nick *)sender,"Users : %d (hash size %d, utilisation %.1f%%); %d unique hosts",
307 cp->users->totalusers,cp->users->hashsize,((float)(100*cp->users->totalusers)/cp->users->hashsize),
308 countuniquehosts(cp));
309 i=0;
310 memset(buf,' ',90);
311 buf[72]='\0';
312 for (j=0;j<=cp->users->hashsize;j++) {
313 if (i==4 || j==cp->users->hashsize) {
314 if(i>0) {
315 sendmessagetouser(mynick,(nick *)sender,"Users : %s",buf);
316 }
317 i=0;
318 memset(buf,' ',72);
319 if (j==cp->users->hashsize)
320 break;
321 }
322 if (cp->users->content[j]!=nouser) {
323 np=getnickbynumeric(cp->users->content[j]);
324 sprintf(&buf[i*18],"%c%c%-15s ",cp->users->content[j]&CUMODE_VOICE?'+':' ',
325 cp->users->content[j]&CUMODE_OP?'@':' ', np?np->nick:"!BUG-NONICK!");
326 i++;
327 if (i<4)
328 buf[i*18]=' ';
329 }
330 }
331
332 for (cbp=cp->bans;cbp;cbp=cbp->next) {
333 sendmessagetouser(mynick,(nick *)sender,"Ban : %s",bantostringdebug(cbp));
334 }
335 return CMD_OK;
336 }
337
338 int controlshowcommands(void *sender, int cargc, char **cargv) {
339 nick *np=(nick *)sender;
340 Command *cmdlist[100];
341 int i,n;
342
343 n=getcommandlist(controlcmds,cmdlist,100);
344
345 controlreply(np,"The following commands are registered at present:");
346
347 for(i=0;i<n;i++) {
348 controlreply(np,"%s (level %d)",cmdlist[i]->command->content,cmdlist[i]->level);
349 }
350
351 controlreply(np,"End of list.");
352 return CMD_OK;
353 }
354
355 void handlemessages(nick *target, int messagetype, void **args) {
356 Command *cmd;
357 char *cargv[50];
358 int cargc;
359 nick *sender;
360
361 switch(messagetype) {
362 case LU_PRIVMSG:
363 case LU_SECUREMSG:
364 /* If it's a message, first arg is nick and second is message */
365 sender=(nick *)args[0];
366
367 Error("control",ERR_INFO,"From: %s!%s@%s: %s",sender->nick,sender->ident,sender->host->name->content, (char *)args[1]);
368
369 /* Split the line into params */
370 cargc=splitline((char *)args[1],cargv,50,0);
371
372 if (!cargc) {
373 /* Blank line */
374 return;
375 }
376
377 cmd=findcommandintree(controlcmds,cargv[0],1);
378 if (cmd==NULL) {
379 sendmessagetouser(mynick,sender,"Unknown command.");
380 return;
381 }
382
383 if (cmd->level>=10 && !IsOper(sender)) {
384 sendmessagetouser(mynick,sender,"You need to be opered to use this command.");
385 return;
386 }
387
388 /* If we were doing "authed user tracking" here we'd put a check in for authlevel */
389
390 /* Check the maxargs */
391 if (cmd->maxparams<(cargc-1)) {
392 /* We need to do some rejoining */
393 rejoinline(cargv[cmd->maxparams],cargc-(cmd->maxparams));
394 cargc=(cmd->maxparams)+1;
395 }
396
397 (cmd->handler)((void *)sender,cargc-1,&(cargv[1]));
398 break;
399
400 case LU_KILLED:
401 /* someone killed me? Bastards */
402 scheduleoneshot(time(NULL)+1,&controlconnect,NULL);
403 mynick=NULL;
404 break;
405
406 default:
407 break;
408 }
409 }
410
411 void controlreply(nick *target, char *message, ... ) {
412 char buf[512];
413 va_list va;
414
415 if (mynick==NULL) {
416 return;
417 }
418
419 va_start(va,message);
420 vsnprintf(buf,512,message,va);
421 va_end(va);
422
423 sendmessagetouser(mynick,target,"%s",buf);
424 }
425
426 void controlchanmsg(channel *cp, char *message, ...) {
427 char buf[512];
428 va_list va;
429
430 if (mynick==NULL) {
431 return;
432 }
433
434 va_start(va,message);
435 vsnprintf(buf,512,message,va);
436 va_end(va);
437
438 sendmessagetochannel(mynick,cp,"%s",buf);
439 }
440
441 void controlnotice(nick *target, char *message, ... ) {
442 char buf[512];
443 va_list va;
444
445 if (mynick==NULL) {
446 return;
447 }
448
449 va_start(va,message);
450 vsnprintf(buf,512,message,va);
451 va_end(va);
452
453 sendnoticetouser(mynick,target,"%s",buf);
454 }
455