}
static int
-protect_user(const struct userNode *victim, const struct userNode *aggressor, struct chanData *channel)
+protect_user(const struct userNode *victim, const struct userNode *aggressor, struct chanData *channel, int protect_invitables)
{
char protect = channel->chOpts[chProtect];
struct userData *cs_victim, *cs_aggressor;
- /* Don't protect if no one is to be protected, someone is attacking
- himself, or if the aggressor is an IRC Operator. */
- if(protect == 'n' || victim == aggressor /* Opers dont get special treatment :/ || IsOper(aggressor) */)
- return 0;
+ /* If victim access level is greater than set invitelevel, don't let
+ * us kick them, but don't consider it punishment if someone else does
+ */
+
+ if(victim == aggressor)
+ return 0;
/* Don't protect if the victim isn't authenticated (because they
can't be a channel user), unless we are to protect non-users
also. */
+
cs_victim = GetChannelAccess(channel, victim->handle_info);
+
+ /* If they have enough access to invite themselvs through a ban,
+ * and its us kicking them, don't. -Rubin */
+ if(protect_invitables==true && cs_victim && (cs_victim->access >= channel->lvlOpts[lvlInviteMe]))
+ return 1;
+
+ if(protect == 'n')
+ return 0;
+
if(protect != 'a' && !cs_victim)
return 0;
/* Protect if the aggressor isn't a user because at this point,
the aggressor can only be less than or equal to the victim. */
+
+ /* Not protected from chanserv except above */
+ /* XXX: need to generic-ize chanserv to "one of x3's services" somehow.. */
+ if(aggressor == chanserv)
+ return 0;
+
cs_aggressor = GetChannelAccess(channel, aggressor->handle_info);
if(!cs_aggressor)
return 1;
return 0;
}
- if(protect_user(victim, user, channel->channel_info))
+ if(protect_user(victim, user, channel->channel_info, false))
{
reply("CSMSG_USER_PROTECTED", victim->nick);
return 0;
return 0;
}
- if(protect_user(victim, user, channel->channel_info))
+ if(protect_user(victim, user, channel->channel_info, false))
{
reply("CSMSG_USER_PROTECTED", victim->nick);
return 0;
static CHANSERV_FUNC(cmd_mdelcoowner)
{
- return cmd_mdel_user(user, channel, UL_COOWNER, UL_COOWNER, argv[1], cmd);
+ return cmd_mdel_user(user, channel, UL_COOWNER, UL_OWNER-1, argv[1], cmd);
}
static CHANSERV_FUNC(cmd_mdelmanager)
{
- return cmd_mdel_user(user, channel, UL_MANAGER, UL_MANAGER, argv[1], cmd);
+ return cmd_mdel_user(user, channel, UL_MANAGER, UL_COOWNER-1, argv[1], cmd);
}
static CHANSERV_FUNC(cmd_mdelop)
{
- return cmd_mdel_user(user, channel, UL_OP, UL_OP, argv[1], cmd);
+ return cmd_mdel_user(user, channel, UL_OP, UL_MANAGER-1, argv[1], cmd);
}
-static CHANSERV_FUNC(cmd_mdelpeon)
+static CHANSERV_FUNC(cmd_mdelhalfop)
{
- return cmd_mdel_user(user, channel, UL_PEON, UL_PEON, argv[1], cmd);
+ return cmd_mdel_user(user, channel, UL_HALFOP, UL_OP-1, argv[1], cmd);
}
-static CHANSERV_FUNC(cmd_mdelhalfop)
+static CHANSERV_FUNC(cmd_mdelpeon)
{
- return cmd_mdel_user(user, channel, UL_HALFOP, UL_HALFOP, argv[1], cmd);
+ return cmd_mdel_user(user, channel, UL_PEON, UL_HALFOP-1, argv[1], cmd);
}
+static CHANSERV_FUNC(cmd_levels)
+{
+ struct helpfile_table tbl;
+ int ii = 0;
+
+ tbl.length = 6 + 1; // 6 levels
+ tbl.width = 4;
+ tbl.flags = 0;
+ tbl.contents = calloc(tbl.length,sizeof(tbl.contents[0]));
+ tbl.contents[0] = calloc(tbl.width,sizeof(tbl.contents[0][0]));
+ tbl.contents[0][0] = "Level";
+ tbl.contents[0][1] = "From";
+ tbl.contents[0][2] = "-";
+ tbl.contents[0][3] = "To";
+
+ tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+ tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_OWNER));
+ tbl.contents[ii][1] = msnprintf(4, "%d", UL_OWNER);
+ tbl.contents[ii][2] = msnprintf(2, " ");
+ tbl.contents[ii][3] = msnprintf(1, "");
+
+ tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+ tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_COOWNER));
+ tbl.contents[ii][1] = msnprintf(4, "%d", UL_COOWNER);
+ tbl.contents[ii][2] = msnprintf(2, "-");
+ tbl.contents[ii][3] = msnprintf(4, "%d", UL_OWNER-1);
+
+ tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+ tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_MANAGER));
+ tbl.contents[ii][1] = msnprintf(4, "%d", UL_MANAGER);
+ tbl.contents[ii][2] = msnprintf(2, "-");
+ tbl.contents[ii][3] = msnprintf(4, "%d", UL_COOWNER-1);
+
+ tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+ tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_OP));
+ tbl.contents[ii][1] = msnprintf(4, "%d", UL_OP);
+ tbl.contents[ii][2] = msnprintf(2, "-");
+ tbl.contents[ii][3] = msnprintf(4, "%d", UL_MANAGER-1);
+
+ tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+ tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_HALFOP));
+ tbl.contents[ii][1] = msnprintf(4, "%d", UL_HALFOP);
+ tbl.contents[ii][2] = msnprintf(2, "-");
+ tbl.contents[ii][3] = msnprintf(4, "%d", UL_OP-1);
+
+ tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+ tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_PEON));
+ tbl.contents[ii][1] = msnprintf(4, "%d", UL_PEON);
+ tbl.contents[ii][2] = msnprintf(2, "-");
+ tbl.contents[ii][3] = msnprintf(4, "%d", UL_HALFOP-1);
+
+ table_send(cmd->parent->bot, user->nick, 0, NULL, tbl);
+ return 0;
+
+/*
+ reply("CSMSG_LEVELS_HEADER");
+ reply("CSMSG_LEVELS", user_level_name_from_level(UL_OWNER), UL_OWNER, UL_OWNER);
+ reply("CSMSG_LEVELS", user_level_name_from_level(UL_COOWNER), UL_COOWNER, UL_OWNER-1);
+ reply("CSMSG_LEVELS", user_level_name_from_level(UL_MANAGER), UL_MANAGER, UL_COOWNER-1);
+ reply("CSMSG_LEVELS", user_level_name_from_level(UL_OP), UL_OP, UL_MANAGER-1);
+ reply("CSMSG_LEVELS", user_level_name_from_level(UL_HALFOP), UL_HALFOP, UL_OP-1);
+ reply("CSMSG_LEVELS", user_level_name_from_level(UL_PEON), UL_PEON, UL_HALFOP-1);
+ reply("CSMSG_BAR");
+ */
+}
+
/* trim_lamers.. */
static int
cmd_trim_bans(struct svccmd *cmd, struct userNode *user, struct chanNode *channel, unsigned long duration)
if(!user_matches_glob(mn->user, ban, MATCH_USENICK | MATCH_VISIBLE))
continue;
- if(protect_user(mn->user, user, channel->channel_info))
+ if(protect_user(mn->user, user, channel->channel_info, false))
return 1;
if(victims)
return 0;
}
- if(protect_user(victim, user, channel->channel_info))
+ if(protect_user(victim, user, channel->channel_info, false))
{
// This translates to send_message(user, cmd->parent->bot, ...)
// if user is x3 (ctcp action) cmd is null and segfault.
}
}
- if(action & ACTION_KICK)
+ if(action & ACTION_ADD_LAMER)
{
char kick_reason[MAXLEN];
sprintf(kick_reason, "(%s) %s", user->nick, reason);
- for(n = 0; n < victimCount; n++)
+ for(n = 0; n < victimCount; n++) {
+ if(!protect_user(victims[n]->user, user, channel->channel_info, true)) {
+ KickChannelUser(victims[n]->user, channel, chanserv, kick_reason);
+ }
+ }
+ }
+ else if(action & ACTION_KICK)
+ {
+ char kick_reason[MAXLEN];
+ sprintf(kick_reason, "(%s) %s", user->nick, reason);
+
+ for(n = 0; n < victimCount; n++) {
KickChannelUser(victims[n]->user, channel, chanserv, kick_reason);
+ }
}
if(!cmd)
if(argc < 2)
target_handle = user->handle_info;
- else if(!IsHelping(user))
+ else if(!(target_handle = modcmd_get_handle_info(user, argv[1])))
+ return 0;
+ else if(!IsHelping(user) && target_handle != user->handle_info)
{
reply("CSMSG_MYACCESS_SELF_ONLY", argv[0]);
return 0;
}
- else if(!(target_handle = modcmd_get_handle_info(user, argv[1])))
- return 0;
-
if(!target_handle->channels)
{
reply("CSMSG_SQUAT_ACCESS", target_handle->handle);
if(!matches)
{
table_send(cmd->parent->bot, user->nick, 0, NULL, tbl);
- reply("MSG_NONE");
+/* reply("MSG_NONE"); */
free(tbl.contents[0]);
free(tbl.contents);
return 0;
SetChannelTopic(channel, chanserv, chanserv, channel->channel_info->topic, 1);
}
+int
+check_bans(struct userNode *user, const char *channel)
+{
+ struct chanNode *chan;
+ struct mod_chanmode change;
+ struct chanData *cData;
+ struct banData *bData;
+
+ if (!(chan = GetChannel(channel)))
+ return 0;
+
+ if(!(cData = chan->channel_info))
+ return 0;
+
+ mod_chanmode_init(&change);
+ change.argc = 1;
+
+ if(chan->banlist.used < MAXBANS)
+ {
+ /* Not joining through a ban. */
+ for(bData = cData->bans;
+ bData && !user_matches_glob(user, bData->mask, MATCH_USENICK);
+ bData = bData->next);
+
+ if(bData)
+ {
+ char kick_reason[MAXLEN];
+ sprintf(kick_reason, "(%s) %s", bData->owner, bData->reason);
+
+ bData->triggered = now;
+ if(bData != cData->bans)
+ {
+ /* Shuffle the ban to the head of the list. */
+ if(bData->next)
+ bData->next->prev = bData->prev;
+ if(bData->prev)
+ bData->prev->next = bData->next;
+
+ bData->prev = NULL;
+ bData->next = cData->bans;
+
+ if(cData->bans)
+ cData->bans->prev = bData;
+
+ cData->bans = bData;
+ }
+
+ change.args[0].mode = MODE_BAN;
+ change.args[0].u.hostmask = bData->mask;
+ mod_chanmode_announce(chanserv, chan, &change);
+ KickChannelUser(user, chan, chanserv, kick_reason);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
/* Welcome to my worst nightmare. Warning: Read (or modify)
the code below at your own risk. */
static int
}
#endif
+ if(user->handle_info)
+ {
+ handle = user->handle_info;
+ if(handle)
+ {
+ uData = GetTrueChannelAccess(cData, handle);
+ }
+ }
+
+
mod_chanmode_init(&change);
change.argc = 1;
- if(channel->banlist.used < MAXBANS)
- {
- /* Not joining through a ban. */
- for(bData = cData->bans;
- bData && !user_matches_glob(user, bData->mask, MATCH_USENICK);
- bData = bData->next);
- if(bData)
+ /* TODO: maybe only people above inviteme level? -Rubin */
+ /* We don't kick people with access */
+ if(!uData)
+ {
+ if(channel->banlist.used < MAXBANS)
{
- char kick_reason[MAXLEN];
- sprintf(kick_reason, "(%s) %s", bData->owner, bData->reason);
+ /* Not joining through a ban. */
+ for(bData = cData->bans;
+ bData && !user_matches_glob(user, bData->mask, MATCH_USENICK);
+ bData = bData->next);
- bData->triggered = now;
- if(bData != cData->bans)
+ if(bData)
{
- /* Shuffle the ban to the head of the list. */
- if(bData->next)
- bData->next->prev = bData->prev;
- if(bData->prev)
- bData->prev->next = bData->next;
+ char kick_reason[MAXLEN];
+ sprintf(kick_reason, "(%s) %s", bData->owner, bData->reason);
- bData->prev = NULL;
- bData->next = cData->bans;
+ bData->triggered = now;
+ if(bData != cData->bans)
+ {
+ /* Shuffle the ban to the head of the list. */
+ if(bData->next)
+ bData->next->prev = bData->prev;
+ if(bData->prev)
+ bData->prev->next = bData->next;
+
+ bData->prev = NULL;
+ bData->next = cData->bans;
+
+ if(cData->bans)
+ cData->bans->prev = bData;
+ cData->bans = bData;
+ }
- if(cData->bans)
- cData->bans->prev = bData;
- cData->bans = bData;
+ change.args[0].mode = MODE_BAN;
+ change.args[0].u.hostmask = bData->mask;
+ mod_chanmode_announce(chanserv, channel, &change);
+ KickChannelUser(user, channel, chanserv, kick_reason);
+ return 1;
}
-
- change.args[0].mode = MODE_BAN;
- change.args[0].u.hostmask = bData->mask;
- mod_chanmode_announce(chanserv, channel, &change);
- KickChannelUser(user, channel, chanserv, kick_reason);
- return 1;
}
}
greeting = cData->greeting;
if(user->handle_info)
{
- handle = user->handle_info;
+/* handle = user->handle_info; */
if(IsHelper(user) && !IsHelping(user))
{
}
}
- uData = GetTrueChannelAccess(cData, handle);
+/* uData = GetTrueChannelAccess(cData, handle); */
if(uData && !IsUserSuspended(uData))
{
/* non users getting automodes are handled above. */
}
static void
-chanserv_autojoin_channel(void *data)
+chanserv_autojoin_channels(struct userNode *user)
{
struct userData *channel;
- struct userNode *user = data;
for(channel = user->handle_info->channels; channel; channel = channel->u_next)
{
|| !channel->channel_info
|| IsSuspended(channel->channel_info))
continue;
+ if(protect_user(user, chanserv, channel->channel_info, true))
+ continue;
for(jj = 0; jj < channel->banlist.used; ++jj)
if(user_matches_glob(user, channel->banlist.list[jj]->ban, MATCH_USENICK))
break;
/* process autojoin channels 5 seconds later as this sometimes
happens before autohide */
- timeq_add(now + 5, chanserv_autojoin_channel, user);
+// timeq_add(now + 5, chanserv_autojoin_channels, user);
+ chanserv_autojoin_channels(user);
}
static void
|| (kicker->handle_info && kicker->handle_info == victim->handle_info))
return;
- if(protect_user(victim, kicker, channel->channel_info))
+ if(protect_user(victim, kicker, channel->channel_info, false))
{
const char *reason = user_find_message(kicker, "CSMSG_USER_PROTECTED_KICK");
KickChannelUser(kicker, channel, chanserv, reason);
if((change->args[ii].mode & (MODE_REMOVE|MODE_CHANOP)) == (MODE_REMOVE|MODE_CHANOP))
{
const struct userNode *victim = change->args[ii].u.member->user;
- if(!protect_user(victim, user, channel->channel_info))
+ if(!protect_user(victim, user, channel->channel_info, false))
continue;
if(!bounce)
bounce = mod_chanmode_alloc(change->argc + 1 - ii);
/* Need not check for bans if they're opped or voiced. */
/* TODO: does this make sense in automode v, h, and o? *
* lets still enforce on voice people anyway, and see how that goes -Rubin */
- if(user->channels.list[ii]->modes & (MODE_CHANOP|MODE_HALFOP /*|MODE_VOICE */))
+ if(user->channels.list[ii]->modes & (MODE_CHANOP|MODE_HALFOP|MODE_VOICE ))
continue;
/* Need not check for bans unless channel registration is active. */
if(!channel->channel_info || IsSuspended(channel->channel_info))
/* Need not act if we found one. */
if(jj < channel->banlist.used)
continue;
+ /* don't kick someone on the userlist */
+ if(protect_user(user, chanserv, channel->channel_info, true))
+ continue;
/* Look for a matching ban in this channel. */
for(bData = channel->channel_info->bans; bData; bData = bData->next)
{
DEFINE_COMMAND(mdelpeon, 2, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);
DEFINE_COMMAND(mdelhalfop, 2, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);
+ DEFINE_COMMAND(levels, 1, 0, NULL);
+
DEFINE_COMMAND(trim, 3, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);
DEFINE_COMMAND(opchan, 1, MODCMD_REQUIRE_REGCHAN|MODCMD_NEVER_CSUSPEND, "access", "1", NULL);
DEFINE_COMMAND(clvl, 3, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);