#include "conf.h"
#include "global.h"
#include "modcmd.h"
-#include "opserv.h" /* for opserv_bad_channel() */
+#include "opserv.h" /* for opserv_bad_channel() and devnull management */
#include "nickserv.h" /* for oper_outranks() */
#include "saxdb.h"
#include "spamserv.h"
#define KEY_MAX_USERINFO_LENGTH "max_userinfo_length"
#define KEY_GIVEOWNERSHIP_PERIOD "giveownership_timeout"
#define KEY_INVITED_INTERVAL "invite_timeout"
+#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"
/* ChanServ database */
#define KEY_CHANNELS "channels"
/* User management */
{ "CSMSG_ADDED_USER", "Added %s to the %s user list with access %d." },
{ "CSMSG_DELETED_USER", "Deleted %s (with access %d) from the %s user list." },
- { "CSMSG_BAD_RANGE", "Invalid access range; minimum (%d) must be greater than maximum (%d)." },
+ { "CSMSG_BAD_RANGE", "Invalid access range; minimum (%d) must be lower than maximum (%d)." },
{ "CSMSG_DELETED_USERS", "Deleted accounts matching $b%s$b with access from $b%d$b to $b%d$b from the %s user list." },
{ "CSMSG_TRIMMED_USERS", "Trimmed $b%d users$b with access from %d to %d from the %s user list who were inactive for at least %s." },
{ "CSMSG_INCORRECT_ACCESS", "%s has access $b%d$b, not %s." },
{ "CSMSG_ACCESS_SEARCH_HEADER", "%s users from level %d to %d matching %s:" },
{ "CSMSG_INVALID_ACCESS", "$b%s$b is an invalid access level." },
{ "CSMSG_CHANGED_ACCESS", "%s now has access $b%d$b in %s." },
+ { "CSMSG_TOTAL_USERS", "There are $b%d$b users in %s." },
/* Channel note list */
{ "CSMSG_NOTELIST_HEADER", "Notes for $b%s$b:" },
{ "CSMSG_UC_H_TITLE", "network helper" },
{ "CSMSG_LC_H_TITLE", "support helper" },
{ "CSMSG_LAME_SMURF_TARGET", "%s is an IRC operator." },
+ { "CSMSG_MYACCESS_COUNT", "%s has access in $b%d$b channels and is owner of $b%d$b channel(s)." },
+ { "CSMSG_MYACCESS_COUNT_1", "%s has access in $b%d$b channel and is owner of $b%d$b channel(s)." },
+
/* Seen information */
{ "CSMSG_NEVER_SEEN", "%s has never been seen in $b%s$b." },
const char *irc_operator_epithet;
const char *network_helper_epithet;
const char *support_helper_epithet;
+
+ const char *new_channel_authed;
+ const char *new_channel_unauthed;
+ const char *new_channel_msg;
} chanserv_conf;
struct listData
#define GetChannelAccess(channel, handle) _GetChannelUser(channel, handle, 0, 0)
#define GetTrueChannelAccess(channel, handle) _GetChannelUser(channel, handle, 0, 1)
+static void unregister_channel(struct chanData *channel, const char *reason);
unsigned short
user_level_from_name(const char *name, unsigned short clamp_level)
return 0;
}
- if(IsProtected(cData))
+ if(IsProtected(cData) && !IsOper(user))
{
reply("CSMSG_UNREG_NODELETE", channel->name);
return 0;
return modify_users(CSFUNC_ARGS, NULL, MODE_REMOVE|MODE_VOICE, "CSMSG_DEVOICED_USERS");
}
+static CHANSERV_FUNC(cmd_opme)
+{
+ struct mod_chanmode change;
+ const char *errmsg;
+
+ mod_chanmode_init(&change);
+ change.argc = 1;
+ change.args[0].u.member = GetUserMode(channel, user);
+ if(!change.args[0].u.member)
+ {
+ if(argc)
+ reply("MSG_CHANNEL_ABSENT", channel->name);
+ return 0;
+ }
+
+ struct devnull_class *devnull;
+ if(user->handle_info->devnull && (devnull = devnull_get(user->handle_info->devnull)) && (devnull->modes & DEVNULL_MODE_OPME))
+ {
+ change.args[0].mode = MODE_CHANOP;
+ errmsg = "CSMSG_ALREADY_OPPED";
+ }
+ else
+ {
+ if(argc)
+ reply("CSMSG_NO_ACCESS");
+ return 0;
+ }
+ change.args[0].mode &= ~change.args[0].u.member->modes;
+ if(!change.args[0].mode)
+ {
+ if(argc)
+ reply(errmsg, channel->name);
+ return 0;
+ }
+ modcmd_chanmode_announce(&change);
+ return 1;
+}
+
static int
bad_channel_ban(struct chanNode *channel, struct userNode *user, const char *ban, unsigned int *victimCount, struct modeNode **victims)
{
offset = (action & ACTION_ADD_TIMED_BAN) ? 3 : 2;
REQUIRE_PARAMS(offset);
+ if(argc > offset && IsNetServ(user))
+ {
+ if(*argv[offset] == '$') {
+ struct userNode *hib;
+ const char *accountnameb = argv[offset] + 1;
+ if(!(hib = GetUserH(accountnameb)))
+ {
+ reply("MSG_HANDLE_UNKNOWN", accountnameb);
+ return 0;
+ }
+ user=hib;
+ offset++;
+ }
+ }
if(argc > offset)
{
reason = unsplit_string(argv + offset, argc - offset, NULL);
return eject_user(CSFUNC_ARGS, ACTION_KICK | ACTION_BAN | ACTION_ADD_BAN | ACTION_ADD_TIMED_BAN);
}
-static struct mod_chanmode *
+struct mod_chanmode *
find_matching_bans(struct banList *bans, struct userNode *actee, const char *mask)
{
struct mod_chanmode *change;
static struct string_buffer sbuf;
struct handle_info *target_handle;
struct userData *uData;
+ int ccount = 0;
+ int ocount = 0;
if(argc < 2)
target_handle = user->handle_info;
for(uData = target_handle->channels; uData; uData = uData->u_next)
{
struct chanData *cData = uData->channel;
+ ccount++;
if(uData->access > UL_OWNER)
continue;
+ if(uData->access == UL_OWNER)
+ ocount++;
+
if(IsProtected(cData)
&& (target_handle != user->handle_info)
- && !GetTrueChannelAccess(cData, user->handle_info))
+ && !GetTrueChannelAccess(cData, user->handle_info)
+ && !IsNetworkHelper(user))
continue;
sbuf.used = 0;
string_buffer_append_printf(&sbuf, "[%s (%d", cData->channel->name, uData->access);
send_message_type(4, user, cmd->parent->bot, "%s", sbuf.list);
}
+ if(ccount == 1) {
+ reply("CSMSG_MYACCESS_COUNT_1", target_handle->handle, ccount, ocount);
+ } else {
+ reply("CSMSG_MYACCESS_COUNT", target_handle->handle, ccount, ocount);
+ }
+
return 1;
}
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)
{
}
free(lData.table.contents[0]);
free(lData.table.contents);
+ reply("CSMSG_TOTAL_USERS",(lData.table.length - 1),channel->name);
return 1;
}
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|MCP_NO_APASS, base_oplevel);
+ change = mod_chanmode_parse(channel, user, argv+1, argc-1, MCP_KEY_FREE|MCP_IGN_REGISTERED|MCP_NO_APASS, base_oplevel);
if(!change)
{
reply("MSG_INVALID_MODES", unsplit_string(argv+1, argc-1, NULL));
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])))
return 1;
}
+static CHANSERV_FUNC(cmd_invitemeall)
+{
+ struct handle_info *target = user->handle_info;
+ struct userData *uData;
+
+ if(!target->channels)
+ {
+ reply("CSMSG_SQUAT_ACCESS", target->handle);
+ return 1;
+ }
+
+ for(uData = target->channels; uData; uData = uData->u_next)
+ {
+ struct chanData *cData = uData->channel;
+ if(uData->access >= cData->lvlOpts[lvlInviteMe])
+ {
+ irc_invite(cmd->parent->bot, user, cData->channel);
+ }
+ }
+ return 1;
+}
+
static void
show_suspension_info(struct svccmd *cmd, struct userNode *user, struct suspended *suspended)
{
continue;
if(IsBot(user))
continue;
+ if(IsInvi(user))
+ continue;
table.contents[table.length] = alloca(table.width*sizeof(**table.contents));
if(IsAway(user))
{
{
if(!(mn->modes & MODE_CHANOP))
{
- changes->args[used].mode = MODE_CHANOP;
- changes->args[used++].u.member = mn;
+ if(!uData || IsUserAutoOp(uData))
+ {
+ changes->args[used].mode = MODE_CHANOP;
+ changes->args[used++].u.member = mn;
+ if(!(mn->modes & MODE_VOICE))
+ {
+ changes->args[used].mode = MODE_VOICE;
+ changes->args[used++].u.member = mn;
+ }
+ }
}
}
else if(!cData->lvlOpts[lvlGiveVoice]
changes->args[used].mode = MODE_REMOVE | (mn->modes & ~MODE_VOICE);
changes->args[used++].u.member = mn;
}
- if(!(mn->modes & MODE_VOICE))
+ if(!(mn->modes & MODE_VOICE) && (!uData || IsUserAutoOp(uData)))
{
changes->args[used].mode = MODE_VOICE;
changes->args[used++].u.member = mn;
{
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|MCP_NO_APASS, 0)))
+ else if(!(new_modes = mod_chanmode_parse(channel, user, argv+1, argc-1, MCP_KEY_FREE|MCP_IGN_REGISTERED|MCP_NO_APASS|(IsOper(user) && IsHelping(user) ? MCP_OPERMODE : 0), 0)))
{
reply("CSMSG_INVALID_MODE_LOCK", unsplit_string(argv+1, argc-1, NULL));
return 0;
struct userData *target;
struct handle_info *hi;
unsigned int votedfor = 0;
- char *votedfor_str;
+ char *votedfor_str = NULL;
if (!cData || !cData->vote) {
reply("CSMSG_NO_VOTE");
irc_privmsg(cmd->parent->bot, channel->name, response);
sprintf(response, user_find_message(user, "CSMSG_STARTVOTE_HOWTO")); //Todo
irc_privmsg(cmd->parent->bot, channel->name, response);
+ return 1;
}
static CHANSERV_FUNC(cmd_endvote)
SetChannelTopic(channel, chanserv, channel->channel_info->topic, 1);
}
+void handle_new_channel_created(char *chan, struct userNode *user) {
+ if(user->handle_info && chanserv_conf.new_channel_authed) {
+ send_target_message(5, chan, chanserv, "%s", chanserv_conf.new_channel_authed);
+ } else if(!user->handle_info && chanserv_conf.new_channel_unauthed) {
+ send_target_message(5, chan, chanserv, "%s", chanserv_conf.new_channel_unauthed);
+ }
+ if(chanserv_conf.new_channel_msg)
+ send_target_message(5, chan, chanserv, "%s", chanserv_conf.new_channel_msg);
+}
+
/* Welcome to my worst nightmare. Warning: Read (or modify)
the code below at your own risk. */
static int
struct handle_info *handle;
unsigned int modes = 0, info = 0;
char *greeting;
+ unsigned int i = 0;
if(IsLocal(user) || !channel->channel_info || IsSuspended(channel->channel_info))
return 0;
chanserv_conf.network_helper_epithet = str ? str : "a wannabe tyrant";
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;
+ str = database_get_data(conf_node, KEY_NEW_CHANNEL_UNAUTHED, RECDB_QSTRING);
+ chanserv_conf.new_channel_unauthed = str ? str : NULL;
+ str = database_get_data(conf_node, KEY_NEW_CHANNEL_MSG, RECDB_QSTRING);
+ chanserv_conf.new_channel_msg = str ? str : NULL;
str = database_get_data(conf_node, "default_modes", RECDB_QSTRING);
if(!str)
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|MCP_NO_APASS, 0))
+ if((change = mod_chanmode_parse(NULL, 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|MCP_NO_APASS, 0))) {
+ && (modes = mod_chanmode_parse(cNode, NULL, argv, argc, MCP_KEY_FREE|MCP_NO_APASS, 0))) {
cData->modes = *modes;
if(off_channel > 0)
cData->modes.modes_set |= MODE_REGISTERED;
DEFINE_COMMAND(topic, 1, MODCMD_REQUIRE_REGCHAN, "template", "op", "flags", "+never_csuspend", NULL);
DEFINE_COMMAND(mode, 1, MODCMD_REQUIRE_REGCHAN, "template", "op", NULL);
DEFINE_COMMAND(inviteme, 1, MODCMD_REQUIRE_CHANNEL, "access", "1", NULL);
+ DEFINE_COMMAND(invitemeall, 1, MODCMD_REQUIRE_AUTHED, NULL);
DEFINE_COMMAND(invite, 1, MODCMD_REQUIRE_CHANNEL, "access", "master", NULL);
DEFINE_COMMAND(set, 1, MODCMD_REQUIRE_CHANUSER, "access", "op", NULL);
DEFINE_COMMAND(wipeinfo, 2, MODCMD_REQUIRE_CHANUSER, "access", "master", NULL);
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);
+
/* Channel options */
DEFINE_CHANNEL_OPTION(defaulttopic);
DEFINE_CHANNEL_OPTION(topicmask);