anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

irc2sql.cpp (10059B)

      1 /*
      2  *
      3  * (C) 2013-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  */
      8 
      9 #include "irc2sql.h"
     10 
     11 void IRC2SQL::OnShutdown()
     12 {
     13 	// TODO: test if we really have to use blocking query here
     14 	// (sometimes m_mysql get unloaded before the other thread executed all queries)
     15 	if (this->sql)
     16 		SQL::Result r = this->sql->RunQuery(SQL::Query("CALL " + prefix + "OnShutdown()"));
     17 	quitting = true;
     18 }
     19 
     20 void IRC2SQL::OnReload(Configuration::Conf *conf)
     21 {
     22 	Configuration::Block *block = Config->GetModule(this);
     23 	prefix = block->Get<const Anope::string>("prefix", "anope_");
     24 	GeoIPDB = block->Get<const Anope::string>("geoip_database");
     25 	ctcpuser = block->Get<bool>("ctcpuser", "no");
     26 	ctcpeob = block->Get<bool>("ctcpeob", "yes");
     27 	Anope::string engine = block->Get<const Anope::string>("engine");
     28 	this->sql = ServiceReference<SQL::Provider>("SQL::Provider", engine);
     29 	if (sql)
     30 		this->CheckTables();
     31 	else
     32 		Log() << "IRC2SQL: no database connection to " << engine;
     33 
     34 	const Anope::string &snick = block->Get<const Anope::string>("client");
     35 	if (snick.empty())
     36 		throw ConfigException(Module::name + ": <client> must be defined");
     37 	StatServ = BotInfo::Find(snick, true);
     38 	if (!StatServ)
     39 		throw ConfigException(Module::name + ": no bot named " + snick);
     40 
     41 	if (firstrun)
     42 	{
     43 		firstrun = false;
     44 
     45 		for (Anope::map<Server *>::const_iterator it = Servers::ByName.begin(); it != Servers::ByName.end(); ++it)
     46 		{
     47 			this->OnNewServer(it->second);
     48 		}
     49 
     50 		for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
     51 		{
     52 			this->OnChannelCreate(it->second);
     53 		}
     54 
     55 		for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
     56 		{
     57 			User *u = it->second;
     58 			bool exempt = false;
     59 			this->OnUserConnect(u, exempt);
     60 			for (User::ChanUserList::const_iterator cit = u->chans.begin(), cit_end = u->chans.end(); cit != cit_end; ++cit)
     61 			{
     62 				this->OnJoinChannel(u, cit->second->chan);
     63 			}
     64 		}
     65 	}
     66 
     67 }
     68 
     69 void IRC2SQL::OnNewServer(Server *server)
     70 {
     71 	query = "INSERT DELAYED INTO `" + prefix + "server` (name, hops, comment, link_time, online, ulined) "
     72 		"VALUES (@name@, @hops@, @comment@, now(), 'Y', @ulined@) "
     73 		"ON DUPLICATE KEY UPDATE name=VALUES(name), hops=VALUES(hops), comment=VALUES(comment), "
     74 			"link_time=VALUES(link_time), online=VALUES(online), ulined=VALUES(ulined)";
     75 	query.SetValue("name", server->GetName());
     76 	query.SetValue("hops", server->GetHops());
     77 	query.SetValue("comment", server->GetDescription());
     78 	query.SetValue("ulined", server->IsULined() ? "Y" : "N");
     79 	this->RunQuery(query);
     80 }
     81 
     82 void IRC2SQL::OnServerQuit(Server *server)
     83 {
     84 	if (quitting)
     85 		return;
     86 
     87 	query = "CALL " + prefix + "ServerQuit(@name@)";
     88 	query.SetValue("name", server->GetName());
     89 	this->RunQuery(query);
     90 }
     91 
     92 void IRC2SQL::OnUserConnect(User *u, bool &exempt)
     93 {
     94 	if (!introduced_myself)
     95 	{
     96 		this->OnNewServer(Me);
     97 		introduced_myself = true;
     98 	}
     99 
    100 	query = "CALL " + prefix + "UserConnect(@nick@,@host@,@vhost@,@chost@,@realname@,@ip@,@ident@,@vident@,"
    101 			"@account@,@secure@,@fingerprint@,@signon@,@server@,@uuid@,@modes@,@oper@)";
    102 	query.SetValue("nick", u->nick);
    103 	query.SetValue("host", u->host);
    104 	query.SetValue("vhost", u->vhost);
    105 	query.SetValue("chost", u->chost);
    106 	query.SetValue("realname", u->realname);
    107 	query.SetValue("ip", u->ip.addr());
    108 	query.SetValue("ident", u->GetIdent());
    109 	query.SetValue("vident", u->GetVIdent());
    110 	query.SetValue("secure", u->HasMode("SSL") || u->HasExt("ssl") ? "Y" : "N");
    111 	query.SetValue("account", u->Account() ? u->Account()->display : "");
    112 	query.SetValue("fingerprint", u->fingerprint);
    113 	query.SetValue("signon", u->signon);
    114 	query.SetValue("server", u->server->GetName());
    115 	query.SetValue("uuid", u->GetUID());
    116 	query.SetValue("modes", u->GetModes());
    117 	query.SetValue("oper", u->HasMode("OPER") ? "Y" : "N");
    118 	this->RunQuery(query);
    119 
    120 	if (ctcpuser && (Me->IsSynced() || ctcpeob) && u->server != Me)
    121 		IRCD->SendPrivmsg(StatServ, u->GetUID(), "\1VERSION\1");
    122 
    123 }
    124 
    125 void IRC2SQL::OnUserQuit(User *u, const Anope::string &msg)
    126 {
    127 	if (quitting || u->server->IsQuitting())
    128 		return;
    129 
    130 	query = "CALL " + prefix + "UserQuit(@nick@)";
    131 	query.SetValue("nick", u->nick);
    132 	this->RunQuery(query);
    133 }
    134 
    135 void IRC2SQL::OnUserNickChange(User *u, const Anope::string &oldnick)
    136 {
    137 	query = "UPDATE `" + prefix + "user` SET nick=@newnick@ WHERE nick=@oldnick@";
    138 	query.SetValue("newnick", u->nick);
    139 	query.SetValue("oldnick", oldnick);
    140 	this->RunQuery(query);
    141 }
    142 
    143 void IRC2SQL::OnUserAway(User *u, const Anope::string &message)
    144 {
    145 	query = "UPDATE `" + prefix + "user` SET away=@away@, awaymsg=@awaymsg@ WHERE nick=@nick@";
    146 	query.SetValue("away", (!message.empty()) ? "Y" : "N");
    147 	query.SetValue("awaymsg", message);
    148 	query.SetValue("nick", u->nick);
    149 	this->RunQuery(query);
    150 }
    151 
    152 void IRC2SQL::OnFingerprint(User *u)
    153 {
    154 	query = "UPDATE `" + prefix + "user` SET secure=@secure@, fingerprint=@fingerprint@ WHERE nick=@nick@";
    155 	query.SetValue("secure", u->HasMode("SSL") || u->HasExt("ssl") ? "Y" : "N");
    156 	query.SetValue("fingerprint", u->fingerprint);
    157 	query.SetValue("nick", u->nick);
    158 	this->RunQuery(query);
    159 }
    160 
    161 void IRC2SQL::OnUserModeSet(const MessageSource &setter, User *u, const Anope::string &mname)
    162 {
    163 	query = "UPDATE `" + prefix + "user` SET modes=@modes@, oper=@oper@ WHERE nick=@nick@";
    164 	query.SetValue("nick", u->nick);
    165 	query.SetValue("modes", u->GetModes());
    166 	query.SetValue("oper", u->HasMode("OPER") ? "Y" : "N");
    167 	this->RunQuery(query);
    168 }
    169 
    170 void IRC2SQL::OnUserModeUnset(const MessageSource &setter, User *u, const Anope::string &mname)
    171 {
    172 	this->OnUserModeSet(setter, u, mname);
    173 }
    174 
    175 void IRC2SQL::OnUserLogin(User *u)
    176 {
    177 	query = "UPDATE `" + prefix + "user` SET account=@account@ WHERE nick=@nick@";
    178 	query.SetValue("nick", u->nick);
    179 	query.SetValue("account", u->Account() ? u->Account()->display : "");
    180 	this->RunQuery(query);
    181 }
    182 
    183 void IRC2SQL::OnNickLogout(User *u)
    184 {
    185 	this->OnUserLogin(u);
    186 }
    187 
    188 void IRC2SQL::OnSetDisplayedHost(User *u)
    189 {
    190 	query = "UPDATE `" + prefix + "user` "
    191 		"SET vhost=@vhost@ "
    192 		"WHERE nick=@nick@";
    193 	query.SetValue("vhost", u->GetDisplayedHost());
    194 	query.SetValue("nick", u->nick);
    195 	this->RunQuery(query);
    196 }
    197 
    198 void IRC2SQL::OnChannelCreate(Channel *c)
    199 {
    200 	query = "INSERT INTO `" + prefix + "chan` (channel, topic, topicauthor, topictime, modes) "
    201 		"VALUES (@channel@,@topic@,@topicauthor@,@topictime@,@modes@) "
    202 		"ON DUPLICATE KEY UPDATE channel=VALUES(channel), topic=VALUES(topic),"
    203 			"topicauthor=VALUES(topicauthor), topictime=VALUES(topictime), modes=VALUES(modes)";
    204 	query.SetValue("channel", c->name);
    205 	query.SetValue("topic", c->topic);
    206 	query.SetValue("topicauthor", c->topic_setter);
    207 	if (c->topic_ts > 0)
    208 		query.SetValue("topictime", c->topic_ts);
    209 	else
    210 		query.SetValue("topictime", "NULL", false);
    211 	query.SetValue("modes", c->GetModes(true,true));
    212 	this->RunQuery(query);
    213 }
    214 
    215 void IRC2SQL::OnChannelDelete(Channel *c)
    216 {
    217 	query = "DELETE FROM `" + prefix + "chan` WHERE channel=@channel@";
    218 	query.SetValue("channel",  c->name);
    219 	this->RunQuery(query);
    220 }
    221 
    222 void IRC2SQL::OnJoinChannel(User *u, Channel *c)
    223 {
    224 	Anope::string modes;
    225 	ChanUserContainer *cu = u->FindChannel(c);
    226 	if (cu)
    227 		modes = cu->status.Modes();
    228 
    229 	query = "CALL " + prefix + "JoinUser(@nick@,@channel@,@modes@)";
    230 	query.SetValue("nick", u->nick);
    231 	query.SetValue("channel", c->name);
    232 	query.SetValue("modes", modes);
    233 	this->RunQuery(query);
    234 }
    235 
    236 EventReturn IRC2SQL::OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param)
    237 {
    238 	if (mode->type == MODE_STATUS)
    239 	{
    240 		User *u = User::Find(param);
    241 		if (u == NULL)
    242 			return EVENT_CONTINUE;
    243 
    244 		ChanUserContainer *cc = u->FindChannel(c);
    245 		if (cc == NULL)
    246 			return EVENT_CONTINUE;
    247 
    248 		query = "UPDATE `" + prefix + "user` AS u, `" + prefix + "ison` AS i, `" + prefix + "chan` AS c"
    249 				" SET i.modes=@modes@"
    250 				" WHERE u.nick=@nick@ AND c.channel=@channel@"
    251 				" AND u.nickid = i.nickid AND c.chanid = i.chanid";
    252 		query.SetValue("nick", u->nick);
    253 		query.SetValue("modes", cc->status.Modes());
    254 		query.SetValue("channel", c->name);
    255 		this->RunQuery(query);
    256 	}
    257 	else
    258 	{
    259 		query = "UPDATE `" + prefix + "chan` SET modes=@modes@ WHERE channel=@channel@";
    260 		query.SetValue("channel", c->name);
    261 		query.SetValue("modes", c->GetModes(true,true));
    262 		this->RunQuery(query);
    263 	}
    264 	return EVENT_CONTINUE;
    265 }
    266 
    267 EventReturn IRC2SQL::OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param)
    268 {
    269 	this->OnChannelModeSet(c, setter, mode, param);
    270 	return EVENT_CONTINUE;
    271 }
    272 
    273 void IRC2SQL::OnLeaveChannel(User *u, Channel *c)
    274 {
    275 	if (quitting)
    276 		return;
    277 	/*
    278 	 * user is quitting, we already received a OnUserQuit()
    279 	 * at this point the user is already removed from SQL and all channels
    280 	 */
    281 	if (u->Quitting())
    282 		return;
    283 	query = "CALL " + prefix + "PartUser(@nick@,@channel@)";
    284 	query.SetValue("nick", u->nick);
    285 	query.SetValue("channel", c->name);
    286 	this->RunQuery(query);
    287 }
    288 
    289 void IRC2SQL::OnTopicUpdated(User *source, Channel *c, const Anope::string &user, const Anope::string &topic)
    290 {
    291 	query = "UPDATE `" + prefix + "chan` "
    292 		"SET topic=@topic@, topicauthor=@author@, topictime=FROM_UNIXTIME(@time@) "
    293 		"WHERE channel=@channel@";
    294 	query.SetValue("topic", c->topic);
    295 	query.SetValue("author", c->topic_setter);
    296 	query.SetValue("time", c->topic_ts);
    297 	query.SetValue("channel", c->name);
    298 	this->RunQuery(query);
    299 }
    300 
    301 void IRC2SQL::OnBotNotice(User *u, BotInfo *bi, Anope::string &message)
    302 {
    303 	Anope::string versionstr;
    304 	if (bi != StatServ)
    305 		return;
    306 	if (message[0] == '\1' && message[message.length() - 1] == '\1')
    307 	{
    308 		if (message.substr(0, 9).equals_ci("\1VERSION "))
    309 		{
    310 			if (u->HasExt("CTCPVERSION"))
    311 				return;
    312 			u->Extend<bool>("CTCPVERSION");
    313 
    314 			versionstr = Anope::NormalizeBuffer(message.substr(9, message.length() - 10));
    315 			if (versionstr.empty())
    316 				return;
    317 			query = "UPDATE `" + prefix + "user` "
    318 				"SET version=@version@ "
    319 				"WHERE nick=@nick@";
    320 			query.SetValue("version", versionstr);
    321 			query.SetValue("nick", u->nick);
    322 			this->RunQuery(query);
    323 		}
    324 	}
    325 }
    326 
    327 MODULE_INIT(IRC2SQL)