diff options
-rw-r--r-- | include/channels.h | 24 | ||||
-rw-r--r-- | include/extern.h | 5 | ||||
-rw-r--r-- | include/regchannel.h | 18 | ||||
-rw-r--r-- | include/services.h | 5 | ||||
-rw-r--r-- | modules/core/cs_topic.cpp | 26 | ||||
-rw-r--r-- | modules/extra/cs_appendtopic.cpp | 36 | ||||
-rw-r--r-- | modules/protocol/bahamut.cpp | 18 | ||||
-rw-r--r-- | modules/protocol/inspircd11.cpp | 45 | ||||
-rw-r--r-- | modules/protocol/inspircd12.cpp | 46 | ||||
-rw-r--r-- | modules/protocol/inspircd20.cpp | 46 | ||||
-rw-r--r-- | modules/protocol/ratbox.cpp | 82 | ||||
-rw-r--r-- | modules/protocol/unreal32.cpp | 32 | ||||
-rw-r--r-- | src/channels.cpp | 104 | ||||
-rw-r--r-- | src/chanserv.cpp | 127 | ||||
-rw-r--r-- | src/regchannel.cpp | 38 | ||||
-rw-r--r-- | src/servers.cpp | 4 |
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(); } } |