]> jfr.im git - irc/quakenet/newserv.git/blob - request/request.c
merge
[irc/quakenet/newserv.git] / request / request.c
1 /* shroud's service request */
2
3 #include <stdio.h>
4 #include <string.h>
5 #include "../localuser/localuser.h"
6 #include "../localuser/localuserchannel.h"
7 #include "../core/schedule.h"
8 #include "../lib/irc_string.h"
9 #include "../lib/splitline.h"
10 #include "../lib/version.h"
11 #include "../control/control.h"
12 #include "../splitlist/splitlist.h"
13 #include "request.h"
14 #include "request_block.h"
15 #include "lrequest.h"
16 #include "sqrequest.h"
17 #include "user.h"
18
19 MODULE_VERSION("");
20
21 nick *rqnick;
22 CommandTree *rqcommands;
23
24 void rq_registeruser(void);
25 void rq_handler(nick *target, int type, void **args);
26
27 int rqcmd_showcommands(void *user, int cargc, char **cargv);
28 int rqcmd_request(void *user, int cargc, char **cargv);
29 int rqcmd_requestspamscan(void *user, int cargc, char **cargv);
30 int rqcmd_addblock(void *user, int cargc, char **cargv);
31 int rqcmd_delblock(void *user, int cargc, char **cargv);
32 int rqcmd_listblocks(void *user, int cargc, char **cargv);
33 int rqcmd_stats(void *user, int cargc, char **cargv);
34 int rqcmd_requestop(void *user, int cargc, char **cargv);
35
36 int rqcmd_adduser(void *user, int cargc, char **cargv);
37 int rqcmd_deluser(void *user, int cargc, char **cargv);
38 int rqcmd_changelev(void *user, int cargc, char **cargv);
39 int rqcmd_userlist(void *user, int cargc, char **cargv);
40
41 #define min(a,b) ((a > b) ? b : a)
42
43 /* stats counters */
44 int rq_count = 0;
45 int rq_failed = 0;
46 int rq_success = 0;
47 int rq_blocked = 0;
48
49 /* log fd */
50 FILE *rq_logfd;
51
52 static int extloaded = 0;
53
54 void _init(void) {
55 if(!rq_initblocks())
56 return;
57
58 extloaded = 1;
59
60 rqcommands = newcommandtree();
61
62 addcommandtotree(rqcommands, "showcommands", RQU_ANY, 1, &rqcmd_showcommands);
63 addcommandtotree(rqcommands, "requestbot", RQU_ANY, 1, &rqcmd_request);
64 addcommandtotree(rqcommands, "requestspamscan", RQU_ANY, 1, &rqcmd_requestspamscan);
65 addcommandtotree(rqcommands, "requestop", RQU_ANY, 2, &rqcmd_requestop);
66
67 addcommandtotree(rqcommands, "addblock", RQU_ACCOUNT, 3, &rqcmd_addblock);
68 addcommandtotree(rqcommands, "delblock", RQU_ACCOUNT, 1, &rqcmd_delblock);
69 addcommandtotree(rqcommands, "listblocks", RQU_ACCOUNT, 1, &rqcmd_listblocks);
70 addcommandtotree(rqcommands, "stats", RQU_ACCOUNT, 1, &rqcmd_stats);
71
72 addcommandtotree(rqcommands, "adduser", RQU_OPER, 2, &rqcmd_adduser);
73 addcommandtotree(rqcommands, "deluser", RQU_OPER, 1, &rqcmd_deluser);
74 addcommandtotree(rqcommands, "changelev", RQU_OPER, 2, &rqcmd_changelev);
75 addcommandtotree(rqcommands, "userlist", RQU_OPER, 1, &rqcmd_userlist);
76
77 qr_initrequest();
78 ru_load();
79
80 rq_logfd = fopen(RQ_LOGFILE, "a");
81
82 scheduleoneshot(time(NULL) + 1, (ScheduleCallback)&rq_registeruser, NULL);
83 }
84
85 void _fini(void) {
86 if(!extloaded)
87 return;
88
89 deregisterlocaluser(rqnick, NULL);
90
91 deletecommandfromtree(rqcommands, "showcommands", &rqcmd_showcommands);
92 deletecommandfromtree(rqcommands, "requestbot", &rqcmd_request);
93 deletecommandfromtree(rqcommands, "requestspamscan", &rqcmd_requestspamscan);
94 deletecommandfromtree(rqcommands, "requestop", &rqcmd_requestop);
95
96 deletecommandfromtree(rqcommands, "addblock", &rqcmd_addblock);
97 deletecommandfromtree(rqcommands, "delblock", &rqcmd_delblock);
98 deletecommandfromtree(rqcommands, "listblocks", &rqcmd_listblocks);
99 deletecommandfromtree(rqcommands, "stats", &rqcmd_stats);
100
101 deletecommandfromtree(rqcommands, "adduser", &rqcmd_adduser);
102 deletecommandfromtree(rqcommands, "deluser", &rqcmd_deluser);
103 deletecommandfromtree(rqcommands, "changelev", &rqcmd_changelev);
104 deletecommandfromtree(rqcommands, "userlist", &rqcmd_userlist);
105
106 destroycommandtree(rqcommands);
107
108 rq_finiblocks();
109 qr_finirequest();
110 ru_persist();
111
112 if (rq_logfd != NULL)
113 fclose(rq_logfd);
114
115 deleteallschedules((ScheduleCallback)&rq_registeruser);
116 }
117
118 void rq_registeruser(void) {
119 channel *cp;
120
121 rqnick = registerlocaluserflags(RQ_REQUEST_NICK, RQ_REQUEST_USER, RQ_REQUEST_HOST,
122 RQ_REQUEST_REAL, RQ_REQUEST_AUTH, 1780711, 0,
123 UMODE_ACCOUNT | UMODE_SERVICE | UMODE_OPER,
124 rq_handler);
125
126 cp = findchannel(RQ_TLZ);
127
128 if (cp == NULL)
129 localcreatechannel(rqnick, RQ_TLZ);
130 else
131 localjoinchannel(rqnick, cp);
132 }
133
134 char *rq_longtoduration(unsigned long interval) {
135 static char buf[100];
136
137 strncpy(buf, longtoduration(interval, 0), sizeof(buf));
138
139 /* chop off last character if it's a space */
140 if (buf[strlen(buf)] == ' ')
141 buf[strlen(buf)] = '\0';
142
143 return buf;
144 }
145
146 void rq_handler(nick *target, int type, void **params) {
147 Command* cmd;
148 nick* user;
149 char* line;
150 int cargc;
151 char* cargv[30];
152
153 switch (type) {
154 case LU_PRIVMSG:
155 case LU_SECUREMSG:
156 user = params[0];
157 line = params[1];
158 cargc = splitline(line, cargv, 30, 0);
159
160 if (cargc == 0)
161 return;
162
163 cmd = findcommandintree(rqcommands, cargv[0], 1);
164
165 if (cmd == NULL) {
166 sendnoticetouser(rqnick, user, "Unknown command.");
167
168 return;
169 }
170
171 if ((cmd->level & RQU_OPER) && !IsOper(user)) {
172 sendnoticetouser(rqnick, user, "Sorry, this command is not "
173 "available to you.");
174
175 return;
176 }
177
178 if ((cmd->level & RQU_ACCOUNT) && (!IsAccount(user) || ru_getlevel(user) == 0) && !IsOper(user)) {
179 sendnoticetouser(rqnick, user, "Sorry, this command is not "
180 "available to you.");
181
182 return;
183 }
184
185 if (cargc - 1 > cmd->maxparams)
186 rejoinline(cargv[cmd->maxparams], cargc - cmd->maxparams);
187
188 /* handle the command */
189 cmd->handler((void*)user, min(cargc - 1, cmd->maxparams), &(cargv[1]));
190
191 break;
192 case LU_KILLED:
193 scheduleoneshot(time(NULL) + 5, (ScheduleCallback)&rq_registeruser, NULL);
194
195 break;
196 case LU_PRIVNOTICE:
197 qr_handle_notice(params[0], params[1]);
198
199 break;
200 }
201 }
202
203 int rqcmd_showcommands(void *user, int cargc, char **cargv) {
204 nick* np = (nick*)user;
205 int n, i;
206 Command* cmdlist[50];
207
208 n = getcommandlist(rqcommands, cmdlist, 50);
209
210 sendnoticetouser(rqnick, np, "Available commands:");
211 sendnoticetouser(rqnick, np, "-------------------");
212
213 for (i = 0; i < n; i++) {
214 if ((cmdlist[i]->level & RQU_OPER) && !IsOper(np))
215 continue;
216
217 if ((cmdlist[i]->level & RQU_ACCOUNT) && !(IsOper(np) || (IsAccount(np) && ru_getlevel(np) > 0)))
218 continue;
219
220 sendnoticetouser(rqnick, np, "%s", cmdlist[i]->command->content);
221 }
222
223 sendnoticetouser(rqnick, np, "End of SHOWCOMMANDS");
224
225 return 0;
226 }
227
228 int rq_genericrequestcheck(nick *np, char *channelname, channel **cp, nick **qnick) {
229 unsigned long *userhand;
230 rq_block *block;
231
232 if (!IsAccount(np)) {
233 sendnoticetouser(rqnick, np, "Error: You must be authed to perform a service request.");
234
235 return RQ_ERROR;
236 }
237
238 *cp = findchannel(channelname);
239
240 if (*cp == NULL) {
241 sendnoticetouser(rqnick, np, "Error: Channel '%s' does not exist on the network.",
242 channelname);
243
244 return RQ_ERROR;
245 }
246
247 *qnick = getnickbynick(RQ_QNICK);
248
249 if (*qnick == NULL || findserver(RQ_QSERVER) < 0) {
250 sendnoticetouser(rqnick, np, "Error: %s does not seem to be online. "
251 "Please try again later.", RQ_QNICK);
252
253 return RQ_ERROR;
254 }
255
256 userhand = getnumerichandlefromchanhash((*cp)->users, np->numeric);
257
258 if (userhand == NULL) {
259 sendnoticetouser(rqnick, np, "Error: You're not on that channel.");
260
261 return RQ_ERROR;
262 }
263
264 if ((*userhand & CUMODE_OP) == 0) {
265 sendnoticetouser(rqnick, np, "Error: You must be op'd on the channel to "
266 "request a service.");
267
268 return RQ_ERROR;
269 }
270
271 block = rq_findblock(channelname);
272
273 if (block != NULL) {
274 /* only say when block expires if <7 days */
275 if ( block->expires < getnettime() + 3600 * 24 * 7) {
276 sendnoticetouser(rqnick, np, "Error: You are not allowed to request a "
277 "service to '%s'. Keep waiting for at least %s before you try again.",
278 channelname, rq_longtoduration(block->expires - getnettime()));
279 /* give them another 5 minutes to think about it */
280 block->expires += 300;
281 rq_saveblocks();
282 } else {
283 sendnoticetouser(rqnick, np, "Error: You are not allowed to request a "
284 "service to '%s'.", channelname);
285 }
286 sendnoticetouser(rqnick, np, "Reason: %s", block->reason->content);
287
288 rq_blocked++;
289
290 return RQ_ERROR;
291 }
292
293 block = rq_findblock(np->authname);
294
295 /* only tell the user if the block is going to expire in the next 48 hours
296 so we can have our fun with longterm blocks.
297 the request subsystems should deal with longterm blocks on their own */
298 if (block != NULL && block->expires < getnettime() + 3600 * 24 * 2) {
299 sendnoticetouser(rqnick, np, "Error: You are not allowed to request a "
300 "service. Keep waiting for at least %s before you try again.",
301 rq_longtoduration(block->expires - getnettime()));
302
303 sendnoticetouser(rqnick, np, "Reason: %s", block->reason->content);
304
305 /* give them another 5 minutes to think about it */
306 block->expires += 300;
307 rq_saveblocks();
308
309 rq_blocked++;
310
311 return RQ_ERROR;
312 }
313
314 return RQ_OK;
315 }
316
317 int rqcmd_request(void *user, int cargc, char **cargv) {
318 nick *np = (nick*)user;
319 nick *qnick;
320 unsigned long *qhand;
321 channel *cp;
322 int retval;
323 time_t now_ts;
324 char now[50];
325
326 if (cargc < 1) {
327 sendnoticetouser(rqnick, np, "Syntax: requestbot <#channel>");
328
329 return RQ_ERROR;
330 }
331
332 rq_count++;
333
334 if (rq_genericrequestcheck(np, cargv[0], &cp, &qnick) == RQ_ERROR) {
335 rq_failed++;
336
337 return RQ_ERROR;
338 }
339
340 qhand = getnumerichandlefromchanhash(cp->users, qnick->numeric);
341
342 if (qhand != NULL) {
343 sendnoticetouser(rqnick, np, "Error: %s is already on that channel.", RQ_QNICK);
344
345 rq_failed++;
346
347 return RQ_ERROR;
348 }
349
350 retval = RQ_ERROR;
351
352 retval = lr_requestl(rqnick, np, cp, qnick);
353
354 if (rq_logfd != NULL) {
355 now[0] = '\0';
356 now_ts = time(NULL);
357 strftime(now, sizeof(now), "%c", localtime(&now_ts));
358
359 fprintf(rq_logfd, "%s: request (%s) for %s from %s!%s@%s%s%s: Request was %s.\n",
360 now, RQ_QNICK, cp->index->name->content,
361 np->nick, np->ident, np->host->name->content, IsAccount(np)?"/":"", IsAccount(np)?np->authname:"",
362 (retval == RQ_OK) ? "accepted" : "denied");
363 fflush(rq_logfd);
364 }
365
366 if (retval == RQ_ERROR)
367 rq_failed++;
368 else if (retval == RQ_OK)
369 rq_success++;
370
371 return retval;
372 }
373
374 int rqcmd_requestspamscan(void *user, int cargc, char **cargv) {
375 nick *np = (nick*)user;
376 channel *cp;
377 nick *qnick, *snick;
378 unsigned long *qhand, *shand;
379 int retval;
380
381 if (cargc < 1) {
382 sendnoticetouser(rqnick, np, "Syntax: requestspamscan <#channel>");
383
384 return RQ_ERROR;
385 }
386
387 rq_count++;
388
389 if (rq_genericrequestcheck(np, cargv[0], &cp, &qnick) == RQ_ERROR) {
390 rq_failed++;
391
392 return RQ_ERROR;
393 }
394
395 snick = getnickbynick(RQ_SNICK);
396
397 if (snick == NULL || findserver(RQ_SSERVER) < 0) {
398 sendnoticetouser(rqnick, np, "Error: %s does not seem to be online. "
399 "Please try again later.", RQ_SNICK);
400
401 rq_failed++;
402
403 return RQ_ERROR;
404 }
405
406 /* does the user already have S on that channel? */
407 shand = getnumerichandlefromchanhash(cp->users, snick->numeric);
408
409 if (shand != NULL) {
410 sendnoticetouser(rqnick, np, "Error: %s is already on that channel.", RQ_SNICK);
411
412 rq_failed++;
413
414 return RQ_ERROR;
415 }
416
417 /* we need Q */
418 qhand = getnumerichandlefromchanhash(cp->users, qnick->numeric);
419
420 if (qhand) {
421 /* great, now try to request */
422 retval = qr_requests(rqnick, np, cp, qnick);
423
424 if (retval == RQ_OK)
425 rq_success++;
426 else if (retval == RQ_ERROR)
427 rq_failed++;
428
429 return retval;
430 } else {
431 /* channel apparently doesn't have Q */
432
433 sendnoticetouser(rqnick, np, "Error: You need %s in order to be "
434 "able to request %s.", RQ_QNICK, RQ_SNICK);
435
436 rq_failed++;
437
438 return RQ_ERROR;
439 }
440 }
441
442 int rqcmd_requestop(void *source, int cargc, char **cargv) {
443 nick *np2, *np = (nick *)source;
444 nick *user = np;
445 channel *cp;
446 int ret, a, count;
447 unsigned long *hand;
448 modechanges changes;
449
450 if (cargc < 1) {
451 sendnoticetouser(rqnick, np, "Syntax: requestop <#channel> [nick]");
452
453 return CMD_ERROR;
454 }
455
456 cp = findchannel(cargv[0]);
457
458 if (cp == NULL) {
459 sendnoticetouser(rqnick, np, "Error: Channel '%s' does not exist on the network.",
460 cargv[0]);
461
462 return CMD_ERROR;
463 }
464
465 if (cargc > 1) {
466 user = getnickbynick(cargv[1]);
467
468 if (!user) {
469 sendnoticetouser(rqnick, np, "Error: No such user.");
470
471 return CMD_ERROR;
472 }
473 }
474
475 if (getnettime() - np->timestamp < 300) {
476 sendnoticetouser(rqnick, np, "Error: You connected %s ago. To"
477 " request ops you must have been on the network for"
478 " at least 5 minutes.",
479 rq_longtoduration(getnettime() - np->timestamp));
480
481 return CMD_ERROR;
482 }
483
484 if (getnettime() - user->timestamp < 300) {
485 sendnoticetouser(rqnick, np, "Error: The nick you requested op for"
486 " connected %s ago. To request op, it must have"
487 "been on the network for at least 5 minutes.",
488 rq_longtoduration(getnettime() - user->timestamp));
489
490 return CMD_ERROR;
491 }
492
493 hand = getnumerichandlefromchanhash(cp->users, user->numeric);
494
495 if (!hand) {
496 sendnoticetouser(rqnick, np, "Error: User %s is not on channel '%s'.", user->nick, cargv[0]);
497
498 return CMD_ERROR;
499 }
500
501
502 count = 0;
503
504 localsetmodeinit(&changes, cp, rqnick);
505
506 /* reop any services first */
507 for(a=0;a<cp->users->hashsize;a++) {
508 if(cp->users->content[a] != nouser) {
509 np2 = getnickbynumeric(cp->users->content[a]);
510
511 if (IsService(np2) && (np2->nick[1] == '\0') && !(cp->users->content[a] & CUMODE_OP)) {
512 localdosetmode_nick(&changes, np2, MC_OP);
513 count++;
514 }
515 }
516 }
517
518 localsetmodeflush(&changes, 1);
519
520 if (count > 0) {
521 if (count == 1)
522 sendnoticetouser(rqnick, np, "1 service was reopped.");
523 else
524 sendnoticetouser(rqnick, np, "%d services were reopped.", count);
525
526 return CMD_ERROR;
527 }
528
529 for (a=0;a<cp->users->hashsize;a++) {
530 if ((cp->users->content[a] != nouser) && (cp->users->content[a] & CUMODE_OP)) {
531 sendnoticetouser(rqnick, np, "There are ops on channel '%s'. This command can only be"
532 " used if there are no ops.", cargv[0]);
533
534 return CMD_ERROR;
535 }
536 }
537
538 if (sp_countsplitservers() > 0) {
539 sendnoticetouser(rqnick, np, "One or more servers are currently split. Wait until the"
540 " netsplit is over and try again.");
541
542 return CMD_ERROR;
543 }
544
545 if (cf_wouldreop(user, cp)) {
546 localsetmodeinit(&changes, cp, rqnick);
547 localdosetmode_nick(&changes, user, MC_OP);
548 localsetmodeflush(&changes, 1);
549
550 sendnoticetouser(rqnick, np, "Chanfix opped you on the specified channel.");
551 } else {
552 ret = cf_fixchannel(cp);
553
554 if (ret == CFX_NOUSERSAVAILABLE)
555 sendnoticetouser(rqnick, np, "Chanfix knows regular ops for that channel. They will"
556 " be opped when they return.");
557 else
558 sendnoticetouser(rqnick, np, "Chanfix has opped known ops for that channel.");
559 }
560
561 return CMD_OK;
562
563 }
564
565 int rqcmd_addblock(void *user, int cargc, char **cargv) {
566 nick *np = (nick*)user;
567 rq_block *block;
568 time_t expires;
569 char *account;
570 int level = ru_getlevel(np);
571
572 if (level < 20) {
573 sendnoticetouser(rqnick, np, "You do not have access to this command.");
574
575 return RQ_ERROR;
576 }
577
578 if (cargc < 3) {
579 sendnoticetouser(rqnick, np, "Syntax: addblock <mask> <duration> <reason>");
580
581 return RQ_ERROR;
582 }
583
584 block = rq_findblock(cargv[0]);
585
586 if (block != NULL) {
587 sendnoticetouser(rqnick, np, "That mask is already blocked by %s "
588 "(reason: %s).", block->creator->content, block->reason->content);
589
590 return RQ_ERROR;
591 }
592
593 if (IsAccount(np))
594 account = np->authname;
595 else
596 account = "unknown";
597
598 expires = getnettime() + durationtolong(cargv[1]);
599
600 if (expires > getnettime() + RQU_HELPER_MAXEXPIRE && level < 30) {
601 sendnoticetouser(rqnick, np, "Maximum expiry time is %s.", rq_longtoduration(RQU_HELPER_MAXEXPIRE));
602
603 return RQ_ERROR;
604 }
605
606 rq_addblock(cargv[0], cargv[2], account, 0, expires);
607
608 sendnoticetouser(rqnick, np, "Blocked channels/accounts matching '%s' from "
609 "requesting a service.", cargv[0]);
610
611 return RQ_OK;
612 }
613
614 int rqcmd_delblock(void *user, int cargc, char **cargv) {
615 nick *np = (nick*)user;
616 int result, level;
617 rq_block *block;
618
619 level = ru_getlevel(np);
620
621 if (level < 20) {
622 sendnoticetouser(rqnick, np, "You do not have access to this command.");
623
624 return RQ_ERROR;
625 }
626
627 if (cargc < 1) {
628 sendnoticetouser(rqnick, np, "Syntax: delblock <mask>");
629
630 return RQ_ERROR;
631 }
632
633 block = rq_findblock(cargv[0]);
634
635 if (block != NULL && level < 50) {
636 if (ircd_strcmp(block->creator->content, np->authname) != 0) {
637 sendnoticetouser(rqnick, np, "This block was created by someone else. You cannot remove it.");
638
639 return RQ_ERROR;
640 }
641 }
642
643 result = rq_removeblock(cargv[0]);
644
645 if (result > 0) {
646 sendnoticetouser(rqnick, np, "Block for '%s' was removed.", cargv[0]);
647
648 return RQ_OK;
649 } else {
650 sendnoticetouser(rqnick, np, "There is no such block.");
651
652 return RQ_OK;
653 }
654 }
655
656 int rqcmd_listblocks(void *user, int cargc, char **cargv) {
657 nick *np = (nick*)user;
658 rq_block block;
659 int i, level;
660
661 level = ru_getlevel(np);
662
663 if (level < 10) {
664 sendnoticetouser(rqnick, np, "You do not have access to this command.");
665
666 return RQ_ERROR;
667 }
668
669 sendnoticetouser(rqnick, np, "Mask By Expires"
670 " Reason");
671
672 for (i = 0; i < rqblocks.cursi; i++) {
673 block = ((rq_block*)rqblocks.content)[i];
674
675 if (block.expires != 0 && block.expires < getnettime())
676 continue; /* ignore blocks which have already expired,
677 rq_findblock will deal with them later on */
678
679 if (cargc < 1 || match2strings(block.pattern->content, cargv[0]))
680 sendnoticetouser(rqnick, np, "%-11s %-9s %-25s %s",
681 block.pattern->content, block.creator->content,
682 rq_longtoduration(block.expires - getnettime()),
683 block.reason->content);
684 }
685
686 sendnoticetouser(rqnick, np, "--- End of blocklist");
687
688 return RQ_OK;
689 }
690
691 int rqcmd_stats(void *user, int cargc, char **cargv) {
692 nick *np = (nick*)user;
693 int level = ru_getlevel(np);
694
695 if (level < 10) {
696 sendnoticetouser(rqnick, np, "You do not have access to this command.");
697
698 return RQ_ERROR;
699 }
700
701 sendnoticetouser(rqnick, np, "Total requests: %d", rq_count);
702 sendnoticetouser(rqnick, np, "Successful requests: %d", rq_success);
703 sendnoticetouser(rqnick, np, "Failed requests: %d", rq_failed);
704 sendnoticetouser(rqnick, np, "- Blocked: %d", rq_blocked);
705
706 lr_requeststats(rqnick, np);
707 qr_requeststats(rqnick, np);
708
709 return RQ_OK;
710 }
711
712 int rqcmd_adduser(void *user, int cargc, char **cargv) {
713 nick *np = (nick*)user;
714 int result, level;
715
716 if (cargc < 2) {
717 sendnoticetouser(rqnick, np, "Syntax: adduser <account> <level>");
718
719 return RQ_ERROR;
720 }
721
722 level = atoi(cargv[1]);
723
724 if (level <= 0) {
725 sendnoticetouser(rqnick, np, "Level must be a positive integer.");
726
727 return RQ_ERROR;
728 }
729
730 result = ru_create(cargv[0], level);
731
732 if (result) {
733 sendnoticetouser(rqnick, np, "User '%s' was added with level '%d'.", cargv[0], level);
734
735 return RQ_OK;
736 } else {
737 sendnoticetouser(rqnick, np, "Something strange happened. Contact shroud.");
738
739 return RQ_ERROR;
740 }
741 }
742
743 int rqcmd_deluser(void *user, int cargc, char **cargv) {
744 nick *np = (nick*)user;
745 int level;
746
747 if (cargc < 1) {
748 sendnoticetouser(rqnick, np, "Syntax: deluser <account>");
749
750 return RQ_ERROR;
751 }
752
753 level = ru_getlevel_str(cargv[0]);
754
755 if (level <= 0) {
756 sendnoticetouser(rqnick, np, "There is no such user.");
757
758 return RQ_ERROR;
759 }
760
761 ru_destroy(cargv[0]);
762
763 sendnoticetouser(rqnick, np, "Done.");
764
765 return RQ_OK;
766 }
767
768 int rqcmd_changelev(void *user, int cargc, char **cargv) {
769 nick *np = (nick*)user;
770 int result, level;
771
772 if (cargc < 2) {
773 sendnoticetouser(rqnick, np, "Syntax: changelev <account> <level>");
774
775 return RQ_ERROR;
776 }
777
778 level = atoi(cargv[1]);
779
780 if (level <= 0) {
781 sendnoticetouser(rqnick, np, "Level must be a positive integer.");
782
783 return RQ_ERROR;
784 }
785
786 if (ru_getlevel_str(cargv[0]) <= 0) {
787 sendnoticetouser(rqnick, np, "Unknown user.");
788
789 return RQ_ERROR;
790 }
791
792 result = ru_setlevel(cargv[0], level);
793
794 if (result != 0) {
795 sendnoticetouser(rqnick, np, "Done.");
796
797 return RQ_OK;
798 } else {
799 sendnoticetouser(rqnick, np, "Something strange happened. Contact shroud.");
800
801 return RQ_ERROR;
802 }
803 }
804
805 int rqcmd_userlist(void *user, int cargc, char **cargv) {
806 nick *np = (nick*)user;
807 r_user_t *userp = r_userlist;
808
809 sendnoticetouser(rqnick, np, "User Level");
810
811 while (userp) {
812 sendnoticetouser(rqnick, np, "%s %d", userp->name, userp->level);
813 userp = userp->next;
814 }
815
816 sendnoticetouser(rqnick, np, "--- End of USERS.");
817
818 return RQ_OK;
819 }
820