*
* x3 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
#include "chanserv.h"
#include "conf.h"
#include "global.h"
+#include "gline.h"
+#include "ioset.h"
#include "modcmd.h"
#include "opserv.h" /* for opserv_bad_channel() */
#include "saxdb.h"
+#include "shun.h"
#include "spamserv.h"
#include "timeq.h"
#define KEY_NOTES "notes"
#define KEY_TOPIC_MASK "topic_mask"
#define KEY_OWNER_TRANSFER "owner_transfer"
+#define KEY_MAXSETINFO "maxsetinfo"
/* User data */
#define KEY_LEVEL "level"
#define KEY_INFO "info"
#define KEY_SEEN "seen"
-#define KEY_EXPIRY "expiry"
+#define KEY_ACCESSEXPIRY "accessexpiry"
+#define KEY_CLVLEXPIRY "clvlexpiry"
+#define KEY_LASTLEVEL "lastlevel"
/* Ban data */
#define KEY_OWNER "owner"
/* User management */
{ "CSMSG_AUTO_DELETED", "Your %s access has expired in %s." },
+ { "CSMSG_CLVL_EXPIRED", "Your CLVL access has expired in %s." },
{ "CSMSG_ADDED_USER", "Added %s to the %s user list with access %s (%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_NO_SELF_CLVL", "You cannot change your own access." },
{ "CSMSG_NO_BUMP_ACCESS", "You cannot give users access greater than or equal to your own." },
+ { "CSMSG_NO_BUMP_EXPIRY", "You cannot give users timed $bCLVL$b's when they already have timed access." },
{ "CSMSG_MULTIPLE_OWNERS", "There is more than one owner in %s; please use $bCLVL$b, $bDELOWNER$b and/or $bADDOWNER$b instead." },
{ "CSMSG_NO_OWNER", "There is no owner for %s; please use $bCLVL$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_BAN_DONE", "Banned $b%s$b from %s." },
{ "CSMSG_REASON_CHANGE", "Reason for LAMER $b%s$b changed." },
{ "CSMSG_LAMER_EXTENDED", "Extended LAMER for $b%s$b, now expires in %s." },
- { "CSMSG_BAN_REMOVED", "Matching ban(s) and LAMER(s) in $b%s$b were removed." },
+ { "CSMSG_BAN_REMOVED", "Ban(s) and LAMER(s) matching $b%s$b were removed." },
{ "CSMSG_TRIMMED_LAMERS", "Trimmed $b%d LAMERs$b from the %s LAMER list that were inactive for at least %s." },
{ "CSMSG_REDUNDANT_BAN", "$b%s$b is already banned in %s." },
{ "CSMSG_REDUNDANT_LAMER", "$b%s$b is already LAMER'd in %s." },
{ "CSMSG_SET_TOPICREFRESH", "$bTopicRefresh$b %d - %s" },
{ "CSMSG_SET_RESYNC", "$bResync $b %d - %s" },
{ "CSMSG_SET_BANTIMEOUT", "$bBanTimeout $b %d - %s" },
+ { "CSMSG_SET_MAXSETINFO", "$bMaxSetInfo $b %d - maximum characters in a setinfo line." },
{ "CSMSG_USET_AUTOOP", "$bAutoOp $b %s" },
{ "CSMSG_USET_AUTOVOICE", "$bAutoVoice $b %s" },
{ "CSMSG_DIE_ROLL", "A $b%lu$b shows on the %lu-sided die." },
{ "CSMSG_HUGGLES_HIM", "\001ACTION huggles %s\001" },
{ "CSMSG_HUGGLES_YOU", "\001ACTION huggles you\001" },
+ { "CSMSG_ROULETTE_LOADS", "\001ACTION loads the gun and sets it on the table\001" },
+ { "CSMSG_ROULETTE_NEW", "Please type .roulette to start a new round" } ,
+ { "CSMSG_ROULETTE_BETTER_LUCK", "Better luck next time, %s" },
+ { "CSMSG_ROULETTE_BANG", "Bang!!!" } ,
+ { "CSMSG_ROULETTE_CLICK", "Click" } ,
+
+ { "CSMSG_SPIN_WHEEL1", "\001ACTION spins the wheel of misfortune for: %s\001" } ,
+ { "CSMSG_SPIN_WHEEL2", "Round and round she goes, where she stops, nobody knows...!" } ,
+ { "CSMSG_SPIN_WHEEL3", "The wheel of misfortune has stopped on..." } ,
+
+ { "CSMSG_SPIN_1", "1: Peer's gonna eat you!!!!" } ,
+ { "CSMSG_SPIN_2", "2: Part all channels" } ,
+ { "CSMSG_SPIN_3", "3: Part all channels" } ,
+ { "CSMSG_SPIN_4", "4: /gline for random amount of time" } ,
+ { "CSMSG_SPIN_5", "5: /shun for random amount of time" } ,
+ { "CSMSG_SPIN_6", "6: Absolutely nothing" } ,
+ { "CSMSG_SPIN_7", "7: Join a bunch of random channels, then /part all of 'em several times" } ,
+ { "CSMSG_SPIN_8", "8: Abuse line added to /whois info" } ,
+ { "CSMSG_SPIN_9", "9: /kick from each channel you're in" } ,
+ { "CSMSG_SPIN_10", "10: Random Nick Change" } ,
+ { "CSMSG_SPIN_11", "11: /kill" } ,
+ { "CSMSG_SPIN_12", "12: Services ignore for random amount of time" } ,
+ { "CSMSG_SPIN_13", "13: /kick and ban from each channel your're in" } ,
/* Other things */
{ "CSMSG_EVENT_SEARCH_RESULTS", "$bChannel Events for %s$b" },
NOTE_VIS_PRIVILEGED
};
+struct io_fd *socket_io_fd;
+extern struct cManagerNode cManager;
+
struct note_type
{
enum note_access_type set_access_type;
#define GetChannelAccess(channel, handle) _GetChannelUser(channel, handle, 0, 0)
#define GetTrueChannelAccess(channel, handle) _GetChannelUser(channel, handle, 0, 1)
+void sputsock(const char *text, ...) PRINTF_LIKE(1, 2);
+
+void
+sputsock(const char *text, ...)
+{
+ va_list arg_list;
+ char buffer[MAXLEN];
+ int pos;
+
+ if (!cManager.uplink || cManager.uplink->state == DISCONNECTED) return;
+ buffer[0] = '\0';
+ va_start(arg_list, text);
+ pos = vsnprintf(buffer, MAXLEN - 2, text, arg_list);
+ va_end(arg_list);
+ if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
+ buffer[pos] = 0;
+ log_replay(MAIN_LOG, true, buffer);
+ buffer[pos++] = '\n';
+ buffer[pos] = 0;
+ ioset_write(socket_io_fd, buffer, pos);
+}
+
unsigned short
user_level_from_name(const char *name, unsigned short clamp_level)
{
}
static struct userData*
-add_channel_user(struct chanData *channel, struct handle_info *handle, unsigned short access, time_t seen, const char *info, time_t expiry)
+add_channel_user(struct chanData *channel, struct handle_info *handle, unsigned short access, time_t seen, const char *info, time_t accessexpiry)
{
struct userData *ud;
ud->seen = seen;
ud->access = access;
ud->info = info ? strdup(info) : NULL;
- ud->expiry = expiry;
+ ud->accessexpiry = accessexpiry ? accessexpiry : 0;
+ ud->clvlexpiry = 0;
+ ud->lastaccess = 0;
ud->prev = NULL;
ud->next = channel->users;
if (data) {
handle = strdup(uData->handle->handle);
- if (uData->expiry > 0) {
+ if (uData->accessexpiry > 0) {
if (uData->present) {
struct userNode *user, *next_un = NULL;
struct handle_info *hi;
}
}
+static void
+chanserv_expire_tempclvl(void *data)
+{
+ struct userData *uData = data;
+ char *handle;
+
+ if (data) {
+ handle = strdup(uData->handle->handle);
+ if (uData->clvlexpiry > 0) {
+ int changemodes = 0;
+ unsigned int mode = 0;
+
+ if (((uData->lastaccess == UL_PEON) || (uData->lastaccess == UL_HALFOP)) && (uData->access >= UL_OP)) {
+ changemodes = 1;
+ mode = MODE_REMOVE | MODE_CHANOP;
+ } else if ((uData->lastaccess == UL_PEON) && (uData->access == UL_HALFOP)) {
+ changemodes = 1;
+ mode = MODE_REMOVE | MODE_HALFOP;
+ } else
+ changemodes = 0;
+
+ if (uData->present) {
+ struct userNode *user, *next_un = NULL;
+ struct handle_info *hi;
+
+ hi = get_handle_info(handle);
+ for (user = hi->users; user; user = next_un) {
+ struct mod_chanmode *change;
+ struct modeNode *mn;
+ unsigned int count = 0;
+
+ send_message(user, chanserv, "CSMSG_CLVL_EXPIRED", uData->channel->channel->name);
+ if (!(mn = GetUserMode(uData->channel->channel, user))) {
+ next_un = user->next_authed;
+ continue;
+ }
+
+ if (changemodes == 0) {
+ next_un = user->next_authed;
+ continue;
+ }
+
+ change = mod_chanmode_alloc(2);
+ change->args[count].mode = mode;
+ change->args[count++].u.member = mn;
+
+ if (count) {
+ change->argc = count;
+ mod_chanmode_announce(chanserv, uData->channel->channel, change);
+ }
+ mod_chanmode_free(change);
+ next_un = user->next_authed;
+ }
+ }
+
+ uData->access = uData->lastaccess;
+ uData->lastaccess = 0;
+ uData->clvlexpiry = 0;
+ }
+ }
+}
+
void
del_channel_user(struct userData *user, int do_gc)
{
userCount--;
timeq_del(0, chanserv_expire_tempuser, user, TIMEQ_IGNORE_WHEN);
+ timeq_del(0, chanserv_expire_tempclvl, user, TIMEQ_IGNORE_WHEN);
if(user->prev)
user->prev->next = user->next;
/* Initialize the channel's max user record. */
cData->max = channel->members.used;
+ cData->maxsetinfo = chanserv_conf.max_userinfo_length;
if(handle != user->handle_info)
reply("CSMSG_PROXY_SUCCESS", handle->handle, channel->name);
return 0;
}
- time_t expiry = 0;
+ time_t accessexpiry = 0;
unsigned int duration = 0;
if (argc > 3) {
if ((duration = ParseInterval(argv[3])))
- expiry = now + duration;
+ accessexpiry = now + duration;
}
- actee = add_channel_user(channel->channel_info, handle, access, 0, NULL, expiry);
+ actee = add_channel_user(channel->channel_info, handle, access, 0, NULL, accessexpiry);
scan_user_presence(actee, NULL);
if (duration > 0)
- timeq_add(expiry, chanserv_expire_tempuser, actee);
+ timeq_add(accessexpiry, chanserv_expire_tempuser, actee);
reply("CSMSG_ADDED_USER", handle->handle, channel->name, user_level_name_from_level(access), access);
return 1;
return 0;
}
+ time_t clvlexpiry = 0;
+ unsigned int duration = 0;
+ if (argc > 3) {
+ if ((duration = ParseInterval(argv[3])))
+ clvlexpiry = now + duration;
+ }
+
+ if (duration > 0) {
+ if (victim->accessexpiry > 0) {
+ reply("CSMSG_NO_BUMP_EXPIRY");
+ return 0;
+ }
+
+ victim->clvlexpiry = clvlexpiry;
+ victim->lastaccess = victim->access;
+ timeq_add(clvlexpiry, chanserv_expire_tempclvl, victim);
+ }
+
victim->access = new_access;
reply("CSMSG_CHANGED_ACCESS", handle->handle, user_level_name_from_level(new_access), new_access, channel->name);
return 1;
if(argc > 2)
{
access = user_level_from_name(argv[1], UL_OWNER);
+ char *useraccess = user_level_name_from_level(victim->access);
if(!access)
{
reply("CSMSG_INVALID_ACCESS", argv[1]);
return 0;
}
- if(access != victim->access)
+ if(strcasecmp(argv[1], useraccess))
{
reply("CSMSG_INCORRECT_ACCESS", handle->handle, user_level_name_from_level(victim->access), argv[1]);
return 0;
else
ary[i++] = "Normal";
- if (uData->expiry > 0) {
+ if ((uData->accessexpiry > 0) || (uData->clvlexpiry > 0)) {
char delay[INTERVALLEN];
time_t diff;
- diff = uData->expiry - now;
- intervalString(delay, diff, user->handle_info);
+ if (uData->accessexpiry > 0) {
+ diff = uData->accessexpiry - now;
+ intervalString(delay, diff, user->handle_info);
+ } else {
+ diff = uData->clvlexpiry - now;
+ intervalString(delay, diff, user->handle_info);
+ }
ary[i++] = delay;
} else
ary[i++] = "Never";
return opt_greeting_common(user, cmd, argc, argv, "CSMSG_SET_USERGREETING", &channel->channel_info->user_greeting);
}
+static MODCMD_FUNC(chan_opt_maxsetinfo)
+{
+ unsigned int charmax;
+
+ if(argc > 1) {
+ charmax = atoi(argv[1]);
+ if ((charmax > 0) && (charmax < chanserv_conf.max_userinfo_length))
+ channel->channel_info->maxsetinfo = charmax;
+ }
+
+ reply("CSMSG_SET_MAXSETINFO", channel->channel_info->maxsetinfo);
+ return 1;
+}
+
static MODCMD_FUNC(chan_opt_modes)
{
struct mod_chanmode *new_modes;
{
size_t bp;
infoline = unsplit_string(argv + 1, argc - 1, NULL);
- if(strlen(infoline) > chanserv_conf.max_userinfo_length)
+ if(strlen(infoline) > channel->channel_info->maxsetinfo)
{
- reply("CSMSG_INFOLINE_TOO_LONG", chanserv_conf.max_userinfo_length);
+ reply("CSMSG_INFOLINE_TOO_LONG", channel->channel_info->maxsetinfo);
return 0;
}
bp = strcspn(infoline, "\001");
giveownership = calloc(1, sizeof(*giveownership));
giveownership->issued = now;
- giveownership->old_owner = curr_user->handle->handle;
- giveownership->target = new_owner_hi->handle;
+ giveownership->old_owner = strdup(curr_user->handle->handle);
+ giveownership->target = strdup(new_owner_hi->handle);
giveownership->target_access = new_owner_old_access;
if(override)
{
return 1;
}
+static CHANSERV_FUNC(cmd_roulette)
+{
+ if(channel) {
+ struct chanData *cData = channel->channel_info;
+
+ if (cData) {
+ if (cData->roulette_chamber) {
+ DelUser(user, chanserv, 1, "BANG - Don't stuff bullets into a loaded gun");
+ return 1;
+ }
+
+ send_target_message(1, channel->name, cmd->parent->bot, "CSMSG_ROULETTE_LOADS");
+ cData->roulette_chamber = 1 + rand() % 6;
+ }
+ }
+
+ return 1;
+}
+static CHANSERV_FUNC(cmd_shoot)
+{
+ if(channel) {
+ struct chanData *cData = channel->channel_info;
+
+ if (cData->roulette_chamber <= 0) {
+ reply("CSMSG_ROULETTE_NEW");
+ return 1;
+ }
+
+ cData->roulette_chamber--;
+
+ if (cData->roulette_chamber == 0) {
+ reply("CSMSG_ROULETTE_BANG");
+ reply("CSMSG_ROULETTE_BETTER_LUCK", user->nick);
+ DelUser(user, chanserv, 1, "BANG!!!!");
+ } else
+ reply("CSMSG_ROULETTE_CLICK");
+ }
+
+ return 1;
+}
+
+static void
+chanserv_remove_abuse(void *data)
+{
+ char *remnick = data;
+ struct userNode *user;
+ /* sometimes the clone was killed and maybe even the user took their nick back
+ * (ie, an oper) so dont kill them here after all unless they are local. */
+ if( (user = GetUserH(remnick)) )
+ if(IsLocal(user) )
+ DelUser(user, NULL, 1, "");
+}
+
+int lamepart(struct userNode *nick) {
+ struct modeNode *mn;
+ unsigned int count, n;
+
+ for (n=count=0; n<nick->channels.used; n++) {
+ mn = nick->channels.list[n];
+ irc_svspart(chanserv, nick, mn->channel);
+ }
+
+ return 0;
+}
+
+static CHANSERV_FUNC(cmd_spin)
+{
+ if(!channel)
+ return 1;
+
+ int type, lamep = 1;
+ char *tstr;
+
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ if(tstr) {
+ type = atoi(tstr);
+ if (type > 6)
+ lamep = 0;
+ }
+
+ int wheel = 1 + rand() % 12;
+
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_WHEEL1", user->nick);
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_WHEEL2");
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_WHEEL3");
+
+ if (wheel == 1) {
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_1");
+ if (type < 7)
+ irc_kill(chanserv, user, "Connection reset by peer");
+ else
+ sputsock("%s SQ %s :Connection reset by peer", self->numeric, user->numeric);
+ }
+ if (wheel == 2) {
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_2");
+ if (lamep)
+ lamepart(user);
+ else
+ sputsock("%s SJ %s 0 "FMT_TIME_T, self->numeric, user->numeric, now);
+ }
+ if (wheel == 3) {
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_3");
+ if (lamep)
+ lamepart(user);
+ else
+ sputsock("%s SJ %s 0 "FMT_TIME_T, self->numeric, user->numeric, now);
+ }
+ if (wheel == 4) {
+ char target[IRC_NTOP_MAX_SIZE + 3] = { '*', '@', '\0' };
+ int wtime = 120 + rand() % 600;
+
+ strcpy(target + 2, user->hostname);
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_4");
+
+ gline_add(chanserv->nick, target, wtime, "Reward for spinning the wheel of misfortune!", now, 1, 0);
+ irc_kill(chanserv, user, "Reward for spinning the wheel of misfortune!");
+ }
+ if (wheel == 5) {
+ char target[IRC_NTOP_MAX_SIZE + 3] = { '*', '@', '\0' };
+ int wtime = 120 + rand() % 600;
+
+ strcpy(target + 2, user->hostname);
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_5");
+
+ shun_add(chanserv->nick, target, wtime, "Reward for spinning the wheel of misfortune!", now, 1);
+ }
+ if (wheel == 6) {
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_6");
+ }
+ if (wheel == 7) {
+ int complete = 0;
+ int rndchans = 0;
+ int chango = 0;
+ int roundz0r = 0;
+
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_7");
+ while(complete != 1) {
+ if (rndchans != 15) {
+ chango = 120 + rand() % 600;
+ sputsock("%s SJ %s #%d %ld", self->numeric, user->numeric, chango, now);
+ rndchans++;
+ } else {
+ if (roundz0r != 1) {
+ if (lamep)
+ lamepart(user);
+ else
+ sputsock("%s SJ %s 0 "FMT_TIME_T, self->numeric, user->numeric, now);
+ roundz0r = 1;
+ rndchans = 0;
+ } else {
+ if (lamep)
+ lamepart(user);
+ else
+ sputsock("%s SJ %s 0 "FMT_TIME_T, self->numeric, user->numeric, now);
+ complete = 1;
+ }
+ }
+ }
+ }
+ if (wheel == 8) {
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_8");
+ irc_swhois(chanserv, user, "is being defecated on by services");
+ }
+ if (wheel == 9) {
+ unsigned int count, n;
+ struct modeNode *mn;
+
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_9");
+
+ for (n=count=0; n<user->channels.used; n++) {
+ mn = user->channels.list[n];
+ irc_kick(chanserv, user, mn->channel, "Reward for spinning the wheel of misfortune!");
+ }
+ }
+ if (wheel == 10) {
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_10");
+
+ char *oldnick = NULL;
+ char *oldident = NULL;
+ char *oldhost = NULL;
+ char abusednick[NICKLEN] = "";
+ int abusednum = time(NULL);
+ struct userNode *clone;
+
+ oldnick = strdup(user->nick);
+ oldident = strdup(user->ident);
+ oldhost = strdup(user->hostname);
+
+ snprintf(abusednick, NICKLEN, "Abused%d", abusednum+(1 + rand() % 120));
+ while (1) {
+ log_module(MAIN_LOG, LOG_DEBUG, "Abused Nick: %s, Client Nick: %s", abusednick, user->nick);
+ snprintf(abusednick, NICKLEN, "Abused%d", abusednum+(1 + rand() % 120));
+ if (user->nick != abusednick)
+ break;
+ }
+
+ SVSNickChange(user, abusednick);
+ irc_svsnick(chanserv, user, abusednick);
+
+ clone = AddClone(oldnick, oldident, oldhost, "I got abused by the wheel of misfortune :D");
+ timeq_add(now + 300, chanserv_remove_abuse, clone->nick);
+ }
+ if (wheel == 11) {
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_11");
+
+ irc_kill(chanserv, user, "Reward for spinning the wheel of misfortune!");
+ }
+ if (wheel == 12) {
+ int gagged, ignoretime = 0;
+ char target[IRC_NTOP_MAX_SIZE + 13] = { '+', 'b', ' ', '*', '!', '*', '@', '\0' };
+
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_12");
+
+ strcpy(target + 4, user->hostname);
+ srand(time(NULL));
+ ignoretime = now + (1 + rand() % 120);
+
+ gagged = gag_create(target, "wheelofabuse", "Reward for spinning the wheel of misfortune!", ignoretime);
+ }
+ if (wheel == 13) {
+ unsigned int count, n;
+ struct modeNode *mn;
+ char target[IRC_NTOP_MAX_SIZE + 1];
+
+ send_target_message(1, channel->name, chanserv, "CSMSG_SPIN_13");
+
+ snprintf(target, sizeof(target), "+b *!*@%s", user->hostname);
+ for (n=count=0; n<user->channels.used; n++) {
+ mn = user->channels.list[n];
+ irc_mode(chanserv, mn->channel, target);
+ irc_kick(chanserv, user, mn->channel, "Reward for spinning the wheel of misfortune!");
+ }
+ }
+
+ return 1;
+}
+
#ifdef lame8ball
static CHANSERV_FUNC(cmd_8ball)
{
SetChannelTopic(channel, chanserv, chanserv, channel->channel_info->topic, 1);
}
+int
+trace_check_bans(struct userNode *user, struct chanNode *chan)
+{
+ struct banData *bData;
+ struct mod_chanmode *change;
+
+ change = find_matching_bans(&chan->banlist, user, NULL);
+ if (change)
+ return 1;
+
+ /* lamer list */
+ if (chan->channel_info) {
+ for(bData = chan->channel_info->bans; bData; bData = bData->next) {
+
+ if(!user_matches_glob(user, bData->mask, MATCH_USENICK))
+ continue;
+
+ if(bData)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
int
check_bans(struct userNode *user, const char *channel)
{
return 0;
}
+int
+channel_user_is_exempt(struct userNode *user, struct chanNode *channel)
+{
+ unsigned int ii;
+ for(ii = 0; ii < channel->exemptlist.used; ii++)
+ {
+ if(user_matches_glob(user, channel->exemptlist.list[ii]->exempt, MATCH_USENICK))
+ return true;
+ }
+ return false;
+}
+
/* Welcome to my worst nightmare. Warning: Read (or modify)
the code below at your own risk. */
unsigned int modes = 0, info = 0;
char *greeting;
- if(IsLocal(user) || !channel->channel_info || IsSuspended(channel->channel_info))
+ if(IsLocal(user) || !channel || !channel->channel_info || IsSuspended(channel->channel_info))
return 0;
cData = channel->channel_info;
/* TODO: maybe only people above inviteme level? -Rubin */
/* We don't kick people with access */
- if(!uData)
+ if(!uData && !channel_user_is_exempt(user, channel))
{
if(channel->banlist.used < MAXBANS)
{
{
struct handle_info *handle;
struct userData *uData;
- char *seen, *inf, *flags, *expires, *expiry;
+ char *seen, *inf, *flags, *expires, *accessexpiry, *clvlexpiry, *lstacc;
time_t last_seen;
- unsigned short access;
+ unsigned short access, lastaccess = 0;
if(rd->type != RECDB_OBJECT || !dict_size(rd->d.object))
{
last_seen = seen ? (signed)strtoul(seen, NULL, 0) : now;
flags = database_get_data(rd->d.object, KEY_FLAGS, RECDB_QSTRING);
expires = database_get_data(rd->d.object, KEY_EXPIRES, RECDB_QSTRING);
- expiry = database_get_data(rd->d.object, KEY_EXPIRY, RECDB_QSTRING);
+ accessexpiry = database_get_data(rd->d.object, KEY_ACCESSEXPIRY, RECDB_QSTRING);
+ clvlexpiry = database_get_data(rd->d.object, KEY_CLVLEXPIRY, RECDB_QSTRING);
+ lstacc = database_get_data(rd->d.object, KEY_LASTLEVEL, RECDB_QSTRING);
+ lastaccess = lstacc ? atoi(lstacc) : 0;
+
handle = get_handle_info(key);
if(!handle)
{
uData = add_channel_user(chan, handle, access, last_seen, inf, 0);
uData->flags = flags ? strtoul(flags, NULL, 0) : 0;
uData->expires = expires ? strtoul(expires, NULL, 0) : 0;
- uData->expiry = expiry ? strtoul(expiry, NULL, 0) : 0;
- if (uData->expiry > 0)
- timeq_add(uData->expiry, chanserv_expire_tempuser, uData);
+
+ uData->accessexpiry = accessexpiry ? strtoul(accessexpiry, NULL, 0) : 0;
+ if (uData->accessexpiry > 0)
+ timeq_add(uData->accessexpiry, chanserv_expire_tempuser, uData);
+
+ uData->clvlexpiry = clvlexpiry ? strtoul(clvlexpiry, NULL, 0) : 0;
+ if (uData->clvlexpiry > 0)
+ timeq_add(uData->clvlexpiry, chanserv_expire_tempclvl, uData);
+
+ uData->lastaccess = lastaccess;
if((uData->flags & USER_SUSPENDED) && uData->expires)
{
str = database_get_data(channel, KEY_TOPIC, RECDB_QSTRING);
cData->topic = str ? strdup(str) : NULL;
+ str = database_get_data(channel, KEY_MAXSETINFO, RECDB_QSTRING);
+ cData->maxsetinfo = str ? strtoul(str, NULL, 0) : chanserv_conf.max_userinfo_length;
+
if(!IsSuspended(cData)
&& (str = database_get_data(channel, KEY_MODES, RECDB_QSTRING))
&& (argc = split_line(str, 0, ArrayLength(argv), argv))
saxdb_start_record(ctx, uData->handle->handle, 0);
saxdb_write_int(ctx, KEY_LEVEL, uData->access);
saxdb_write_int(ctx, KEY_SEEN, uData->seen);
- saxdb_write_int(ctx, KEY_EXPIRY, uData->expiry);
+ saxdb_write_int(ctx, KEY_ACCESSEXPIRY, uData->accessexpiry);
+ saxdb_write_int(ctx, KEY_CLVLEXPIRY, uData->clvlexpiry);
+ saxdb_write_int(ctx, KEY_LASTLEVEL, uData->lastaccess);
if(uData->flags)
saxdb_write_int(ctx, KEY_FLAGS, uData->flags);
if(uData->expires)
}
saxdb_end_record(ctx);
+ if (channel->maxsetinfo)
+ saxdb_write_int(ctx, KEY_MAXSETINFO, channel->maxsetinfo);
+
if(channel->modes.modes_set || channel->modes.modes_clear)
{
mod_chanmode_format(&channel->modes, buf);
{
struct chanNode *chan;
unsigned int i;
+
CS_LOG = log_register_type("ChanServ", "file:chanserv.log");
conf_register_reload(chanserv_conf_read);
DEFINE_COMMAND(huggle, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
DEFINE_COMMAND(calc, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
DEFINE_COMMAND(reply, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
+ DEFINE_COMMAND(roulette, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
+ DEFINE_COMMAND(shoot, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL);
+ DEFINE_COMMAND(spin, 1, MODCMD_REQUIRE_AUTHED, "spin", "+nolog,+toy,+acceptchan", NULL);
/* Channel options */
DEFINE_CHANNEL_OPTION(defaulttopic);
DEFINE_CHANNEL_OPTION(ctcpreaction);
DEFINE_CHANNEL_OPTION(bantimeout);
DEFINE_CHANNEL_OPTION(inviteme);
+ DEFINE_CHANNEL_OPTION(maxsetinfo);
if(off_channel > 1)
DEFINE_CHANNEL_OPTION(offchannel);
modcmd_register(chanserv_module, "set defaults", chan_opt_defaults, 1, 0, "access", "owner", NULL);
reg_exit_func(chanserv_db_cleanup);
message_register_table(msgtab);
}
+