/* * ================================================================= * Filename: m_rmtkl.c * Description: Command /rmtkl * Author: AngryWolf * Documentation: m_rmtkl.txt (comes with the package) * ================================================================= */ #include "config.h" #include "struct.h" #include "common.h" #include "sys.h" #include "numeric.h" #include "msg.h" #include "channel.h" #include #include #include #include #include #ifdef _WIN32 #include #endif #include #include "h.h" #ifdef STRIPBADWORDS #include "badwords.h" #endif #ifdef _WIN32 #include "version.h" #endif #ifndef MODVAR /* Unreal3.2.1 */ #define MODVAR #endif #define IsParam(x) (parc > (x) && !BadPtr(parv[(x)])) #define IsNotParam(x) (parc <= (x) || BadPtr(parv[(x)])) #define DelCommand(x) if (x) CommandDel(x); x = NULL extern void sendto_one(aClient *to, char *pattern, ...); extern void sendto_serv_butone_token(aClient *one, char *prefix, char *command, char *token, char *pattern, ...); extern aTKline *tkl_del_line(aTKline *tkl); #ifdef TKLISTLEN /* Unreal3.2-RC1 */ extern MODVAR int tkl_hash(char c); extern MODVAR aTKline *tklines[TKLISTLEN]; #else extern aTKline *tklines; #endif static int m_rmtkl(aClient *cptr, aClient *sptr, int parc, char *parv[]); Command *CmdRmtkl = NULL; ModuleHeader MOD_HEADER(m_rmtkl) = { "rmtkl", "$Id: m_rmtkl.c,v 3.3 2004/08/30 13:55:54 angrywolf Exp $", "command /rmtkl", "3.2-b8-1", NULL }; DLLFUNC int MOD_INIT(m_rmtkl)(ModuleInfo *modinfo) { if (CommandExists("RMTKL")) { config_error("Command RMTKL already exists"); return MOD_FAILED; } CmdRmtkl = CommandAdd(modinfo->handle, "RMTKL", NULL, m_rmtkl, 3, 0); // CmdRmtkl = CommandAdd(modinfo->handle, "RMTKL", NULL, m_rmtkl, MAXPARA, 0); #ifndef STATIC_LINKING if (ModuleGetError(modinfo->handle) != MODERR_NOERROR || !CmdRmtkl) #else if (!CmdRmtkl) #endif { #ifndef STATIC_LINKING config_error("Error adding command RMTKL: %s", ModuleGetErrorStr(modinfo->handle)); #else config_error("Error adding command RMTKL"); #endif return MOD_FAILED; } return MOD_SUCCESS; } DLLFUNC int MOD_LOAD(m_rmtkl)(int module_load) { return MOD_SUCCESS; } DLLFUNC int MOD_UNLOAD(m_rmtkl)(int module_unload) { DelCommand(CmdRmtkl); return MOD_SUCCESS; } /* * ================================================================= * tkl_check_local_remove_shun: * Copied from src/s_kline.c (because it's declared statically, * but I want to use it). * ================================================================= */ static void tkl_check_local_remove_shun(aTKline *tmp) { long i1, i; char *chost, *cname, *cip; int is_ip; aClient *acptr; for (i1 = 0; i1 <= 5; i1++) { for (i = 0; i <= LastSlot; ++i) { if ((acptr = local[i])) if (MyClient(acptr) && IsShunned(acptr)) { chost = acptr->sockhost; cname = acptr->user->username; cip = (char *)Inet_ia2p(&acptr->ip); if (!(*tmp->hostmask < '0') && (*tmp->hostmask > '9')) is_ip = 1; else is_ip = 0; if (is_ip == 0 ? (!match(tmp->hostmask, chost) && !match(tmp->usermask, cname)) : (!match(tmp-> hostmask, chost) || !match(tmp->hostmask, cip)) && !match(tmp->usermask, cname)) { ClearShunned(acptr); #ifdef SHUN_NOTICES sendto_one(acptr, ":%s NOTICE %s :*** You are no longer shunned", me.name, acptr->name); #endif } } } } } /* * ================================================================= * my_tkl_del_line: * Modified version of tkl_del_line (from src/s_kline.c), * because using loops is unnecessary here). Also, I don't * delete any spamfilter entries with this module either. * ================================================================= */ #ifdef TKLISTLEN /* Unreal3.2-RC1 */ void my_tkl_del_line(aTKline *p, int tklindex) { MyFree(p->hostmask); MyFree(p->reason); MyFree(p->setby); #ifdef OFLAG_ADDLINE /* Unreal3.2.1 */ if ((p->type & TKL_KILL || p->type & TKL_ZAP || p->type & TKL_SHUN) && p->ptr.netmask) MyFree(p->ptr.netmask); #endif DelListItem(p, tklines[tklindex]); MyFree(p); } #endif /* * ================================================================= * dumpit: * Dump a NULL-terminated array of strings to user sptr using * the numeric rplnum, and then return 0. * (Taken from DarkFire IRCd) * ================================================================= */ static int dumpit(aClient *sptr, char **p) { for (; *p != NULL; p++) sendto_one(sptr, ":%s %03d %s :%s", me.name, RPL_TEXT, sptr->name, *p); /* let user take 8 seconds to read it! */ sptr->since += 8; return 0; } /* help for /rmtkl command */ static char *rmtkl_help[] = { "*** Help on /rmtkl *** ", "COMMAND - Removes all TKLs matching the given conditions from the", "local server or the IRC Network depending on it's a global ban or not.", "With this command you can remove any type of TKLs (including K:Line", "G:Line, Z:Line, Global Z:Line and Shun).", "Syntax:", " /rmtkl type user@host [comment]", "The type field may contain any number of the following characters:", " K, z, G, Z, q, Q and *", " (asterix includes every types but q & Q).", "The user@host field is a wildcard mask to match an user@host which", " a ban was set on.", "The comment field is also wildcard mask that you can match the", " text of the reason for a ban.", "Examples:", " - /rmtkl * *", " [remove all TKLs but q and Q lines]", " - /rmtkl GZ *@*.mx", " [remove all Mexican G/Z:Lines]", " - /rmtkl * * *Zombie*", " [remove all non-nick bans having Zombie in their reasons]", "*** End of help ***", NULL }; // ================================================================= // Array of TKL types // ================================================================= typedef struct _tkl_type TKLType; struct _tkl_type { int type; char flag; char *txt; u_long oflag; }; TKLType tkl_types[] = { { TKL_KILL, 'K', "K:Line", OFLAG_KLINE }, { TKL_ZAP, 'z', "Z:Line", OFLAG_ZLINE }, { TKL_KILL | TKL_GLOBAL, 'G', "G:Line", OFLAG_TKL }, { TKL_ZAP | TKL_GLOBAL, 'Z', "Global Z:Line", OFLAG_GZL }, { TKL_SHUN | TKL_GLOBAL, 's', "Shun", OFLAG_TKL }, #ifdef TKL_NICK { TKL_NICK, 'q', "Q:Line", OFLAG_TKL }, { TKL_NICK | TKL_GLOBAL, 'Q', "Global Q:Line", OFLAG_TKL }, #endif { 0, 0, "Unknown *:Line", 0 }, }; #ifndef TKLISTLEN /* Unreal3.2-RC1 */ static TKLType *find_TKLType_by_type(int type) { TKLType *t; for (t = tkl_types; t->type; t++) if (t->type == type) break; return t; } #endif static TKLType *find_TKLType_by_flag(char flag) { TKLType *t; for (t = tkl_types; t->type; t++) if (t->flag == flag) break; return t; } /* * ================================================================= * m_rmtkl -- Remove all matching TKLs from the network * parv[0] = sender prefix * parv[1] = ban types * parv[2] = userhost mask * parv[3] = comment mask (optional) * ================================================================= */ static int m_rmtkl(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aTKline *tk, *next = NULL; TKLType *tkltype; char *types, *uhmask, *cmask, *p; char gmt[256], flag; #ifdef TKLISTLEN /* Unreal3.2-RC1 */ int tklindex; #endif if (!IsULine(sptr) && !(IsPerson(sptr) && IsAnOper(sptr))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return -1; } if (IsNotParam(1)) return dumpit(sptr, rmtkl_help); if (IsNotParam(2)) { /* * In this case we don't send the entire help text to * the client. */ sendto_one(sptr, ":%s NOTICE %s :Not enough parameters. " "Type /%s for help.", me.name, parv[0], "RMTKL"); return 0; } types = parv[1]; uhmask = parv[2]; cmask = IsParam(3) ? parv[3] : NULL; /* I don't add 'q' and 'Q' here. They are different. */ if (strchr(types, '*')) types = "KzGZs"; /* check access */ if (!IsULine(sptr)) for (p = types; *p; p++) { tkltype = find_TKLType_by_flag(*p); if (!tkltype->type) continue; if (((tkltype->type & TKL_GLOBAL) && !IsOper(sptr)) || !(sptr->oflag & tkltype->oflag)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return -1; } } #ifdef TKLISTLEN /* Unreal3.2-RC1 */ for (tkltype = tkl_types; tkltype->type; tkltype++) { flag = tkltype->flag; tklindex = tkl_hash(flag); if (!strchr(types, flag)) continue; for (tk = tklines[tklindex]; tk; tk = next) { next = tk->next; if (tk->type != tkltype->type) continue; #ifdef TKL_NICK if (tk->type & TKL_NICK) { /* * If it's a services hold (ie. NickServ is holding * a nick), it's better not to touch it */ if (*tk->usermask == 'H') continue; if (match(uhmask, tk->hostmask)) continue; } else #endif if (match(uhmask, make_user_host(tk->usermask, tk->hostmask))) continue; if (cmask && _match(cmask, tk->reason)) continue; strncpyzt(gmt, asctime(gmtime((TS *)&tk->set_at)), sizeof gmt); iCstrip(gmt); #ifdef TKL_NICK if (tk->type & TKL_NICK) { sendto_snomask(SNO_TKL, "%s removed %s %s (set at %s " "- reason: %s)", sptr->name, tkltype->txt, tk->hostmask, gmt, tk->reason); ircd_log(LOG_TKL, "%s removed %s %s (set at %s " "- reason: %s)", sptr->name, tkltype->txt, tk->hostmask, gmt, tk->reason); } else { #endif sendto_snomask(SNO_TKL, "%s removed %s %s@%s (set at " "%s - reason: %s)", sptr->name, tkltype->txt, tk->usermask, tk->hostmask, gmt, tk->reason); ircd_log(LOG_TKL, "%s removed %s %s@%s (set at " "%s - reason: %s)", sptr->name, tkltype->txt, tk->usermask, tk->hostmask, gmt, tk->reason); #ifdef TKL_NICK } #endif if ((tk->type & TKL_GLOBAL) && flag) sendto_serv_butone_token(&me, me.name, MSG_TKL, TOK_TKL, "- %c %s %s %s", flag, tk->usermask, tk->hostmask, parv[0]); if (tk->type & TKL_SHUN) tkl_check_local_remove_shun(tk); my_tkl_del_line(tk, tklindex); } } #else for (tk = tklines; tk; tk = (aTKline *) next) { next = (ListStruct *) tk->next; tkltype = find_TKLType_by_type(tk->type); flag = tkltype->flag; if (!strchr(types, flag)) continue; if (match(uhmask, make_user_host(tk->usermask, tk->hostmask))) continue; if (cmask && _match(cmask, tk->reason)) continue; strncpyzt(gmt, asctime(gmtime((TS *)&tk->set_at)), sizeof(gmt)); iCstrip(gmt); sendto_snomask(SNO_TKL, "%s removed %s %s@%s (set at %s - reason: %s)", sptr->name, tkltype->txt, tk->usermask, tk->hostmask, gmt, tk->reason); ircd_log(LOG_TKL, "%s removed %s %s@%s (set at %s - reason: %s)", sptr->name, tkltype->txt, tk->usermask, tk->hostmask, gmt, tk->reason); if ((tk->type & TKL_GLOBAL) && flag) sendto_serv_butone_token(&me, me.name, MSG_TKL, TOK_TKL, "- %c %s %s %s", flag, tk->usermask, tk->hostmask, parv[0]); if (tk->type & TKL_SHUN) tkl_check_local_remove_shun(tk); tkl_del_line(tk); } #endif return 0; }