summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/channels.h24
-rw-r--r--include/extern.h5
-rw-r--r--include/regchannel.h18
-rw-r--r--include/services.h5
-rw-r--r--modules/core/cs_topic.cpp26
-rw-r--r--modules/extra/cs_appendtopic.cpp36
-rw-r--r--modules/protocol/bahamut.cpp18
-rw-r--r--modules/protocol/inspircd11.cpp45
-rw-r--r--modules/protocol/inspircd12.cpp46
-rw-r--r--modules/protocol/inspircd20.cpp46
-rw-r--r--modules/protocol/ratbox.cpp82
-rw-r--r--modules/protocol/unreal32.cpp32
-rw-r--r--src/channels.cpp104
-rw-r--r--src/chanserv.cpp127
-rw-r--r--src/regchannel.cpp38
-rw-r--r--src/servers.cpp4
16 files changed, 226 insertions, 430 deletions
diff --git a/include/channels.h b/include/channels.h
index 73c97d3aa..d82e61037 100644
--- a/include/channels.h
+++ b/include/channels.h
@@ -71,7 +71,7 @@ class CoreExport Channel : public Extensible, public Flags<ChannelFlags>
/* Modes set on the channel */
Flags<ChannelModeName, CMODE_END * 2> modes;
-
+
public:
/** Default constructor
* @param name The channel name
@@ -86,9 +86,6 @@ class CoreExport Channel : public Extensible, public Flags<ChannelFlags>
Anope::string name; /* Channel name */
ChannelInfo *ci; /* Corresponding ChannelInfo */
time_t creation_time; /* When channel was created */
- Anope::string topic;
- Anope::string topic_setter;
- time_t topic_time; /* When topic was set */
EList *bans;
EList *excepts;
@@ -97,6 +94,10 @@ class CoreExport Channel : public Extensible, public Flags<ChannelFlags>
/* List of users in the channel */
CUserList users;
+ Anope::string topic; /* Current topic of the channel */
+ Anope::string topic_setter; /* Who set the topic */
+ time_t topic_time; /* When the topic was set*/
+
std::list<BanData *> bd;
time_t server_modetime; /* Time of last server MODE */
@@ -104,7 +105,6 @@ class CoreExport Channel : public Extensible, public Flags<ChannelFlags>
int16 server_modecount; /* Number of server MODEs this second */
int16 chanserv_modecount; /* Number of check_mode()'s this sec */
int16 bouncy_modes; /* Did we fail to set modes here? */
- int16 topic_sync; /* Is the topic in sync? */
/** Call if we need to unset all modes and clear all user status (internally).
* Only useful if we get a SJOIN with a TS older than what we have here
@@ -286,6 +286,20 @@ class CoreExport Channel : public Extensible, public Flags<ChannelFlags>
* @return A mode string
*/
Anope::string GetModes(bool complete, bool plus);
+
+ /** Update the topic of the channel internally, and reset it if topiclock etc says to
+ * @param user THe user setting the new topic
+ * @param newtopic The new topic
+ * @param ts The time the new topic is being set
+ */
+ void ChangeTopicInternal(const Anope::string &user, const Anope::string &newtopic, time_t ts = Anope::CurTime);
+
+ /** Update the topic of the channel, and reset it if topiclock etc says to
+ * @param user The user setting the topic
+ * @param newtopic The new topic
+ * @param ts The time when the new topic is being set
+ */
+ void ChangeTopic(const Anope::string &user, const Anope::string &newtopic, time_t ts = Anope::CurTime);
};
#endif // CHANNELS_H
diff --git a/include/extern.h b/include/extern.h
index e0e6a6a9b..50d806189 100644
--- a/include/extern.h
+++ b/include/extern.h
@@ -73,11 +73,9 @@ E void do_cmode(const Anope::string &source, int ac, const char **av);
E void do_join(const Anope::string &source, int ac, const char **av);
E void do_kick(const Anope::string &source, int ac, const char **av);
E void do_part(const Anope::string &source, int ac, const char **av);
-E void do_topic(const Anope::string &source, int ac, const char **av);
E void MassChannelModes(BotInfo *bi, const Anope::string &modes);
E void chan_set_correct_modes(User *user, Channel *c, int give_modes);
-E void restore_unsynced_topics();
E Entry *entry_create(const Anope::string &mask);
E Entry *entry_add(EList *list, const Anope::string &mask);
@@ -112,9 +110,6 @@ E void cs_remove_nick(const NickCore *nc);
E void check_modes(Channel *c);
E int check_valid_admin(User *user, Channel *chan, int servermode);
E int check_valid_op(User *user, Channel *chan, int servermode);
-E void record_topic(const Anope::string &chan);
-E void restore_topic(const Anope::string &chan);
-E int check_topiclock(Channel *c, time_t topic_time);
E ChannelInfo *cs_findchan(const Anope::string &chan);
E int check_access(User *user, ChannelInfo *ci, int what);
diff --git a/include/regchannel.h b/include/regchannel.h
index fb6810220..2b7ea67f4 100644
--- a/include/regchannel.h
+++ b/include/regchannel.h
@@ -89,9 +89,10 @@ class CoreExport ChannelInfo : public Extensible, public Flags<ChannelInfoFlag,
time_t time_registered;
time_t last_used;
- Anope::string last_topic; /* Last topic on the channel */
- Anope::string last_topic_setter; /* Who set the last topic */
- time_t last_topic_time; /* When the last topic was set */
+
+ Anope::string last_topic; /* The last topic that was set on this channel */
+ Anope::string last_topic_setter; /* Setter */
+ time_t last_topic_time; /* Time */
Anope::string forbidby;
Anope::string forbidreason;
@@ -286,6 +287,17 @@ class CoreExport ChannelInfo : public Extensible, public Flags<ChannelInfoFlag,
* @return true if they are allowed, false if they aren't and were kicked
*/
bool CheckKick(User *user);
+
+ /** Check the channel topic
+ * If topic lock is enabled will change the topic back, else it records
+ * the new topic in the ChannelInfo
+ */
+ void CheckTopic();
+
+ /** Restore the channel topic, used on channel creation when not syncing with the uplink
+ * and after uplink sync
+ */
+ void RestoreTopic();
};
#endif // REGCHANNEL_H
diff --git a/include/services.h b/include/services.h
index e0ed8709f..3034613b4 100644
--- a/include/services.h
+++ b/include/services.h
@@ -436,10 +436,7 @@ struct IRCDVar
int snline; /* Supports SNline */
int sqline; /* Supports SQline */
int szline; /* Supports SZline */
- int join2set; /* Join 2 Set Modes */
int join2msg; /* Join 2 Message */
- int topictsforward; /* TS on Topics Forward */
- int topictsbackward; /* TS on Topics Backward */
int chansqline; /* Supports Channel Sqlines */
int quitonkill; /* IRCD sends QUIT when kill */
int svsmode_unban; /* svsmode can be used to unban */
@@ -949,7 +946,7 @@ class CoreExport IRCDProto
virtual ~IRCDProto() { }
virtual void SendSVSNOOP(const Anope::string &, int) { }
- virtual void SendTopic(const BotInfo *, const Channel *, const Anope::string &, const Anope::string &) = 0;
+ virtual void SendTopic(BotInfo *, Channel *) = 0;
virtual void SendVhostDel(User *) { }
virtual void SendAkill(const XLine *) = 0;
virtual void SendAkillDel(const XLine *) = 0;
diff --git a/modules/core/cs_topic.cpp b/modules/core/cs_topic.cpp
index 98ca4a2ac..fbb9a23f4 100644
--- a/modules/core/cs_topic.cpp
+++ b/modules/core/cs_topic.cpp
@@ -34,28 +34,14 @@ class CommandCSTopic : public Command
notice_lang(Config->s_ChanServ, u, ACCESS_DENIED);
else
{
- ci->last_topic = topic;
- ci->last_topic_setter = u->nick;
- ci->last_topic_time = Anope::CurTime;
-
- c->topic = topic;
- c->topic_setter = u->nick;
- if (ircd->topictsbackward)
- c->topic_time = c->topic_time - 1;
- else
- c->topic_time = ci->last_topic_time;
-
+ bool has_topiclock = ci->HasFlag(CI_TOPICLOCK);
+ ci->UnsetFlag(CI_TOPICLOCK);
+ c->ChangeTopic(u->nick, topic, Anope::CurTime);
+ if (has_topiclock)
+ ci->SetFlag(CI_TOPICLOCK);
+
bool override = !check_access(u, ci, CA_TOPIC);
Log(override ? LOG_OVERRIDE : LOG_COMMAND, u, this, ci) << "to change the topic to " << (!topic.empty() ? topic : "No topic");
-
- if (ircd->join2set && whosends(ci) == ChanServ) // XXX what if the service bot is chanserv?
- {
- ChanServ->Join(c);
- ircdproto->SendMode(NULL, c, "+o %s", Config->s_ChanServ.c_str()); // XXX
- }
- ircdproto->SendTopic(whosends(ci), c, u->nick, topic);
- if (ircd->join2set && whosends(ci) == ChanServ)
- ChanServ->Part(c);
}
return MOD_CONT;
}
diff --git a/modules/extra/cs_appendtopic.cpp b/modules/extra/cs_appendtopic.cpp
index e331d46c6..09ab3b481 100644
--- a/modules/extra/cs_appendtopic.cpp
+++ b/modules/extra/cs_appendtopic.cpp
@@ -62,12 +62,8 @@ class CommandCSAppendTopic : public Command
{
Anope::string chan = params[0];
Anope::string newtopic = params[1];
- Anope::string topic;
- Channel *c = findchan(chan);
- ChannelInfo *ci;
-
- if (c)
- ci = c->ci;
+ ChannelInfo *ci = cs_findchan(chan);
+ Channel *c = ci ? ci->c : NULL;
if (!c)
notice_lang(Config->s_ChanServ, u, CHAN_X_NOT_IN_USE, chan.c_str());
@@ -75,6 +71,7 @@ class CommandCSAppendTopic : public Command
notice_lang(Config->s_ChanServ, u, ACCESS_DENIED);
else
{
+ Anope::string topic;
if (!ci->last_topic.empty())
{
topic = ci->last_topic + " " + newtopic;
@@ -83,27 +80,14 @@ class CommandCSAppendTopic : public Command
else
topic = newtopic;
- ci->last_topic = topic;
- ci->last_topic_setter = u->nick;
- ci->last_topic_time = Anope::CurTime;
-
- c->topic = topic;
- c->topic_setter = u->nick;
- if (ircd->topictsbackward)
- c->topic_time = c->topic_time - 1;
- else
- c->topic_time = ci->last_topic_time;
+ bool has_topiclock = ci->HasFlag(CI_TOPICLOCK);
+ ci->UnsetFlag(CI_TOPICLOCK);
+ c->ChangeTopic(u->nick, topic, Anope::CurTime);
+ if (has_topiclock)
+ ci->SetFlag(CI_TOPICLOCK);
- if (!check_access(u, ci, CA_TOPIC))
- Log(LOG_OVERRIDE, u, this, ci) << "changed topic to " << topic;
- if (ircd->join2set && whosends(ci) == ChanServ)
- {
- ChanServ->Join(c);
- ircdproto->SendMode(NULL, c, "+o %s", Config->s_ChanServ.c_str()); // XXX
- }
- ircdproto->SendTopic(whosends(ci), c, u->nick, topic);
- if (ircd->join2set && whosends(ci) == ChanServ)
- ChanServ->Part(c);
+ bool override = !check_access(u, ci, CA_TOPIC);
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, u, this, ci) << "changed topic to " << topic;
}
return MOD_CONT;
}
diff --git a/modules/protocol/bahamut.cpp b/modules/protocol/bahamut.cpp
index 65924c97f..c1a223672 100644
--- a/modules/protocol/bahamut.cpp
+++ b/modules/protocol/bahamut.cpp
@@ -23,10 +23,7 @@ IRCDVar myIrcd[] = {
1, /* Supports SNlines */
1, /* Supports SQlines */
1, /* Supports SZlines */
- 0, /* Join 2 Set */
0, /* Join 2 Message */
- 0, /* TS Topic Forward */
- 0, /* TS Topci Backward */
1, /* Chan SQlines */
1, /* Quit on Kill */
1, /* SVSMODE unban */
@@ -174,9 +171,9 @@ class BahamutIRCdProto : public IRCDProto
}
/* TOPIC */
- void SendTopic(const BotInfo *whosets, const Channel *c, const Anope::string &whosetit, const Anope::string &topic)
+ void SendTopic(BotInfo *whosets, Channel *c)
{
- send_cmd(whosets->nick, "TOPIC %s %s %lu :%s", c->name.c_str(), whosetit.c_str(), static_cast<unsigned long>(c->topic_time), topic.c_str());
+ send_cmd(whosets->nick, "TOPIC %s %s %lu :%s", c->name.c_str(), c->topic_setter.c_str(), static_cast<unsigned long>(c->topic_time), c->topic.c_str());
}
/* UNSQLINE */
@@ -565,7 +562,16 @@ int anope_event_topic(const Anope::string &source, int ac, const char **av)
{
if (ac != 4)
return MOD_CONT;
- do_topic(source, ac, av);
+
+ Channel *c = findchan(av[0]);
+ if (!c)
+ {
+ Log() << "TOPIC for nonexistant channel " << av[0];
+ return MOD_CONT;
+ }
+
+ c->ChangeTopicInternal(av[1], av[3], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : Anope::CurTime);
+
return MOD_CONT;
}
diff --git a/modules/protocol/inspircd11.cpp b/modules/protocol/inspircd11.cpp
index 557fe7389..8053a577a 100644
--- a/modules/protocol/inspircd11.cpp
+++ b/modules/protocol/inspircd11.cpp
@@ -24,10 +24,7 @@ IRCDVar myIrcd[] = {
1, /* Supports SNlines */
1, /* Supports SQlines */
1, /* Supports SZlines */
- 0, /* Join 2 Set */
1, /* Join 2 Message */
- 1, /* TS Topic Forward */
- 0, /* TS Topci Backward */
0, /* Chan SQlines */
0, /* Quit on Kill */
0, /* SVSMODE unban */
@@ -92,9 +89,9 @@ class InspIRCdProto : public IRCDProto
send_cmd(Config->s_OperServ, "GLINE %s", x->Mask.c_str());
}
- void SendTopic(const BotInfo *whosets, const Channel *c, const Anope::string &whosetit, const Anope::string &topic)
+ void SendTopic(BotInfo *whosets, Channel *c)
{
- send_cmd(whosets->nick, "FTOPIC %s %lu %s :%s", c->name.c_str(), static_cast<unsigned long>(c->topic_time), whosetit.c_str(), topic.c_str());
+ send_cmd(whosets->nick, "FTOPIC %s %lu %s :%s", c->name.c_str(), static_cast<unsigned long>(c->topic_time + 1), c->topic_setter.c_str(), c->topic.c_str());
}
void SendVhostDel(User *u)
@@ -303,13 +300,18 @@ class InspIRCdProto : public IRCDProto
int anope_event_ftopic(const Anope::string &source, int ac, const char **av)
{
/* :source FTOPIC channel ts setby :topic */
- const char *temp;
if (ac < 4)
return MOD_CONT;
- temp = av[1]; /* temp now holds ts */
- av[1] = av[2]; /* av[1] now holds set by */
- av[2] = temp; /* av[2] now holds ts */
- do_topic(source, ac, av);
+
+ Channel *c = findchan(av[0]);
+ if (!c)
+ {
+ Log() << "TOPIC for nonexistant channel " << av[0];
+ return MOD_CONT;
+ }
+
+ c->ChangeTopicInternal(av[2], av[3], Anope::string(av[1]).is_pos_number_only() ? convertTo<time_t>(av[1]) : Anope::CurTime);
+
return MOD_CONT;
}
@@ -517,30 +519,11 @@ int anope_event_topic(const Anope::string &source, int ac, const char **av)
if (!c)
{
- Log(LOG_DEBUG) << "TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
+ Log() << "TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
return MOD_CONT;
}
- if (check_topiclock(c, Anope::CurTime))
- return MOD_CONT;
-
- c->topic.clear();
- if (ac > 1 && *av[1])
- c->topic = av[1];
-
- c->topic_setter = source;
- c->topic_time = Anope::CurTime;
-
- record_topic(av[0]);
-
- if (ac > 1 && *av[1])
- {
- FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(c, av[1]));
- }
- else
- {
- FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(c, ""));
- }
+ c->ChangeTopicInternal(source, (ac > 1 && *av[1] ? av[1] : ""), Anope::CurTime);
return MOD_CONT;
}
diff --git a/modules/protocol/inspircd12.cpp b/modules/protocol/inspircd12.cpp
index 9532e7669..592fc9e1a 100644
--- a/modules/protocol/inspircd12.cpp
+++ b/modules/protocol/inspircd12.cpp
@@ -24,10 +24,7 @@ IRCDVar myIrcd[] = {
0, /* Supports SNlines */
1, /* Supports SQlines */
1, /* Supports SZlines */
- 0, /* Join 2 Set */
0, /* Join 2 Message */
- 1, /* TS Topic Forward */
- 0, /* TS Topci Backward */
0, /* Chan SQlines */
0, /* Quit on Kill */
0, /* SVSMODE unban */
@@ -95,9 +92,9 @@ class InspIRCdProto : public IRCDProto
send_cmd(OperServ->GetUID(), "GLINE %s", x->Mask.c_str());
}
- void SendTopic(const BotInfo *whosets, const Channel *c, const Anope::string &whosetit, const Anope::string &topic)
+ void SendTopic(BotInfo *whosets, Channel *c)
{
- send_cmd(whosets->GetUID(), "FTOPIC %s %lu %s :%s", c->name.c_str(), static_cast<unsigned long>(c->topic_time), whosetit.c_str(), topic.c_str());
+ send_cmd(whosets->GetUID(), "FTOPIC %s %lu %s :%s", c->name.c_str(), static_cast<unsigned long>(c->topic_time + 1), c->topic_setter.c_str(), c->topic.c_str());
}
void SendVhostDel(User *u)
@@ -313,13 +310,18 @@ class InspIRCdProto : public IRCDProto
int anope_event_ftopic(const Anope::string &source, int ac, const char **av)
{
/* :source FTOPIC channel ts setby :topic */
- const char *temp;
if (ac < 4)
return MOD_CONT;
- temp = av[1]; /* temp now holds ts */
- av[1] = av[2]; /* av[1] now holds set by */
- av[2] = temp; /* av[2] now holds ts */
- do_topic(source, ac, av);
+
+ Channel *c = findchan(av[0]);
+ if (!c)
+ {
+ Log(LOG_DEBUG) << "TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
+ return MOD_CONT;
+ }
+
+ c->ChangeTopicInternal(av[2], av[2], Anope::string(av[1]).is_pos_number_only() ? convertTo<time_t>(av[1]) : Anope::CurTime);
+
return MOD_CONT;
}
@@ -554,34 +556,14 @@ int anope_event_away(const Anope::string &source, int ac, const char **av)
int anope_event_topic(const Anope::string &source, int ac, const char **av)
{
Channel *c = findchan(av[0]);
- User *u = finduser(source);
if (!c)
{
- Log(LOG_DEBUG) << "debug: TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
+ Log() << "TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
return MOD_CONT;
}
- if (check_topiclock(c, Anope::CurTime))
- return MOD_CONT;
-
- c->topic.clear();
- if (ac > 1 && *av[1])
- c->topic = av[1];
-
- c->topic_setter = u ? u->nick : source;
- c->topic_time = Anope::CurTime;
-
- record_topic(av[0]);
-
- if (ac > 1 && *av[1])
- {
- FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(c, av[0]));
- }
- else
- {
- FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(c, ""));
- }
+ c->ChangeTopicInternal(source, (ac > 1 && *av[1] ? av[1] : ""), Anope::CurTime);
return MOD_CONT;
}
diff --git a/modules/protocol/inspircd20.cpp b/modules/protocol/inspircd20.cpp
index 47413da23..5d0f9436e 100644
--- a/modules/protocol/inspircd20.cpp
+++ b/modules/protocol/inspircd20.cpp
@@ -24,10 +24,7 @@ IRCDVar myIrcd[] = {
0, /* Supports SNlines */
1, /* Supports SQlines */
1, /* Supports SZlines */
- 0, /* Join 2 Set */
0, /* Join 2 Message */
- 1, /* TS Topic Forward */
- 0, /* TS Topci Backward */
0, /* Chan SQlines */
0, /* Quit on Kill */
0, /* SVSMODE unban */
@@ -93,9 +90,9 @@ class InspIRCdProto : public IRCDProto
send_cmd(OperServ->GetUID(), "GLINE %s", x->Mask.c_str());
}
- void SendTopic(const BotInfo *whosets, const Channel *c, const Anope::string &whosetit, const Anope::string &topic)
+ void SendTopic(BotInfo *whosets, Channel *c)
{
- send_cmd(whosets->GetUID(), "FTOPIC %s %lu %s :%s", c->name.c_str(), static_cast<unsigned long>(c->topic_time), whosetit.c_str(), topic.c_str());
+ send_cmd(whosets->GetUID(), "FTOPIC %s %lu %s :%s", c->name.c_str(), static_cast<unsigned long>(c->topic_time + 1), c->topic_setter.c_str(), c->topic.c_str());
}
void SendVhostDel(User *u)
@@ -311,13 +308,18 @@ class InspIRCdProto : public IRCDProto
int anope_event_ftopic(const Anope::string &source, int ac, const char **av)
{
/* :source FTOPIC channel ts setby :topic */
- const char *temp;
if (ac < 4)
return MOD_CONT;
- temp = av[1]; /* temp now holds ts */
- av[1] = av[2]; /* av[1] now holds set by */
- av[2] = temp; /* av[2] now holds ts */
- do_topic(source, ac, av);
+
+ Channel *c = findchan(av[0]);
+ if (!c)
+ {
+ Log(LOG_DEBUG) << "TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
+ return MOD_CONT;
+ }
+
+ c->ChangeTopicInternal(av[2], av[2], Anope::string(av[1]).is_pos_number_only() ? convertTo<time_t>(av[1]) : Anope::CurTime);
+
return MOD_CONT;
}
@@ -552,34 +554,14 @@ int anope_event_away(const Anope::string &source, int ac, const char **av)
int anope_event_topic(const Anope::string &source, int ac, const char **av)
{
Channel *c = findchan(av[0]);
- User *u = finduser(source);
if (!c)
{
- Log(LOG_DEBUG) << "debug: TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
+ Log() << "TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
return MOD_CONT;
}
- if (check_topiclock(c, Anope::CurTime))
- return MOD_CONT;
-
- c->topic.clear();
- if (ac > 1 && *av[1])
- c->topic = av[1];
-
- c->topic_setter = u ? u->nick : source;
- c->topic_time = Anope::CurTime;
-
- record_topic(av[0]);
-
- if (ac > 1 && *av[1])
- {
- FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(c, av[0]));
- }
- else
- {
- FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(c, ""));
- }
+ c->ChangeTopicInternal(source, (ac > 1 && *av[1] ? av[1] : ""), Anope::CurTime);
return MOD_CONT;
}
diff --git a/modules/protocol/ratbox.cpp b/modules/protocol/ratbox.cpp
index 505d143fd..807abf202 100644
--- a/modules/protocol/ratbox.cpp
+++ b/modules/protocol/ratbox.cpp
@@ -23,10 +23,7 @@ IRCDVar myIrcd[] = {
1, /* Supports SNlines */
1, /* Supports SQlines */
0, /* Supports SZlines */
- 1, /* Join 2 Set */
1, /* Join 2 Message */
- 0, /* TS Topic Forward */
- 0, /* TS Topci Backward */
1, /* Chan SQlines */
0, /* Quit on Kill */
0, /* SVSMODE unban */
@@ -249,9 +246,22 @@ class RatboxProto : public IRCDProto
return true;
}
- void SendTopic(const BotInfo *bi, const Channel *c, const Anope::string &, const Anope::string &topic)
+ void SendTopic(BotInfo *bi, Channel *c)
{
- send_cmd(bi->GetUID(), "TOPIC %s :%s", c->name.c_str(), topic.c_str());
+ bool needjoin = c->FindUser(bi) != NULL;
+ if (needjoin)
+ {
+ ChannelStatus status;
+ status .SetFlag(CMODE_OP);
+ ChannelContainer cc(c);
+ cc.Status = &status;
+ ircdproto->SendJoin(bi, &cc);
+ }
+ send_cmd(bi->GetUID(), "TOPIC %s :%s", c->name.c_str(), c->topic.c_str());
+ if (needjoin)
+ {
+ ircdproto->SendPart(bi, c, NULL);
+ }
}
void SetAutoIdentificationToken(User *u)
@@ -417,75 +427,41 @@ int anope_event_nick(const Anope::string &source, int ac, const char **av)
int anope_event_topic(const Anope::string &source, int ac, const char **av)
{
- User *u;
+ Channel *c = findchan(av[0]);
+ if (!c)
+ {
+ Log() << "TOPIC for nonexistant channel " << av[0];
+ return MOD_CONT;
+ }
if (ac == 4)
- do_topic(source, ac, av);
+ {
+ c->ChangeTopicInternal(av[1], av[3], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : Anope::CurTime);
+ }
else
{
- Channel *c = findchan(av[0]);
-
- if (!c)
- {
- Log(LOG_DEBUG) << "TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
- return MOD_CONT;
- }
-
- if (check_topiclock(c, Anope::CurTime))
- return MOD_CONT;
-
- c->topic.clear();
- if (ac > 1 && *av[1])
- c->topic = av[1];
-
- u = finduser(source);
- c->topic_setter = u ? u->nick : source;
- c->topic_time = Anope::CurTime;
-
- record_topic(av[0]);
-
- if (ac > 1 && *av[1])
- {
- FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(c, av[1]));
- }
- else
- {
- FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(c, ""));
- }
+ c->ChangeTopicInternal(source, (ac > 1 && *av[1] ? av[1] : ""));
}
return MOD_CONT;
}
int anope_event_tburst(const Anope::string &source, int ac, const char **av)
{
- Channel *c;
- time_t topic_time;
-
if (ac != 4)
return MOD_CONT;
Anope::string setter = myStrGetToken(av[2], '!', 0);
-
- c = findchan(av[0]);
- topic_time = Anope::string(av[1]).is_pos_number_only() ? convertTo<time_t>(av[1]) : 0;
+ time_t topic_time = Anope::string(av[1]).is_pos_number_only() ? convertTo<time_t>(av[1]) : Anope::CurTime;
+ Channel *c = findchan(av[0]);
if (!c)
{
- Log(LOG_DEBUG) << "debug: TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
+ Log() << "TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
return MOD_CONT;
}
- if (check_topiclock(c, topic_time))
- return MOD_CONT;
-
- c->topic.clear();
- if (ac > 1 && *av[3])
- c->topic = av[3];
-
- c->topic_setter = setter;
- c->topic_time = topic_time;
+ c->ChangeTopicInternal(setter, ac > 3 && *av[3] ? av[3] : "", topic_time);
- record_topic(av[0]);
return MOD_CONT;
}
diff --git a/modules/protocol/unreal32.cpp b/modules/protocol/unreal32.cpp
index 0b5b56b08..892c4fc57 100644
--- a/modules/protocol/unreal32.cpp
+++ b/modules/protocol/unreal32.cpp
@@ -23,10 +23,7 @@ IRCDVar myIrcd[] = {
1, /* Supports SNlines */
1, /* Supports SQlines */
1, /* Supports SZlines */
- 0, /* Join 2 Set */
0, /* Join 2 Message */
- 1, /* TS Topic Forward */
- 0, /* TS Topci Backward */
0, /* Chan SQlines */
0, /* Quit on Kill */
1, /* SVSMODE unban */
@@ -112,9 +109,9 @@ class UnrealIRCdProto : public IRCDProto
send_cmd("", "BD - G %s %s %s", x->GetUser().c_str(), x->GetHost().c_str(), Config->s_OperServ.c_str());
}
- void SendTopic(const BotInfo *whosets, const Channel *c, const Anope::string &whosetit, const Anope::string &topic)
+ void SendTopic(BotInfo *whosets, Channel *c)
{
- send_cmd(whosets->nick, ") %s %s %lu :%s", c->name.c_str(), whosetit.c_str(), static_cast<unsigned long>(c->topic_time), topic.c_str());
+ send_cmd(whosets->nick, ") %s %s %lu :%s", c->name.c_str(), c->topic_setter.c_str(), static_cast<unsigned long>(c->topic_time + 1), c->topic.c_str());
}
void SendVhostDel(User *u)
@@ -612,21 +609,26 @@ int anope_event_away(const Anope::string &source, int ac, const char **av)
/*
** m_topic
-** parv[0] = sender prefix
-** parv[1] = topic text
-**
-** For servers using TS:
-** parv[0] = sender prefix
-** parv[1] = channel name
-** parv[2] = topic nickname
-** parv[3] = topic time
-** parv[4] = topic text
+** source = sender prefix
+** parv[0] = channel name
+** parv[1] = topic nickname
+** parv[2] = topic time
+** parv[3] = topic text
*/
int anope_event_topic(const Anope::string &source, int ac, const char **av)
{
if (ac != 4)
return MOD_CONT;
- do_topic(source, ac, av);
+
+ Channel *c = findchan(av[0]);
+ if (!c)
+ {
+ Log() << "TOPIC for nonexistant channel " << av[0];
+ return MOD_CONT;
+ }
+
+ c->ChangeTopicInternal(av[1], av[3], Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : Anope::CurTime);
+
return MOD_CONT;
}
diff --git a/src/channels.cpp b/src/channels.cpp
index 76db386e4..24d18b102 100644
--- a/src/channels.cpp
+++ b/src/channels.cpp
@@ -31,7 +31,7 @@ Channel::Channel(const Anope::string &nname, time_t ts)
this->creation_time = ts;
this->bans = this->excepts = this->invites = NULL;
this->server_modetime = this->chanserv_modetime = 0;
- this->server_modecount = this->chanserv_modecount = this->bouncy_modes = this->topic_sync = this->topic_time = 0;
+ this->server_modecount = this->chanserv_modecount = this->bouncy_modes = this->topic_time = 0;
this->ci = cs_findchan(this->name);
if (this->ci)
@@ -113,10 +113,10 @@ void Channel::Sync()
if (this->ci)
{
check_modes(this);
- }
- if (Me && Me->IsSynced() && !this->topic_sync)
- restore_topic(name);
+ if (Me && Me->IsSynced())
+ this->ci->RestoreTopic();
+ }
}
void Channel::JoinUser(User *user)
@@ -1026,6 +1026,38 @@ Anope::string Channel::GetModes(bool complete, bool plus)
return res;
}
+void Channel::ChangeTopicInternal(const Anope::string &user, const Anope::string &newtopic, time_t ts)
+{
+ this->topic = newtopic;
+ this->topic_setter = user;
+ this->topic_time = ts;
+
+ Log(LOG_DEBUG) << "Topic of " << this->name << " changed by " << user << " to " << newtopic;
+
+ FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(this, this->topic));
+
+ if (this->ci)
+ {
+ this->ci->CheckTopic();
+ }
+}
+
+void Channel::ChangeTopic(const Anope::string &user, const Anope::string &newtopic, time_t ts)
+{
+ this->topic = newtopic;
+ this->topic_setter = user;
+ this->topic_time = ts;
+
+ ircdproto->SendTopic(whosends(this->ci), this);
+
+ FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(this, this->topic));
+
+ if (this->ci)
+ {
+ this->ci->CheckTopic();
+ }
+}
+
/*************************************************************************/
Channel *findchan(const Anope::string &chan)
@@ -1312,57 +1344,6 @@ void do_cmode(const Anope::string &source, int ac, const char **av)
/*************************************************************************/
-/* Handle a TOPIC command. */
-
-void do_topic(const Anope::string &source, int ac, const char **av)
-{
- Channel *c = findchan(av[0]);
- ChannelInfo *ci;
- time_t topic_time = Anope::string(av[2]).is_pos_number_only() ? convertTo<time_t>(av[2]) : 0;
-
- if (!c)
- {
- Log() << "TOPIC " << merge_args(ac - 1, av + 1) << " for nonexistent channel " << av[0];
- return;
- }
-
- /* We can be sure that the topic will be in sync here -GD */
- c->topic_sync = 1;
-
- ci = c->ci;
-
- /* For Unreal, cut off the ! and any futher part of the topic setter.
- * This way, nick!ident@host setters will only show the nick. -GD
- */
- Anope::string topicsetter = myStrGetToken(av[1], '!', 0);
-
- /* If the current topic we have matches the last known topic for this
- * channel exactly, there's no need to update anything and we can as
- * well just return silently without updating anything. -GD
- */
- if (ac > 3 && *av[3] && ci && !ci->last_topic.empty() && ci->last_topic.equals_cs(av[3]) && ci->last_topic_setter.equals_cs(topicsetter))
- return;
-
- if (check_topiclock(c, topic_time))
- return;
-
- if (!c->topic.empty())
- c->topic.clear();
- if (ac > 3 && *av[3])
- c->topic = av[3];
-
- c->topic_setter = topicsetter;
- c->topic_time = topic_time;
-
- record_topic(av[0]);
-
- FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(c, av[0]));
-}
-
-/*************************************************************************/
-/**************************** Internal Calls *****************************/
-/*************************************************************************/
-
/**
* Set the correct modes, or remove the ones granted without permission,
* for the specified user on ths specified channel. This doesn't give
@@ -1443,19 +1424,6 @@ void MassChannelModes(BotInfo *bi, const Anope::string &modes)
/*************************************************************************/
-void restore_unsynced_topics()
-{
- for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
- {
- Channel *c = it->second;
-
- if (!c->topic_sync)
- restore_topic(c->name);
- }
-}
-
-/*************************************************************************/
-
/**
* This handles creating a new Entry.
* This function destroys and free's the given mask as a side effect.
diff --git a/src/chanserv.cpp b/src/chanserv.cpp
index c0ae4efd9..9d8fb411a 100644
--- a/src/chanserv.cpp
+++ b/src/chanserv.cpp
@@ -422,133 +422,6 @@ int check_valid_op(User *user, Channel *chan, int servermode)
/*************************************************************************/
-/* Record the current channel topic in the ChannelInfo structure. */
-
-void record_topic(const Anope::string &chan)
-{
- Channel *c;
- ChannelInfo *ci;
-
- if (readonly)
- return;
-
- c = findchan(chan);
- if (!c || !(ci = c->ci))
- return;
-
- ci->last_topic = c->topic;
- ci->last_topic_setter = c->topic_setter;
- ci->last_topic_time = c->topic_time;
-}
-
-/*************************************************************************/
-
-/* Restore the topic in a channel when it's created, if we should. */
-
-void restore_topic(const Anope::string &chan)
-{
- Channel *c = findchan(chan);
- ChannelInfo *ci;
-
- if (!c || !(ci = c->ci))
- return;
- /* We can be sure that the topic will be in sync when we return -GD */
- c->topic_sync = 1;
- if (!ci->HasFlag(CI_KEEPTOPIC))
- {
- /* We need to reset the topic here, since it's currently empty and
- * should be updated with a TOPIC from the IRCd soon. -GD
- */
- ci->last_topic.clear();
- ci->last_topic_setter = whosends(ci)->nick;
- ci->last_topic_time = Anope::CurTime;
- return;
- }
- if (!ci->last_topic.empty())
- {
- c->topic = ci->last_topic;
- c->topic_setter = ci->last_topic_setter;
- c->topic_time = ci->last_topic_time;
- }
- else
- {
- c->topic.clear();
- c->topic_setter = whosends(ci)->nick;
- }
- if (ircd->join2set && whosends(ci) == ChanServ)
- {
- ChanServ->Join(chan);
- c->SetMode(NULL, CMODE_OP, Config->s_ChanServ);
- }
- ircdproto->SendTopic(whosends(ci), c, c->topic_setter, c->topic);
- if (ircd->join2set && whosends(ci) == ChanServ)
- ChanServ->Part(c);
-}
-
-/*************************************************************************/
-
-/* See if the topic is locked on the given channel, and return 1 (and fix
- * the topic) if so. */
-
-int check_topiclock(Channel *c, time_t topic_time)
-{
- ChannelInfo *ci;
-
- if (!c)
- {
- Log() << "check_topiclock called with NULL values";
- return 0;
- }
-
- if (!(ci = c->ci) || !ci->HasFlag(CI_TOPICLOCK))
- return 0;
-
- if (!ci->last_topic.empty())
- {
- c->topic = ci->last_topic;
- c->topic_setter = ci->last_topic_setter;
- }
- else
- {
- c->topic.clear();
- /* Bot assigned & Symbiosis ON?, the bot will set the topic - doc */
- /* Altough whosends() also checks for Config->BSMinUsers -GD */
- c->topic_setter = whosends(ci)->nick;
- }
-
- if (ircd->topictsforward)
- {
- /* Because older timestamps are rejected */
- /* Some how the topic_time from do_topic is 0 set it to current + 1 */
- if (!topic_time)
- c->topic_time = Anope::CurTime + 1;
- else
- c->topic_time = topic_time + 1;
- }
- else
- {
- /* If no last topic, we can't use last topic time! - doc */
- if (!ci->last_topic.empty())
- c->topic_time = ci->last_topic_time;
- else
- c->topic_time = Anope::CurTime + 1;
- }
-
- if (ircd->join2set && whosends(ci) == ChanServ)
- {
- ChanServ->Join(c);
- c->SetMode(NULL, CMODE_OP, Config->s_ChanServ);
- }
-
- ircdproto->SendTopic(whosends(ci), c, c->topic_setter, c->topic);
-
- if (ircd->join2set && whosends(ci) == ChanServ)
- ChanServ->Part(c);
- return 1;
-}
-
-/*************************************************************************/
-
/* Remove all channels which have expired. */
void expire_chans()
diff --git a/src/regchannel.cpp b/src/regchannel.cpp
index e88065eb5..fb8036677 100644
--- a/src/regchannel.cpp
+++ b/src/regchannel.cpp
@@ -398,7 +398,7 @@ void ChannelInfo::LoadMLock()
ChanServ->Assign(NULL, this);
this->bi->Join(c);
check_modes(this->c);
- restore_topic(this->name);
+ this->CheckTopic();
}
}
@@ -607,7 +607,7 @@ bool ChannelInfo::CheckKick(User *user)
* ChanServ always enforces channels like this to keep people from deleting bots etc
* that are holding channels.
*/
- if (this->c->users.size() == (this->bi ? 2 : 1) && !this->HasFlag(CI_INHABIT) && !this->c->HasFlag(CH_SYNCING))
+ if (this->c->users.size() == (this->bi && this->c->FindUser(this->bi) ? 2 : 1) && !this->HasFlag(CI_INHABIT) && !this->c->HasFlag(CH_SYNCING))
{
/* If channel was forbidden, etc, set it +si to prevent rejoin */
if (set_modes)
@@ -627,3 +627,37 @@ bool ChannelInfo::CheckKick(User *user)
return true;
}
+
+void ChannelInfo::CheckTopic()
+{
+ if (!this->c)
+ return;
+
+ /* We only compare the topics here, not the time or setter. This is because some (old) IRCds do not
+ * allow us to set the topic as someone else, meaning we have to bump the TS and change the setter to us.
+ * This desyncs what is really set with what we have stored, and we end up resetting the topic often when
+ * it is not required
+ */
+ if (this->HasFlag(CI_TOPICLOCK) && this->last_topic != this->c->topic)
+ {
+ this->c->ChangeTopic(this->last_topic_setter, this->last_topic, this->last_topic_time);
+ }
+ else
+ {
+ this->last_topic = this->c->topic;
+ this->last_topic_setter = this->c->topic_setter;
+ this->last_topic_time = this->c->topic_time;
+ }
+}
+
+void ChannelInfo::RestoreTopic()
+{
+ if (!this->c)
+ return;
+
+ if ((this->HasFlag(CI_KEEPTOPIC) || this->HasFlag(CI_TOPICLOCK)) && this->last_topic != this->c->topic)
+ {
+ this->c->ChangeTopic(!this->last_topic_setter.empty() ? this->last_topic_setter : whosends(this)->nick, this->last_topic, this->last_topic_time ? this->last_topic_time : Anope::CurTime);
+ }
+}
+
diff --git a/src/servers.cpp b/src/servers.cpp
index 37518e01e..d8752d90b 100644
--- a/src/servers.cpp
+++ b/src/servers.cpp
@@ -248,7 +248,9 @@ void Server::Sync(bool SyncLinks)
if (this->GetUplink() && this->GetUplink() == Me)
{
FOREACH_MOD(I_OnUplinkSync, OnUplinkSync(this));
- restore_unsynced_topics();
+ for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
+ if (it->second->ci)
+ it->second->ci->RestoreTopic();
}
}