#define KEY_NETWORK_HELPER_EPITHET "network_helper_epithet"
#define KEY_SUPPORT_HELPER_EPITHET "support_helper_epithet"
#define KEY_NODELETE_LEVEL "nodelete_level"
+#define KEY_MAX_USERINFO_LENGTH "max_userinfo_length"
/* ChanServ database */
#define KEY_CHANNELS "channels"
{ "CSMSG_ALREADY_PRESENT", "%s is already in $b%s$b." },
{ "CSMSG_YOU_ALREADY_PRESENT", "You are already in $b%s$b." },
{ "CSMSG_LOW_CHANNEL_ACCESS", "You lack sufficient access in %s to use this command." },
+ { "CSMSG_INFOLINE_TOO_LONG", "Your infoline may not exceed %u characters." },
+ { "CSMSG_BAD_INFOLINE", "You may not use the character \\%03o in your infoline." },
{ "CSMSG_KICK_DONE", "Kicked $b%s$b from %s." },
{ "CSMSG_NO_BANS", "No channel bans found on $b%s$b." },
{ "CSMSG_NETWORK_SERVERS", "$bServers: $b%i" },
{ "CSMSG_NETWORK_USERS", "$bTotal Users: $b%i" },
{ "CSMSG_NETWORK_BANS", "$bTotal Ban Count: $b%i" },
+ { "CSMSG_NETWORK_CHANUSERS", "$bTotal User Count: $b%i" },
{ "CSMSG_NETWORK_OPERS", "$bIRC Operators: $b%i" },
{ "CSMSG_NETWORK_CHANNELS","$bRegistered Channels: $b%i" },
{ "CSMSG_SERVICES_UPTIME", "$bServices Uptime: $b%s" },
{ "CSMSG_WUT_RESPONSE", "wut" },
{ "CSMSG_BAD_NUMBER", "$b%s$b is an invalid number. Please use a number greater than 1 with this command." },
{ "CSMSG_BAD_DIE_FORMAT", "I do not understand $b%s$b. Please use either a single number or standard 4d6+3 format." },
- { "CSMSG_BAD_DICE_COUNT", "%d is too many dice. Please use at most %d." },
- { "CSMSG_DICE_ROLL", "The total is $b%d$b from rolling %dd%d+%d." },
- { "CSMSG_DIE_ROLL", "A $b%d$b shows on the %d-sided die." },
+ { "CSMSG_BAD_DICE_COUNT", "%lu is too many dice. Please use at most %lu." },
+ { "CSMSG_DICE_ROLL", "The total is $b%lu$b from rolling %lud%lu+%lu." },
+ { "CSMSG_DIE_ROLL", "A $b%lu$b shows on the %lu-sided die." },
{ "CSMSG_HUGGLES_HIM", "\001ACTION huggles %s\001" },
{ "CSMSG_HUGGLES_YOU", "\001ACTION huggles you\001" },
unsigned int max_owned;
unsigned int max_chan_users;
unsigned int max_chan_bans;
+ unsigned int max_userinfo_length;
struct string_list *set_shows;
struct string_list *eightball;
{
unsigned int level = 0, ii;
if(isdigit(name[0]))
- level = atoi(name);
+ level = strtoul(name, NULL, 10);
else for(ii = 0; (ii < ArrayLength(accessLevels)) && !level; ++ii)
if(!irccasecmp(name, accessLevels[ii].name))
level = accessLevels[ii].level;
change.args[0].mode = MODE_CHANOP;
errmsg = "CSMSG_ALREADY_OPPED";
}
- else
+ else if(uData->access >= channel->channel_info->lvlOpts[lvlGiveVoice])
{
change.args[0].mode = MODE_VOICE;
errmsg = "CSMSG_ALREADY_VOICED";
}
+ else
+ {
+ if(argc)
+ reply("CSMSG_NO_ACCESS");
+ return 0;
+ }
change.args[0].mode &= ~change.args[0].member->modes;
if(!change.args[0].mode)
{
static CHANSERV_FUNC(cmd_myaccess)
{
+ static struct string_buffer sbuf;
struct handle_info *target_handle;
struct userData *uData;
- const char *chanName;
if(argc < 2)
target_handle = user->handle_info;
&& (target_handle != user->handle_info)
&& !GetTrueChannelAccess(cData, user->handle_info))
continue;
- chanName = cData->channel->name;
+ sbuf.used = 0;
+ string_buffer_append_printf(&sbuf, "[%s (%d", cData->channel->name, uData->access);
+ if(uData->flags != USER_AUTO_OP)
+ string_buffer_append(&sbuf, ',');
+ if(IsUserSuspended(uData))
+ string_buffer_append(&sbuf, 's');
+ if(IsUserAutoOp(uData))
+ {
+ if(uData->access >= cData->lvlOpts[lvlGiveOps])
+ string_buffer_append(&sbuf, 'o');
+ else if(uData->access >= cData->lvlOpts[lvlGiveVoice])
+ string_buffer_append(&sbuf, 'v');
+ }
+ if(IsUserAutoInvite(uData) && (uData->access >= cData->lvlOpts[lvlInviteMe]))
+ string_buffer_append(&sbuf, 'i');
if(uData->info)
- send_message_type(4, user, cmd->parent->bot, "[%s (%d)] %s", chanName, uData->access, uData->info);
+ string_buffer_append_printf(&sbuf, ")] %s", uData->info);
else
- send_message_type(4, user, cmd->parent->bot, "[%s (%d)]", chanName, uData->access);
+ string_buffer_append_string(&sbuf, ")]");
+ string_buffer_append(&sbuf, '\0');
+ send_message_type(4, user, cmd->parent->bot, sbuf.list);
}
return 1;
reply("CSMSG_NETWORK_OPERS", curr_opers.used);
reply("CSMSG_NETWORK_CHANNELS", registered_channels);
reply("CSMSG_NETWORK_BANS", banCount);
- reply("CSMSG_CHANNEL_USERS", userCount);
+ reply("CSMSG_NETWORK_CHANUSERS", userCount);
reply("CSMSG_SERVICES_UPTIME", intervalString(interval, time(NULL) - boot_time, user->handle_info));
reply("CSMSG_BURST_LENGTH", intervalString(interval, burst_length, user->handle_info));
return 1;
targData = GetTrueChannelAccess(channel->channel_info, targ->handle_info);
if(!targData)
continue;
- if(pos + strlen(targ->nick) + strlen(targ->handle_info->handle) + 6 > sizeof(buf))
+ if(pos + strlen(targ->nick) + strlen(targ->handle_info->handle) + 8 > sizeof(buf))
{
buf[pos] = 0;
reply("CSMSG_CHANNEL_NAMES", channel->name, buf);
unsigned int matches, limit;
limit = (argc > 1) ? atoi(argv[1]) : 10;
- if(limit < 1 || limit > 200) limit = 10;
+ if(limit < 1 || limit > 200)
+ limit = 10;
memset(&discrim, 0, sizeof(discrim));
discrim.masks.bot = chanserv;
discrim.masks.channel_name = channel->name;
- if(argc > 2) discrim.masks.command = argv[2];
+ if(argc > 2)
+ discrim.masks.command = argv[2];
discrim.limit = limit;
discrim.max_time = INT_MAX;
discrim.severities = 1 << LOG_COMMAND;
if(argc > 1)
{
+ size_t bp;
infoline = unsplit_string(argv + 1, argc - 1, NULL);
+ if(strlen(infoline) > chanserv_conf.max_userinfo_length)
+ {
+ reply("CSMSG_INFOLINE_TOO_LONG", chanserv_conf.max_userinfo_length);
+ return 0;
+ }
+ bp = strcspn(infoline, "\001");
+ if(infoline[bp])
+ {
+ reply("CSMSG_BAD_INFOLINE", infoline[bp]);
+ return 0;
+ }
if(uData->info)
free(uData->info);
if(infoline[0] == '*' && infoline[1] == 0)
if(!IsUserSuspended(channel)
&& IsUserAutoInvite(channel)
&& (channel->access >= channel->channel->lvlOpts[lvlInviteMe])
- && (cn->modes & (MODE_KEY | MODE_INVITEONLY))
- && !self->burst)
+ && !self->burst
+ && !user->uplink->burst)
irc_invite(chanserv, user, cn);
continue;
}
}
static void
-handle_part(struct userNode *user, struct chanNode *channel, UNUSED_ARG(const char *reason))
+handle_part(struct modeNode *mn, UNUSED_ARG(const char *reason))
{
struct chanData *cData;
struct userData *uData;
- cData = channel->channel_info;
- if(!cData || IsSuspended(cData) || IsLocal(user))
+ cData = mn->channel->channel_info;
+ if(!cData || IsSuspended(cData) || IsLocal(mn->user))
return;
- if((cData->flags & CHANNEL_DYNAMIC_LIMIT) && !channel->join_flooded)
+ if((cData->flags & CHANNEL_DYNAMIC_LIMIT) && !mn->channel->join_flooded)
{
/* Allow for a bit of padding so that the limit doesn't
track the user count exactly, which could get annoying. */
- if((channel->limit - channel->members.used) > chanserv_conf.adjust_threshold + 5)
+ if((mn->channel->limit - mn->channel->members.used) > chanserv_conf.adjust_threshold + 5)
{
timeq_del(0, chanserv_adjust_limit, cData, TIMEQ_IGNORE_WHEN);
timeq_add(now + chanserv_conf.adjust_delay, chanserv_adjust_limit, cData);
}
}
- if((uData = GetTrueChannelAccess(cData, user->handle_info)))
+ if((uData = GetTrueChannelAccess(cData, mn->user->handle_info)))
{
- scan_user_presence(uData, user);
+ scan_user_presence(uData, mn->user);
uData->seen = now;
}
- if(IsHelping(user) && IsSupportHelper(user))
+ if(IsHelping(mn->user) && IsSupportHelper(mn->user))
{
unsigned int ii, jj;
for(ii = 0; ii < chanserv_conf.support_channels.used; ++ii)
{
- for(jj = 0; jj < user->channels.used; ++jj)
- if(user->channels.list[jj]->channel == chanserv_conf.support_channels.list[ii])
+ for(jj = 0; jj < mn->user->channels.used; ++jj)
+ if(mn->user->channels.list[jj]->channel == chanserv_conf.support_channels.list[ii])
break;
- if(jj < user->channels.used)
+ if(jj < mn->user->channels.used)
break;
}
if(ii == chanserv_conf.support_channels.used)
- HANDLE_CLEAR_FLAG(user->handle_info, HELPING);
+ HANDLE_CLEAR_FLAG(mn->user->handle_info, HELPING);
}
}
bounce->args[bnc].member = change->args[ii].member;
bnc++;
}
- else if(change->args[ii].mode & MODE_BAN)
+ else if((change->args[ii].mode & (MODE_REMOVE | MODE_BAN)) == MODE_BAN)
{
const char *ban = change->args[ii].hostmask;
if(!bad_channel_ban(channel, user, ban, NULL, NULL))
struct string_list *strlist;
struct chanNode *chan;
unsigned int ii;
+ extern int off_channel;
if(!(conf_node = conf_get_data(CHANSERV_CONF_NAME, RECDB_OBJECT)))
{
chanserv_conf.max_chan_users = str ? atoi(str) : 512;
str = database_get_data(conf_node, KEY_MAX_CHAN_BANS, RECDB_QSTRING);
chanserv_conf.max_chan_bans = str ? atoi(str) : 512;
+ str = database_get_data(conf_node, KEY_MAX_USERINFO_LENGTH, RECDB_QSTRING);
+ chanserv_conf.max_userinfo_length = str ? atoi(str) : 400;
str = database_get_data(conf_node, KEY_NICK, RECDB_QSTRING);
if(chanserv && str)
NickChange(chanserv, str, 0);
else
strlist = alloc_string_list(2);
chanserv_conf.old_ban_names = strlist;
+ /* the variable itself is actually declared in proto-common.c; this is equally
+ * parse issue. */
+ str = database_get_data(conf_node, "off_channel", RECDB_QSTRING);
+ off_channel = (str && enabled_string(str)) ? 1 : 0;
}
static void
char *str, *argv[10];
dict_iterator_t it;
unsigned int argc;
+ extern int off_channel;
channel = hir->d.object;
cData->flags &= ~CHANNEL_SUSPENDED;
}
- if(!(cData->flags & CHANNEL_SUSPENDED))
- {
- struct mod_chanmode change;
- mod_chanmode_init(&change);
- change.argc = 1;
- change.args[0].mode = MODE_CHANOP;
- change.args[0].member = AddChannelUser(chanserv, cNode);
- mod_chanmode_announce(chanserv, cNode, &change);
- }
- else if(suspended->expires > now)
- {
- timeq_add(suspended->expires, chanserv_expire_suspension, suspended);
+ if (!off_channel) {
+ if (!(cData->flags & CHANNEL_SUSPENDED)) {
+ struct mod_chanmode change;
+ mod_chanmode_init(&change);
+ change.argc = 1;
+ change.args[0].mode = MODE_CHANOP;
+ change.args[0].member = AddChannelUser(chanserv, cNode);
+ mod_chanmode_announce(chanserv, cNode, &change);
+
+ } else if (suspended->expires > now) {
+ timeq_add(suspended->expires, chanserv_expire_suspension, suspended);
+ }
}
str = database_get_data(channel, KEY_REGISTERED, RECDB_QSTRING);
&& (argc = split_line(str, 0, ArrayLength(argv), argv))
&& (modes = mod_chanmode_parse(cNode, argv, argc, MCP_KEY_FREE))) {
cData->modes = *modes;
+ if(off_channel && !(REGISTERED_MODE == 0))
+ cData->modes.modes_set |= REGISTERED_MODE;
if(cData->modes.argc > 1)
cData->modes.argc = 1;
if(!IsSuspended(cData))
dict_set_free_data(note_types, chanserv_deref_note_type);
if(nick)
{
- chanserv = AddService(nick, "Channel Services");
- service_register(chanserv, '!');
+ chanserv = AddService(nick, "Channel Services", NULL);
+ service_register(chanserv)->trigger = '!';
reg_chanmsg_func('\001', chanserv, chanserv_ctcp_check);
}
saxdb_register("ChanServ", chanserv_saxdb_read, chanserv_saxdb_write);