#define KEY_MAX_USERINFO_LENGTH "max_userinfo_length"
#define KEY_GIVEOWNERSHIP_PERIOD "giveownership_timeout"
#define KEY_INVITED_INTERVAL "invite_timeout"
+#define KEY_REVOKE_MODE_A "revoke_mode_a"
#define KEY_NEW_CHANNEL_AUTHED "new_channel_authed_join"
#define KEY_NEW_CHANNEL_UNAUTHED "new_channel_unauthed_join"
#define KEY_NEW_CHANNEL_MSG "new_channel_message"
#define KEY_REVOKED "revoked"
#define KEY_SUSPEND_EXPIRES "suspend_expires"
#define KEY_SUSPEND_REASON "suspend_reason"
+#define KEY_GIVEOWNERSHIP "giveownership"
+#define KEY_STAFF_ISSUER "staff_issuer"
+#define KEY_OLD_OWNER "old_owner"
+#define KEY_TARGET "target"
+#define KEY_TARGET_ACCESS "target_access"
#define KEY_VISITED "visited"
#define KEY_TOPIC "topic"
#define KEY_GREETING "greeting"
{ "CSMSG_CHANNEL_REGISTERED", "$bRegistered: $b%s ago." },
{ "CSMSG_CHANNEL_VISITED", "$bVisited: $b%s ago." },
+ { "CSMSG_CHANNEL_OWNERSHIP_HISTORY", "Ownership transfer history for %s" },
+ { "CSMSG_CHANNEL_OWNERSHIP_STAFF_REASON", " from %s to %s (%d access) by %s on %s (Reason: %s)" },
+ { "CSMSG_CHANNEL_OWNERSHIP_STAFF", " from %s to %s (%d access) by %s on %s" },
+ { "CSMSG_CHANNEL_OWNERSHIP_NORMAL", " from %s to %s (%d access) on %s" },
+
{ "CSMSG_PEEK_INFO", "$b%s$b Status:" },
{ "CSMSG_PEEK_TOPIC", "$bTopic: $b%s" },
{ "CSMSG_PEEK_MODES", "$bModes: $b%s" },
unsigned int max_chan_users;
unsigned int max_chan_bans;
unsigned int max_userinfo_length;
+
+ unsigned int revoke_mode_a;
struct string_list *set_shows;
struct string_list *eightball;
timeq_del(0, NULL, channel, TIMEQ_IGNORE_FUNC | TIMEQ_IGNORE_WHEN);
- if(off_channel > 0)
- {
- mod_chanmode_init(&change);
- change.modes_clear |= MODE_REGISTERED;
- mod_chanmode_announce(chanserv, channel->channel, &change);
+ if(off_channel > 0 || chanserv_conf.revoke_mode_a) {
+ mod_chanmode_init(&change);
+ if(off_channel > 0)
+ change.modes_clear |= MODE_REGISTERED;
+ if(chanserv_conf.revoke_mode_a)
+ change.modes_clear |= MODE_ACCESS;
+ mod_chanmode_announce(chanserv, channel->channel, &change);
}
while(channel->users)
}
static void
-expire_channels(UNUSED_ARG(void *data))
+expire_channels(void *data)
{
struct chanData *channel, *next;
struct userData *user;
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);
}
return 0;
}
- if(IsProtected(cData))
+ if(IsProtected(cData) && !IsOper(user))
{
reply("CSMSG_UNREG_NODELETE", channel->name);
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);
static CHANSERV_FUNC(cmd_opme)
{
struct mod_chanmode change;
- struct userData *uData;
const char *errmsg;
mod_chanmode_init(&change);
{
struct chanData *cData = uData->channel;
ccount++;
+ unsigned int base_len;
if(uData->access > UL_OWNER)
continue;
&& !IsNetworkHelper(user))
continue;
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, ',');
+ string_buffer_append_printf(&sbuf, "[%s (%d,", cData->channel->name, uData->access);
+ base_len = sbuf.used;
if(IsUserSuspended(uData))
string_buffer_append(&sbuf, 's');
if(IsUserAutoOp(uData))
}
if(IsUserAutoInvite(uData) && (uData->access >= cData->lvlOpts[lvlInviteMe]))
string_buffer_append(&sbuf, 'i');
+ if(sbuf.used==base_len)
+ sbuf.used--;
if(uData->info)
string_buffer_append_printf(&sbuf, ")] %s", uData->info);
else
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)
{
static CHANSERV_FUNC(cmd_invite)
{
- struct userData *uData;
struct userNode *invite;
struct ChanUser *chanuser;
unsigned int i;
- uData = GetChannelUser(channel->channel_info, user->handle_info);
-
if(argc > 1)
{
if(!(invite = GetUserH(argv[1])))
}
}
+static void
+show_giveownership_info(struct svccmd *cmd, struct userNode *user, struct giveownership *giveownership)
+{
+ char buf[MAXLEN];
+ const char *fmt = "%a %b %d %H:%M %Y";
+ strftime(buf, sizeof(buf), fmt, localtime(&giveownership->issued));
+
+ if(giveownership->staff_issuer)
+ {
+ if(giveownership->reason)
+ reply("CSMSG_CHANNEL_OWNERSHIP_STAFF_REASON", giveownership->old_owner,
+ giveownership->target, giveownership->target_access,
+ giveownership->staff_issuer, buf, giveownership->reason);
+ else
+ reply("CSMSG_CHANNEL_OWNERSHIP_STAFF", giveownership->old_owner,
+ giveownership->target, giveownership->target_access,
+ giveownership->staff_issuer, buf);
+ }
+ else
+ {
+ reply("CSMSG_CHANNEL_OWNERSHIP_NORMAL", giveownership->old_owner, giveownership->target, giveownership->target_access, buf);
+ }
+}
+
static CHANSERV_FUNC(cmd_info)
{
char modes[MAXLEN], buffer[INTERVALLEN];
reply("CSMSG_CHANNEL_SUSPENDED", channel->name);
show_suspension_info(cmd, user, cData->suspended);
}
+
+ if(cData->giveownership && ((uData && (uData->access >= UL_COOWNER)) || IsStaff(user)))
+ {
+ struct giveownership *giveownership;
+ reply("CSMSG_CHANNEL_OWNERSHIP_HISTORY", channel->name);
+ for(giveownership = cData->giveownership; giveownership; giveownership = giveownership->previous)
+ show_giveownership_info(cmd, user, giveownership);
+ }
return 1;
}
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;
}
struct chanData *cData = channel->channel_info;
struct do_not_register *dnr;
const char *confirm;
- unsigned int force;
- unsigned short co_access;
- char reason[MAXLEN];
+ struct giveownership *giveownership;
+ unsigned int force, override;
+ unsigned short co_access, new_owner_old_access;
+ char reason[MAXLEN], transfer_reason[MAXLEN];
REQUIRE_PARAMS(2);
curr_user = GetChannelAccess(cData, user->handle_info);
force = IsHelping(user) && (argc > 2) && !irccasecmp(argv[2], "force");
+
+ struct userData *uData = _GetChannelUser(channel->channel_info, user->handle_info, 1, 0);
+ override = ((cmd->effective_flags & MODCMD_REQUIRE_CHANUSER)
+ && (uData->access > 500)
+ && (!(uData = _GetChannelUser(channel->channel_info, user->handle_info, 0, 0))
+ || uData->access < 500));
+
if(!curr_user || (curr_user->access != UL_OWNER))
{
struct userData *owner = NULL;
return 0;
}
}
+ new_owner_old_access = new_owner->access;
if(new_owner->access >= UL_COOWNER)
co_access = new_owner->access;
else
if(curr_user)
curr_user->access = co_access;
cData->ownerTransfer = now;
+ giveownership = calloc(1, sizeof(*giveownership));
+ giveownership->issued = now;
+ giveownership->old_owner = curr_user->handle->handle;
+ giveownership->target = new_owner_hi->handle;
+ giveownership->target_access = new_owner_old_access;
+ if(override)
+ {
+ if(argc > (2 + force))
+ {
+ unsplit_string(argv + 2 + force, argc - 2 - force, transfer_reason);
+ giveownership->reason = strdup(transfer_reason);
+ }
+ giveownership->staff_issuer = strdup(user->handle_info->handle);
+ }
+
+ giveownership->previous = channel->channel_info->giveownership;
+ channel->channel_info->giveownership = giveownership;
reply("CSMSG_OWNERSHIP_GIVEN", channel->name, new_owner_hi->handle);
sprintf(reason, "%s ownership transferred to %s by %s.", channel->name, new_owner_hi->handle, user->handle_info->handle);
global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
chanserv_conf.dnr_expire_frequency = str ? ParseInterval(str) : 3600;
str = database_get_data(conf_node, KEY_INVITED_INTERVAL, RECDB_QSTRING);
chanserv_conf.invited_timeout = str ? ParseInterval(str) : 600*2;
+ str = database_get_data(conf_node, KEY_REVOKE_MODE_A, RECDB_QSTRING);
+ chanserv_conf.revoke_mode_a = str ? atoi(str) : 1;
str = database_get_data(conf_node, KEY_NODELETE_LEVEL, RECDB_QSTRING);
chanserv_conf.nodelete_level = str ? atoi(str) : 1;
str = database_get_data(conf_node, KEY_MAX_CHAN_USERS, RECDB_QSTRING);
str = database_get_data(conf_node, KEY_SUPPORT_HELPER_EPITHET, RECDB_QSTRING);
chanserv_conf.support_helper_epithet = str ? str : "a wannabe tyrant";
str = database_get_data(conf_node, KEY_NEW_CHANNEL_AUTHED, RECDB_QSTRING);
- chanserv_conf.new_channel_authed = str ? str : NULL;
+ chanserv_conf.new_channel_authed = (str && *str) ? str : NULL;
str = database_get_data(conf_node, KEY_NEW_CHANNEL_UNAUTHED, RECDB_QSTRING);
- chanserv_conf.new_channel_unauthed = str ? str : NULL;
+ chanserv_conf.new_channel_unauthed = (str && *str) ? str : NULL;
str = database_get_data(conf_node, KEY_NEW_CHANNEL_MSG, RECDB_QSTRING);
- chanserv_conf.new_channel_msg = str ? str : NULL;
+ chanserv_conf.new_channel_msg = (str && *str) ? str : NULL;
str = database_get_data(conf_node, "default_modes", RECDB_QSTRING);
if(!str)
str = "+nt";
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 *
return suspended;
}
+static struct giveownership *
+chanserv_read_giveownership(dict_t obj)
+{
+ struct giveownership *giveownership = calloc(1, sizeof(*giveownership));
+ char *str;
+ dict_t previous;
+
+ str = database_get_data(obj, KEY_STAFF_ISSUER, RECDB_QSTRING);
+ giveownership->staff_issuer = str ? strdup(str) : NULL;
+
+ giveownership->old_owner = strdup(database_get_data(obj, KEY_OLD_OWNER, RECDB_QSTRING));
+
+ giveownership->target = strdup(database_get_data(obj, KEY_TARGET, RECDB_QSTRING));
+ giveownership->target_access = atoi(database_get_data(obj, KEY_TARGET_ACCESS, RECDB_QSTRING));
+
+ str = database_get_data(obj, KEY_REASON, RECDB_QSTRING);
+ giveownership->reason = str ? strdup(str) : NULL;
+ str = database_get_data(obj, KEY_ISSUED, RECDB_QSTRING);
+ giveownership->issued = str ? (time_t)strtoul(str, NULL, 0) : 0;
+
+ previous = database_get_data(obj, KEY_PREVIOUS, RECDB_OBJECT);
+ giveownership->previous = previous ? chanserv_read_giveownership(previous) : NULL;
+ return giveownership;
+}
+
static int
chanserv_channel_read(const char *key, struct record_data *hir)
{
struct suspended *suspended;
+ struct giveownership *giveownership;
struct mod_chanmode *modes;
struct chanNode *cNode;
struct chanData *cData;
cData->flags &= ~CHANNEL_SUSPENDED;
}
+ if((obj = database_get_data(hir->d.object, KEY_GIVEOWNERSHIP, RECDB_OBJECT)))
+ {
+ giveownership = chanserv_read_giveownership(obj);
+ cData->giveownership = giveownership;
+ }
+
if((!off_channel || !IsOffChannel(cData)) && !IsSuspended(cData)) {
struct mod_chanmode change;
mod_chanmode_init(&change);
saxdb_end_record(ctx);
}
+static void
+chanserv_write_giveownership(struct saxdb_context *ctx, const char *name, struct giveownership *giveownership)
+{
+ saxdb_start_record(ctx, name, 0);
+ if(giveownership->staff_issuer)
+ saxdb_write_string(ctx, KEY_STAFF_ISSUER, giveownership->staff_issuer);
+ if(giveownership->old_owner)
+ saxdb_write_string(ctx, KEY_OLD_OWNER, giveownership->old_owner);
+ if(giveownership->target)
+ saxdb_write_string(ctx, KEY_TARGET, giveownership->target);
+ if(giveownership->target_access)
+ saxdb_write_int(ctx, KEY_TARGET_ACCESS, giveownership->target_access);
+ if(giveownership->reason)
+ saxdb_write_string(ctx, KEY_REASON, giveownership->reason);
+ if(giveownership->issued)
+ saxdb_write_int(ctx, KEY_ISSUED, giveownership->issued);
+ if(giveownership->previous)
+ chanserv_write_giveownership(ctx, KEY_PREVIOUS, giveownership->previous);
+ saxdb_end_record(ctx);
+}
+
static void
chanserv_write_channel(struct saxdb_context *ctx, struct chanData *channel)
{
saxdb_write_string(ctx, KEY_TOPIC_MASK, channel->topic_mask);
if(channel->suspended)
chanserv_write_suspended(ctx, "suspended", channel->suspended);
+ if(channel->giveownership)
+ chanserv_write_giveownership(ctx, "giveownership", channel->giveownership);
if(channel->expiry)
saxdb_write_int(ctx, KEY_EXPIRE, channel->expiry);
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);
- DEFINE_COMMAND(addvote, 1, MODCMD_REQUIRE_AUTHED, NULL);
- DEFINE_COMMAND(delvote, 1, MODCMD_REQUIRE_AUTHED, NULL);
- DEFINE_COMMAND(addoption, 1, MODCMD_REQUIRE_AUTHED, NULL);
- DEFINE_COMMAND(deloption, 1, MODCMD_REQUIRE_AUTHED, NULL);
- DEFINE_COMMAND(vote, 1, MODCMD_REQUIRE_AUTHED, NULL);
- DEFINE_COMMAND(startvote, 1, MODCMD_REQUIRE_AUTHED, NULL);
- DEFINE_COMMAND(endvote, 1, MODCMD_REQUIRE_AUTHED, NULL);
- DEFINE_COMMAND(voteresults, 1, MODCMD_REQUIRE_AUTHED, NULL);
+ DEFINE_COMMAND(addvote, 1, MODCMD_REQUIRE_AUTHED | MODCMD_REQUIRE_REGCHAN, NULL);
+ DEFINE_COMMAND(delvote, 1, MODCMD_REQUIRE_AUTHED | MODCMD_REQUIRE_REGCHAN, NULL);
+ DEFINE_COMMAND(addoption, 1, MODCMD_REQUIRE_AUTHED | MODCMD_REQUIRE_REGCHAN, NULL);
+ DEFINE_COMMAND(deloption, 1, MODCMD_REQUIRE_AUTHED | MODCMD_REQUIRE_REGCHAN, NULL);
+ DEFINE_COMMAND(vote, 1, MODCMD_REQUIRE_AUTHED | MODCMD_REQUIRE_REGCHAN, NULL);
+ DEFINE_COMMAND(startvote, 1, MODCMD_REQUIRE_AUTHED | MODCMD_REQUIRE_REGCHAN, NULL);
+ DEFINE_COMMAND(endvote, 1, MODCMD_REQUIRE_AUTHED | MODCMD_REQUIRE_REGCHAN, NULL);
+ DEFINE_COMMAND(voteresults, 1, MODCMD_REQUIRE_AUTHED | MODCMD_REQUIRE_REGCHAN, NULL);
DEFINE_COMMAND(opme, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);