summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
12 files changed, 917 insertions, 792 deletions
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;
}