00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "module.h"
00017
00018
00019 int do_akick(User * u);
00020 void myChanServHelp(User * u);
00021
00028 int AnopeInit(int argc, char **argv)
00029 {
00030 Command *c;
00031
00032 moduleAddAuthor("Anope");
00033 moduleAddVersion("$Id: cs_akick.c 1322 2007-12-28 19:12:02Z geniusdex $");
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 void myChanServHelp(User * u)
00060 {
00061 notice_lang(s_ChanServ, u, CHAN_HELP_CMD_AKICK);
00062 }
00063
00069
00070 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 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 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 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 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 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 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 char *argv[3];
00194 int count = 0;
00195
00196 if (!cmd || (!mask && (!stricmp(cmd, "ADD") || !stricmp(cmd, "STICK")
00197 || !stricmp(cmd, "UNSTICK")
00198 || !stricmp(cmd, "DEL")))) {
00199
00200 syntax_error(s_ChanServ, u, "AKICK", CHAN_AKICK_SYNTAX);
00201 } else if (!(ci = cs_findchan(chan))) {
00202 notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
00203 } else if (ci->flags & CI_VERBOTEN) {
00204 notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
00205 } else if (!check_access(u, ci, CA_AKICK) && !is_services_admin(u)) {
00206 notice_lang(s_ChanServ, u, ACCESS_DENIED);
00207 } else if (stricmp(cmd, "ADD") == 0) {
00208
00209 NickAlias *na = findnick(mask);
00210 NickCore *nc = NULL;
00211 char *nick, *user, *host;
00212
00213 if (readonly) {
00214 notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
00215 return MOD_CONT;
00216 }
00217
00218 if (!na) {
00219 split_usermask(mask, &nick, &user, &host);
00220 mask =
00221 scalloc(strlen(nick) + strlen(user) + strlen(host) + 3, 1);
00222 sprintf(mask, "%s!%s@%s", nick, user, host);
00223 free(nick);
00224 free(user);
00225 free(host);
00226 } else {
00227 if (na->status & NS_VERBOTEN) {
00228 notice_lang(s_ChanServ, u, NICK_X_FORBIDDEN, mask);
00229 return MOD_CONT;
00230 }
00231 nc = na->nc;
00232 }
00233
00234
00235 if (ircd->except) {
00236 if (is_excepted_mask(ci, mask) == 1) {
00237 notice_lang(s_ChanServ, u, CHAN_EXCEPTED, mask, chan);
00238 return MOD_CONT;
00239 }
00240 }
00241
00242 for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
00243 if (!(akick->flags & AK_USED))
00244 continue;
00245 if ((akick->flags & AK_ISNICK) ? akick->u.nc == nc
00246 : stricmp(akick->u.mask, mask) == 0) {
00247 notice_lang(s_ChanServ, u, CHAN_AKICK_ALREADY_EXISTS,
00248 (akick->flags & AK_ISNICK) ? akick->u.nc->
00249 display : akick->u.mask, chan);
00250 return MOD_CONT;
00251 }
00252 }
00253
00254
00255
00256 if (ci->akickcount >= CSAutokickMax) {
00257 notice_lang(s_ChanServ, u, CHAN_AKICK_REACHED_LIMIT, CSAutokickMax);
00258 return MOD_CONT;
00259 }
00260 ci->akickcount++;
00261 ci->akick =
00262 srealloc(ci->akick, sizeof(AutoKick) * ci->akickcount);
00263 akick = &ci->akick[i];
00264 akick->flags = AK_USED;
00265 if (nc) {
00266 akick->flags |= AK_ISNICK;
00267 akick->u.nc = nc;
00268 } else {
00269 akick->u.mask = mask;
00270 }
00271 akick->creator = sstrdup(u->nick);
00272 akick->addtime = time(NULL);
00273 if (reason) {
00274 if (strlen(reason) > 200)
00275 reason[200] = '\0';
00276 akick->reason = sstrdup(reason);
00277 } else {
00278 akick->reason = NULL;
00279 }
00280
00281
00282 c = findchan(ci->name);
00283 if (c) {
00284 cu = c->users;
00285 while (cu) {
00286 next = cu->next;
00287 if (check_kick(cu->user, c->name, c->creation_time)) {
00288 argv[0] = sstrdup(c->name);
00289 argv[1] = sstrdup(cu->user->nick);
00290 if (akick->reason)
00291 argv[2] = sstrdup(akick->reason);
00292 else
00293 argv[2] = sstrdup("none");
00294
00295 do_kick(s_ChanServ, 3, argv);
00296
00297 free(argv[2]);
00298 free(argv[1]);
00299 free(argv[0]);
00300 count++;
00301
00302 }
00303 cu = next;
00304 }
00305 }
00306 notice_lang(s_ChanServ, u, CHAN_AKICK_ADDED, mask, chan);
00307
00308 if (count)
00309 notice_lang(s_ChanServ, u, CHAN_AKICK_ENFORCE_DONE, chan,
00310 count);
00311
00312 } else if (stricmp(cmd, "STICK") == 0) {
00313 NickAlias *na;
00314 NickCore *nc;
00315
00316 if (readonly) {
00317 notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
00318 return MOD_CONT;
00319 }
00320
00321 if (ci->akickcount == 0) {
00322 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, ci->name);
00323 return MOD_CONT;
00324 }
00325
00326 na = findnick(mask);
00327 nc = (na ? na->nc : NULL);
00328
00329 for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
00330 if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK))
00331 continue;
00332 if (!stricmp(akick->u.mask, mask))
00333 break;
00334 }
00335
00336 if (i == ci->akickcount) {
00337 notice_lang(s_ChanServ, u, CHAN_AKICK_NOT_FOUND, mask,
00338 ci->name);
00339 return MOD_CONT;
00340 }
00341
00342 akick->flags |= AK_STUCK;
00343 notice_lang(s_ChanServ, u, CHAN_AKICK_STUCK, akick->u.mask,
00344 ci->name);
00345
00346 if (ci->c)
00347 stick_mask(ci, akick);
00348 } else if (stricmp(cmd, "UNSTICK") == 0) {
00349 NickAlias *na;
00350 NickCore *nc;
00351
00352 if (readonly) {
00353 notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
00354 return MOD_CONT;
00355 }
00356
00357 if (ci->akickcount == 0) {
00358 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, ci->name);
00359 return MOD_CONT;
00360 }
00361
00362 na = findnick(mask);
00363 nc = (na ? na->nc : NULL);
00364
00365 for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
00366 if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK))
00367 continue;
00368 if (!stricmp(akick->u.mask, mask))
00369 break;
00370 }
00371
00372 if (i == ci->akickcount) {
00373 notice_lang(s_ChanServ, u, CHAN_AKICK_NOT_FOUND, mask,
00374 ci->name);
00375 return MOD_CONT;
00376 }
00377
00378 akick->flags &= ~AK_STUCK;
00379 notice_lang(s_ChanServ, u, CHAN_AKICK_UNSTUCK, akick->u.mask,
00380 ci->name);
00381
00382 } else if (stricmp(cmd, "DEL") == 0) {
00383 int deleted, a, b;
00384
00385 if (readonly) {
00386 notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
00387 return MOD_CONT;
00388 }
00389
00390 if (ci->akickcount == 0) {
00391 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, chan);
00392 return MOD_CONT;
00393 }
00394
00395
00396 if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
00397 int count, last = -1;
00398 deleted = process_numlist(mask, &count, akick_del_callback, u,
00399 ci, &last);
00400 if (!deleted) {
00401 if (count == 1) {
00402 notice_lang(s_ChanServ, u, CHAN_AKICK_NO_SUCH_ENTRY,
00403 last, ci->name);
00404 } else {
00405 notice_lang(s_ChanServ, u, CHAN_AKICK_NO_MATCH,
00406 ci->name);
00407 }
00408 } else if (deleted == 1) {
00409 notice_lang(s_ChanServ, u, CHAN_AKICK_DELETED_ONE,
00410 ci->name);
00411 } else {
00412 notice_lang(s_ChanServ, u, CHAN_AKICK_DELETED_SEVERAL,
00413 deleted, ci->name);
00414 }
00415 } else {
00416 NickAlias *na = findnick(mask);
00417 NickCore *nc = (na ? na->nc : NULL);
00418
00419 for (akick = ci->akick, i = 0; i < ci->akickcount;
00420 akick++, i++) {
00421 if (!(akick->flags & AK_USED))
00422 continue;
00423 if (((akick->flags & AK_ISNICK) && akick->u.nc == nc)
00424 || (!(akick->flags & AK_ISNICK)
00425 && stricmp(akick->u.mask, mask) == 0))
00426 break;
00427 }
00428 if (i == ci->akickcount) {
00429 notice_lang(s_ChanServ, u, CHAN_AKICK_NOT_FOUND, mask,
00430 chan);
00431 return MOD_CONT;
00432 }
00433 notice_lang(s_ChanServ, u, CHAN_AKICK_DELETED, mask, chan);
00434 akick_del(u, akick);
00435 deleted = 1;
00436 }
00437 if (deleted) {
00438
00439 for (b = 0; b < ci->akickcount; b++) {
00440 if (ci->akick[b].flags & AK_USED) {
00441 for (a = 0; a < ci->akickcount; a++) {
00442 if (a > b)
00443 break;
00444 if (!(ci->akick[a].flags & AK_USED)) {
00445 ci->akick[a].flags = ci->akick[b].flags;
00446 if (ci->akick[b].flags & AK_ISNICK) {
00447 ci->akick[a].u.nc = ci->akick[b].u.nc;
00448 } else {
00449 ci->akick[a].u.mask =
00450 sstrdup(ci->akick[b].u.mask);
00451 }
00452
00453
00454 if (ci->akick[b].reason)
00455 ci->akick[a].reason =
00456 sstrdup(ci->akick[b].reason);
00457 else
00458 ci->akick[a].reason = NULL;
00459 ci->akick[a].creator =
00460 sstrdup(ci->akick[b].creator);
00461 ci->akick[a].addtime = ci->akick[b].addtime;
00462
00463 akick_del(u, &ci->akick[b]);
00464 break;
00465 }
00466 }
00467 }
00468 }
00469
00470
00471 for (i = ci->akickcount - 1; i >= 0; i--) {
00472 if (ci->akick[i].flags & AK_USED)
00473 break;
00474
00475 ci->akickcount--;
00476 }
00477 ci->akick =
00478 srealloc(ci->akick,sizeof(AutoKick) * ci->akickcount);
00479 }
00480 } else if (stricmp(cmd, "LIST") == 0) {
00481 int sent_header = 0;
00482
00483 if (ci->akickcount == 0) {
00484 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, chan);
00485 return MOD_CONT;
00486 }
00487 if (mask && isdigit(*mask) &&
00488 strspn(mask, "1234567890,-") == strlen(mask)) {
00489 process_numlist(mask, NULL, akick_list_callback, u, ci,
00490 &sent_header);
00491 } else {
00492 for (akick = ci->akick, i = 0; i < ci->akickcount;
00493 akick++, i++) {
00494 if (!(akick->flags & AK_USED))
00495 continue;
00496 if (mask) {
00497 if (!(akick->flags & AK_ISNICK)
00498 && !match_wild_nocase(mask, akick->u.mask))
00499 continue;
00500 if ((akick->flags & AK_ISNICK)
00501 && !match_wild_nocase(mask, akick->u.nc->display))
00502 continue;
00503 }
00504 akick_list(u, i, ci, &sent_header);
00505 }
00506 }
00507 if (!sent_header)
00508 notice_lang(s_ChanServ, u, CHAN_AKICK_NO_MATCH, chan);
00509
00510 } else if (stricmp(cmd, "VIEW") == 0) {
00511 int sent_header = 0;
00512
00513 if (ci->akickcount == 0) {
00514 notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, chan);
00515 return MOD_CONT;
00516 }
00517 if (mask && isdigit(*mask) &&
00518 strspn(mask, "1234567890,-") == strlen(mask)) {
00519 process_numlist(mask, NULL, akick_view_callback, u, ci,
00520 &sent_header);
00521 } else {
00522 for (akick = ci->akick, i = 0; i < ci->akickcount;
00523 akick++, i++) {
00524 if (!(akick->flags & AK_USED))
00525 continue;
00526 if (mask) {
00527 if (!(akick->flags & AK_ISNICK)
00528 && !match_wild_nocase(mask, akick->u.mask))
00529 continue;
00530 if ((akick->flags & AK_ISNICK)
00531 && !match_wild_nocase(mask, akick->u.nc->display))
00532 continue;
00533 }
00534 akick_view(u, i, ci, &sent_header);
00535 }
00536 }
00537 if (!sent_header)
00538 notice_lang(s_ChanServ, u, CHAN_AKICK_NO_MATCH, chan);
00539
00540 } else if (stricmp(cmd, "ENFORCE") == 0) {
00541 Channel *c = findchan(ci->name);
00542 struct c_userlist *cu = NULL;
00543 struct c_userlist *next;
00544 char *argv[3];
00545 int count = 0;
00546
00547 if (!c) {
00548 notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, ci->name);
00549 return MOD_CONT;
00550 }
00551
00552 cu = c->users;
00553
00554 while (cu) {
00555 next = cu->next;
00556 if (check_kick(cu->user, c->name, c->creation_time)) {
00557 argv[0] = sstrdup(c->name);
00558 argv[1] = sstrdup(cu->user->nick);
00559 argv[2] = sstrdup(CSAutokickReason);
00560
00561 do_kick(s_ChanServ, 3, argv);
00562
00563 free(argv[2]);
00564 free(argv[1]);
00565 free(argv[0]);
00566
00567 count++;
00568 }
00569 cu = next;
00570 }
00571
00572 notice_lang(s_ChanServ, u, CHAN_AKICK_ENFORCE_DONE, chan, count);
00573
00574 } else if (stricmp(cmd, "CLEAR") == 0) {
00575
00576 if (readonly) {
00577 notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
00578 return MOD_CONT;
00579 }
00580
00581 for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
00582 if (!(akick->flags & AK_USED))
00583 continue;
00584 akick_del(u, akick);
00585 }
00586
00587 free(ci->akick);
00588 ci->akick = NULL;
00589 ci->akickcount = 0;
00590
00591 notice_lang(s_ChanServ, u, CHAN_AKICK_CLEAR, ci->name);
00592
00593 } else {
00594 syntax_error(s_ChanServ, u, "AKICK", CHAN_AKICK_SYNTAX);
00595 }
00596 return MOD_CONT;
00597 }