summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam- <Adam-@5417fbe8-f217-4b02-8779-1006273d7864>2010-01-14 21:29:08 +0000
committerAdam- <Adam-@5417fbe8-f217-4b02-8779-1006273d7864>2010-01-14 21:29:08 +0000
commit711787b54d8b57ace877b09587f368cee5553b70 (patch)
treef5093aeeec5c1f4155e31f72488ae4040e37f551
parentf2c44c67b59bd4f6a5a01412f2dc5df59010b1da (diff)
Burned do_sjoin and rewrote it to be sane. This changes how Anope handles new channel creations drasitcally as we now truely track it all instead of hack around it by not initially tracking user joins to new channels
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@2755 5417fbe8-f217-4b02-8779-1006273d7864
-rw-r--r--TODO2
-rw-r--r--include/extern.h6
-rw-r--r--include/modes.h10
-rw-r--r--include/modules.h5
-rw-r--r--include/services.h23
-rw-r--r--src/channels.c827
-rw-r--r--src/chanserv.c79
-rw-r--r--src/core/cs_forbid.c1
-rw-r--r--src/core/cs_set.c2
-rw-r--r--src/core/os_defcon.c2
-rw-r--r--src/modes.cpp4
-rw-r--r--src/protocol/bahamut.c166
-rw-r--r--src/protocol/inspircd11.c157
-rw-r--r--src/protocol/inspircd12.cpp181
-rw-r--r--src/protocol/ratbox.c130
-rw-r--r--src/protocol/unreal32.c158
-rw-r--r--src/users.c2
17 files changed, 944 insertions, 811 deletions
diff --git a/TODO b/TODO
index 5850982b4..c09940f74 100644
--- a/TODO
+++ b/TODO
@@ -30,6 +30,7 @@ Legend:
[x] CS SET INHABIT to keep pseudoclient in a channel after it empties to maintain banlists and such
[x] Set forbidden channels +s
[x] SendAkill should just take a pointer to the Akill class instead of millions of fields (same for some other stuff)
+[x] burn do_sjoin with fire
Future
------
@@ -37,7 +38,6 @@ Future
[?] Remote identification (1.9.1? will this break stuff?)
[ ] Language charset stuff, including collation (1.9.1? phoenix?)
[ ] Add support for +k, +q, etc type umodes
-[ ] burn do_sjoin with fire
[ ] fantasy: allow replies/notifications to fantasy commands to go to the channel via notice
[?] a way for a module to queue itself (or even another module) for unloading
[ ] add overridden form of SendGlobops accepting BotInfo
diff --git a/include/extern.h b/include/extern.h
index 75ad3eb28..a46894fa2 100644
--- a/include/extern.h
+++ b/include/extern.h
@@ -68,9 +68,6 @@ E void bot_raw_mode(User * requester, ChannelInfo * ci, const char *mode, char *
E Channel *chanlist[1024];
-E void chan_adduser2(User * user, Channel * c);
-E Channel *join_user_update(User * user, Channel * chan, const char *name, time_t chants);
-
E void get_channel_stats(long *nrec, long *memuse);
E Channel *findchan(const char *chan);
E Channel *firstchan();
@@ -78,8 +75,6 @@ E Channel *nextchan();
E void ChanSetInternalModes(Channel *c, int ac, const char **av);
-E void chan_deluser(User * user, Channel * c);
-
E int is_on_chan(Channel * c, User * u);
E User *nc_on_chan(Channel * c, NickCore * nc);
@@ -97,7 +92,6 @@ E void do_cmode(const char *source, int ac, const char **av);
E void do_join(const char *source, int ac, const char **av);
E void do_kick(const std::string &source, int ac, const char **av);
E void do_part(const char *source, int ac, const char **av);
-E void do_sjoin(const char *source, int ac, const char **av);
E void do_topic(const char *source, int ac, const char **av);
E void MassChannelModes(BotInfo *bi, const std::string &modes);
diff --git a/include/modes.h b/include/modes.h
index 5a1fd60b5..64532bb6d 100644
--- a/include/modes.h
+++ b/include/modes.h
@@ -99,7 +99,7 @@ class UserModeParam : public UserMode
* @param value The param
* @return true or false
*/
- virtual bool IsValid(const char *value) { return true; }
+ virtual bool IsValid(const std::string &value) { return true; }
};
/** This class is a channel mode, all channel modes use this/inherit from this
@@ -151,7 +151,7 @@ class CoreExport ChannelModeList : public ChannelMode
* @param mask The mask
* @return true for yes, false for no
*/
- virtual bool IsValid(const char *mask) { return true; }
+ virtual bool IsValid(const std::string &mask) { return true; }
/** Add the mask to the channel, this should be overridden
* @param chan The channel
@@ -190,7 +190,7 @@ class CoreExport ChannelModeParam : public ChannelMode
* @param value The param
* @return true for yes, false for no
*/
- virtual bool IsValid(const char *value) { return true; }
+ virtual bool IsValid(const std::string &value) { return true; }
};
/** This is a mode that is a channel status, eg +v/h/o/a/q.
@@ -264,7 +264,7 @@ class CoreExport ChannelModeKey : public ChannelModeParam
public:
ChannelModeKey() : ChannelModeParam(CMODE_KEY) { }
- bool IsValid(const char *value);
+ bool IsValid(const std::string &value);
};
/** Channel mode +f (flood)
@@ -274,7 +274,7 @@ class ChannelModeFlood : public ChannelModeParam
public:
ChannelModeFlood() : ChannelModeParam(CMODE_FLOOD) { }
- bool IsValid(const char *value);
+ bool IsValid(const std::string &value);
};
/** This class is used for channel mode +A (Admin only)
diff --git a/include/modules.h b/include/modules.h
index 8903eb9c2..45541c28c 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -644,9 +644,10 @@ class CoreExport Module
/** Called before a user joins a channel
* @param u The user
- * @param channel The channel
+ * @param c The channel
+ * @return EVENT_STOP to allow the user to join the channel through restrictions, EVENT_CONTINUE to let other modules decide
*/
- virtual void OnPreJoinChannel(User *u, const char *channel) { }
+ virtual EventReturn OnPreJoinChannel(User *u, Channel *c) { return EVENT_CONTINUE; }
/** Called when a user joins a channel
* @param u The user
diff --git a/include/services.h b/include/services.h
index de6972fc2..244377419 100644
--- a/include/services.h
+++ b/include/services.h
@@ -410,10 +410,7 @@ struct ircdvars_ {
int knock_needs_i; /* Check if we needed +i when setting NOKNOCK */
char *chanmodes; /* If the ircd sends CHANMODE in CAPAB this is where we store it */
int token; /* Does Anope support the tokens for the ircd */
- int sjb64; /* Base 64 encode TIMESTAMP */
- int sjoinbanchar; /* use single quotes to define it */
- int sjoinexchar; /* use single quotes to define it */
- int sjoininvchar; /* use single quotes to define it */
+ int sjb64;
int svsmode_ucmode; /* Can remove User Channel Modes with SVSMODE */
int sglineenforce;
int ts6; /* ircd is TS6 */
@@ -832,7 +829,9 @@ struct c_userlist {
enum ChannelFlags
{
/* Channel still exists when emptied */
- CH_PERSIST
+ CH_PERSIST,
+ /* If set the channel is syncing users (eg, multi user SJOIN) and it should not be deleted */
+ CH_SYNCING
};
class CoreExport Channel : public Extensible, public Flags<ChannelFlags>
@@ -878,6 +877,20 @@ class CoreExport Channel : public Extensible, public Flags<ChannelFlags>
int16 bouncy_modes; /* Did we fail to set modes here? */
int16 topic_sync; /* Is the topic in sync? */
+ /** Restore the channel topic, set mlock (key), set stickied bans, etc
+ */
+ void Sync();
+
+ /** Join a user internally to the channel
+ * @param u The user
+ */
+ void JoinUser(User *u);
+
+ /** Remove a user internally from the channel
+ * @param u The user
+ */
+ void DeleteUser(User *u);
+
/**
* See if a channel has a mode
* @param Name The mode name
diff --git a/src/channels.c b/src/channels.c
index 6c6c399c6..e82da8dc2 100644
--- a/src/channels.c
+++ b/src/channels.c
@@ -52,16 +52,8 @@ Channel::Channel(const std::string &name, time_t ts)
this->ci = cs_findchan(this->name);
if (this->ci)
- {
this->ci->c = this;
- check_modes(this);
- stick_all(this->ci);
- }
-
- if (serv_uplink && is_sync(serv_uplink) && (!(this->topic_sync)))
- restore_topic(name.c_str());
-
FOREACH_MOD(I_OnChannelCreate, OnChannelCreate(this));
}
@@ -122,6 +114,141 @@ Channel::~Channel()
chanlist[HASH(this->name)] = this->next;
}
+void Channel::Sync()
+{
+ if (this->ci)
+ {
+ check_modes(this);
+ stick_all(this->ci);
+ }
+
+ if (serv_uplink && is_sync(serv_uplink) && !this->topic_sync)
+ restore_topic(name.c_str());
+}
+
+void Channel::JoinUser(User *user)
+{
+ struct u_chanlist *c;
+
+ if (debug)
+ alog("debug: %s joins %s", user->nick.c_str(), this->name.c_str());
+
+ c = new u_chanlist;
+ c->prev = NULL;
+ c->next = user->chans;
+ if (user->chans)
+ user->chans->prev = c;
+ user->chans = c;
+ c->chan = this;
+ c->status = 0;
+
+ struct c_userlist *u;
+
+ u = new c_userlist;
+ u->prev = NULL;
+ u->next = this->users;
+ if (this->users)
+ this->users->prev = u;
+ this->users = u;
+ u->user = user;
+ u->ud = NULL;
+ this->usercount++;
+
+ if (get_ignore(user->nick.c_str()) == NULL)
+ {
+ if (this->ci && (check_access(user, this->ci, CA_MEMO)) && (this->ci->memos.memos.size() > 0))
+ {
+ if (this->ci->memos.memos.size() == 1)
+ notice_lang(Config.s_MemoServ, user, MEMO_X_ONE_NOTICE, this->ci->memos.memos.size(), this->ci->name.c_str());
+ else
+ notice_lang(Config.s_MemoServ, user, MEMO_X_MANY_NOTICE, this->ci->memos.memos.size(), this->ci->name.c_str());
+ }
+ /* Added channelname to entrymsg - 30.03.2004, Certus */
+ /* Also, don't send the entrymsg when bursting -GD */
+ if (this->ci && this->ci->entry_message && is_sync(user->server))
+ user->SendMessage(whosends(this->ci)->nick, "[%s] %s", this->name.c_str(), this->ci->entry_message);
+ }
+
+ /**
+ * We let the bot join even if it was an ignored user, as if we don't,
+ * and the ignored user doesnt just leave, the bot will never
+ * make it into the channel, leaving the channel botless even for
+ * legit users - Rob
+ * But don't join the bot if the channel is persistant - Adam
+ **/
+ if (Config.s_BotServ && this->ci && this->ci->bi && !this->ci->HasFlag(CI_PERSIST))
+ {
+ if (this->usercount == Config.BSMinUsers)
+ bot_join(this->ci);
+ }
+ if (Config.s_BotServ && this->ci && this->ci->bi)
+ {
+ if (this->usercount >= Config.BSMinUsers && (this->ci->botflags.HasFlag(BS_GREET))
+ && user->nc && user->nc->greet && check_access(user, this->ci, CA_GREET))
+ {
+ /* Only display the greet if the main uplink we're connected
+ * to has synced, or we'll get greet-floods when the net
+ * recovers from a netsplit. -GD
+ */
+ if (is_sync(user->server))
+ {
+ ircdproto->SendPrivmsg(this->ci->bi, this->name.c_str(), "[%s] %s", user->nc->display, user->nc->greet);
+ this->ci->bi->lastmsg = time(NULL);
+ }
+ }
+ }
+}
+
+/** Remove a user internally from the channel
+ * @param u The user
+ */
+void Channel::DeleteUser(User *user)
+{
+ if (this->ci)
+ update_cs_lastseen(user, this->ci);
+
+ struct c_userlist *u;
+ for (u = this->users; u && u->user != user; u = u->next);
+ if (!u)
+ return;
+
+ if (u->ud)
+ {
+ if (u->ud->lastline)
+ delete [] u->ud->lastline;
+ delete u->ud;
+ }
+
+ if (u->next)
+ u->next->prev = u->prev;
+ if (u->prev)
+ u->prev->next = u->next;
+ else
+ this->users = u->next;
+ delete u;
+ this->usercount--;
+
+ /* Channel is persistant, it shouldn't be deleted and the service bot should stay */
+ if (this->HasFlag(CH_PERSIST) || (this->ci && this->ci->HasFlag(CI_PERSIST)))
+ return;
+
+ /* Channel is syncing from a netburst, don't destroy it as more users are probably wanting to join immediatly
+ * We also don't part the bot here either, if necessary we will part it after the sync
+ */
+ if (this->HasFlag(CH_SYNCING))
+ return;
+
+ /* Additionally, do not delete this channel if ChanServ/a BotServ bot is inhabiting it */
+ if (this->ci && this->ci->HasFlag(CI_INHABIT))
+ return;
+
+ if (Config.s_BotServ && this->ci && this->ci->bi && this->usercount <= Config.BSMinUsers - 1)
+ ircdproto->SendPart(this->ci->bi, this, NULL);
+
+ if (!this->users)
+ delete this;
+}
+
/**
* See if a channel has a mode
* @param Name The mode name
@@ -290,12 +417,12 @@ void Channel::RemoveModeInternal(ChannelMode *cm, const std::string &param, bool
User *u = finduser(param);
if (!u)
{
- alog("Channel::RemoveModeInternal() MODE %s +%c for nonexistant user %s", this->name.c_str(), cm->ModeChar, param.c_str());
+ alog("Channel::RemoveModeInternal() MODE %s -%c for nonexistant user %s", this->name.c_str(), cm->ModeChar, param.c_str());
return;
}
if (debug)
- alog("debug: Setting +%c on %s for %s", cm->ModeChar, this->name.c_str(), u->nick.c_str());
+ alog("debug: Setting -%c on %s for %s", cm->ModeChar, this->name.c_str(), u->nick.c_str());
ChannelModeStatus *cms = dynamic_cast<ChannelModeStatus *>(cm);
chan_remove_user_status(this, u, cms->Status);
@@ -381,9 +508,24 @@ void Channel::RemoveModeInternal(ChannelMode *cm, const std::string &param, bool
*/
void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const std::string &param, bool EnforceMLock)
{
- if (!cm || HasMode(cm->Name))
+ if (!cm)
+ return;
+ /* Don't set modes already set */
+ if ((cm->Type == MODE_REGULAR || cm->Type == MODE_PARAM) && HasMode(cm->Name))
return;
+ else if (cm->Type == MODE_STATUS)
+ {
+ User *u = finduser(param);
+ if (u)
+ {
+ if (chan_has_user_status(this, u, dynamic_cast<ChannelModeStatus *>(cm)->Status))
+ {
+ return;
+ }
+ }
+ }
+
ModeManager::StackerAdd(bi, this, cm, true, param);
SetModeInternal(cm, param, EnforceMLock);
}
@@ -420,8 +562,23 @@ void Channel::SetMode(BotInfo *bi, char Mode, const std::string &param, bool Enf
*/
void Channel::RemoveMode(BotInfo *bi, ChannelMode *cm, const std::string &param, bool EnforceMLock)
{
- if (!cm || !HasMode(cm->Name))
+ if (!cm)
+ return;
+ /* Don't unset modes that arent set */
+ if ((cm->Type == MODE_REGULAR || cm->Type == MODE_PARAM) && !HasMode(cm->Name))
return;
+ /* Don't unset status that aren't set */
+ else if (cm->Type == MODE_STATUS)
+ {
+ User *u = finduser(param);
+ if (u)
+ {
+ if (!chan_has_user_status(this, u, dynamic_cast<ChannelModeStatus *>(cm)->Status))
+ {
+ return;
+ }
+ }
+ }
ModeManager::StackerAdd(bi, this, cm, false, param);
RemoveModeInternal(cm, param, EnforceMLock);
@@ -748,7 +905,7 @@ void Channel::KickInternal(const std::string &source, const std::string &nick, c
if (c)
{
FOREACH_MOD(I_OnUserKicked, OnUserKicked(c->chan, user, source, reason));
- chan_deluser(user, c->chan);
+ c->chan->DeleteUser(user);
if (c->next)
c->next->prev = c->prev;
if (c->prev)
@@ -784,47 +941,6 @@ bool Channel::Kick(BotInfo *bi, User *u, const char *reason, ...)
return true;
}
-/*************************************************************************/
-
-void chan_deluser(User * user, Channel * c)
-{
- struct c_userlist *u;
-
- if (c->ci)
- update_cs_lastseen(user, c->ci);
-
- for (u = c->users; u && u->user != user; u = u->next);
- if (!u)
- return;
-
- if (u->ud) {
- if (u->ud->lastline)
- delete [] u->ud->lastline;
- delete u->ud;
- }
-
- if (u->next)
- u->next->prev = u->prev;
- if (u->prev)
- u->prev->next = u->next;
- else
- c->users = u->next;
- delete u;
- c->usercount--;
-
- /* Channel is persistant, it shouldn't be deleted and the service bot should stay */
- if (c->HasFlag(CH_PERSIST) || (c->ci && c->ci->HasFlag(CI_PERSIST)))
- return;
-
- if (Config.s_BotServ && c->ci && c->ci->bi && c->usercount == Config.BSMinUsers - 1)
- ircdproto->SendPart(c->ci->bi, c, NULL);
-
- if (!c->users)
- delete c;
-}
-
-/*************************************************************************/
-
/* Returns a fully featured binary modes string. If complete is 0, the
* eventual parameters won't be added to the string.
*/
@@ -1134,6 +1250,7 @@ void do_join(const char *source, int ac, const char **av)
char *s, *t;
struct u_chanlist *c, *nextc;
char *channame;
+ time_t ctime = time(NULL);
if (ircd->ts6) {
user = find_byuid(source);
@@ -1162,7 +1279,7 @@ void do_join(const char *source, int ac, const char **av)
nextc = c->next;
channame = sstrdup(c->chan->name.c_str());
FOREACH_MOD(I_OnPrePartChannel, OnPrePartChannel(user, c->chan));
- chan_deluser(user, c->chan);
+ c->chan->DeleteUser(user);
FOREACH_MOD(I_OnPartChannel, OnPartChannel(user, findchan(channame), channame, ""));
delete [] channame;
delete c;
@@ -1174,28 +1291,52 @@ void do_join(const char *source, int ac, const char **av)
chan = findchan(s);
- /* how about not triggering the JOIN event on an actual /part :) -certus */
- FOREACH_MOD(I_OnPreJoinChannel, OnPreJoinChannel(user, s));
+ /* Channel doesn't exist, create it */
+ if (!chan)
+ {
+ chan = new Channel(av[0], ctime);
+ }
- /* Make sure check_kick comes before chan_adduser, so banned users
- * don't get to see things like channel keys. */
- /* If channel already exists, check_kick() will use correct TS.
- * Otherwise, we lose. */
- if (chan && chan->ci && chan->ci->CheckKick(user))
- continue;
+ /* Join came with a TS */
+ if (ac == 2)
+ {
+ time_t ts = atol(av[1]);
- time_t ts = time(NULL);
- if (ac == 2) {
- ts = strtoul(av[1], NULL, 10);
- if (debug) {
- alog("debug: recieved a new TS for JOIN: %ld",
- static_cast<long>(ts));
+ /* Their time is older, we lose */
+ if (chan->creation_time > ts)
+ {
+ if (debug)
+ alog("debug: recieved a new TS for JOIN: %ld", ts);
+
+ if (chan->ci)
+ {
+ /* Cycle the bot to fix ts */
+ if (chan->ci->bi)
+ {
+ ircdproto->SendPart(chan->ci->bi, chan, "TS reop");
+ bot_join(chan->ci);
+ }
+ /* Be sure to set mlock again, else we could be -r etc.. */
+ check_modes(chan);
+ }
}
}
- chan = join_user_update(user, chan, s, ts);
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(user, chan));
+
+ /* Join the user to the channel */
+ chan->JoinUser(user);
+ /* Set the propre modes on the user */
chan_set_correct_modes(user, chan, 1);
+ /* Modules may want to allow this user in the channel, check.
+ * If not, CheckKick will kick/ban them, don't call OnJoinChannel after this as the user will have
+ * been destroyed
+ */
+ if (MOD_RESULT != EVENT_STOP && chan && chan->ci && chan->ci->CheckKick(user))
+ continue;
+
FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(user, chan));
}
}
@@ -1269,7 +1410,7 @@ void do_part(const char *source, int ac, const char **av)
FOREACH_MOD(I_OnPrePartChannel, OnPrePartChannel(user, c->chan));
std::string ChannelName = c->chan->name;
- chan_deluser(user, c->chan);
+ c->chan->DeleteUser(user);
FOREACH_MOD(I_OnPartChannel, OnPartChannel(user, findchan(ChannelName.c_str()), ChannelName, av[1] ? av[1] : ""));
@@ -1286,424 +1427,6 @@ void do_part(const char *source, int ac, const char **av)
/*************************************************************************/
-/* Handle a SJOIN command.
-
- On channel creation, syntax is:
-
- av[0] = timestamp
- av[1] = channel name
- av[2|3|4] = modes \ depends of whether the modes k and l
- av[3|4|5] = users / are set or not.
-
- When a single user joins an (existing) channel, it is:
-
- av[0] = timestamp
- av[1] = user
-
- ============================================================
-
- Unreal SJOIN
-
- On Services connect there is
- SJOIN !11LkOb #ircops +nt :@Trystan &*!*@*.aol.com "*@*.home.com
-
- av[0] = time stamp (base64)
- av[1] = channel
- av[2] = modes
- av[3] = users + bans + exceptions
-
- On Channel Creation or a User joins an existing
- Luna.NomadIrc.Net SJOIN !11LkW9 #akill :@Trystan
- Luna.NomadIrc.Net SJOIN !11LkW9 #akill :Trystan`
-
- av[0] = time stamp (base64)
- av[1] = channel
- av[2] = users
-
-*/
-
-void do_sjoin(const char *source, int ac, const char **av)
-{
- Channel *c;
- User *user;
- Server *serv;
- struct c_userlist *cu;
- const char *s = NULL;
- char *buf, *end, cubuf[7], *end2, value;
- const char *modes[6];
- int is_sqlined = 0;
- int ts = 0;
- int is_created = 0;
- int keep_their_modes = 1;
- ChannelModeList *cml;
-
- serv = findserver(servlist, source);
-
- if (ircd->sjb64) {
- ts = base64dects(av[0]);
- } else {
- ts = strtoul(av[0], NULL, 10);
- }
- c = findchan(av[1]);
- if (c != NULL) {
- if (c->creation_time == 0 || ts == 0)
- c->creation_time = 0;
- else if (c->creation_time > ts) {
- c->creation_time = ts;
- for (cu = c->users; cu; cu = cu->next) {
- c->RemoveMode(NULL, CMODE_OP, cu->user->nick);
- c->RemoveMode(NULL, CMODE_VOICE, cu->user->nick);
- }
- if (c->ci)
- {
- if (c->ci->bi)
- {
- /* This is ugly, but it always works */
- ircdproto->SendPart(c->ci->bi, c, "TS reop");
- bot_join(c->ci);
- }
- /* Make sure +r is set */
- if (ModeManager::FindChannelModeByName(CMODE_REGISTERED))
- {
- c->SetMode(NULL, CMODE_REGISTERED);
- }
- }
- /* XXX simple modes and bans */
- } else if (c->creation_time < ts)
- keep_their_modes = 0;
- } else
- is_created = 1;
-
- /* Double check to avoid unknown modes that need parameters */
- if (ac >= 4) {
- if (ircd->chansqline) {
- if (!c)
- is_sqlined = check_chan_sqline(av[1]);
- }
-
- cubuf[0] = '+';
- modes[0] = cubuf;
-
- /* We make all the users join */
- s = av[ac - 1]; /* Users are always the last element */
-
- while (*s) {
- end = const_cast<char *>(strchr(s, ' '));
- if (end)
- *end = 0;
-
- end2 = cubuf + 1;
-
-
- if (ircd->sjoinbanchar) {
- if (*s == ircd->sjoinbanchar && keep_their_modes) {
- buf = myStrGetToken(s, ircd->sjoinbanchar, 1);
-
- cml = dynamic_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_BAN));
- if (cml->IsValid(buf))
- cml->AddMask(c, buf);
-
- delete [] buf;
- if (!end)
- break;
- s = end + 1;
- continue;
- }
- }
- if (ircd->sjoinexchar) {
- if (*s == ircd->sjoinexchar && keep_their_modes) {
- buf = myStrGetToken(s, ircd->sjoinexchar, 1);
-
- cml = dynamic_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_EXCEPT));
- if (cml->IsValid(buf))
- cml->AddMask(c, buf);
-
- delete [] buf;
- if (!end)
- break;
- s = end + 1;
- continue;
- }
- }
-
- if (ircd->sjoininvchar) {
- if (*s == ircd->sjoininvchar && keep_their_modes) {
- buf = myStrGetToken(s, ircd->sjoininvchar, 1);
-
- cml = dynamic_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE));
- if (cml->IsValid(buf))
- cml->AddMask(c, buf);
-
- delete [] buf;
- if (!end)
- break;
- s = end + 1;
- continue;
- }
- }
-
- while ((value = ModeManager::GetStatusChar(*s)))
- {
- *end2++ = value;
- *s++;
- }
- *end2 = 0;
-
- if (ircd->ts6) {
- user = find_byuid(s);
- if (!user)
- user = finduser(s);
- } else {
- user = finduser(s);
- }
-
- if (!user) {
- if (debug) {
- alog("debug: SJOIN for nonexistent user %s on %s", s,
- av[1]);
- }
- return;
- }
-
- if (is_sqlined && !is_oper(user)) {
- ircdproto->SendKick(findbot(Config.s_OperServ), c, user, "Q-Lined");
- } else {
- if (!c || !c->ci || !c->ci->CheckKick(user))
- {
- FOREACH_MOD(I_OnPreJoinChannel, OnPreJoinChannel(user, av[1]));
-
- /* Make the user join; if the channel does not exist it
- * will be created there. This ensures that the channel
- * is not created to be immediately destroyed, and
- * that the locked key or topic is not shown to anyone
- * who joins the channel when empty.
- */
- c = join_user_update(user, c, av[1], ts);
-
- /* We update user mode on the channel */
- if (end2 - cubuf > 1 && keep_their_modes) {
- int i;
-
- for (i = 1; i < end2 - cubuf; i++)
- modes[i] = user->nick.c_str();
-
- ChanSetInternalModes(c, 1 + (end2 - cubuf - 1), modes);
- }
-
- if (c->ci && (!serv || is_sync(serv))
- && !c->topic_sync)
- restore_topic(c->name.c_str());
- chan_set_correct_modes(user, c, 1);
-
- FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(user, c));
- }
- }
-
- if (!end)
- break;
- s = end + 1;
- }
-
- if (c && keep_their_modes) {
- /* We now update the channel mode. */
- ChanSetInternalModes(c, ac - 3, &av[2]);
- }
-
- /* Unreal just had to be different */
- } else if (ac == 3 && !ircd->ts6) {
- if (ircd->chansqline) {
- if (!c)
- is_sqlined = check_chan_sqline(av[1]);
- }
-
- cubuf[0] = '+';
- modes[0] = cubuf;
-
- /* We make all the users join */
- s = av[2]; /* Users are always the last element */
-
- while (*s) {
- end = const_cast<char *>(strchr(s, ' '));
- if (end)
- *end = 0;
-
- end2 = cubuf + 1;
-
- while ((value = ModeManager::GetStatusChar(*s)))
- {
- *end2++ = value;
- *s++;
- }
- *end2 = 0;
-
- if (ircd->ts6) {
- user = find_byuid(s);
- if (!user)
- user = finduser(s);
- } else {
- user = finduser(s);
- }
-
- if (!user) {
- if (debug) {
- alog("debug: SJOIN for nonexistent user %s on %s", s,
- av[1]);
- }
- return;
- }
-
- if (is_sqlined && !is_oper(user)) {
- ircdproto->SendKick(findbot(Config.s_OperServ), c, user, "Q-Lined");
- } else {
- if (!c || !c->ci || !c->ci->CheckKick(user))
- {
- FOREACH_MOD(I_OnPreJoinChannel, OnPreJoinChannel(user, av[1]));
-
- /* Make the user join; if the channel does not exist it
- * will be created there. This ensures that the channel
- * is not created to be immediately destroyed, and
- * that the locked key or topic is not shown to anyone
- * who joins the channel when empty.
- */
- c = join_user_update(user, c, av[1], ts);
-
- /* We update user mode on the channel */
- if (end2 - cubuf > 1 && keep_their_modes) {
- int i;
-
- for (i = 1; i < end2 - cubuf; i++)
- modes[i] = user->nick.c_str();
- ChanSetInternalModes(c, 1 + (end2 - cubuf - 1), modes);
- }
-
- chan_set_correct_modes(user, c, 1);
-
- FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(user, c));
- }
- }
-
- if (!end)
- break;
- s = end + 1;
- }
- } else if (ac == 3 && ircd->ts6) {
- if (ircd->chansqline) {
- if (!c)
- is_sqlined = check_chan_sqline(av[1]);
- }
-
- cubuf[0] = '+';
- modes[0] = cubuf;
-
- /* We make all the users join */
- s = sstrdup(source); /* Users are always the last element */
-
- while (*s) {
- end = const_cast<char *>(strchr(s, ' '));
- if (end)
- *end = 0;
-
- end2 = cubuf + 1;
-
- while ((value = ModeManager::GetStatusChar(*s)))
- {
- *end2++ = value;
- *s++;
- }
- *end2 = 0;
-
- if (ircd->ts6) {
- user = find_byuid(s);
- if (!user)
- user = finduser(s);
- } else {
- user = finduser(s);
- }
- if (!user) {
- if (debug) {
- alog("debug: SJOIN for nonexistent user %s on %s", s,
- av[1]);
- }
- delete [] s;
- return;
- }
-
- if (is_sqlined && !is_oper(user)) {
- ircdproto->SendKick(findbot(Config.s_OperServ), c, user, "Q-Lined");
- } else {
- if (!c || !c->ci || !c->ci->CheckKick(user))
- {
- FOREACH_MOD(I_OnPreJoinChannel, OnPreJoinChannel(user, av[1]));
-
- /* Make the user join; if the channel does not exist it
- * will be created there. This ensures that the channel
- * is not created to be immediately destroyed, and
- * that the locked key or topic is not shown to anyone
- * who joins the channel when empty.
- */
- c = join_user_update(user, c, av[1], ts);
-
- /* We update user mode on the channel */
- if (end2 - cubuf > 1 && keep_their_modes) {
- int i;
-
- for (i = 1; i < end2 - cubuf; i++)
- modes[i] = user->nick.c_str();
- ChanSetInternalModes(c, 1 + (end2 - cubuf - 1), modes);
- }
-
- chan_set_correct_modes(user, c, 1);
-
- FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(user, c));
- }
- }
-
- if (!end)
- break;
- s = end + 1;
- }
- delete [] s;
- } else if (ac == 2) {
- if (ircd->ts6) {
- user = find_byuid(source);
- if (!user)
- user = finduser(source);
- } else {
- user = finduser(source);
- }
- if (!user) {
- if (debug) {
- alog("debug: SJOIN for nonexistent user %s on %s", source,
- av[1]);
- }
- return;
- }
-
- if (c && c->ci && c->ci->CheckKick(user))
- return;
-
- if (ircd->chansqline) {
- if (!c)
- is_sqlined = check_chan_sqline(av[1]);
- }
-
- if (is_sqlined && !is_oper(user)) {
- ircdproto->SendKick(findbot(Config.s_OperServ), c, user, "Q-Lined");
- } else {
- FOREACH_MOD(I_OnPreJoinChannel, OnPreJoinChannel(user, av[1]));
-
- c = join_user_update(user, c, av[1], ts);
- if (is_created && c->ci)
- restore_topic(c->name.c_str());
- chan_set_correct_modes(user, c, 1);
-
- FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(user, c));
- }
- }
-}
-
-/*************************************************************************/
-
/** Process a MODE command from the server, and set the modes on the user/channel
* it was sent for
* @param source The source of the command
@@ -1997,132 +1720,6 @@ void chan_set_correct_modes(User * user, Channel * c, int give_modes)
/*************************************************************************/
-/* Add/remove a user to/from a channel, creating or deleting the channel as
- * necessary. If creating the channel, restore mode lock and topic as
- * necessary. Also check for auto-opping and auto-voicing.
- */
-
-void chan_adduser2(User * user, Channel * c)
-{
- struct c_userlist *u;
-
- u = new c_userlist;
- u->prev = NULL;
- u->next = c->users;
- if (c->users)
- c->users->prev = u;
- c->users = u;
- u->user = user;
- u->ud = NULL;
- c->usercount++;
-
- if (get_ignore(user->nick.c_str()) == NULL) {
- if (c->ci && (check_access(user, c->ci, CA_MEMO))
- && (c->ci->memos.memos.size() > 0)) {
- if (c->ci->memos.memos.size() == 1) {
- notice_lang(Config.s_MemoServ, user, MEMO_X_ONE_NOTICE,
- c->ci->memos.memos.size(), c->ci->name.c_str());
- } else {
- notice_lang(Config.s_MemoServ, user, MEMO_X_MANY_NOTICE,
- c->ci->memos.memos.size(), c->ci->name.c_str());
- }
- }
- /* Added channelname to entrymsg - 30.03.2004, Certus */
- /* Also, don't send the entrymsg when bursting -GD */
- if (c->ci && c->ci->entry_message && is_sync(user->server))
- user->SendMessage(whosends(c->ci)->nick, "[%s] %s", c->name.c_str(), c->ci->entry_message);
- }
-
- /**
- * We let the bot join even if it was an ignored user, as if we don't,
- * and the ignored user dosnt just leave, the bot will never
- * make it into the channel, leaving the channel botless even for
- * legit users - Rob
- * But don't join the bot if the channel is persistant - Adam
- **/
- if (Config.s_BotServ && c->ci && c->ci->bi && !c->ci->HasFlag(CI_PERSIST))
- {
- if (c->usercount == Config.BSMinUsers)
- bot_join(c->ci);
- }
- if (Config.s_BotServ && c->ci && c->ci->bi)
- {
- if (c->usercount >= Config.BSMinUsers && (c->ci->botflags.HasFlag(BS_GREET))
- && user->nc && user->nc->greet
- && check_access(user, c->ci, CA_GREET)) {
- /* Only display the greet if the main uplink we're connected
- * to has synced, or we'll get greet-floods when the net
- * recovers from a netsplit. -GD
- */
- if (is_sync(user->server)) {
- ircdproto->SendPrivmsg(c->ci->bi, c->name.c_str(), "[%s] %s",
- user->nc->display, user->nc->greet);
- c->ci->bi->lastmsg = time(NULL);
- }
- }
- }
-}
-
-/*************************************************************************/
-
-Channel *join_user_update(User * user, Channel * chan, const char *name,
- time_t chants)
-{
- struct u_chanlist *c;
-
- /* If it's a new channel, so we need to create it first. */
- if (!chan)
- chan = new Channel(name, chants);
- else
- {
- // Check chants against 0, as not every ircd sends JOIN with a TS.
- if (chan->creation_time > chants && chants != 0)
- {
- struct c_userlist *cu;
-
- chan->creation_time = chants;
- for (cu = chan->users; cu; cu = cu->next)
- {
- chan->RemoveMode(NULL, CMODE_OP, cu->user->nick);
- chan->RemoveMode(NULL, CMODE_VOICE, cu->user->nick);
- }
- if (chan->ci)
- {
- if (chan->ci->bi)
- {
- /* This is ugly, but it always works */
- ircdproto->SendPart(chan->ci->bi, chan, "TS reop");
- bot_join(chan->ci);
- }
- /* Make sure +r is set */
- if (ModeManager::FindChannelModeByName(CMODE_REGISTERED))
- {
- chan->SetMode(NULL, CMODE_REGISTERED);
- }
- }
- /* XXX simple modes and bans */
- }
- }
-
- if (debug)
- alog("debug: %s joins %s", user->nick.c_str(), chan->name.c_str());
-
- c = new u_chanlist;
- c->prev = NULL;
- c->next = user->chans;
- if (user->chans)
- user->chans->prev = c;
- user->chans = c;
- c->chan = chan;
- c->status = 0;
-
- chan_adduser2(user, chan);
-
- return chan;
-}
-
-/*************************************************************************/
-
/** Set modes on every channel
* This overrides mlock on channels
* @param bi The bot to send the modes from
diff --git a/src/chanserv.c b/src/chanserv.c
index 8c74d1c6a..af458e42b 100644
--- a/src/chanserv.c
+++ b/src/chanserv.c
@@ -119,26 +119,41 @@ void moduleAddChanServCmds() {
/* *INDENT-ON* */
/*************************************************************************/
+/** A timer used to keep the BotServ bot/ChanServ in the channel
+ * after kicking the last user in a channel
+ */
class ChanServTimer : public Timer
{
- private:
- std::string channel;
+ private:
+ Channel *c;
- public:
- ChanServTimer(long delay, const std::string &chan) : Timer(delay), channel(chan)
- {
- }
+ public:
+ ChanServTimer(Channel *chan) : Timer(Config.CSInhabit), c(chan)
+ {
+ if (c->ci)
+ c->ci->SetFlag(CI_INHABIT);
+ }
- void Tick(time_t ctime)
- {
- ChannelInfo *ci = cs_findchan(channel);
+ void Tick(time_t)
+ {
+ if (!c->ci)
+ return;
- if (ci)
- ci->UnsetFlag(CI_INHABIT);
+ c->ci->UnsetFlag(CI_INHABIT);
- if (ci->c)
- ircdproto->SendPart(findbot(Config.s_ChanServ), ci->c, NULL);
- }
+ /* If the channel has users again, don't part it and halt */
+ if (c->usercount)
+ return;
+
+ if (c->ci->bi)
+ ircdproto->SendPart(c->ci->bi, c, NULL);
+ else
+ ircdproto->SendPart(findbot(Config.s_ChanServ), c, NULL);
+
+ /* Now delete the channel as it is empty */
+ if (!c->HasFlag(CH_PERSIST) && !c->ci->HasFlag(CI_PERSIST))
+ delete c;
+ }
};
/*************************************************************************/
@@ -611,9 +626,8 @@ bool ChannelInfo::CheckKick(User *user)
NickCore *nc;
char mask[BUFSIZE];
const char *reason;
- ChanServTimer *t;
- if (!user)
+ if (!user || !this->c)
return false;
if (user->isSuperAdmin == 1)
@@ -680,18 +694,12 @@ bool ChannelInfo::CheckKick(User *user)
alog("debug: channel: AutoKicking %s!%s@%s from %s", user->nick.c_str(),
user->GetIdent().c_str(), user->host, this->name.c_str());
- /* Remember that the user has not been added to our channel user list
- * yet, so we check whether the channel does not exist OR has no user
- * on it (before SJOIN would have created the channel structure, while
- * JOIN would not). */
- /* Don't check for CI_INHABIT before for the Channel record cos else
- * c may be NULL even if it exists */
- if ((!this->c || this->c->usercount == 0) && !this->HasFlag(CI_INHABIT))
+ /* If the channel doesnt have any users and if a bot isn't already in the channel, join it
+ * NOTE: we use usercount == 1 here as there is one user, but they are about to be destroyed
+ */
+ if (this->c->usercount == 1 && !this->HasFlag(CI_INHABIT))
{
- ircdproto->SendJoin(findbot(Config.s_ChanServ), this->name.c_str(), (this->c ? this->c->creation_time : time(NULL)));
- /*
- * If channel was forbidden, etc, set it +si to prevent rejoin
- */
+ /* If channel was forbidden, etc, set it +si to prevent rejoin */
if (set_modes)
{
c->SetMode(NULL, CMODE_NOEXTERNAL);
@@ -700,15 +708,18 @@ bool ChannelInfo::CheckKick(User *user)
c->SetMode(NULL, CMODE_INVITE);
}
- t = new ChanServTimer(Config.CSInhabit, this->name.c_str());
- this->SetFlag(CI_INHABIT);
+ /* This channel has no bot assigned to it, join ChanServ */
+ if (!this->bi)
+ {
+ ircdproto->SendJoin(findbot(Config.s_ChanServ), this->name.c_str(), this->c->creation_time);
+ }
+
+ /* Set a timer for this channel to part the bots later */
+ new ChanServTimer(this->c);
}
- if (c)
- {
- c->SetMode(NULL, CMODE_BAN, mask);
- ircdproto->SendKick(whosends(this), c, user, "%s", reason);
- }
+ this->c->SetMode(NULL, CMODE_BAN, mask);
+ this->c->Kick(NULL, user, "%s", reason);
return true;
}
diff --git a/src/core/cs_forbid.c b/src/core/cs_forbid.c
index adf82ab2c..718cd41a1 100644
--- a/src/core/cs_forbid.c
+++ b/src/core/cs_forbid.c
@@ -68,7 +68,6 @@ class CommandCSForbid : public Command
if ((c = findchan(ci->name.c_str())))
{
struct c_userlist *cu, *nextu;
- const char *av[3];
/* Before banning everyone, it might be prudent to clear +e and +I lists..
* to prevent ppl from rejoining.. ~ Viper */
diff --git a/src/core/cs_set.c b/src/core/cs_set.c
index dbe35f79c..277649cfb 100644
--- a/src/core/cs_set.c
+++ b/src/core/cs_set.c
@@ -217,7 +217,7 @@ class CommandCSSet : public Command
if (!modeparams.GetToken(param))
continue;
- if (!cmp->IsValid(param.c_str()))
+ if (!cmp->IsValid(param))
continue;
ci->SetMLock(cmp->Name, true, param);
diff --git a/src/core/os_defcon.c b/src/core/os_defcon.c
index 081cefa23..e9583adfc 100644
--- a/src/core/os_defcon.c
+++ b/src/core/os_defcon.c
@@ -461,7 +461,7 @@ void defconParseModeString(const char *str)
continue;
}
- if (!cmp->IsValid(param.c_str()))
+ if (!cmp->IsValid(param))
continue;
SetDefConParam(cmp->Name, param);
diff --git a/src/modes.cpp b/src/modes.cpp
index 23cc87132..9f886cc3e 100644
--- a/src/modes.cpp
+++ b/src/modes.cpp
@@ -168,9 +168,9 @@ ChannelModeStatus::~ChannelModeStatus()
* @param value The key
* @return true or false
*/
-bool ChannelModeKey::IsValid(const char *value)
+bool ChannelModeKey::IsValid(const std::string &value)
{
- if (value && *value != ':' && !strchr(value, ','))
+ if (!value.empty() && value.find(':') != std::string::npos && value.find(',') != std::string::npos)
return true;
return false;
diff --git a/src/protocol/bahamut.c b/src/protocol/bahamut.c
index bd5a323dc..ac0647d41 100644
--- a/src/protocol/bahamut.c
+++ b/src/protocol/bahamut.c
@@ -48,9 +48,6 @@ IRCDVar myIrcd[] = {
NULL, /* CAPAB Chan Modes */
0, /* We support TOKENS */
0, /* TIME STAMPS are BASE64 */
- 0, /* SJOIN ban char */
- 0, /* SJOIN except char */
- 0, /* SJOIN invite char */
0, /* Can remove User Channel Modes with SVSMODE */
0, /* Sglines are not enforced until user reconnects */
0, /* ts6 */
@@ -350,7 +347,163 @@ class BahamutIRCdProto : public IRCDProto
/* EVENT: SJOIN */
int anope_event_sjoin(const char *source, int ac, const char **av)
{
- do_sjoin(source, ac, av);
+ Channel *c = findchan(av[1]);
+ time_t ts = atol(av[0]);
+ bool was_created = false;
+ bool keep_their_modes = false;
+
+ if (!c)
+ {
+ c = new Channel(av[1], ts);
+ was_created = true;
+ }
+ /* Our creation time is newer than what the server gave us */
+ else if (c->creation_time > ts)
+ {
+ c->creation_time = ts;
+
+ /* Remove status from all of our users */
+ for (struct c_userlist *cu = c->users; cu; cu = cu->next)
+ {
+ c->RemoveMode(NULL, CMODE_OWNER, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_PROTECT, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_OP, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_HALFOP, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_VOICE, cu->user->nick);
+ }
+ if (c->ci)
+ {
+ /* Rejoin the bot to fix the TS */
+ if (c->ci->bi)
+ {
+ ircdproto->SendPart(c->ci->bi, c, "TS reop");
+ bot_join(c->ci);
+ }
+ /* Reset mlock */
+ check_modes(c);
+ }
+ }
+ /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */
+ else
+ keep_their_modes = false;
+
+ /* Mark the channel as syncing */
+ if (was_created)
+ c->SetFlag(CH_SYNCING);
+
+ /* If we need to keep their modes, and this SJOIN string contains modes */
+ if (keep_their_modes && ac >= 4)
+ {
+ /* Set the modes internally */
+ ChanSetInternalModes(c, ac - 3, av + 2);
+ }
+
+ /* For a reason unknown to me, bahamut will send a SJOIN from the user joining a channel
+ * if the channel already existed
+ */
+ if (!was_created && ac == 2)
+ {
+ User *u = finduser(source);
+ if (!u)
+ {
+ if (debug)
+ alog("debug: SJOIN for nonexistant user %s on %s", source, c->name.c_str());
+ }
+ else
+ {
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c));
+
+ /* Add the user to the channel */
+ c->JoinUser(u);
+
+ /* Now set whatever modes this user is allowed to have on the channel */
+ chan_set_correct_modes(u, c, 1);
+
+ /* Check to see if modules want the user to join, if they do
+ * check to see if they are allowed to join (CheckKick will kick/ban them)
+ * Don't trigger OnJoinChannel event then as the user will be destroyed
+ */
+ if (MOD_RESULT == EVENT_STOP && (!c->ci || !c->ci->CheckKick(u)))
+ {
+ FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c));
+ }
+ }
+ }
+ else
+ {
+ spacesepstream sep(av[ac - 1]);
+ std::string buf;
+ while (sep.GetToken(buf))
+ {
+ std::list<ChannelMode *> Status;
+ Status.clear();
+ char ch;
+
+ /* Get prefixes from the nick */
+ while ((ch = ModeManager::GetStatusChar(buf[0])))
+ {
+ buf.erase(buf.begin());
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(ch);
+ if (!cm)
+ {
+ alog("Recieved unknown mode prefix %c in SJOIN string", buf[0]);
+ continue;
+ }
+
+ Status.push_back(cm);
+ }
+
+ User *u = finduser(buf);
+ if (!u)
+ {
+ if (debug)
+ alog("debug: SJOIN for nonexistant user %s on %s", buf.c_str(), c->name.c_str());
+ continue;
+ }
+
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c));
+
+ /* Add the user to the channel */
+ c->JoinUser(u);
+
+ /* Update their status internally on the channel
+ * This will enforce secureops etc on the user
+ */
+ for (std::list<ChannelMode *>::iterator it = Status.begin(); it != Status.end(); ++it)
+ {
+ c->SetModeInternal(*it, buf);
+ }
+
+ /* Now set whatever modes this user is allowed to have on the channel */
+ chan_set_correct_modes(u, c, 1);
+
+ /* Check to see if modules want the user to join, if they do
+ * check to see if they are allowed to join (CheckKick will kick/ban them)
+ * Don't trigger OnJoinChannel event then as the user will be destroyed
+ */
+ if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u))
+ continue;
+
+ FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c));
+ }
+ }
+
+ /* Channel is done syncing */
+ if (was_created)
+ {
+ /* Unset the syncing flag */
+ c->UnsetFlag(CH_SYNCING);
+
+ /* If there are users in the channel they are allowed to be, set topic mlock etc. */
+ if (c->usercount)
+ c->Sync();
+ /* If there are no users in the channel, there is a ChanServ timer set to part the service bot
+ * and destroy the channel soon
+ */
+ }
+
return MOD_CONT;
}
@@ -614,11 +767,11 @@ int anope_event_burst(const char *source, int ac, const char **av)
return MOD_CONT;
}
-bool ChannelModeFlood::IsValid(const char *value)
+bool ChannelModeFlood::IsValid(const std::string &value)
{
char *dp, *end;
- if (value && *value != ':' && strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0 && *dp == ':' && *(++dp) && strtoul(dp, &end, 10) > 0 && !*end)
+ if (!value.empty() && value[0] != ':' && strtoul((value[0] == '*' ? value.c_str() + 1 : value.c_str()), &dp, 10) > 0 && *dp == ':' && *(++dp) && strtoul(dp, &end, 10) > 0 && !*end)
return true;
return false;
@@ -707,6 +860,7 @@ class ProtoBahamut : public Module
pmodule_ircd_var(myIrcd);
pmodule_ircd_useTSMode(0);
+ moduleAddIRCDMsgs();
moduleAddModes();
pmodule_ircd_proto(&ircd_proto);
diff --git a/src/protocol/inspircd11.c b/src/protocol/inspircd11.c
index 55f0858e3..91b400e9b 100644
--- a/src/protocol/inspircd11.c
+++ b/src/protocol/inspircd11.c
@@ -65,9 +65,6 @@ IRCDVar myIrcd[] = {
NULL, /* CAPAB Chan Modes */
0, /* We support inspircd TOKENS */
0, /* TIME STAMPS are BASE64 */
- 0, /* SJOIN ban char */
- 0, /* SJOIN except char */
- 0, /* SJOIN invite char */
0, /* Can remove User Channel Modes with SVSMODE */
0, /* Sglines are not enforced until user reconnects */
0, /* ts6 */
@@ -460,59 +457,121 @@ int anope_event_fmode(const char *source, int ac, const char **av)
int anope_event_fjoin(const char *source, int ac, const char **av)
{
- const char *newav[10];
-
- /* storing the current nick */
- char *curnick;
-
- /* these are used to generate the final string that is passed to ircservices' core */
- int nlen = 0;
- char nicklist[514];
+ Channel *c = findchan(av[0]);
+ time_t ts = atol(av[1]);
+ bool was_created = false;
+ bool keep_their_modes = true;
- /* temporary buffer */
- char prefixandnick[60];
+ if (!c)
+ {
+ c = new Channel(av[0], ts);
+ was_created = true;
+ }
+ /* Our creation time is newer than what the server gave us */
+ else if (c->creation_time > ts)
+ {
+ c->creation_time = ts;
- *nicklist = '\0';
- *prefixandnick = '\0';
+ /* Remove status from all of our users */
+ for (struct c_userlist *cu = c->users; cu; cu = cu->next)
+ {
+ c->RemoveMode(NULL, CMODE_OWNER, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_PROTECT, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_OP, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_HALFOP, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_VOICE, cu->user->nick);
+ }
+ if (c->ci)
+ {
+ /* Rejoin the bot to fix the TS */
+ if (c->ci->bi)
+ {
+ ircdproto->SendPart(c->ci->bi, c, "TS reop");
+ bot_join(c->ci);
+ }
+ /* Reset mlock */
+ check_modes(c);
+ }
+ }
+ /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */
+ else
+ keep_their_modes = false;
+
+ /* Mark the channel as syncing */
+ if (was_created)
+ c->SetFlag(CH_SYNCING);
+
+ spacesepstream sep(av[ac - 1]);
+ std::string buf;
+ while (sep.GetToken(buf))
+ {
+ std::list<ChannelMode *> Status;
+ Status.clear();
+ char ch;
- if (ac < 3)
- return MOD_CONT;
+ /* Loop through prefixes */
+ while ((ch = ModeManager::GetStatusChar(buf[0])))
+ {
+ buf.erase(buf.begin());
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(ch);
- spacesepstream nicks(av[2]);
- std::string nick;
-
- while (nicks.GetToken(nick)) {
- curnick = sstrdup(nick.c_str());
- char *curnick_real = curnick;
- for (; *curnick; curnick++) {
- /* I bet theres a better way to do this... */
- if ((*curnick == '&') ||
- (*curnick == '~') || (*curnick == '@') || (*curnick == '%')
- || (*curnick == '+')) {
- prefixandnick[nlen++] = *curnick;
+ if (cm)
+ {
+ alog("Recieved unknown mode prefix %c in FJOIN string", buf[0]);
continue;
- } else {
- if (*curnick == ',') {
- curnick++;
- strncpy(prefixandnick + nlen, curnick,
- sizeof(prefixandnick) - nlen);
- break;
- } else {
- alog("fjoin: unrecognised prefix: %c", *curnick);
- }
}
+
+ Status.push_back(cm);
}
- strlcat(nicklist, prefixandnick, sizeof(nicklist));
- strlcat(nicklist, " ", sizeof(nicklist));
- delete [] curnick_real;
- nlen = 0;
+
+ User *u = finduser(buf);
+ if (!u)
+ {
+ if (debug)
+ alog("debug: FJOIN for nonexistant user %s on %s", buf.c_str(), c->name.c_str());
+ continue;
+ }
+
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c));
+
+ /* Add the user to the channel */
+ c->JoinUser(u);
+
+ /* Update their status internally on the channel
+ * This will enforce secureops etc on the user
+ */
+ for (std::list<ChannelMode *>::iterator it = Status.begin(); it != Status.end(); ++it)
+ {
+ c->SetModeInternal(*it, buf);
+ }
+
+ /* Now set whatever modes this user is allowed to have on the channel */
+ chan_set_correct_modes(u, c, 1);
+
+ /* Check to see if modules want the user to join, if they do
+ * check to see if they are allowed to join (CheckKick will kick/ban them)
+ * Don't trigger OnJoinChannel event then as the user will be destroyed
+ */
+ if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u))
+ continue;
+
+ FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c));
}
- newav[0] = av[1]; /* timestamp */
- newav[1] = av[0]; /* channel name */
- newav[2] = "+"; /* channel modes */
- newav[3] = nicklist;
- do_sjoin(source, 4, newav);
+ /* Channel is done syncing */
+ if (was_created)
+ {
+ /* Unset the syncing flag */
+ c->UnsetFlag(CH_SYNCING);
+
+ /* If there are users in the channel they are allowed to be, set topic mlock etc. */
+ if (c->usercount)
+ c->Sync();
+ /* If there are no users in the channel, there is a ChanServ timer set to part the service bot
+ * and destroy the channel soon
+ */
+ }
return MOD_CONT;
}
@@ -972,11 +1031,11 @@ void moduleAddIRCDMsgs() {
m = createMessage("IDLE", anope_event_idle); addCoreMessage(IRCD,m);
}
-bool ChannelModeFlood::IsValid(const char *value)
+bool ChannelModeFlood::IsValid(const std::string &value)
{
char *dp, *end;
- if (value && *value != ':' && strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0 && *dp == ':' && *(++dp) && strtoul(dp, &end, 10) > 0 && !*end)
+ if (!value.empty() && value[0] != ':' && strtoul((value[0] == '*' ? value.c_str() + 1 : value.c_str()), &dp, 10) > 0 && *dp == ':' && *(++dp) && strtoul(dp, &end, 10) > 0 && !*end)
return true;
return false;
diff --git a/src/protocol/inspircd12.cpp b/src/protocol/inspircd12.cpp
index 9587f57a7..78d3a88fc 100644
--- a/src/protocol/inspircd12.cpp
+++ b/src/protocol/inspircd12.cpp
@@ -65,9 +65,6 @@ IRCDVar myIrcd[] = {
NULL, /* CAPAB Chan Modes */
0, /* We support inspircd TOKENS */
0, /* TIME STAMPS are BASE64 */
- 0, /* SJOIN ban char */
- 0, /* SJOIN except char */
- 0, /* SJOIN invite char */
0, /* Can remove User Channel Modes with SVSMODE */
0, /* Sglines are not enforced until user reconnects */
1, /* ts6 */
@@ -513,91 +510,133 @@ int anope_event_fmode(const char *source, int ac, const char **av)
*
* 0: name
* 1: channel ts (when it was created, see protocol docs for more info)
- * 2: channel modes + params (NOTEL this may definitely be more than one param!)
+ * 2: channel modes + params (NOTE: this may definitely be more than one param!)
* last: users
*/
int anope_event_fjoin(const char *source, int ac, const char **av)
{
- const char *newav[30]; // hopefully 30 will do until the stupid ac/av stuff goes away.
-
- /* storing the current nick */
- char *curnick;
-
- /* these are used to generate the final string that is passed to ircservices' core */
- int nlen = 0;
- char nicklist[514];
-
- /* temporary buffer */
- char prefixandnick[60];
-
- *nicklist = '\0';
- *prefixandnick = '\0';
+ Channel *c = findchan(av[0]);
+ time_t ts = atol(av[1]);
+ bool was_created = false;
+ bool keep_their_modes = true;
- if (ac <= 3)
- return MOD_CONT;
+ if (!c)
+ {
+ c = new Channel(av[0], ts);
+ was_created = true;
+ }
+ /* Our creation time is newer than what the server gave us */
+ else if (c->creation_time > ts)
+ {
+ c->creation_time = ts;
- spacesepstream nicks(av[ac - 1]);
- std::string nick;
+ /* Remove status from all of our users */
+ for (struct c_userlist *cu = c->users; cu; cu = cu->next)
+ {
+ c->RemoveMode(NULL, CMODE_OWNER, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_PROTECT, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_OP, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_HALFOP, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_VOICE, cu->user->nick);
+ }
+ if (c->ci)
+ {
+ /* Rejoin the bot to fix the TS */
+ if (c->ci->bi)
+ {
+ ircdproto->SendPart(c->ci->bi, c, "TS reop");
+ bot_join(c->ci);
+ }
+ /* Reset mlock */
+ check_modes(c);
+ }
+ }
+ /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */
+ else
+ keep_their_modes = false;
+
+ /* Mark the channel as syncing */
+ if (was_created)
+ c->SetFlag(CH_SYNCING);
+
+ /* If we need to keep their modes, and this FJOIN string contains modes */
+ if (keep_their_modes && ac >= 4)
+ {
+ /* Set the modes internally */
+ ChanSetInternalModes(c, ac - 3, av + 2);
+ }
- while (nicks.GetToken(nick))
+ spacesepstream sep(av[ac - 1]);
+ std::string buf;
+ while (sep.GetToken(buf))
{
- curnick = sstrdup(nick.c_str());
- char *curnick_real = curnick;
- for (; *curnick; curnick++)
+ std::list<ChannelMode *> Status;
+ Status.clear();
+
+ /* Loop through prefixes and find modes for them */
+ while (buf[0] != ',')
{
- /* XXX: bleagh! -- w00t */
- switch (*curnick)
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(buf[0]);
+ buf.erase(buf.begin());
+ if (!cm)
{
- case 'q':
- prefixandnick[nlen++] = '~';
- break;
- case 'a':
- prefixandnick[nlen++] = '&';
- break;
- case 'o':
- prefixandnick[nlen++] = '@';
- break;
- case 'h':
- prefixandnick[nlen++] = '%';
- break;
- case 'v':
- prefixandnick[nlen++] = '+';
- break;
- case ',':
- curnick++;
- strncpy(prefixandnick + nlen, curnick, sizeof(prefixandnick) - nlen);
- goto endnick;
- break;
- default:
- alog("fjoin: unrecognised prefix: %c", *curnick);
- break;
+ alog("Recieved unknown mode prefix %c in FJOIN string", buf[0]);
+ continue;
}
+
+ Status.push_back(cm);
}
+ buf.erase(buf.begin());
-// Much as I hate goto.. I can't `break 2' to get here.. XXX ugly
-endnick:
- strlcat(nicklist, prefixandnick, sizeof(nicklist));
- strlcat(nicklist, " ", sizeof(nicklist));
- delete [] curnick_real;
- nlen = 0;
- }
+ User *u = find_byuid(buf);
+ if (!u)
+ {
+ if (debug)
+ alog("debug: FJOIN for nonexistant user %s on %s", buf.c_str(), c->name.c_str());
+ continue;
+ }
- newav[0] = av[1]; /* timestamp */
- newav[1] = av[0]; /* channel name */
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c));
- int i;
+ /* Add the user to the channel */
+ c->JoinUser(u);
- /* We want to replace the last string with our newly formatted user string */
- for (i = 2; i != ac - 1; i++)
- {
- newav[i] = av[i];
- }
+ /* Update their status internally on the channel
+ * This will enforce secureops etc on the user
+ */
+ for (std::list<ChannelMode *>::iterator it = Status.begin(); it != Status.end(); ++it)
+ {
+ c->SetModeInternal(*it, buf);
+ }
- newav[i] = nicklist;
- i++;
+ /* Now set whatever modes this user is allowed to have on the channel */
+ chan_set_correct_modes(u, c, 1);
- do_sjoin(source, i, newav);
+ /* Check to see if modules want the user to join, if they do
+ * check to see if they are allowed to join (CheckKick will kick/ban them)
+ * Don't trigger OnJoinChannel event then as the user will be destroyed
+ */
+ if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u))
+ continue;
+ FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c));
+ }
+
+ /* Channel is done syncing */
+ if (was_created)
+ {
+ /* Unset the syncing flag */
+ c->UnsetFlag(CH_SYNCING);
+
+ /* If there are users in the channel they are allowed to be, set topic mlock etc */
+ if (c->usercount)
+ c->Sync();
+ /* If there are no users in the channel, there is a ChanServ timer set to part the service bot
+ * and destroy the channel soon
+ */
+ }
+
return MOD_CONT;
}
@@ -1177,10 +1216,10 @@ void moduleAddIRCDMsgs() {
m = createMessage("METADATA", anope_event_metadata); addCoreMessage(IRCD,m);
}
-bool ChannelModeFlood::IsValid(const char *value)
+bool ChannelModeFlood::IsValid(const std::string &value)
{
char *dp, *end;
- if (value && *value != ':' && strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0 && *dp == ':' && *(++dp) && strtoul(dp, &end, 10) > 0 && !*end) return 1;
+ if (!value.empty() && value[0] != ':' && strtoul((value[0] == '*' ? value.c_str() + 1 : value.c_str()), &dp, 10) > 0 && *dp == ':' && *(++dp) && strtoul(dp, &end, 10) > 0 && !*end) return 1;
else return 0;
}
diff --git a/src/protocol/ratbox.c b/src/protocol/ratbox.c
index e605a922a..40ed33634 100644
--- a/src/protocol/ratbox.c
+++ b/src/protocol/ratbox.c
@@ -46,9 +46,6 @@ IRCDVar myIrcd[] = {
NULL, /* CAPAB Chan Modes */
0, /* We support TOKENS */
0, /* TIME STAMPS are BASE64 */
- 0, /* SJOIN ban char */
- 0, /* SJOIN except char */
- 0, /* SJOIN invite char */
0, /* Can remove User Channel Modes with SVSMODE */
0, /* Sglines are not enforced until user reconnects */
1, /* ts6 */
@@ -335,7 +332,7 @@ class RatboxProto : public IRCDTS6Proto
snprintf(svidbuf, sizeof(svidbuf), "%ld", static_cast<long>(u->timestamp));
u->nc->Shrink("authenticationtoken");
- u->nc->Extend("authenticationtoken", new ExtensibleItemPointerArray<char>(svidbuf));
+ u->nc->Extend("authenticationtoken", new ExtensibleItemPointerArray<char>(sstrdup(svidbuf)));
}
} ircd_proto;
@@ -345,7 +342,128 @@ class RatboxProto : public IRCDTS6Proto
int anope_event_sjoin(const char *source, int ac, const char **av)
{
- do_sjoin(source, ac, av);
+ Channel *c = findchan(av[1]);
+ time_t ts = atol(av[0]);
+ bool was_created = false;
+ bool keep_their_modes = true;
+
+ if (!c)
+ {
+ c = new Channel(av[1], ts);
+ was_created = true;
+ }
+ /* Our creation time is newer than what the server gave us */
+ else if (c->creation_time > ts)
+ {
+ c->creation_time = ts;
+
+ /* Remove status from all of our users */
+ for (struct c_userlist *cu = c->users; cu; cu = cu->next)
+ {
+ c->RemoveMode(NULL, CMODE_OWNER, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_PROTECT, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_OP, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_HALFOP, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_VOICE, cu->user->nick);
+ }
+ if (c->ci)
+ {
+ /* Rejoin the bot to fix the TS */
+ if (c->ci->bi)
+ {
+ ircdproto->SendPart(c->ci->bi, c, "TS reop");
+ bot_join(c->ci);
+ }
+ /* Reset mlock */
+ check_modes(c);
+ }
+ }
+ /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */
+ else
+ keep_their_modes = false;
+
+ /* Mark the channel as syncing */
+ if (was_created)
+ c->SetFlag(CH_SYNCING);
+
+ /* If we need to keep their modes, and this SJOIN string contains modes */
+ if (keep_their_modes && ac >= 4)
+ {
+ /* Set the modes internally */
+ ChanSetInternalModes(c, ac - 3, av + 2);
+ }
+
+ spacesepstream sep(av[ac - 1]);
+ std::string buf;
+ while (sep.GetToken(buf))
+ {
+ std::list<ChannelMode *> Status;
+ Status.clear();
+ char ch;
+
+ /* Get prefixes from the nick */
+ while ((ch = ModeManager::GetStatusChar(buf[0])))
+ {
+ buf.erase(buf.begin());
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(ch);
+ if (!cm)
+ {
+ alog("Recieved unknown mode prefix %c in SJOIN string", buf[0]);
+ continue;
+ }
+
+ Status.push_back(cm);
+ }
+
+ User *u = find_byuid(buf);
+ if (!u)
+ {
+ if (debug)
+ alog("debug: SJOIN for nonexistant user %s on %s", buf.c_str(), c->name.c_str());
+ continue;
+ }
+
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c));
+
+ /* Add the user to the channel */
+ c->JoinUser(u);
+
+ /* Update their status internally on the channel
+ * This will enforce secureops etc on the user
+ */
+ for (std::list<ChannelMode *>::iterator it = Status.begin(); it != Status.end(); ++it)
+ {
+ c->SetModeInternal(*it, buf);
+ }
+
+ /* Now set whatever modes this user is allowed to have on the channel */
+ chan_set_correct_modes(u, c, 1);
+
+ /* Check to see if modules want the user to join, if they do
+ * check to see if they are allowed to join (CheckKick will kick/ban them)
+ * Don't trigger OnJoinChannel event then as the user will be destroyed
+ */
+ if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u))
+ continue;
+
+ FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c));
+ }
+
+ /* Channel is done syncing */
+ if (was_created)
+ {
+ /* Unset the syncing flag */
+ c->UnsetFlag(CH_SYNCING);
+
+ /* If there are users in the channel they are allowed to be, set topic mlock etc. */
+ if (c->usercount)
+ c->Sync();
+ /* If there are no users in the channel, there is a ChanServ timer set to part the service bot
+ * and destroy the channel soon
+ */
+ }
+
return MOD_CONT;
}
@@ -541,7 +659,7 @@ int anope_event_kick(const char *source, int ac, const char **av)
int anope_event_join(const char *source, int ac, const char **av)
{
if (ac != 1) {
- do_sjoin(source, ac, av);
+ anope_event_sjoin(source, ac, av);
return MOD_CONT;
} else {
do_join(source, ac, av);
diff --git a/src/protocol/unreal32.c b/src/protocol/unreal32.c
index 8f5d70fe8..7b924ff52 100644
--- a/src/protocol/unreal32.c
+++ b/src/protocol/unreal32.c
@@ -48,9 +48,6 @@ IRCDVar myIrcd[] = {
NULL, /* CAPAB Chan Modes */
1, /* We support Unreal TOKENS */
1, /* TIME STAMPS are BASE64 */
- '&', /* SJOIN ban char */
- '\"', /* SJOIN except char */
- '\'', /* SJOIN invite char */
1, /* Can remove User Channel Modes with SVSMODE */
0, /* Sglines are not enforced until user reconnects */
0, /* ts6 */
@@ -970,7 +967,157 @@ int anope_event_userhost(const char *source, int ac, const char **av)
int anope_event_sjoin(const char *source, int ac, const char **av)
{
- do_sjoin(source, ac, av);
+ Channel *c = findchan(av[1]);
+ time_t ts = base64dects(av[0]);
+ bool keep_their_modes = true;
+ bool was_created = false;
+
+ if (!c)
+ {
+ c = new Channel(av[1], ts);
+ was_created = true;
+ }
+ /* Our creation time is newer than what the server gave us */
+ else if (c->creation_time > ts)
+ {
+ c->creation_time = ts;
+
+ /* Remove status from all of our users */
+ for (struct c_userlist *cu = c->users; cu; cu = cu->next)
+ {
+ c->RemoveMode(NULL, CMODE_OWNER, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_PROTECT, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_OP, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_HALFOP, cu->user->nick);
+ c->RemoveMode(NULL, CMODE_VOICE, cu->user->nick);
+ }
+ if (c->ci)
+ {
+ /* Rejoin the bot to fix the TS */
+ if (c->ci->bi)
+ {
+ ircdproto->SendPart(c->ci->bi, c, "TS reop");
+ bot_join(c->ci);
+ }
+ /* Reset mlock */
+ check_modes(c);
+ }
+ }
+ /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */
+ else
+ keep_their_modes = false;
+
+ /* Mark the channel as syncing */
+ if (was_created)
+ c->SetFlag(CH_SYNCING);
+
+ /* If we need to keep their modes, and this SJOIN string contains modes */
+ if (keep_their_modes && ac >= 4)
+ {
+ /* Set the modes internally */
+ ChanSetInternalModes(c, ac - 3, av + 2);
+ }
+
+ spacesepstream sep(av[ac - 1]);
+ std::string buf;
+ while (sep.GetToken(buf))
+ {
+ /* Ban */
+ if (keep_their_modes && buf[0] == '&')
+ {
+ buf.erase(buf.begin());
+ ChannelModeList *cml = dynamic_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_BAN));
+ if (cml->IsValid(buf))
+ cml->AddMask(c, buf.c_str());
+ }
+ /* Except */
+ else if (keep_their_modes && buf[0] == '"')
+ {
+ buf.erase(buf.begin());
+ ChannelModeList *cml = dynamic_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_EXCEPT));
+
+ if (cml->IsValid(buf))
+ cml->AddMask(c, buf.c_str());
+ }
+ /* Invex */
+ else if (keep_their_modes && buf[0] == '\'')
+ {
+ buf.erase(buf.begin());
+ ChannelModeList *cml = dynamic_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE));
+
+ if (cml->IsValid(buf))
+ cml->AddMask(c, buf.c_str());
+ }
+ else
+ {
+ std::list<ChannelMode *> Status;
+ Status.clear();
+ char ch;
+
+ /* Get prefixes from the nick */
+ while ((ch = ModeManager::GetStatusChar(buf[0])))
+ {
+ buf.erase(buf.begin());
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(ch);
+ if (!cm)
+ {
+ alog("Recieved unknown mode prefix %c in SJOIN string", buf[0]);
+ continue;
+ }
+
+ Status.push_back(cm);
+ }
+
+ User *u = finduser(buf);
+ if (!u)
+ {
+ if (debug)
+ alog("debug: SJOIN for nonexistant user %s on %s", buf.c_str(), c->name.c_str());
+ continue;
+ }
+
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c));
+
+ /* Add the user to the channel */
+ c->JoinUser(u);
+
+ /* Update their status internally on the channel
+ * This will enforce secureops etc on the user
+ */
+ for (std::list<ChannelMode *>::iterator it = Status.begin(); it != Status.end(); ++it)
+ {
+ c->SetModeInternal(*it, buf);
+ }
+
+ /* Now set whatever modes this user is allowed to have on the channel */
+ chan_set_correct_modes(u, c, 1);
+
+ /* Check to see if modules want the user to join, if they do
+ * check to see if they are allowed to join (CheckKick will kick/ban them)
+ * Don't trigger OnJoinChannel event then as the user will be destroyed
+ */
+ if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u))
+ continue;
+
+ FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c));
+ }
+ }
+
+ /* Channel is done syncing */
+ if (was_created)
+ {
+ /* Unset the syncing flag */
+ c->UnsetFlag(CH_SYNCING);
+
+ /* If there are users in the channel they are allowed to be, set topic mlock etc. */
+ if (c->usercount)
+ c->Sync();
+ /* If there are no users in the channel, there is a ChanServ timer set to part the service bot
+ * and destroy the channel soon
+ */
+ }
+
return MOD_CONT;
}
@@ -1047,8 +1194,9 @@ void moduleAddIRCDMsgs() {
}
/* Borrowed part of this check from UnrealIRCd */
-bool ChannelModeFlood::IsValid(const char *value)
+bool ChannelModeFlood::IsValid(const std::string &value2)
{
+ const char *value = value2.c_str();
char *dp, *end;
/* NEW +F */
char xbuf[256], *p, *p2, *x = xbuf + 1;
diff --git a/src/users.c b/src/users.c
index 137190d05..c98a99133 100644
--- a/src/users.c
+++ b/src/users.c
@@ -277,7 +277,7 @@ User::~User()
while (c)
{
c2 = c->next;
- chan_deluser(this, c->chan);
+ c->chan->DeleteUser(this);
delete c;
c = c2;
}