{ "CSMSG_PEEK_INFO", "$b%s$b Status:" },
{ "CSMSG_PEEK_TOPIC", "$bTopic: $b%s" },
{ "CSMSG_PEEK_MODES", "$bModes: $b%s" },
- { "CSMSG_PEEK_USERS", "$bTotal users: $b%d" },
+ { "CSMSG_PEEK_USERS", "$bTotal users: $b%d (%d ops, %d voices, %d regulars)" },
{ "CSMSG_PEEK_OPS", "$bOps:$b" },
{ "CSMSG_PEEK_NO_OPS", "$bOps: $bNone present" },
}
static void
-expire_channels(UNUSED_ARG(void *data))
+expire_channels(void *data)
{
struct chanData *channel, *next;
struct userData *user;
/* Make sure there are no high-ranking users still in the channel. */
for(user=channel->users; user; user=user->next)
- if(user->present && (user->access >= UL_PRESENT))
+ if(user->present && (user->access >= UL_PRESENT) && !HANDLE_FLAGGED(user->handle, BOT))
break;
if(user)
continue;
unregister_channel(channel, "registration expired.");
}
- if(chanserv_conf.channel_expire_frequency)
+ if(chanserv_conf.channel_expire_frequency && !data)
timeq_add(now + chanserv_conf.channel_expire_frequency, expire_channels, NULL);
}
target->channel_info->channel = target;
channel->channel_info = NULL;
+ /* Check whether users are present in the new channel. */
+ for(uData = target->channel_info->users; uData; uData = uData->next)
+ scan_user_presence(uData, NULL);
+
reply("CSMSG_MOVE_SUCCESS", target->name);
sprintf(reason, "%s moved to %s by %s.", channel->name, target->name, user->handle_info->handle);
choice = (suData->seen > tuData->seen) ? suData : tuData;
else /* Otherwise, keep the higher access level. */
choice = (suData->access > tuData->access) ? suData : tuData;
+ /* Use the later seen time. */
+ if(suData->seen < tuData->seen)
+ suData->seen = tuData->seen;
+ else
+ tuData->seen = suData->seen;
/* Remove the user that wasn't picked. */
if(choice == tuData)
/* Update the user counts for the target channel; the
source counts are left alone. */
target->userCount++;
+
+ /* Check whether the user is in the target channel. */
+ scan_user_presence(suData, NULL);
}
/* Possible to assert (source->users == NULL) here. */
return 0;
}
- if((actor->access <= max_access) && !IsHelping(user))
+ if(actor->access <= max_access)
{
reply("CSMSG_NO_ACCESS");
return 0;
unsigned int count;
unsigned long limit;
- actor = GetChannelAccess(channel->channel_info, user->handle_info);
+ actor = GetChannelUser(channel->channel_info, user->handle_info);
if(min_access > max_access)
{
send_message(user, chanserv, "CSMSG_BAD_RANGE", min_access, max_access);
else if(!is_ircmask(argv[1]) && (*argv[1] == '*'))
{
struct handle_info *hi;
+ extern const char *titlehost_suffix;
char banmask[NICKLEN + USERLEN + HOSTLEN + 3];
const char *accountname = argv[1] + 1;
return 0;
}
- snprintf(banmask, sizeof(banmask), "*!*@%s.*", hi->handle);
+ snprintf(banmask, sizeof(banmask), "*!*@%s.*.%s", hi->handle, titlehost_suffix);
victims = alloca(sizeof(victims[0]) * channel->members.used);
if(bad_channel_ban(channel, user, banmask, &victimCount, victims))
return 1;
}
-static void
-zoot_list(struct listData *list)
-{
- struct userData *uData;
- unsigned int start, curr, highest, lowest;
- struct helpfile_table tmp_table;
- const char **temp, *msg;
-
- if(list->table.length == 1)
- {
- if(list->search)
- send_message(list->user, list->bot, "CSMSG_ACCESS_SEARCH_HEADER", list->channel->name, list->lowest, list->highest, list->search);
- else
- send_message(list->user, list->bot, "CSMSG_ACCESS_ALL_HEADER", list->channel->name, list->lowest, list->highest);
- msg = user_find_message(list->user, "MSG_NONE");
- send_message_type(4, list->user, list->bot, " %s", msg);
- }
- tmp_table.width = list->table.width;
- tmp_table.flags = list->table.flags;
- list->table.contents[0][0] = " ";
- highest = list->highest;
- if(list->lowest != 0)
- lowest = list->lowest;
- else if(highest < 100)
- lowest = 1;
- else
- lowest = highest - 100;
- for(start = curr = 1; curr < list->table.length; )
- {
- uData = list->users[curr-1];
- list->table.contents[curr++][0] = " ";
- if((curr == list->table.length) || (list->users[curr-1]->access < lowest))
- {
- if(list->search)
- send_message(list->user, list->bot, "CSMSG_ACCESS_SEARCH_HEADER", list->channel->name, lowest, highest, list->search);
- else
- send_message(list->user, list->bot, "CSMSG_ACCESS_ALL_HEADER", list->channel->name, lowest, highest);
- temp = list->table.contents[--start];
- list->table.contents[start] = list->table.contents[0];
- tmp_table.contents = list->table.contents + start;
- tmp_table.length = curr - start;
- table_send(list->bot, list->user->nick, 0, NULL, tmp_table);
- list->table.contents[start] = temp;
- start = curr;
- highest = lowest - 1;
- lowest = (highest < 100) ? 0 : (highest - 99);
- }
- }
-}
-
static void
def_list(struct listData *list)
{
lData.highest = highest;
lData.search = (argc > 1) ? argv[1] : NULL;
send_list = def_list;
- (void)zoot_list; /* since it doesn't show user levels */
if(user->handle_info)
{
ary[3] = "Suspended";
else if(HANDLE_FLAGGED(uData->handle, FROZEN))
ary[3] = "Vacation";
+ else if(HANDLE_FLAGGED(uData->handle, BOT))
+ ary[3] = "Bot";
else
ary[3] = "Normal";
}
struct userData *uData;
struct mod_chanmode *change;
short base_oplevel;
+ char fmt[MAXLEN];
if(argc < 2)
{
base_oplevel = 1;
else
base_oplevel = 1 + UL_OWNER - uData->access;
- change = mod_chanmode_parse(channel, argv+1, argc-1, MCP_KEY_FREE|MCP_REGISTERED, base_oplevel);
+ change = mod_chanmode_parse(channel, argv+1, argc-1, MCP_KEY_FREE|MCP_REGISTERED|MCP_NO_APASS, base_oplevel);
if(!change)
{
reply("MSG_INVALID_MODES", unsplit_string(argv+1, argc-1, NULL));
}
modcmd_chanmode_announce(change);
+ mod_chanmode_format(change, fmt);
mod_chanmode_free(change);
- reply("CSMSG_MODES_SET", unsplit_string(argv+1, argc-1, NULL));
+ reply("CSMSG_MODES_SET", fmt);
return 1;
}
static CHANSERV_FUNC(cmd_invite)
{
- struct userData *uData;
struct userNode *invite;
- uData = GetChannelUser(channel->channel_info, user->handle_info);
-
if(argc > 1)
{
if(!(invite = GetUserH(argv[1])))
char modes[MODELEN];
unsigned int n;
struct helpfile_table table;
+ int opcount = 0, voicecount = 0, srvcount = 0;
irc_make_chanmode(channel, modes);
reply("CSMSG_PEEK_INFO", channel->name);
reply("CSMSG_PEEK_TOPIC", channel->topic);
reply("CSMSG_PEEK_MODES", modes);
- reply("CSMSG_PEEK_USERS", channel->members.used);
table.length = 0;
table.width = 1;
for(n = 0; n < channel->members.used; n++)
{
mn = channel->members.list[n];
+ if(IsLocal(mn->user))
+ srvcount++;
+ else if(mn->modes & MODE_CHANOP)
+ opcount++;
+ else if(mn->modes & MODE_VOICE)
+ voicecount++;
+
if(!(mn->modes & MODE_CHANOP) || IsLocal(mn->user))
continue;
table.contents[table.length] = alloca(sizeof(**table.contents));
table.contents[table.length][0] = mn->user->nick;
table.length++;
}
+
+ reply("CSMSG_PEEK_USERS", channel->members.used, opcount, voicecount,
+ (channel->members.used - opcount - voicecount - srvcount));
+
if(table.length)
{
reply("CSMSG_PEEK_OPS");
static CHANSERV_FUNC(cmd_expire)
{
int channel_count = registered_channels;
- expire_channels(NULL);
+ expire_channels(chanserv);
reply("CSMSG_CHANNELS_EXPIRED", channel_count - registered_channels);
return 1;
}
static MODCMD_FUNC(chan_opt_modes)
{
struct mod_chanmode *new_modes;
- char modes[MODELEN];
+ char modes[MAXLEN];
if(argc > 1)
{
{
memset(&channel->channel_info->modes, 0, sizeof(channel->channel_info->modes));
}
- else if(!(new_modes = mod_chanmode_parse(channel, argv+1, argc-1, MCP_KEY_FREE|MCP_REGISTERED, 0)))
+ else if(!(new_modes = mod_chanmode_parse(channel, argv+1, argc-1, MCP_KEY_FREE|MCP_REGISTERED|MCP_NO_APASS, 0)))
{
reply("CSMSG_INVALID_MODE_LOCK", unsplit_string(argv+1, argc-1, NULL));
return 0;
}
}
- /* ChanServ will not modify the limits in join-flooded channels.
- It will also skip DynLimit processing when the user (or srvx)
- is bursting in, because there are likely more incoming. */
+ /* ChanServ will not modify the limits in join-flooded channels,
+ or when there are enough slots left below the limit. */
if((cData->flags & CHANNEL_DYNAMIC_LIMIT)
- && !user->uplink->burst
&& !channel->join_flooded
&& (channel->limit - channel->members.used) < chanserv_conf.adjust_threshold)
{
else if(uData->access >= cData->lvlOpts[lvlGiveVoice])
modes |= MODE_VOICE;
}
- if(uData->access >= UL_PRESENT)
+ if(uData->access >= UL_PRESENT && !HANDLE_FLAGGED(uData->handle, BOT))
cData->visited = now;
if(cData->user_greeting)
greeting = cData->user_greeting;
}
if(greeting)
send_message_type(4, user, chanserv, "(%s) %s", channel->name, greeting);
- if(uData && info)
+ if(uData && info && (modes || !(channel->modes & MODE_DELAYJOINS)))
send_target_message(5, channel->name, chanserv, "[%s] %s", user->nick, uData->info);
}
return 0;
continue;
}
- if(channel->access >= UL_PRESENT)
+ if(channel->access >= UL_PRESENT && !HANDLE_FLAGGED(channel->handle, BOT))
channel->channel->visited = now;
if(IsUserAutoOp(channel))
{
scan_user_presence(uData, mn->user);
uData->seen = now;
- if (uData->access >= UL_PRESENT)
+ if (uData->access >= UL_PRESENT && !HANDLE_FLAGGED(uData->handle, BOT))
cData->visited = now;
}
str = "+nt";
safestrncpy(mode_line, str, sizeof(mode_line));
ii = split_line(mode_line, 0, ArrayLength(modes), modes);
- if((change = mod_chanmode_parse(NULL, modes, ii, MCP_KEY_FREE, 0))
+ if((change = mod_chanmode_parse(NULL, modes, ii, MCP_KEY_FREE|MCP_NO_APASS, 0))
&& (change->argc < 2))
{
chanserv_conf.default_modes = *change;
static void
ban_read_helper(const char *key, struct record_data *rd, struct chanData *chan)
{
- struct banData *bData;
char *set, *triggered, *s_duration, *s_expires, *reason, *owner;
unsigned long set_time, triggered_time, expires_time;
if(!reason || (expires_time && (expires_time < now)))
return;
- bData = add_channel_ban(chan, key, owner, set_time, triggered_time, expires_time, reason);
+ add_channel_ban(chan, key, owner, set_time, triggered_time, expires_time, reason);
}
static struct suspended *
if(!IsSuspended(cData)
&& (str = database_get_data(channel, KEY_MODES, RECDB_QSTRING))
&& (argc = split_line(str, 0, ArrayLength(argv), argv))
- && (modes = mod_chanmode_parse(cNode, argv, argc, MCP_KEY_FREE, 0))) {
+ && (modes = mod_chanmode_parse(cNode, argv, argc, MCP_KEY_FREE|MCP_NO_APASS, 0))) {
cData->modes = *modes;
if(off_channel > 0)
cData->modes.modes_set |= MODE_REGISTERED;
saxdb_start_record(ctx, KEY_USERS, 1);
for(; uData; uData = uData->next)
{
- if((uData->access >= UL_PRESENT) && uData->present)
+ if((uData->access >= UL_PRESENT) && uData->present && !HANDLE_FLAGGED(uData->handle, BOT))
high_present = 1;
saxdb_start_record(ctx, uData->handle->handle, 0);
saxdb_write_int(ctx, KEY_LEVEL, uData->access);
DEFINE_COMMAND(unf, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
DEFINE_COMMAND(ping, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
DEFINE_COMMAND(wut, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
- DEFINE_COMMAND(8ball, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
- DEFINE_COMMAND(d, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
+ DEFINE_COMMAND(8ball, 2, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
+ DEFINE_COMMAND(d, 2, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
DEFINE_COMMAND(huggle, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
/* Channel options */