diff options
Diffstat (limited to 'modules/extra')
| -rw-r--r-- | modules/extra/m_chanstats.cpp | 268 | ||||
| -rw-r--r-- | modules/extra/m_helpchan.cpp | 2 |
2 files changed, 269 insertions, 1 deletions
diff --git a/modules/extra/m_chanstats.cpp b/modules/extra/m_chanstats.cpp new file mode 100644 index 000000000..8f6d8ffb6 --- /dev/null +++ b/modules/extra/m_chanstats.cpp @@ -0,0 +1,268 @@ +#include "module.h" +#include "../extra/sql.h" + +class MySQLInterface : public SQLInterface +{ + public: + MySQLInterface(Module *o) : SQLInterface(o) { } + + void OnResult(const SQLResult &r) anope_override + { + } + + void OnError(const SQLResult &r) anope_override + { + if (!r.GetQuery().query.empty()) + Log(LOG_DEBUG) << "Chanstats: Error executing query " << r.finished_query << ": " << r.GetError(); + else + Log(LOG_DEBUG) << "Chanstats: Error executing query: " << r.GetError(); + } +}; + +class MChanstats : public Module +{ + service_reference<SQLProvider> sql; + MySQLInterface sqlinterface; + SQLQuery query; + Anope::string SmileysHappy, SmileysSad, SmileysOther; + std::vector<Anope::string> TableList; + + void RunQuery(const SQLQuery &q) + { + if (sql) + sql->Run(&sqlinterface, q); + } + + void SetQuery() + { + query = "INSERT DELAYED INTO `anope_bs_chanstats` (chanserv_name, nickserv_display, day, hour, @what@) " + "VALUES (@chanserv_name@, @nickserv_display@, CURRENT_DATE, HOUR(NOW()), '1') " + "ON DUPLICATE KEY UPDATE @what@=@what@+1;"; + } + size_t CountWords(const Anope::string &msg) + { + size_t words = 0; + for (size_t pos = 0; pos != Anope::string::npos; pos = msg.find(" ", pos+1)) + words++; + return words; + } + size_t CountSmileys(const Anope::string &msg, const Anope::string &smileylist) + { + size_t smileys = 0; + spacesepstream sep(smileylist); + Anope::string buf; + + while (sep.GetToken(buf) && !buf.empty()) + { + for (size_t pos = msg.find(buf, 0); pos != Anope::string::npos; pos = msg.find(buf, pos+1)) + smileys++; + } + return smileys; + } + + void GetTables() + { + TableList.clear(); + SQLResult r = this->sql->RunQuery(this->sql->GetTables()); + for (int i = 0; i < r.Rows(); ++i) + { + const std::map<Anope::string, Anope::string> &map = r.Row(i); + for (std::map<Anope::string, Anope::string>::const_iterator it = map.begin(); it != map.end(); ++it) + TableList.push_back(it->second); + } + } + + bool HasTable(const Anope::string &table) + { + for (std::vector<Anope::string>::const_iterator it = TableList.begin(); it != TableList.end(); ++it) + if (*it == table) + return true; + return false; + } + + void CheckTables() + { + this->GetTables(); + if (!this->HasTable("anope_bs_chanstats")) + { + query = "CREATE TABLE `anope_bs_chanstats` (" + "`id` int(11) NOT NULL AUTO_INCREMENT," + "`chanserv_name` varchar(255) NOT NULL DEFAULT ''," + "`nickserv_display` varchar(255) NOT NULL DEFAULT ''," + "`day` date NOT NULL," + "`hour` tinyint(2) NOT NULL," + "`letters` int(10) unsigned NOT NULL DEFAULT '0'," + "`words` int(10) unsigned NOT NULL DEFAULT '0'," + "`line` int(10) unsigned NOT NULL DEFAULT '0'," + "`actions` int(10) unsigned NOT NULL DEFAULT '0'," + "`smileys_happy` int(10) unsigned NOT NULL DEFAULT '0'," + "`smileys_sad` int(10) unsigned NOT NULL DEFAULT '0'," + "`smileys_other` int(10) unsigned NOT NULL DEFAULT '0'," + "`kicks` int(10) unsigned NOT NULL DEFAULT '0'," + "`kicked` int(10) unsigned NOT NULL DEFAULT '0'," + "`modes` int(10) unsigned NOT NULL DEFAULT '0'," + "`topics` int(10) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`id`)," + "UNIQUE KEY `chanserv_name` (`chanserv_name`,`nickserv_display`,`day`,`hour`)," + "KEY `nickserv_display` (`nickserv_display`), " + "KEY `day` (`day`)," + "KEY `hour` (`hour`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8;"; + this->RunQuery(query); + } + if (!this->HasTable("anope_bs_chanstats_view_sum_all")) + { + query = "CREATE OR REPLACE VIEW `anope_bs_chanstats_view_sum_all` AS " + "SELECT `anope_bs_chanstats`.`chanserv_name` AS `chanserv_name`," + "`anope_bs_chanstats`.`nickserv_display` AS `nickserv_display`," + "sum(`anope_bs_chanstats`.`letters`) AS `letters`," + "sum(`anope_bs_chanstats`.`words`) AS `words`," + "sum(`anope_bs_chanstats`.`line`) AS `line`," + "sum(`anope_bs_chanstats`.`actions`) AS `actions`," + "((sum(`anope_bs_chanstats`.`smileys_happy`) " + "+ sum(`anope_bs_chanstats`.`smileys_sad`)) " + "+ sum(`anope_bs_chanstats`.`smileys_other`)) AS `smileys`," + "sum(`anope_bs_chanstats`.`smileys_happy`) AS `smileys_happy`," + "sum(`anope_bs_chanstats`.`smileys_sad`) AS `smileys_sad`," + "sum(`anope_bs_chanstats`.`smileys_other`) AS `smileys_other`," + "sum(`anope_bs_chanstats`.`kicks`) AS `kicks`," + "sum(`anope_bs_chanstats`.`kicked`) AS `kicked`," + "sum(`anope_bs_chanstats`.`modes`) AS `modes`," + "sum(`anope_bs_chanstats`.`topics`) AS `topics` " + "FROM `anope_bs_chanstats` " + "GROUP BY `anope_bs_chanstats`.`chanserv_name`,`anope_bs_chanstats`.`nickserv_display`;"; + this->RunQuery(query); + } + } + + + public: + MChanstats(const Anope::string &modname, const Anope::string &creator) : + Module(modname, creator, CORE), sql("", ""), sqlinterface(this) + { + this->SetAuthor("Anope"); + + Implementation i[] = { I_OnPrivmsg, + I_OnUserKicked, + I_OnChannelModeSet, + I_OnChannelModeUnset, + I_OnTopicUpdated, + I_OnReload}; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + this->OnReload(); + } + void OnReload() anope_override + { + ConfigReader config; + SmileysHappy = config.ReadValue("chanstats", "SmileysHappy", ":) :-) ;) :D :-D", 0); + SmileysSad = config.ReadValue("chanstats", "SmileysSad", ":( :-( ;( ;-(", 0); + SmileysOther = config.ReadValue("chanstats", "SmileysOther", ":/", 0); + + Anope::string engine = config.ReadValue("chanstats", "engine", "", 0); + this->sql = service_reference<SQLProvider>("SQLProvider", engine); + this->CheckTables(); + + } + void OnTopicUpdated(Channel *c, User *u, const Anope::string &topic) anope_override + { + if (!u || !u->Account() || !c->ci || !c->ci->HasFlag(CI_STATS)) + return; + + bool has_display = u->Account()->HasFlag(NI_STATS); + + this->SetQuery(); + query.setValue("chanserv_name", c->name); + query.setValue("nickserv_display", has_display ? u->Account()->display : ""); + query.setValue("what", "topics", false); + this->RunQuery(query); + } + EventReturn OnChannelModeSet(Channel *c, User *setter, ChannelModeName Name, const Anope::string ¶m) anope_override + { + this->OnModeChange(c, setter); + return EVENT_CONTINUE; + } + EventReturn OnChannelModeUnset(Channel *c, User *setter, ChannelModeName Name, const Anope::string ¶m) anope_override + { + this->OnModeChange(c, setter); + return EVENT_CONTINUE; + } + void OnModeChange(Channel *c, User *u) + { + if (!u || !u->Account() || !c->ci || !c->ci->HasFlag(CI_STATS)) + return; + + bool has_display = u->Account()->HasFlag(NI_STATS); + + this->SetQuery(); + query.setValue("chanserv_name", c->name); + query.setValue("nickserv_display", has_display ? u->Account()->display : ""); + query.setValue("what", "modes", false); + this->RunQuery(query); + } + void OnUserKicked(Channel *c, User *target, const Anope::string &source, const Anope::string &kickmsg) anope_override + { + if (!c->ci || !c->ci->HasFlag(CI_STATS)) + return; + + + bool has_display = target && target->Account() && target->Account()->HasFlag(NI_STATS); + + this->SetQuery(); + query.setValue("chanserv_name", c->name); + query.setValue("nickserv_display", has_display ? target->Account()->display : ""); + query.setValue("what", "kicked", false); + this->RunQuery(query); + + User *kicker = finduser(source); + has_display = kicker && kicker->Account() && kicker->Account()->HasFlag(NI_STATS); + + this->SetQuery(); + query.setValue("chanserv_name", c->name); + query.setValue("nickserv_display", has_display ? kicker->Account()->display : ""); + query.setValue("what", "kicks", false); + this->RunQuery(query); + } + void OnPrivmsg(User *u, Channel *c, Anope::string &msg) anope_override + { + if (!c->ci || !c->ci->HasFlag(CI_STATS) || (msg[0] == Config->BSFantasyCharacter[0])) + return; + + size_t letters = msg.length(); + size_t words = this->CountWords(msg); + + size_t action = 0; + if (msg.find("\01ACTION")!=Anope::string::npos) + { + action = 1; + letters = letters - 7; + words--; + } + + // count smileys + size_t smileys_happy = CountSmileys(msg, SmileysHappy); + size_t smileys_sad = CountSmileys(msg, SmileysSad); + size_t smileys_other = CountSmileys(msg, SmileysOther); + + // do not count smileys as words + words = words - smileys_happy - smileys_sad - smileys_other; + bool has_display = u && u->Account() && u->Account()->HasFlag(NI_STATS); + query = "INSERT DELAYED INTO `anope_bs_chanstats` (chanserv_name, nickserv_display, day, hour, letters, words, line, actions, smileys_happy, smileys_sad, smileys_other) " + "VALUES (@chanserv_name@, @nickserv_display@, CURRENT_DATE, HOUR(NOW()), @letters@, @words@, 1, @actions@, @smileys_happy@, @smileys_sad@, @smileys_other@) " + "ON DUPLICATE KEY UPDATE letters=letters+VALUES(letters), words=words+VALUES(words), line=line+1, actions=actions+VALUES(actions), " + "smileys_happy=smileys_happy+VALUES(smileys_happy), smileys_sad=smileys_sad+VALUES(smileys_sad), smileys_other=smileys_other+VALUES(smileys_other);"; + query.setValue("nickserv_display", has_display ? u->Account()->display : ""); + query.setValue("chanserv_name", c->name); + query.setValue("letters", letters); + query.setValue("words", words); + query.setValue("actions", action); + query.setValue("smileys_happy", smileys_happy); + query.setValue("smileys_sad", smileys_sad); + query.setValue("smileys_other", smileys_other); + this->RunQuery(query); + } +}; + + + +MODULE_INIT(MChanstats) + diff --git a/modules/extra/m_helpchan.cpp b/modules/extra/m_helpchan.cpp index 7152f81ae..b3971f257 100644 --- a/modules/extra/m_helpchan.cpp +++ b/modules/extra/m_helpchan.cpp @@ -22,7 +22,7 @@ class HelpChannel : public Module OnReload(); } - EventReturn OnChannelModeSet(Channel *c, ChannelModeName Name, const Anope::string ¶m) anope_override + EventReturn OnChannelModeSet(Channel *c, User *setter, ChannelModeName Name, const Anope::string ¶m) anope_override { if (Name == CMODE_OP && c && c->ci && c->name.equals_ci(this->HelpChan)) { |
