X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/aa222db2f6f30aaca4ea75578a8d72a4000f1901..c8ca69a02e41114aa1303505df301df5f4fd686c:/src/chanserv.c?ds=sidebyside diff --git a/src/chanserv.c b/src/chanserv.c index b29c0a4..24b061b 100644 --- a/src/chanserv.c +++ b/src/chanserv.c @@ -56,9 +56,13 @@ #define KEY_GIVEOWNERSHIP_PERIOD "giveownership_timeout" /* ChanServ database */ +#define KEY_VERSION_CONTROL "version_control" #define KEY_CHANNELS "channels" #define KEY_NOTE_TYPES "note_types" +/* version control paramiter */ +#define KEY_VERSION_NUMBER "version_number" + /* Note type parameters */ #define KEY_NOTE_OPSERV_ACCESS "opserv_access" #define KEY_NOTE_CHANNEL_ACCESS "channel_access" @@ -242,9 +246,11 @@ static const struct message_entry msgtab[] = { { "CSMSG_CONFIRM_DEFAULTS", "To reset %s's settings to the defaults, you must use 'set defaults %s'." }, { "CSMSG_SETTINGS_DEFAULTED", "All settings for %s have been reset to default values." }, { "CSMSG_BAD_SETLEVEL", "You cannot change any setting to above your level." }, + /* { "CSMSG_BAD_GIVEVOICE", "You cannot change GiveVoice to above GiveHalfOps (%d)." }, { "CSMSG_BAD_GIVEHOPS", "You cannot change GiveHalfOps to below GiveOps (%d)." }, { "CSMSG_BAD_GIVEOPS", "You cannot change GiveOps to below GiveVoice (%d)." }, + */ { "CSMSG_BAD_SETTERS", "You cannot change Setters to above your level." }, { "CSMSG_INVALID_MODE_LOCK", "$b%s$b is an invalid mode lock." }, { "CSMSG_INVALID_NUMERIC", "$b%d$b is not a valid choice. Choose one:" }, @@ -257,24 +263,29 @@ static const struct message_entry msgtab[] = { { "CSMSG_SET_DYNLIMIT", "$bDynLimit $b %s" }, { "CSMSG_SET_OFFCHANNEL", "$bOffChannel $b %s" }, { "CSMSG_SET_USERINFO", "$bUserInfo $b %d" }, + /* { "CSMSG_SET_GIVE_VOICE", "$bGiveVoice $b %d" }, { "CSMSG_SET_GIVE_HALFOPS", "$bGiveHalfOps $b %d" }, + */ { "CSMSG_SET_TOPICSNARF", "$bTopicSnarf $b %d" }, { "CSMSG_SET_INVITEME", "$bInviteMe $b %d" }, { "CSMSG_SET_ENFOPS", "$bEnfOps $b %d" }, { "CSMSG_SET_ENFHALFOPS", "$bEnfHalfOps $b %d" }, + /* { "CSMSG_SET_GIVE_OPS", "$bGiveOps $b %d" }, + */ { "CSMSG_SET_ENFMODES", "$bEnfModes $b %d" }, { "CSMSG_SET_ENFTOPIC", "$bEnfTopic $b %d" }, { "CSMSG_SET_PUBCMD", "$bPubCmd $b %d" }, { "CSMSG_SET_SETTERS", "$bSetters $b %d" }, { "CSMSG_SET_CTCPUSERS", "$bCTCPUsers $b %d" }, + { "CSMSG_SET_VOICE", "$bvoice $b %d - %s" }, { "CSMSG_SET_PROTECT", "$bProtect $b %d - %s" }, { "CSMSG_SET_TOYS", "$bToys $b %d - %s" }, { "CSMSG_SET_CTCPREACTION", "$bCTCPReaction$b %d - %s" }, { "CSMSG_SET_TOPICREFRESH", "$bTopicRefresh$b %d - %s" }, - { "CSMSG_USET_NOAUTOOP", "$bNoAutoOp $b %s" }, - { "CSMSG_USET_NOAUTOVOICE", "$bNoAutoVoice $b %s" }, + { "CSMSG_USET_AUTOOP", "$bAutoOp $b %s" }, + { "CSMSG_USET_AUTOVOICE", "$bAutoVoice $b %s" }, { "CSMSG_USET_AUTOINVITE", "$bAutoInvite $b %s" }, { "CSMSG_USET_INFO", "$bInfo $b %s" }, @@ -288,6 +299,9 @@ static const struct message_entry msgtab[] = { { "CSMSG_DEHALFOPPED_USERS", "DeHalfopped users in $b%s$b." }, { "CSMSG_VOICED_USERS", "Voiced users in $b%s$b." }, { "CSMSG_DEVOICED_USERS", "Devoiced users in $b%s$b." }, + { "CSMSG_VOICE_NONE", "Noone will be auto-voiced" }, + { "CSMSG_VOICE_PEON", "PEONs will be auto-voiced" }, + { "CSMSG_VOICE_ALL", "Everyone will be auto-voiced" }, { "CSMSG_PROTECT_ALL", "Non-users and users will be protected from those of equal or lower access." }, { "CSMSG_PROTECT_EQUAL", "Users will be protected from those of equal or lower access." }, { "CSMSG_PROTECT_LOWER", "Users will be protected from those of lower access." }, @@ -616,7 +630,11 @@ static const struct { struct charOptionValues { char value; char *format_name; -} protectValues[] = { +} voiceValues[] = { + { 'n', "CSMSG_VOICE_NONE" }, + { 'p', "CSMSG_VOICE_PEON" }, + { 'a', "CSMSG_VOICE_ALL" } +}, protectValues[] = { { 'a', "CSMSG_PROTECT_ALL" }, { 'e', "CSMSG_PROTECT_EQUAL" }, { 'l', "CSMSG_PROTECT_LOWER" }, @@ -646,8 +664,9 @@ static const struct { unsigned char count; struct charOptionValues *values; } charOptions[] = { - { "CSMSG_SET_PROTECT", "protect", 'l', 0, ArrayLength(protectValues), protectValues }, - { "CSMSG_SET_TOYS", "toys", 'p', 6, ArrayLength(toysValues), toysValues }, + { "CSMSG_SET_VOICE", "voice", 'p', 99, ArrayLength(voiceValues), voiceValues }, + { "CSMSG_SET_PROTECT", "protect", 'l', 0, ArrayLength(protectValues), protectValues }, + { "CSMSG_SET_TOYS", "toys", 'p', 6, ArrayLength(toysValues), toysValues }, { "CSMSG_SET_TOPICREFRESH", "topicrefresh", 'n', 8, ArrayLength(topicRefreshValues), topicRefreshValues }, { "CSMSG_SET_CTCPREACTION", "ctcpreaction", 't', 10, ArrayLength(ctcpReactionValues), ctcpReactionValues } }; @@ -656,6 +675,9 @@ struct userData *helperList; struct chanData *channelList; static struct module *chanserv_module; static unsigned int userCount; +unsigned int chanserv_read_version = 0; /* db version control */ + +#define CHANSERV_DB_VERSION 2 #define GetChannelUser(channel, handle) _GetChannelUser(channel, handle, 1, 0) #define GetChannelAccess(channel, handle) _GetChannelUser(channel, handle, 0, 0) @@ -1163,6 +1185,7 @@ add_channel_user(struct chanData *channel, struct handle_info *handle, unsigned ud->u_next->u_prev = ud; ud->handle->channels = ud; + ud->flags = USER_FLAGS_DEFAULT; return ud; } @@ -1421,7 +1444,7 @@ protect_user(const struct userNode *victim, const struct userNode *aggressor, st /* 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 || IsOper(aggressor)) + if(protect == 'n' || victim == aggressor /* Opers dont get special treatment :/ || IsOper(aggressor) */) return 0; /* Don't protect if the victim isn't authenticated (because they @@ -1464,7 +1487,7 @@ validate_op(struct userNode *user, struct chanNode *channel, struct userNode *vi struct userData *cs_victim; if((!(cs_victim = GetChannelUser(cData, victim->handle_info)) - || (cs_victim->access < cData->lvlOpts[lvlGiveOps])) + || (cs_victim->access < UL_OP /* cData->lvlOpts[lvlGiveOps]*/)) && !check_user_level(channel, user, lvlEnfOps, 0, 0)) { send_message(user, chanserv, "CSMSG_OPBY_LOCKED"); @@ -1481,7 +1504,7 @@ validate_halfop(struct userNode *user, struct chanNode *channel, struct userNode struct userData *cs_victim; if((!(cs_victim = GetChannelUser(cData, victim->handle_info)) - || (cs_victim->access < cData->lvlOpts[lvlGiveHalfOps])) + || (cs_victim->access < UL_HALFOP /* cData->lvlOpts[lvlGiveHalfOps] */)) && !check_user_level(channel, user, lvlEnfHalfOps, 0, 0)) { send_message(user, chanserv, "CSMSG_HOPBY_LOCKED"); @@ -2620,17 +2643,17 @@ static CHANSERV_FUNC(cmd_up) reply("CSMSG_GODMODE_UP", argv[0]); return 0; } - else if(uData->access >= channel->channel_info->lvlOpts[lvlGiveOps]) + else if(uData->access >= UL_OP /*channel->channel_info->lvlOpts[lvlGiveOps]*/) { change.args[0].mode = MODE_CHANOP; errmsg = "CSMSG_ALREADY_OPPED"; } - else if(uData->access >= channel->channel_info->lvlOpts[lvlGiveHalfOps]) + else if(uData->access >= UL_HALFOP /*channel->channel_info->lvlOpts[lvlGiveHalfOps]*/) { change.args[0].mode = MODE_HALFOP; errmsg = "CSMSG_ALREADY_HALFOPPED"; } - else if(uData->access >= channel->channel_info->lvlOpts[lvlGiveVoice]) + else if(uData->access >= UL_PEON && (channel->channel_info->chOpts[chVoice] == 'p' || channel->channel_info->chOpts[chVoice] == 'a')) { change.args[0].mode = MODE_VOICE; errmsg = "CSMSG_ALREADY_VOICED"; @@ -3336,17 +3359,17 @@ static CHANSERV_FUNC(cmd_myaccess) continue; sbuf.used = 0; string_buffer_append_printf(&sbuf, "[%s (%d", cData->channel->name, uData->access); - if(uData->flags != USER_AUTO_OP) + 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]) + if(uData->access >= UL_OP /*cData->lvlOpts[lvlGiveOps]*/) string_buffer_append(&sbuf, 'o'); - else if(uData->access >= cData->lvlOpts[lvlGiveHalfOps]) + else if(uData->access >= UL_HALFOP /*cData->lvlOpts[lvlGiveHalfOps]*/) string_buffer_append(&sbuf, 'h'); - else if(uData->access >= cData->lvlOpts[lvlGiveVoice]) + else if(uData->access >= UL_PEON /*cData->lvlOpts[lvlGiveVoice]*/) string_buffer_append(&sbuf, 'v'); } if(IsUserAutoInvite(uData) && (uData->access >= cData->lvlOpts[lvlInviteMe])) @@ -3783,20 +3806,71 @@ static CHANSERV_FUNC(cmd_bans) return 1; } +/* bad_topic + * + * return + if the user does NOT have the right to set the topic, and + * the topic is changed. + */ static int bad_topic(struct chanNode *channel, struct userNode *user, const char *new_topic) { struct chanData *cData = channel->channel_info; if(check_user_level(channel, user, lvlEnfTopic, 1, 0)) return 0; - if(cData->topic_mask) - return !match_ircglob(new_topic, cData->topic_mask); else if(cData->topic) return irccasecmp(new_topic, cData->topic); else return 0; } +/* conform_topic + * + * Makes a givin topic fit into a givin topic mask and returns + * the results. + * + * topic_mask - the mask to conform to + * topic - the topic to make conform + * new_topic - the pre-allocated char* to put the new topic into + * + * modifies: new_topic + */ +void +conform_topic(char* topic_mask, char* topic, char *new_topic) +{ + //char *topic_mask = cData->topic_mask; + char tchar; + int pos=0, starpos=-1, dpos=0, len; + + while((tchar = topic_mask[pos++]) && (dpos <= TOPICLEN)) + { + switch(tchar) + { + case '*': + if(starpos != -1) + { + strcpy(new_topic, ""); + return; + } + len = strlen(topic); + if((dpos + len) > TOPICLEN) + len = TOPICLEN + 1 - dpos; + memcpy(new_topic+dpos, topic, len); + dpos += len; + starpos = pos; + break; + case '\\': tchar = topic_mask[pos++]; /* and fall through */ + default: new_topic[dpos++] = tchar; break; + } + } + if((dpos > TOPICLEN) || tchar) + { + strcpy(new_topic, ""); + return; + } + new_topic[dpos] = 0; + return; +} + static CHANSERV_FUNC(cmd_topic) { struct chanData *cData; @@ -3805,12 +3879,12 @@ static CHANSERV_FUNC(cmd_topic) cData = channel->channel_info; if(argc < 2) { - if(cData->topic) - { - SetChannelTopic(channel, chanserv, cData->topic, 1); - reply("CSMSG_TOPIC_SET", cData->topic); + if(cData->topic) + { + SetChannelTopic(channel, chanserv, cData->topic, 1); + reply("CSMSG_TOPIC_SET", cData->topic); return 1; - } + } reply("CSMSG_NO_TOPIC", channel->name); return 0; @@ -3820,48 +3894,34 @@ static CHANSERV_FUNC(cmd_topic) /* If they say "!topic *", use an empty topic. */ if((topic[0] == '*') && (topic[1] == 0)) topic[0] = 0; + if(bad_topic(channel, user, topic)) { - char *topic_mask = cData->topic_mask; - if(topic_mask) + reply("CSMSG_TOPIC_LOCKED", channel->name); + return 0; + } + else + { + /* If there is a topicmask set, and the new topic doesnt match, make it */ + if(cData->topic_mask && !match_ircglob(topic, cData->topic_mask)) { - char new_topic[TOPICLEN+1], tchar; - int pos=0, starpos=-1, dpos=0, len; + char *topic_mask = cData->topic_mask; + char new_topic[TOPICLEN+1]; - while((tchar = topic_mask[pos++]) && (dpos <= TOPICLEN)) - { - switch(tchar) - { - case '*': - if(starpos != -1) - goto bad_mask; - len = strlen(topic); - if((dpos + len) > TOPICLEN) - len = TOPICLEN + 1 - dpos; - memcpy(new_topic+dpos, topic, len); - dpos += len; - starpos = pos; - break; - case '\\': tchar = topic_mask[pos++]; /* and fall through */ - default: new_topic[dpos++] = tchar; break; - } - } - if((dpos > TOPICLEN) || tchar) + /* make a new topic fitting mask */ + conform_topic(topic_mask, topic, new_topic); + if(!*new_topic) { - bad_mask: + /* Topic couldnt fit into mask, was too long */ reply("CSMSG_TOPICMASK_CONFLICT1", channel->name, topic_mask); reply("CSMSG_TOPICMASK_CONFLICT2", TOPICLEN); return 0; } - new_topic[dpos] = 0; SetChannelTopic(channel, chanserv, new_topic, 1); - } else { - reply("CSMSG_TOPIC_LOCKED", channel->name); - return 0; } + else /* No mask set, just set the topic */ + SetChannelTopic(channel, chanserv, topic, 1); } - else - SetChannelTopic(channel, chanserv, topic, 1); if(check_user_level(channel, user, lvlTopicSnarf, 1, 0)) { @@ -4038,7 +4098,7 @@ static CHANSERV_FUNC(cmd_info) reply("CSMSG_BAR"); uData = GetChannelUser(cData, user->handle_info); - if(uData && (uData->access >= cData->lvlOpts[lvlGiveOps])) + if(uData && (uData->access >= UL_OP /*cData->lvlOpts[lvlGiveOps]*/)) { mod_chanmode_format(&cData->modes, modes); reply("CSMSG_CHANNEL_TOPIC", cData->topic); @@ -4243,8 +4303,7 @@ static CHANSERV_FUNC(cmd_resync) continue; uData = GetChannelAccess(cData, mn->user->handle_info); - if(!cData->lvlOpts[lvlGiveOps] - || (uData && uData->access >= cData->lvlOpts[lvlGiveOps])) + if(uData && uData->access >= UL_OP /* cData->lvlOpts[lvlGiveOps]*/) { if(!(mn->modes & MODE_CHANOP)) { @@ -4252,8 +4311,7 @@ static CHANSERV_FUNC(cmd_resync) changes->args[used++].u.member = mn; } } - else if(!cData->lvlOpts[lvlGiveHalfOps] - || (uData && uData->access >= cData->lvlOpts[lvlGiveHalfOps])) + else if(uData && uData->access >= UL_HALFOP /*cData->lvlOpts[lvlGiveHalfOps]*/) { if(!(mn->modes & MODE_HALFOP)) { @@ -4271,8 +4329,7 @@ static CHANSERV_FUNC(cmd_resync) changes->args[used++].u.member = mn; } } - else if(!cData->lvlOpts[lvlGiveVoice] - || (uData && uData->access >= cData->lvlOpts[lvlGiveVoice])) + else if(uData && uData->access >= UL_PEON /* cData->lvlOpts[lvlGiveVoice]*/) { if(mn->modes & MODE_CHANOP) { @@ -5232,6 +5289,7 @@ channel_level_option(enum levelOption option, struct userNode *user, struct chan } switch(option) { + /* removing these level sets.. case lvlGiveVoice: if(value > cData->lvlOpts[lvlGiveOps]) { @@ -5253,6 +5311,7 @@ channel_level_option(enum levelOption option, struct userNode *user, struct chan return 0; } break; + */ case lvlSetters: /* This test only applies to owners, since non-owners * trying to set an option to above their level get caught @@ -5282,7 +5341,7 @@ static MODCMD_FUNC(chan_opt_enfhalfops) { return channel_level_option(lvlEnfHalfOps, CSFUNC_ARGS); } - +/* static MODCMD_FUNC(chan_opt_giveops) { return channel_level_option(lvlGiveOps, CSFUNC_ARGS); @@ -5292,7 +5351,7 @@ static MODCMD_FUNC(chan_opt_givehalfops) { return channel_level_option(lvlGiveHalfOps, CSFUNC_ARGS); } - +*/ static MODCMD_FUNC(chan_opt_enfmodes) { return channel_level_option(lvlEnfModes, CSFUNC_ARGS); @@ -5323,10 +5382,12 @@ static MODCMD_FUNC(chan_opt_userinfo) return channel_level_option(lvlUserInfo, CSFUNC_ARGS); } +/* static MODCMD_FUNC(chan_opt_givevoice) { return channel_level_option(lvlGiveVoice, CSFUNC_ARGS); } +*/ static MODCMD_FUNC(chan_opt_topicsnarf) { @@ -5378,6 +5439,11 @@ channel_multiple_option(enum charOption option, struct userNode *user, struct ch return 1; } +static MODCMD_FUNC(chan_opt_voice) +{ + return channel_multiple_option(chVoice, CSFUNC_ARGS); +} + static MODCMD_FUNC(chan_opt_protect) { return channel_multiple_option(chProtect, CSFUNC_ARGS); @@ -5499,7 +5565,7 @@ user_binary_option(char *name, unsigned long mask, struct userNode *user, struct return 1; } -static MODCMD_FUNC(user_opt_noautoop) +static MODCMD_FUNC(user_opt_autoop) { struct userData *uData; @@ -5509,10 +5575,11 @@ static MODCMD_FUNC(user_opt_noautoop) reply("CSMSG_NOT_USER", channel->name); return 0; } - if(uData->access < channel->channel_info->lvlOpts[lvlGiveOps]) - return user_binary_option("CSMSG_USET_NOAUTOVOICE", USER_AUTO_OP, CSFUNC_ARGS); + if(uData->access < UL_OP /*channel->channel_info->lvlOpts[lvlGiveOps]*/) + return user_binary_option("CSMSG_USET_AUTOVOICE", USER_AUTO_OP, CSFUNC_ARGS); else - return user_binary_option("CSMSG_USET_NOAUTOOP", USER_AUTO_OP, CSFUNC_ARGS); + return user_binary_option("CSMSG_USET_AUTOOP", USER_AUTO_OP, CSFUNC_ARGS); + /* TODO: add halfops error message? or is the op one generic enough? */ } static MODCMD_FUNC(user_opt_autoinvite) @@ -5578,7 +5645,7 @@ static CHANSERV_FUNC(cmd_uset) { char *options[] = { - "NoAutoOp", "AutoInvite", "Info" + "AutoOp", "AutoInvite", "Info" }; if(!uset_shows_list.size) @@ -6123,13 +6190,10 @@ handle_join(struct modeNode *mNode) if(channel->join_flooded) { - /* don't automatically give ops or voice during a join flood */ + /* don't automatically give non users ops or voice during a join flood */ } - else if(cData->lvlOpts[lvlGiveOps] == 0) - modes |= MODE_CHANOP; - else if(cData->lvlOpts[lvlGiveHalfOps] == 0) - modes |= MODE_HALFOP; - else if(cData->lvlOpts[lvlGiveVoice] == 0) + /* EVERYONE is to get voice */ + else if(cData->chOpts[chVoice] == 'a') modes |= MODE_VOICE; greeting = cData->greeting; @@ -6153,14 +6217,14 @@ handle_join(struct modeNode *mNode) uData = GetTrueChannelAccess(cData, handle); if(uData && !IsUserSuspended(uData)) { - /* Ops and above were handled by the above case. */ + /* non users getting voice are handled above. */ if(IsUserAutoOp(uData)) { - if(uData->access >= cData->lvlOpts[lvlGiveOps]) + if(uData->access >= UL_OP /*cData->lvlOpts[lvlGiveOps]*/) modes |= MODE_CHANOP; - if(uData->access >= cData->lvlOpts[lvlGiveHalfOps]) + if(uData->access >= UL_HALFOP /*cData->lvlOpts[lvlGiveHalfOps]*/) modes |= MODE_HALFOP; - else if(uData->access >= cData->lvlOpts[lvlGiveVoice]) + else if(uData->access >= UL_PEON && cData->chOpts[chVoice] == 'p') modes |= MODE_VOICE; } if(uData->access >= UL_PRESENT) @@ -6234,11 +6298,11 @@ handle_auth(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle)) if(IsUserAutoOp(channel)) { - if(channel->access >= cn->channel_info->lvlOpts[lvlGiveOps]) + if(channel->access >= UL_OP /* cn->channel_info->lvlOpts[lvlGiveOps] */) change.args[0].mode = MODE_CHANOP; - else if(channel->access >= cn->channel_info->lvlOpts[lvlGiveHalfOps]) + else if(channel->access >= UL_HALFOP /* cn->channel_info->lvlOpts[lvlGiveHalfOps]*/) change.args[0].mode = MODE_HALFOP; - else if(channel->access >= cn->channel_info->lvlOpts[lvlGiveVoice]) + else if(channel->access >= UL_PEON /* cn->channel_info->lvlOpts[lvlGiveVoice]*/) change.args[0].mode = MODE_VOICE; else change.args[0].mode = 0; @@ -6366,14 +6430,30 @@ handle_topic(struct userNode *user, struct chanNode *channel, const char *old_to cData = channel->channel_info; if(bad_topic(channel, user, channel->topic)) - { + { /* User doesnt have privs to set topics. Undo it */ send_message(user, chanserv, "CSMSG_TOPIC_LOCKED", channel->name); - if(cData->topic_mask && match_ircglob(old_topic, cData->topic_mask)) - SetChannelTopic(channel, chanserv, old_topic, 1); - else if(cData->topic) - SetChannelTopic(channel, chanserv, cData->topic, 1); + SetChannelTopic(channel, chanserv, old_topic, 1); return 1; } + /* If there is a topic mask set, and the new topic doesnt match, + * set the topic to mask + new_topic */ + if(cData->topic_mask && !match_ircglob(channel->topic, cData->topic_mask)) + { + char new_topic[TOPICLEN+1]; + conform_topic(cData->topic_mask, channel->topic, new_topic); + if(*new_topic) + { + SetChannelTopic(channel, chanserv, new_topic, 1); + /* and fall through to topicsnarf code below.. */ + } + else /* Topic couldnt fit into mask, was too long */ + { + SetChannelTopic(channel, chanserv, old_topic, 1); + send_message(user, chanserv, "CSMSG_TOPICMASK_CONFLICT1", channel->name, cData->topic_mask); + send_message(user, chanserv, "CSMSG_TOPICMASK_CONFLICT2", TOPICLEN); + return 1; + } + } /* With topicsnarf, grab the topic and save it as the default topic. */ if(check_user_level(channel, user, lvlTopicSnarf, 0, 0)) { @@ -6650,7 +6730,7 @@ chanserv_conf_read(void) /* free form text */ "DefaultTopic", "TopicMask", "Greeting", "UserGreeting", "Modes", /* options based on user level */ - "PubCmd", "InviteMe", "UserInfo", "GiveVoice", "GiveHalfOps", "GiveOps", "EnfOps", + "PubCmd", "InviteMe", "UserInfo",/* "GiveVoice", "GiveHalfOps", "GiveOps", */ "EnfOps", "EnfHalfOps", "EnfModes", "EnfTopic", "TopicSnarf", "Setters", "CtcpUsers", /* multiple choice options */ "CtcpReaction", "Protect", "Toys", "TopicRefresh", @@ -6786,6 +6866,18 @@ user_read_helper(const char *key, struct record_data *rd, struct chanData *chan) uData = add_channel_user(chan, handle, access, last_seen, inf); uData->flags = flags ? strtoul(flags, NULL, 0) : 0; + + /* Upgrade: set autoop to the inverse of noautoop */ + if(chanserv_read_version < 2) + { + /* if noautoop is true, set autoop false, and vice versa */ + if(uData->flags & USER_NOAUTO_OP) + uData->flags = uData->flags & ~USER_AUTO_OP; + else + uData->flags = uData->flags | USER_AUTO_OP; + log_module(CS_LOG, LOG_INFO, "UPGRADE: to db version 2 from %u. Changing flag to %d for %s in %s.", chanserv_read_version, uData->flags, key, chan->channel->name); + } + } static void @@ -7086,12 +7178,26 @@ chanserv_dnr_read(const char *key, struct record_data *hir) dnr->set = 0; } +static void +chanserv_version_read(struct dict *section) +{ + /* global var.. */ + char *str; + str = database_get_data(section, KEY_VERSION_NUMBER, RECDB_QSTRING); + if(str) + chanserv_read_version = atoi(str); + log_module(CS_LOG, LOG_DEBUG, "Chanserv db version is %d.", chanserv_read_version); +} + static int chanserv_saxdb_read(struct dict *database) { struct dict *section; dict_iterator_t it; + if((section = database_get_data(database, KEY_VERSION_CONTROL, RECDB_OBJECT))) + chanserv_version_read(section); + if((section = database_get_data(database, KEY_NOTE_TYPES, RECDB_OBJECT))) for(it = dict_first(section); it; it = iter_next(it)) chanserv_note_type_read(iter_key(it), iter_data(it)); @@ -7290,6 +7396,11 @@ chanserv_saxdb_write(struct saxdb_context *ctx) dict_iterator_t it; struct chanData *channel; + /* Version Control*/ + saxdb_start_record(ctx, KEY_VERSION_CONTROL, 1); + saxdb_write_int(ctx, KEY_VERSION_NUMBER, CHANSERV_DB_VERSION); + saxdb_end_record(ctx); + /* Notes */ saxdb_start_record(ctx, KEY_NOTE_TYPES, 1); for(it = dict_first(note_types); it; it = iter_next(it)) @@ -7479,13 +7590,16 @@ init_chanserv(const char *nick) DEFINE_CHANNEL_OPTION(modes); DEFINE_CHANNEL_OPTION(enfops); DEFINE_CHANNEL_OPTION(enfhalfops); - DEFINE_CHANNEL_OPTION(giveops); + /*DEFINE_CHANNEL_OPTION(giveops); DEFINE_CHANNEL_OPTION(givehalfops); + */ + DEFINE_CHANNEL_OPTION(voice); DEFINE_CHANNEL_OPTION(protect); DEFINE_CHANNEL_OPTION(enfmodes); DEFINE_CHANNEL_OPTION(enftopic); DEFINE_CHANNEL_OPTION(pubcmd); - DEFINE_CHANNEL_OPTION(givevoice); + /*DEFINE_CHANNEL_OPTION(givevoice); + */ DEFINE_CHANNEL_OPTION(userinfo); DEFINE_CHANNEL_OPTION(dynlimit); DEFINE_CHANNEL_OPTION(topicsnarf); @@ -7504,12 +7618,12 @@ init_chanserv(const char *nick) modcmd_register(chanserv_module, "set topic", chan_opt_defaulttopic, 1, 0, NULL); /* User options */ - DEFINE_USER_OPTION(noautoop); DEFINE_USER_OPTION(autoinvite); DEFINE_USER_OPTION(info); + DEFINE_USER_OPTION(autoop); /* Alias uset autovoice to uset autoop. */ - modcmd_register(chanserv_module, "uset noautovoice", user_opt_noautoop, 1, 0, NULL); + modcmd_register(chanserv_module, "uset autovoice", user_opt_autoop, 1, 0, NULL); note_types = dict_new(); dict_set_free_data(note_types, chanserv_deref_note_type); @@ -7520,6 +7634,7 @@ init_chanserv(const char *nick) service_register(chanserv)->trigger = '!'; reg_chanmsg_func('\001', chanserv, chanserv_ctcp_check); } + saxdb_register("ChanServ", chanserv_saxdb_read, chanserv_saxdb_write); if(chanserv_conf.channel_expire_frequency)