cs_akick.c

Go to the documentation of this file.
00001 /* ChanServ core functions
00002  *
00003  * (C) 2003-2007 Anope Team
00004  * Contact us at info@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church. 
00010  * 
00011  * $Id: cs_akick.c 1322 2007-12-28 19:12:02Z geniusdex $
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  /* `last' is set to the last index this routine was called with */
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         /* Check excepts BEFORE we get this far */
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         /* All entries should be in use so we don't have to go over
00255          * the entire list. We simply add new entries at the end. */
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         /* Auto ENFORCE #63 */
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         /* Special case: is it a number/list?  Only do search if it isn't. */
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             /* Reordering - DrStein */
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                             /* maybe we should first check whether there
00453                                is a reason before we sstdrup it -Certus */
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             /* After reordering only the entries at the end could still be empty.
00470              * We ll free the places no longer in use... - Viper */
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 }

Generated on Sun Dec 30 09:26:46 2007 for Anope by  doxygen 1.5.1-20070107