00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "module.h"
00016
00017
00018 static int do_akick(User * u);
00019 static void myChanServHelp(User * u);
00020 static int get_access_nc(NickCore *nc, ChannelInfo *ci);
00021
00028 int AnopeInit(int argc, char **argv)
00029 {
00030 Command *c;
00031
00032 moduleAddAuthor("Anope");
00033 moduleAddVersion(VERSION_STRING);
00034 moduleSetType(CORE);
00035
00036 c = createCommand("AKICK", do_akick, NULL, CHAN_HELP_AKICK, -1, -1, -1,
00037 -1);
00038 moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
00039
00040 moduleSetChanHelp(myChanServHelp);
00041
00042 return MOD_CONT;
00043 }
00044
00048 void AnopeFini(void)
00049 {
00050
00051 }
00052
00053
00054
00059 static void myChanServHelp(User * u)
00060 {
00061 notice_lang(s_ChanServ, u, CHAN_HELP_CMD_AKICK);
00062 }
00063
00069
00070 static int akick_del(User * u, AutoKick * akick)
00071 {
00072 if (!(akick->flags & AK_USED))
00073 return 0;
00074 if (akick->flags & AK_ISNICK) {
00075 akick->u.nc = NULL;
00076 } else {
00077 free(akick->u.mask);
00078 akick->u.mask = NULL;
00079 }
00080 if (akick->reason) {
00081 free(akick->reason);
00082 akick->reason = NULL;
00083 }
00084 if (akick->creator) {
00085 free(akick->creator);
00086 akick->creator = NULL;
00087 }
00088 akick->addtime = 0;
00089 akick->flags = 0;
00090 return 1;
00091 }
00092
00093 static int akick_del_callback(User * u, int num, va_list args)
00094 {
00095 ChannelInfo *ci = va_arg(args, ChannelInfo *);
00096 int *last = va_arg(args, int *);
00097
00098 *last = num;
00099
00100 if (num < 1 || num > ci->akickcount)
00101 return 0;
00102
00103 return akick_del(u, &ci->akick[num - 1]);
00104 }
00105
00106
00107 static int akick_list(User * u, int index, ChannelInfo * ci, int *sent_header)
00108 {
00109 AutoKick *akick = &ci->akick[index];
00110
00111 if (!(akick->flags & AK_USED))
00112 return 0;
00113 if (!*sent_header) {
00114 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_HEADER, ci->name);
00115 *sent_header = 1;
00116 }
00117
00118 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_FORMAT, index + 1,
00119 ((akick->flags & AK_ISNICK) ? akick->u.nc->
00120 display : akick->u.mask),
00121 (akick->reason ? akick->
00122 reason : getstring(u->na, NO_REASON)));
00123 return 1;
00124 }
00125
00126 static int akick_list_callback(User * u, int num, va_list args)
00127 {
00128 ChannelInfo *ci = va_arg(args, ChannelInfo *);
00129 int *sent_header = va_arg(args, int *);
00130 if (num < 1 || num > ci->akickcount)
00131 return 0;
00132 return akick_list(u, num - 1, ci, sent_header);
00133 }
00134
00135 static int akick_view(User * u, int index, ChannelInfo * ci, int *sent_header)
00136 {
00137 AutoKick *akick = &ci->akick[index];
00138 char timebuf[64];
00139 struct tm tm;
00140
00141 if (!(akick->flags & AK_USED))
00142 return 0;
00143 if (!*sent_header) {
00144 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_HEADER, ci->name);
00145 *sent_header = 1;
00146 }
00147
00148 if (akick->addtime) {
00149 tm = *localtime(&akick->addtime);
00150 strftime_lang(timebuf, sizeof(timebuf), u,
00151 STRFTIME_SHORT_DATE_FORMAT, &tm);
00152 } else {
00153 snprintf(timebuf, sizeof(timebuf), getstring(u->na, UNKNOWN));
00154 }
00155
00156 notice_lang(s_ChanServ, u,
00157 ((akick->
00158 flags & AK_STUCK) ? CHAN_AKICK_VIEW_FORMAT_STUCK :
00159 CHAN_AKICK_VIEW_FORMAT), index + 1,
00160 ((akick->flags & AK_ISNICK) ? akick->u.nc->
00161 display : akick->u.mask),
00162 akick->creator ? akick->creator : getstring(u->na,
00163 UNKNOWN),
00164 timebuf,
00165 (akick->reason ? akick->
00166 reason : getstring(u->na, NO_REASON)));
00167 return 1;
00168 }
00169
00170 static int akick_view_callback(User * u, int num, va_list args)
00171 {
00172 ChannelInfo *ci = va_arg(args, ChannelInfo *);
00173 int *sent_header = va_arg(args, int *);
00174 if (num < 1 || num > ci->akickcount)
00175 return 0;
00176 return akick_view(u, num - 1, ci, sent_header);
00177 }
00178
00179
00180
00181 static int do_akick(User * u)
00182 {
00183 char *chan = strtok(NULL, " ");
00184 char *cmd = strtok(NULL, " ");
00185 char *mask = strtok(NULL, " ");
00186 char *reason = strtok(NULL, "");
00187 ChannelInfo *ci;
00188 AutoKick *akick;
00189 int i;
00190 Channel *c;
00191 struct c_userlist *cu = NULL;
00192 struct c_userlist *next;
00193 User *u2;
00194 char *argv[3];
00195 int count = 0;
00196
00197 if (!cmd || (!mask && (!stricmp(cmd, "ADD") || !stricmp(cmd, "STICK")
00198 || !stricmp(cmd, "UNSTICK")
00199 || !stricmp(cmd, "DEL")))) {
00200
00201 syntax_error(s_ChanServ, u, "AKICK", CHAN_AKICK_SYNTAX);
00202 } else if (!(ci = cs_findchan(chan))) {
00203 notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
00204 } else if (ci->flags & CI_VERBOTEN) {
00205 notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
00206 } else if (!check_access(u, ci, CA_AKICK) && !is_services_admin(u)) {
00207 notice_lang(s_ChanServ, u, ACCESS_DENIED);
00208 } else if (stricmp(cmd, "ADD") == 0) {
00209 NickAlias *na = findnick(mask), *na2;
00210 NickCore *nc = NULL;
00211 char *nick, *user, *host;
00212 int freemask = 0;
00213
00214 if (readonly) {
00215 notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
00216 return MOD_CONT;
00217 }
00218
00219 if (!na) {
00220 split_usermask(mask, &nick, &user, &host);
00221 mask =
00222 scalloc(strlen(nick) + strlen(user) + strlen(host) + 3, 1);
00223 freemask = 1;
00224 sprintf(mask, "%s!%s@%s", nick, user, host);
00225 free(nick);
00226 free(user);
00227 free(host);
00228 } else {
00229 if (na->status & NS_VERBOTEN) {
00230 notice_lang(s_ChanServ, u, NICK_X_FORBIDDEN, mask);
00231 return MOD_CONT;
00232 }
00233 nc = na->nc;
00234 }
00235
00236
00237 if (ircd->except) {
00238 if (is_excepted_mask(ci, mask) == 1) {
00239 notice_lang(s_ChanServ, u, CHAN_EXCEPTED, mask, chan);
00240 if (freemask)
00241 free(mask);
00242 return MOD_CONT;
00243 }
00244 }
00245
00246
00247
00248 if ((ci->flags & CI_PEACE) && nc) {
00249 if ((nc == ci->founder) || (get_access_nc(nc, ci) >= get_access(u, ci))) {
00250 notice_lang(s_ChanServ, u, PERMISSION_DENIED);
00251 if (freemask)
00252 free(mask);
00253 return MOD_CONT;
00254 }
00255 } else if ((ci->flags & CI_PEACE)) {
00256 char buf[BUFSIZE];
00257
00258
00259 for (i = 0; i < 1024; i++) {
00260 for (u2 = userlist[i]; u2; u2 = u2->next) {
00261 if (is_founder(u2, ci) || (get_access(u2, ci) >= get_access(u, ci))) {
00262 if (match_usermask(mask, u2)) {
00263 notice_lang(s_ChanServ, u, PERMISSION_DENIED);
00264 free(mask);
00265 return MOD_CONT;
00266 }
00267 }
00268 }
00269 }
00270
00271
00272
00273 for (i = 0; i < 1024; i++) {
00274 for (na2 = nalists[i]; na2; na2 = na2->next) {
00275 if (na2->status & NS_VERBOTEN)
00276 continue;
00277
00278 if (na2->nc && ((na2->nc == ci->founder) || (get_access_nc(na2->nc, ci)
00279 >= get_access(u, ci)))) {
00280 snprintf(buf, BUFSIZE, "%s!%s", na2->nick, na2->last_usermask);
00281 if (match_wild_nocase(mask, buf)) {
00282 notice_lang(s_ChanServ, u, PERMISSION_DENIED);
00283 free(mask);
00284 return MOD_CONT;
00285 }
00286 }
00287 }
00288 }
00289 }
00290
00291 for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
00292 if (!(akick->flags & AK_USED))
00293 continue;
00294 if ((akick->flags & AK_ISNICK) ? akick->u.nc == nc
00295 : stricmp(akick->u.mask, mask) == 0) {
00296 notice_lang(s_ChanServ, u, CHAN_AKICK_ALREADY_EXISTS,
00297 (akick->flags & AK_ISNICK) ? akick->u.nc->
00298 display : akick->u.mask, chan);
00299 if (freemask)
00300 free(mask);
00301 return MOD_CONT;
00302 }
00303 }
00304
00305
00306
00307 if (ci->akickcount >= CSAutokickMax) {
00308 notice_lang(s_ChanServ, u, CHAN_AKICK_REACHED_LIMIT, CSAutokickMax);
00309 if (freemask)
00310 free(mask);
00311 return MOD_CONT;
00312 }
00313 ci->akickcount++;
00314 ci->akick =
00315 srealloc(ci->akick, sizeof(AutoKick) * ci->akickcount);
00316 akick = &ci->akick[i];
00317 akick->flags = AK_USED;
00318 if (nc) {
00319 akick->flags |= AK_ISNICK;
00320 akick->u.nc = nc;
00321 } else {
00322 akick->u.mask = sstrdup(mask);
00323 }
00324 akick->creator = sstrdup(u->nick);
00325 akick->addtime = time(NULL);
00326 if (reason) {
00327 if (strlen(reason) > 200)
00328 reason[200] = '\0';
00329 akick->reason = sstrdup(reason);
00330 } else {
00331 akick->reason = NULL;
00332 }
00333
00334
00335 c = findchan(ci->name);
00336 if (c) {
00337 cu = c->users;
00338 while (cu) {
00339 next = cu->next;
00340 if (check_kick(cu->user, c->name, c->creation_time)) {
00341 argv[0] = sstrdup(c->name);
00342 argv[1] = sstrdup(cu->user->nick);
00343 if (akick->reason)
00344 argv[2] = sstrdup(akick->reason);
00345 else
00346 argv[2] = sstrdup("none");
00347
00348 do_kick(s_ChanServ, 3, argv);
00349
00350 free(argv[2]);
00351 free(argv[1]);
00352 free(argv[0]);
00353 count++;
00354
00355 }
00356 cu = next;
00357 }
00358 }
00359 alog("%s: %s!%s@%s added akick for %s to %s",
00360 s_ChanServ, u->nick, u->username, u->host, mask, chan);
00361 notice_lang(s_ChanServ, u, CHAN_AKICK_ADDED, mask, chan);
00362
00363 if (count)
00364 notice_lang(s_ChanServ, u, CHAN_AKICK_ENFORCE_DONE, chan,
00365 count);
00366
00367 if (freemask)
00368 free(mask);
00369
00370 } else if (stricmp(cmd, "STICK") == 0) {
00371
00372 if (readonly) {
00373 notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
00374 return MOD_CONT;
00375 }
00376
00377 if (ci->akickcount == 0) {
00378 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, ci->name);
00379 return MOD_CONT;
00380 }
00381
00382 for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
00383 if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK))
00384 continue;
00385 if (!stricmp(akick->u.mask, mask))
00386 break;
00387 }
00388
00389 if (i == ci->akickcount) {
00390 notice_lang(s_ChanServ, u, CHAN_AKICK_NOT_FOUND, mask,
00391 ci->name);
00392 return MOD_CONT;
00393 }
00394
00395 akick->flags |= AK_STUCK;
00396 alog("%s: %s!%s@%s set STICK on akick %s on %s",
00397 s_ChanServ, u->nick, u->username, u->host, akick->u.mask, ci->name);
00398 notice_lang(s_ChanServ, u, CHAN_AKICK_STUCK, akick->u.mask,
00399 ci->name);
00400
00401 if (ci->c)
00402 stick_mask(ci, akick);
00403 } else if (stricmp(cmd, "UNSTICK") == 0) {
00404 if (readonly) {
00405 notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
00406 return MOD_CONT;
00407 }
00408
00409 if (ci->akickcount == 0) {
00410 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, ci->name);
00411 return MOD_CONT;
00412 }
00413
00414 for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
00415 if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK))
00416 continue;
00417 if (!stricmp(akick->u.mask, mask))
00418 break;
00419 }
00420
00421 if (i == ci->akickcount) {
00422 notice_lang(s_ChanServ, u, CHAN_AKICK_NOT_FOUND, mask,
00423 ci->name);
00424 return MOD_CONT;
00425 }
00426
00427 akick->flags &= ~AK_STUCK;
00428 alog("%s: %s!%s@%s unset STICK on akick %s on %s",
00429 s_ChanServ, u->nick, u->username, u->host, akick->u.mask, ci->name);
00430 notice_lang(s_ChanServ, u, CHAN_AKICK_UNSTUCK, akick->u.mask,
00431 ci->name);
00432
00433 } else if (stricmp(cmd, "DEL") == 0) {
00434 int deleted, a, b;
00435
00436 if (readonly) {
00437 notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
00438 return MOD_CONT;
00439 }
00440
00441 if (ci->akickcount == 0) {
00442 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, chan);
00443 return MOD_CONT;
00444 }
00445
00446
00447 if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
00448 int count, last = -1;
00449 deleted = process_numlist(mask, &count, akick_del_callback, u,
00450 ci, &last);
00451 if (!deleted) {
00452 if (count == 1) {
00453 notice_lang(s_ChanServ, u, CHAN_AKICK_NO_SUCH_ENTRY,
00454 last, ci->name);
00455 } else {
00456 notice_lang(s_ChanServ, u, CHAN_AKICK_NO_MATCH,
00457 ci->name);
00458 }
00459 } else if (deleted == 1) {
00460 alog("%s: %s!%s@%s deleted 1 akick on %s",
00461 s_ChanServ, u->nick, u->username, u->host, ci->name);
00462 notice_lang(s_ChanServ, u, CHAN_AKICK_DELETED_ONE,
00463 ci->name);
00464 } else {
00465 alog("%s: %s!%s@%s deleted %d akicks on %s",
00466 s_ChanServ, u->nick, u->username, u->host, deleted,
00467 ci->name);
00468 notice_lang(s_ChanServ, u, CHAN_AKICK_DELETED_SEVERAL,
00469 deleted, ci->name);
00470 }
00471 } else {
00472 NickAlias *na = findnick(mask);
00473 NickCore *nc = (na ? na->nc : NULL);
00474
00475 for (akick = ci->akick, i = 0; i < ci->akickcount;
00476 akick++, i++) {
00477 if (!(akick->flags & AK_USED))
00478 continue;
00479 if (((akick->flags & AK_ISNICK) && akick->u.nc == nc)
00480 || (!(akick->flags & AK_ISNICK)
00481 && stricmp(akick->u.mask, mask) == 0))
00482 break;
00483 }
00484 if (i == ci->akickcount) {
00485 notice_lang(s_ChanServ, u, CHAN_AKICK_NOT_FOUND, mask,
00486 chan);
00487 return MOD_CONT;
00488 }
00489 alog("%s: %s!%s@%s deleted akick %s on %s",
00490 s_ChanServ, u->nick, u->username, u->host, mask, chan);
00491 notice_lang(s_ChanServ, u, CHAN_AKICK_DELETED, mask, chan);
00492 akick_del(u, akick);
00493 deleted = 1;
00494 }
00495 if (deleted) {
00496
00497 for (b = 0; b < ci->akickcount; b++) {
00498 if (ci->akick[b].flags & AK_USED) {
00499 for (a = 0; a < ci->akickcount; a++) {
00500 if (a > b)
00501 break;
00502 if (!(ci->akick[a].flags & AK_USED)) {
00503 ci->akick[a].flags = ci->akick[b].flags;
00504 if (ci->akick[b].flags & AK_ISNICK) {
00505 ci->akick[a].u.nc = ci->akick[b].u.nc;
00506 } else {
00507 ci->akick[a].u.mask =
00508 sstrdup(ci->akick[b].u.mask);
00509 }
00510
00511
00512 if (ci->akick[b].reason)
00513 ci->akick[a].reason =
00514 sstrdup(ci->akick[b].reason);
00515 else
00516 ci->akick[a].reason = NULL;
00517 ci->akick[a].creator =
00518 sstrdup(ci->akick[b].creator);
00519 ci->akick[a].addtime = ci->akick[b].addtime;
00520
00521 akick_del(u, &ci->akick[b]);
00522 break;
00523 }
00524 }
00525 }
00526 }
00527
00528
00529 for (i = ci->akickcount - 1; i >= 0; i--) {
00530 if (ci->akick[i].flags & AK_USED)
00531 break;
00532
00533 ci->akickcount--;
00534 }
00535 ci->akick =
00536 srealloc(ci->akick,sizeof(AutoKick) * ci->akickcount);
00537 }
00538 } else if (stricmp(cmd, "LIST") == 0) {
00539 int sent_header = 0;
00540
00541 if (ci->akickcount == 0) {
00542 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, chan);
00543 return MOD_CONT;
00544 }
00545 if (mask && isdigit(*mask) &&
00546 strspn(mask, "1234567890,-") == strlen(mask)) {
00547 process_numlist(mask, NULL, akick_list_callback, u, ci,
00548 &sent_header);
00549 } else {
00550 for (akick = ci->akick, i = 0; i < ci->akickcount;
00551 akick++, i++) {
00552 if (!(akick->flags & AK_USED))
00553 continue;
00554 if (mask) {
00555 if (!(akick->flags & AK_ISNICK)
00556 && !match_wild_nocase(mask, akick->u.mask))
00557 continue;
00558 if ((akick->flags & AK_ISNICK)
00559 && !match_wild_nocase(mask, akick->u.nc->display))
00560 continue;
00561 }
00562 akick_list(u, i, ci, &sent_header);
00563 }
00564 }
00565 if (!sent_header)
00566 notice_lang(s_ChanServ, u, CHAN_AKICK_NO_MATCH, chan);
00567
00568 } else if (stricmp(cmd, "VIEW") == 0) {
00569 int sent_header = 0;
00570
00571 if (ci->akickcount == 0) {
00572 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, chan);
00573 return MOD_CONT;
00574 }
00575 if (mask && isdigit(*mask) &&
00576 strspn(mask, "1234567890,-") == strlen(mask)) {
00577 process_numlist(mask, NULL, akick_view_callback, u, ci,
00578 &sent_header);
00579 } else {
00580 for (akick = ci->akick, i = 0; i < ci->akickcount;
00581 akick++, i++) {
00582 if (!(akick->flags & AK_USED))
00583 continue;
00584 if (mask) {
00585 if (!(akick->flags & AK_ISNICK)
00586 && !match_wild_nocase(mask, akick->u.mask))
00587 continue;
00588 if ((akick->flags & AK_ISNICK)
00589 && !match_wild_nocase(mask, akick->u.nc->display))
00590 continue;
00591 }
00592 akick_view(u, i, ci, &sent_header);
00593 }
00594 }
00595 if (!sent_header)
00596 notice_lang(s_ChanServ, u, CHAN_AKICK_NO_MATCH, chan);
00597
00598 } else if (stricmp(cmd, "ENFORCE") == 0) {
00599 Channel *c = findchan(ci->name);
00600 struct c_userlist *cu = NULL;
00601 struct c_userlist *next;
00602 char *argv[3];
00603 int count = 0;
00604
00605 if (!c) {
00606 notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, ci->name);
00607 return MOD_CONT;
00608 }
00609
00610 cu = c->users;
00611
00612 while (cu) {
00613 next = cu->next;
00614 if (check_kick(cu->user, c->name, c->creation_time)) {
00615 argv[0] = sstrdup(c->name);
00616 argv[1] = sstrdup(cu->user->nick);
00617 argv[2] = sstrdup(CSAutokickReason);
00618
00619 do_kick(s_ChanServ, 3, argv);
00620
00621 free(argv[2]);
00622 free(argv[1]);
00623 free(argv[0]);
00624
00625 count++;
00626 }
00627 cu = next;
00628 }
00629
00630 notice_lang(s_ChanServ, u, CHAN_AKICK_ENFORCE_DONE, chan, count);
00631
00632 } else if (stricmp(cmd, "CLEAR") == 0) {
00633
00634 if (readonly) {
00635 notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
00636 return MOD_CONT;
00637 }
00638
00639 for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
00640 if (!(akick->flags & AK_USED))
00641 continue;
00642 akick_del(u, akick);
00643 }
00644
00645 free(ci->akick);
00646 ci->akick = NULL;
00647 ci->akickcount = 0;
00648
00649 alog("%s: %s!%s@%s cleared akicks on %s",
00650 s_ChanServ, u->nick, u->username, u->host, ci->name);
00651 notice_lang(s_ChanServ, u, CHAN_AKICK_CLEAR, ci->name);
00652
00653 } else {
00654 syntax_error(s_ChanServ, u, "AKICK", CHAN_AKICK_SYNTAX);
00655 }
00656 return MOD_CONT;
00657 }
00658
00659
00660 static int get_access_nc(NickCore *nc, ChannelInfo *ci)
00661 {
00662 ChanAccess *access;
00663 if (!ci || !nc)
00664 return 0;
00665
00666 if ((access = get_access_entry(nc, ci)))
00667 return access->level;
00668 return 0;
00669 }
00670
00671