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 ¶m) 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 ¶m) 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)