/***********************************************************************
X3 ChangeLog
+2005-05-04 Alex Schumann <rubin@afternet.org>
+
+ * src/chanserv.c: changed uset noautoop to uset autoop (removed double
+ negitive). Added set voice to provide control over use of voice.
+ Implimented a basic chanserv db version control system for upgrading
+ seamlessly.
+
+ * src/chanserv.help: adjusted help to reflect voice and uset autoop
+ changes.
+
+ * src/hash.h: updated ssz comment from z to Z
+
+ * src/modcmd.help: rewrote BIND help
+
+ * src/proto-p10.c: Added Z (sslonly) support back in
+
+ * UPGRADE: created file to document upgrading procedures needed
+
2005-04-23 Alex Schumann <rubin@afternet.org>
* src/chanserv.c: removed settings: oplevel, halfoplevel, and
voicelevel, hard coding them to OP, HALFOP, and PEON. Changed
--- /dev/null
+**************************************
+*** X3 IRC Services ***
+**************************************
+*** IMPORTANT UPGRADE INSTRUCTIONS ***
+**************************************
+From srvx 1.4:
+ Rename srvx.conf to x3.conf
+ Review .conf file settings.
+ * remove giveops, givevoice from set_shows and add "Voice" above "Protect".
+ * you can change from srvx.db to x3.db here also (dont forget to rename the file)
+ Run all of the steps below
+
+As of CVS version 1.24:
+ bind chanserv 'uset autoop' and 'set voice' (see note below).
+
+
+NOTE about command bindings:
+You may do: 'bind x3 * *chanserv.*' to re-bind ALL builtin commands on chanserv. This
+is the simplest approach and probably a good idea to run for each module (chanserv,
+opserv, nickserv, modcmd, etc) after upgrading or changing some features (such as email).
+Alternatively you can edit the .db by hand or using the 'bind' command on irc.
+IMPORTANT: You will need to shut down x3 gracefully (using the die or restart commands)
+after binding in order for 'set' and 'uset' subcommand changes to function properly since
+the listing is cached.
--- /dev/null
+Using translations:
+ copy the languages folder into your x3 runtime directory, and restart x3.
+ alternate languages will be available in /msg authserv set lanugage
+ NOTE: Currently no other languages are caught up to recent development.
+ if you speak them, please see below for updating instructions.
+
+Translating:
+Thanks for your interest in helping to translate X3 to other languages.
+
+How to make a new language:
+
+1: run the export script, to make an up-to-date "C" baseline db:
+ ./lang_export.sh > strings.db
+2: make a dir for your language such as de/
+ mkdir fo
+3: copy thi strings.db into your new dir
+ cp strings.db fo
+4: copy the help files into your new dir
+ cp ../src/*.help fo
+5: edit the .help and .db files, translating them to your laungage.
+ nano fo/strings.db (etc)
+6: test the strings.db file
+ ./validate_lang.pl fo
+7: fix any problems.
+
+
+How to keep your language up to date after changes:
+
+1: run the export script, to make an up-to-date "C" baseline db:
+ ./lang_export.sh > strings.db
+2: test the strings.db file
+ ./validate_lang.pl fo
+3: fix any changes.
+
+You should also watch the cvs mailing list for changes in meaning of the strings
+since X3 is under active development.
+
+
#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"
{ "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" },
{ "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." },
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" },
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 }
};
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)
ud->u_next->u_prev = ud;
ud->handle->channels = ud;
+ ud->flags = USER_FLAGS_DEFAULT;
return ud;
}
change.args[0].mode = MODE_HALFOP;
errmsg = "CSMSG_ALREADY_HALFOPPED";
}
- else if(uData->access >= UL_PEON /* 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";
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');
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);
return 1;
}
-static MODCMD_FUNC(user_opt_noautoop)
+static MODCMD_FUNC(user_opt_autoop)
{
struct userData *uData;
return 0;
}
if(uData->access < UL_OP /*channel->channel_info->lvlOpts[lvlGiveOps]*/)
- return user_binary_option("CSMSG_USET_NOAUTOVOICE", USER_AUTO_OP, CSFUNC_ARGS);
+ 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? */
}
{
char *options[] =
{
- "NoAutoOp", "AutoInvite", "Info"
+ "AutoOp", "AutoInvite", "Info"
};
if(!uset_shows_list.size)
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 */
}
- /* I don't understand why we do this, so im removing it -rubin *
- 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;
if(user->handle_info)
{
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 >= UL_OP /*cData->lvlOpts[lvlGiveOps]*/)
modes |= MODE_CHANOP;
if(uData->access >= UL_HALFOP /*cData->lvlOpts[lvlGiveHalfOps]*/)
modes |= MODE_HALFOP;
- else if(uData->access >= UL_PEON /* cData->lvlOpts[lvlGiveVoice] */)
+ else if(uData->access >= UL_PEON && cData->chOpts[chVoice] == 'p')
modes |= MODE_VOICE;
}
if(uData->access >= UL_PRESENT)
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
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));
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))
/*DEFINE_CHANNEL_OPTION(giveops);
DEFINE_CHANNEL_OPTION(givehalfops);
*/
+ DEFINE_CHANNEL_OPTION(voice);
DEFINE_CHANNEL_OPTION(protect);
DEFINE_CHANNEL_OPTION(enfmodes);
DEFINE_CHANNEL_OPTION(enftopic);
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);
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)
};
enum charOption {
+ chVoice,
chProtect,
chToys,
chTopicRefresh,
struct chanData *next;
};
-#define USER_AUTO_OP 0x00000001
+#define USER_NOAUTO_OP 0x00000001 /* OLD; Not used at all.. */
#define USER_SUSPENDED 0x00000002
#define USER_AUTO_INVITE 0x00000004
-#define USER_FLAGS_SIZE 7
+#define USER_AUTO_OP 0x00000008
+#define USER_FLAGS_SIZE 15
+#define USER_FLAGS_DEFAULT USER_AUTO_OP
-#define IsUserAutoOp(USER) (!((USER)->flags & USER_AUTO_OP))
+#define IsUserAutoOp(USER) ((USER)->flags & USER_AUTO_OP)
#define IsUserSuspended(USER) ((USER)->flags & USER_SUSPENDED)
#define IsUserAutoInvite(USER) ((USER)->flags & USER_AUTO_INVITE)
"SETTERS: Who may change channel settings (using $bSET$b).",
"CTCPUSERS: Who is allowed to send CTCPs to the channel.",
"CTCPREACTION: What happens when a disallowed CTCP is sent to the channel.",
+ "VOICE: Who should be auto-voiced in the channel.",
"PROTECT: The protection level $b$C$b provides.",
"TOYS: Toggles how $b$C$b will respond to toy commands (!8ball etc).",
"TOPICREFRESH: Controls if (and how often) $b$C$b will reset the topic.",
"If a topic mask is set, then a person may change the topic as long as it matches that mask $bor$b they have the above access.",
"If no topic mask is set, then a person must have the above access to change the topic from the default.",
"$uSee Also:$u set, set topic, set topicmask");
+"SET VOICE" ("/msg $C SET <#channel> VOICE <value>",
+ "This setting configures who $C auto-voices. Valid settings are:",
+ "$b0$b Noone will get voice",
+ "$b1$b PEONs will get voice (default).",
+ "$b2$b Everyone will get voice.",
+ "$uSee Also:$u set, uset autoop");
"SET PROTECT" ("/msg $C SET <#channel> PROTECT <value>",
"This setting restricts the protection that $C enforces. Valid settings are:",
"$b0$b Non-users and users will be protected from those of equal or lower access",
"The $buset$b command allows you to toggle various channel user settings. With no arguments, it will print the current values of all channel user options.",
"$bOptions:$b",
"INFO: Sets the infoline that $C sends when you join the channel.",
- "NOAUTOOP: Enable or disable $C automatically opping you upon joining or authenticating.",
+ "AUTOOP: Enable or disable $C automatically opping you upon joining or authenticating.",
"AUTOINVITE: $C will invite you to this channel if you have access to and are not in when you authenticate if this setting is on.",
- "NOTE: The NoAutoOp setting is equivalent to the !togop command in previous versions of X3.",
"$uSee Also:$u set");
"USET INFO" ("/msg $C USET <#channel> INFO <info>",
"This command will set a user defined information message to be displayed when you join the channel. Set to '*' to clear the message.",
#define MODE_OPERSONLY 0x00080000 /* +O Opers only */
#define MODE_NOQUITMSGS 0x00100000 /* +Q suppress messages from quit notices */
#define MODE_NOAMSG 0x00200000 /* +T no multi-target messages */
-#define MODE_SSLONLY 0x00400000 /* +z ssl only */
+#define MODE_SSLONLY 0x00400000 /* +Z ssl only */
#define MODE_HALFOP 0x00800000 /* +h USER */
#define MODE_EXEMPT 0x01000000 /* +e exempt */
#define MODE_REMOVE 0x80000000
-"bind" ("/msg $S BIND <service> <bindname> <command> [additional args..]",
- "Binds (adds) a command to an existing service. $bbindname$b is the name of the new command for the service. $bcommand$b may be one of:",
- " CommandName To refer to a command on the same service.",
- " ServiceNick.CommandName To refer to a command bound on a different service such as $O, $C, $N, etc.",
- " *ModuleName.CommandName To bind a command directly from a module (note the asterisk before the module name).",
- " *ModuleName.* To bind all commands from the named module, where ModuleName is one of OpServ, NickServ, ChanServ, modcmd, or others.",
- "For simplicity, you cannot bind to a command that is itself an alias. Certain commands will not bound with the last form; you must bind them by name.",
- "(A command binding is very similar to an alias, but only pays the speed penalty for alias expansion when there are additional arguments in the binding.)",
- "If you want to be able to bind $bfoo bar$b as a command, you need to bind $bfoo$b to modcmd.joiner first.",
+"bind" ("/msg $S BIND <ServiceNick> <BindName> [Nick|*Module.]<Command> [Arg [Arg[..]]]",
+ "Bind creates a command. ",
+ " $bServiceNick$b is which service the new command will work on.",
+ " $bBindName$b is the name of the new command you are making.",
+ " $bCommand$b To refer to a command on the same service.",
+ " $bNick$b To refer to a command on a different ",
+ " service such as $O, $C, $N, etc.",
+ " $b*Module$b To bind a command directly from a module such as",
+ " ChanServ, OpServ, NickServ, modcmd, etc",
+ " (note the asterisk before the module name).",
+ " $barg(s)$b Can be anything, or you can use $$1 $$2 $$3 etc",
+ " which will be replaced with the arguments passed",
+ " to the command. Use a - after ($$2-) to indicate",
+ " that argument and all arguments after it.",
+ "$b$b",
+ "There is a special case to load ALL commands from a module:",
+ "/msg $S bind <serviceNick> * *<Module>.* ",
+ " You may need to run this after installing previously",
+ " missing modules, or making changes such as enabling",
+ " the email features, so all the commands are bound.",
+ " Note: Certain(??) commands will not bind this way; ",
+ " you must bind them by name.",
+ "$b$b",
+ "For simplicity, you cannot bind to a command that is an alias.",
+ "$b$b",
+ "If you want to bind $bfoo bar$b as a command, bind $bfoo$b to $b*modcmd.joiner$b first, unless foo is a builtin command such as uset, in which case use '\\' to escape the space (example: $bbind x3 uset\ autoop x3.uset\ autoop$b)",
+ "$b$b",
+ "$uExamples$u",
+ " bind X3 autoop *chanserv.uset\\ autoop",
+ " bind O3 murder o3.trace gline nick $$1 duration 1m reason $$2-",
+ " bind X3 * *chanserv.*",
+ "$b$b",
"$uSee also:$u unbind, joiner");
"commands" "${index}";
case 'Q': do_chan_mode(MODE_NOQUITMSGS); break;
case 'T': do_chan_mode(MODE_NOAMSG); break;
case 'O': do_chan_mode(MODE_OPERSONLY); break;
+ case 'Z': do_chan_mode(MODE_SSLONLY); break;
case 'z':
if (!(flags & MCP_REGISTERED)) {
do_chan_mode(MODE_REGISTERED);
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
DO_MODE_CHAR(REGISTERED, 'z');
- // uncomment this for ssl support
- //DO_MODE_CHAR(SSLONLY, 'Z');
+ DO_MODE_CHAR(SSLONLY, 'Z');
#undef DO_MODE_CHAR
if (change->modes_clear & channel->modes & MODE_KEY)
mod_chanmode_append(&chbuf, 'k', channel->key);
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
DO_MODE_CHAR(REGISTERED, 'z');
- // uncomment this for ssl support
- //DO_MODE_CHAR(SSLONLY, 'Z');
+ DO_MODE_CHAR(SSLONLY, 'Z');
#undef DO_MODE_CHAR
if(change->modes_set & MODE_KEY)
mod_chanmode_append(&chbuf, 'k', change->new_key);
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
DO_MODE_CHAR(REGISTERED, 'z');
- // uncomment this for ssl support
- //DO_MODE_CHAR(SSLONLY, 'Z');
+ DO_MODE_CHAR(SSLONLY, 'Z');
#undef DO_MODE_CHAR
}
if (change->modes_set) {
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
DO_MODE_CHAR(REGISTERED, 'z');
- // uncomment this for ssl support
- //DO_MODE_CHAR(SSLONLY, 'Z');
+ DO_MODE_CHAR(SSLONLY, 'Z');
#undef DO_MODE_CHAR
switch (change->modes_set & (MODE_KEY|MODE_LIMIT)) {
case MODE_KEY|MODE_LIMIT:
case 'T': remove |= MODE_NOAMSG; break;
case 'O': remove |= MODE_OPERSONLY; break;
case 'z': remove |= MODE_REGISTERED; break;
+ case 'Z': remove |= MODE_SSLONLY; break;
}
}