{ "CSMSG_MULTIPLE_OWNERS", "There is more than one owner in %s; please use $bCLVL$b, $bDELOWNER$b and/or $bADDOWNER$b instead." },
{ "CSMSG_TRANSFER_WAIT", "You must wait %s before you can give ownership of $b%s$b to someone else." },
{ "CSMSG_NO_TRANSFER_SELF", "You cannot give ownership to your own account." },
+ { "CSMSG_CONFIRM_GIVEOWNERSHIP", "To really give ownership to $b%1$s$b, you must use 'giveownership %1$s %2$s'." },
{ "CSMSG_OWNERSHIP_GIVEN", "Ownership of $b%s$b has been transferred to account $b%s$b." },
/* Ban management */
{ "CSMSG_TOPIC_SET", "Topic is now '%s'." },
{ "CSMSG_NO_TOPIC", "$b%s$b does not have a default topic." },
{ "CSMSG_TOPICMASK_CONFLICT1", "I do not know how to make that topic work with the current topic mask in $b%s$b, which is: %s" },
- { "CSMSG_TOPICMASK_CONFLICT2", "Please make sure your topic at most %d characters and matches the topic mask pattern." },
+ { "CSMSG_TOPICMASK_CONFLICT2", "Please make sure your topic is at most %d characters and matches the topic mask pattern." },
{ "CSMSG_TOPIC_LOCKED", "The %s topic is locked." },
{ "CSMSG_MASK_BUT_NO_TOPIC", "Warning: $b%s$b does not have a default topic, but you just set the topic mask." },
{ "CSMSG_TOPIC_MISMATCH", "Warning: The default topic for $b%s$b does not match the topic mask; changing it anyway." },
/* Channel configuration */
{ "CSMSG_INVALID_OPTION", "$b%s$b is not a valid %s option." },
+ { "CSMSG_INVALID_CFLAG", "$b%s$b is not a recognized channel flag." },
{ "CSMSG_CHANNEL_OPTIONS", "Channel Options:" },
{ "CSMSG_GREETING_TOO_LONG", "Your greeting ($b%d$b characters) must be shorter than $b%d$b characters." },
}
static int
-cmd_trim_users(struct userNode *user, struct chanNode *channel, unsigned short min_access, unsigned short max_access, unsigned long duration)
+cmd_trim_users(struct userNode *user, struct chanNode *channel, unsigned short min_access, unsigned short max_access, unsigned long duration, int vacation)
{
struct userData *actor, *uData, *next;
char interval[INTERVALLEN];
{
next = uData->next;
- if((uData->seen > limit) || uData->present)
+ if((uData->seen > limit)
+ || uData->present
+ || (HANDLE_FLAGGED(uData->handle, FROZEN) && !vacation))
continue;
if(((uData->access >= min_access) && (uData->access <= max_access))
{
unsigned long duration;
unsigned short min_level, max_level;
+ int vacation;
REQUIRE_PARAMS(3);
+ vacation = argc > 3 && !strcmp(argv[3], "vacation");
duration = ParseInterval(argv[2]);
if(duration < 60)
{
}
else if(!irccasecmp(argv[1], "users"))
{
- cmd_trim_users(user, channel, 0, 0, duration);
+ cmd_trim_users(user, channel, 0, 0, duration, vacation);
return 1;
}
else if(parse_level_range(&min_level, &max_level, argv[1]))
{
- cmd_trim_users(user, channel, min_level, max_level, duration);
+ cmd_trim_users(user, channel, min_level, max_level, duration, vacation);
return 1;
}
else if((min_level = user_level_from_name(argv[1], UL_OWNER)))
{
- cmd_trim_users(user, channel, min_level, min_level, duration);
+ cmd_trim_users(user, channel, min_level, min_level, duration, vacation);
return 1;
}
else
static CHANSERV_FUNC(cmd_bans)
{
+ struct userNode *search_u = NULL;
struct helpfile_table tbl;
- unsigned int matches = 0, timed = 0, ii;
+ unsigned int matches = 0, timed = 0, search_wilds = 0, ii;
char t_buffer[INTERVALLEN], e_buffer[INTERVALLEN], *search;
const char *msg_never, *triggered, *expires;
struct banData *ban, **bans;
- if(argc > 1)
- search = argv[1];
- else
+ if(argc < 2)
search = NULL;
+ else if(strchr(search = argv[1], '!'))
+ {
+ search = argv[1];
+ search_wilds = search[strcspn(search, "?*")];
+ }
+ else if(!(search_u = GetUserH(search)))
+ reply("MSG_NICK_UNKNOWN", search);
bans = alloca(channel->channel_info->banCount * sizeof(struct banData *));
for(ban = channel->channel_info->bans; ban; ban = ban->next)
{
- if(search && !match_ircglobs(search, ban->mask))
- continue;
+ if(search_u)
+ {
+ if(!user_matches_glob(search_u, ban->mask, MATCH_USENICK | MATCH_VISIBLE))
+ continue;
+ }
+ else if(search)
+ {
+ if(search_wilds ? !match_ircglobs(search, ban->mask) : !match_ircglob(search, ban->mask))
+ continue;
+ }
bans[matches++] = ban;
if(ban->expires)
timed = 1;
struct userData *new_owner, *curr_user;
struct chanData *cData = channel->channel_info;
struct do_not_register *dnr;
+ const char *confirm;
unsigned int force;
unsigned short co_access;
char reason[MAXLEN];
chanserv_show_dnrs(user, cmd, NULL, new_owner_hi->handle);
return 0;
}
+ confirm = make_confirmation_string(curr_user);
+ if(!force && ((argc < 3) || strcmp(argv[2], confirm)))
+ {
+ reply("CSMSG_CONFIRM_GIVEOWNERSHIP", new_owner_hi->handle, confirm);
+ return 0;
+ }
if(new_owner->access >= UL_COOWNER)
co_access = new_owner->access;
else
unsigned int ii;
for(ii = 0; ii < channel->banlist.used; ii++)
{
- if(user_matches_glob(user, channel->banlist.list[ii]->ban, MATCH_USENICK | MATCH_VISIBLE))
+ if(user_matches_glob(user, channel->banlist.list[ii]->ban, MATCH_USENICK))
{
/* Riding a netburst. Naughty. */
KickChannelUser(user, channel, chanserv, "User from far side of netsplit should have been banned - bye.");
{
/* Not joining through a ban. */
for(bData = cData->bans;
- bData && !user_matches_glob(user, bData->mask, MATCH_USENICK | MATCH_VISIBLE);
+ bData && !user_matches_glob(user, bData->mask, MATCH_USENICK);
bData = bData->next);
if(bData)
uData->present = 1;
}
}
+
+ /* If user joining normally (not during burst), apply op or voice,
+ * and send greeting/userinfo as appropriate.
+ */
if(!user->uplink->burst)
{
if(modes)
change.args[0].u.member = mNode;
mod_chanmode_announce(chanserv, channel, &change);
}
- if(greeting && !user->uplink->burst)
+ if(greeting)
send_message_type(4, user, chanserv, "(%s) %s", channel->name, greeting);
if(uData && info)
send_target_message(5, channel->name, chanserv, "[%s] %s", user->nick, uData->info);
|| IsSuspended(channel->channel_info))
continue;
for(jj = 0; jj < channel->banlist.used; ++jj)
- if(user_matches_glob(user, channel->banlist.list[jj]->ban, MATCH_USENICK | MATCH_VISIBLE))
+ if(user_matches_glob(user, channel->banlist.list[jj]->ban, MATCH_USENICK))
break;
if(jj < channel->banlist.used)
continue;
continue;
/* Look for a matching ban already on the channel. */
for(jj = 0; jj < channel->banlist.used; ++jj)
- if(user_matches_glob(user, channel->banlist.list[jj]->ban, MATCH_USENICK | MATCH_VISIBLE))
+ if(user_matches_glob(user, channel->banlist.list[jj]->ban, MATCH_USENICK))
break;
/* Need not act if we found one. */
if(jj < channel->banlist.used)