| 1 |
/* ircd-hybrid-8 protocol module |
| 2 |
* |
| 3 |
* (C) 2003-2012 Anope Team |
| 4 |
* (C) 2012 by the Hybrid Development Team |
| 5 |
* |
| 6 |
* Please read COPYING and README for further details. |
| 7 |
* |
| 8 |
* Based on the original code of Epona by Lara. |
| 9 |
* Based on the original code of Services by Andy Church. |
| 10 |
* |
| 11 |
*/ |
| 12 |
|
| 13 |
#include "module.h" |
| 14 |
|
| 15 |
static Anope::string UplinkSID; |
| 16 |
|
| 17 |
class HybridProto : public IRCDProto |
| 18 |
{ |
| 19 |
public: |
| 20 |
HybridProto() : IRCDProto("Hybrid 8.0.0") |
| 21 |
{ |
| 22 |
DefaultPseudoclientModes = "+oi"; |
| 23 |
CanSNLine = true; |
| 24 |
CanSQLine = true; |
| 25 |
CanSZLine = true; |
| 26 |
RequiresID = true; |
| 27 |
MaxModes = 4; |
| 28 |
} |
| 29 |
|
| 30 |
void SendGlobalNotice(const BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override |
| 31 |
{ |
| 32 |
UplinkSocket::Message(bi) << "NOTICE $$" << dest->GetName() << " :" << msg; |
| 33 |
} |
| 34 |
|
| 35 |
void SendGlobalPrivmsg(const BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override |
| 36 |
{ |
| 37 |
UplinkSocket::Message(bi) << "PRIVMSG $$" << dest->GetName() << " :" << msg; |
| 38 |
} |
| 39 |
|
| 40 |
void SendSQLine(User *, const XLine *x) anope_override |
| 41 |
{ |
| 42 |
const BotInfo *bi = findbot(Config->OperServ); |
| 43 |
|
| 44 |
UplinkSocket::Message(bi) << "RESV * " << x->Mask << " :" << x->GetReason(); |
| 45 |
} |
| 46 |
|
| 47 |
void SendSGLineDel(const XLine *x) anope_override |
| 48 |
{ |
| 49 |
const BotInfo *bi = findbot(Config->OperServ); |
| 50 |
|
| 51 |
UplinkSocket::Message(bi) << "UNXLINE * " << x->Mask; |
| 52 |
} |
| 53 |
|
| 54 |
void SendSGLine(User *, const XLine *x) anope_override |
| 55 |
{ |
| 56 |
const BotInfo *bi = findbot(Config->OperServ); |
| 57 |
|
| 58 |
UplinkSocket::Message(bi) << "XLINE * " << x->Mask << " 0 :" << x->GetReason(); |
| 59 |
} |
| 60 |
|
| 61 |
void SendSZLineDel(const XLine *x) anope_override |
| 62 |
{ |
| 63 |
const BotInfo *bi = findbot(Config->OperServ); |
| 64 |
|
| 65 |
UplinkSocket::Message(bi) << "UNDLINE * " << x->GetHost(); |
| 66 |
} |
| 67 |
|
| 68 |
void SendSZLine(User *, const XLine *x) anope_override |
| 69 |
{ |
| 70 |
const BotInfo *bi = findbot(Config->OperServ); |
| 71 |
/* Calculate the time left before this would expire, capping it at 2 days */ |
| 72 |
time_t timeleft = x->Expires - Anope::CurTime; |
| 73 |
|
| 74 |
if (timeleft > 172800 || !x->Expires) |
| 75 |
timeleft = 172800; |
| 76 |
|
| 77 |
UplinkSocket::Message(bi) << "DLINE * " << timeleft << " " << x->GetHost() << " :" << x->GetReason(); |
| 78 |
} |
| 79 |
|
| 80 |
void SendAkillDel(const XLine *x) anope_override |
| 81 |
{ |
| 82 |
if (x->IsRegex() || x->HasNickOrReal()) |
| 83 |
return; |
| 84 |
|
| 85 |
const BotInfo *bi = findbot(Config->OperServ); |
| 86 |
|
| 87 |
UplinkSocket::Message(bi) << "UNKLINE * " << x->GetUser() << " " << x->GetHost(); |
| 88 |
} |
| 89 |
|
| 90 |
void SendSQLineDel(const XLine *x) anope_override |
| 91 |
{ |
| 92 |
const BotInfo *bi = findbot(Config->OperServ); |
| 93 |
|
| 94 |
UplinkSocket::Message(bi) << "UNRESV * " << x->Mask; |
| 95 |
} |
| 96 |
|
| 97 |
void SendJoin(const User *user, Channel *c, const ChannelStatus *status) anope_override |
| 98 |
{ |
| 99 |
/* |
| 100 |
* Note that we must send our modes with the SJOIN and |
| 101 |
* can not add them to the mode stacker because ircd-hybrid |
| 102 |
* does not allow *any* client to op itself |
| 103 |
*/ |
| 104 |
UplinkSocket::Message() << "SJOIN " << c->creation_time << " " << c->name << " +" |
| 105 |
<< c->GetModes(true, true) << " :" |
| 106 |
<< (status != NULL ? status->BuildModePrefixList() : "") << user->GetUID(); |
| 107 |
|
| 108 |
/* And update our internal status for this user since this is not going through our mode handling system */ |
| 109 |
if (status != NULL) |
| 110 |
{ |
| 111 |
UserContainer *uc = c->FindUser(user); |
| 112 |
|
| 113 |
if (uc != NULL) |
| 114 |
*uc->Status = *status; |
| 115 |
} |
| 116 |
} |
| 117 |
|
| 118 |
void SendAkill(User *u, XLine *x) anope_override |
| 119 |
{ |
| 120 |
const BotInfo *bi = findbot(Config->OperServ); |
| 121 |
|
| 122 |
if (x->IsRegex() || x->HasNickOrReal()) |
| 123 |
{ |
| 124 |
if (!u) |
| 125 |
{ |
| 126 |
/* |
| 127 |
* No user (this akill was just added), and contains nick and/or realname. |
| 128 |
* Find users that match and ban them. |
| 129 |
*/ |
| 130 |
for (Anope::insensitive_map<User *>::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) |
| 131 |
if (x->manager->Check(it->second, x)) |
| 132 |
this->SendAkill(it->second, x); |
| 133 |
|
| 134 |
return; |
| 135 |
} |
| 136 |
|
| 137 |
const XLine *old = x; |
| 138 |
|
| 139 |
if (old->manager->HasEntry("*@" + u->host)) |
| 140 |
return; |
| 141 |
|
| 142 |
/* We can't akill x as it has a nick and/or realname included, so create a new akill for *@host */ |
| 143 |
XLine *xline = new XLine("*@" + u->host, old->By, old->Expires, old->Reason, old->UID); |
| 144 |
|
| 145 |
old->manager->AddXLine(xline); |
| 146 |
x = xline; |
| 147 |
|
| 148 |
Log(bi, "akill") << "AKILL: Added an akill for " << x->Mask << " because " << u->GetMask() << "#" |
| 149 |
<< u->realname << " matches " << old->Mask; |
| 150 |
} |
| 151 |
|
| 152 |
/* Calculate the time left before this would expire, capping it at 2 days */ |
| 153 |
time_t timeleft = x->Expires - Anope::CurTime; |
| 154 |
|
| 155 |
if (timeleft > 172800 || !x->Expires) |
| 156 |
timeleft = 172800; |
| 157 |
|
| 158 |
UplinkSocket::Message(bi) << "KLINE * " << timeleft << " " << x->GetUser() << " " << x->GetHost() << " :" << x->GetReason(); |
| 159 |
} |
| 160 |
|
| 161 |
void SendServer(const Server *server) anope_override |
| 162 |
{ |
| 163 |
UplinkSocket::Message() << "SERVER " << server->GetName() << " " << server->GetHops() << " :" << server->GetDescription(); |
| 164 |
} |
| 165 |
|
| 166 |
void SendConnect() anope_override |
| 167 |
{ |
| 168 |
UplinkSocket::Message() << "PASS " << Config->Uplinks[CurrentUplink]->password << " TS 6 :" << Me->GetSID(); |
| 169 |
|
| 170 |
/* |
| 171 |
* As of October 13, 2012, ircd-hybrid-8 does support the following capabilities |
| 172 |
* which are required to work with IRC-services: |
| 173 |
* |
| 174 |
* QS - Can handle quit storm removal |
| 175 |
* EX - Can do channel +e exemptions |
| 176 |
* CHW - Can do channel wall @# |
| 177 |
* IE - Can do invite exceptions |
| 178 |
* KNOCK - Supports KNOCK |
| 179 |
* TBURST - Supports topic burst |
| 180 |
* ENCAP - Supports ENCAP |
| 181 |
* HOPS - Supports HalfOps |
| 182 |
* SVS - Supports services |
| 183 |
* EOB - Supports End Of Burst message |
| 184 |
* TS6 - Capable of TS6 support |
| 185 |
*/ |
| 186 |
UplinkSocket::Message() << "CAPAB :QS EX CHW IE ENCAP TBURST SVS HOPS EOB TS6"; |
| 187 |
|
| 188 |
SendServer(Me); |
| 189 |
|
| 190 |
UplinkSocket::Message() << "SVINFO 6 5 0 :" << Anope::CurTime; |
| 191 |
} |
| 192 |
|
| 193 |
void SendClientIntroduction(const User *u) anope_override |
| 194 |
{ |
| 195 |
Anope::string modes = "+" + u->GetModes(); |
| 196 |
|
| 197 |
UplinkSocket::Message(Me) << "UID " << u->nick << " 1 " << u->timestamp << " " << modes << " " |
| 198 |
<< u->GetIdent() << " " << u->host << " 0 " << u->GetUID() << " 0 :" << u->realname; |
| 199 |
} |
| 200 |
|
| 201 |
void SendEOB() anope_override |
| 202 |
{ |
| 203 |
UplinkSocket::Message(Me) << "EOB"; |
| 204 |
} |
| 205 |
|
| 206 |
void SendModeInternal(const BotInfo *bi, const User *u, const Anope::string &buf) anope_override |
| 207 |
{ |
| 208 |
if (bi) |
| 209 |
UplinkSocket::Message(bi) << "SVSMODE " << u->nick << " " << u->timestamp << " " << buf; |
| 210 |
else |
| 211 |
UplinkSocket::Message(Me) << "SVSMODE " << u->nick << " " << u->timestamp << " " << buf; |
| 212 |
} |
| 213 |
|
| 214 |
void SendLogin(User *u) anope_override |
| 215 |
{ |
| 216 |
const BotInfo *ns = findbot(Config->NickServ); |
| 217 |
|
| 218 |
ircdproto->SendMode(ns, u, "+d %s", u->Account()->display.c_str()); |
| 219 |
} |
| 220 |
|
| 221 |
void SendLogout(User *u) anope_override |
| 222 |
{ |
| 223 |
const BotInfo *ns = findbot(Config->NickServ); |
| 224 |
|
| 225 |
ircdproto->SendMode(ns, u, "+d 0"); |
| 226 |
} |
| 227 |
|
| 228 |
void SendChannel(Channel *c) anope_override |
| 229 |
{ |
| 230 |
Anope::string modes = c->GetModes(true, true); |
| 231 |
|
| 232 |
if (modes.empty()) |
| 233 |
modes = "+"; |
| 234 |
|
| 235 |
UplinkSocket::Message() << "SJOIN " << c->creation_time << " " << c->name << " " << modes << " :"; |
| 236 |
} |
| 237 |
|
| 238 |
void SendTopic(BotInfo *bi, Channel *c) anope_override |
| 239 |
{ |
| 240 |
bool needjoin = c->FindUser(bi) == NULL; |
| 241 |
|
| 242 |
if (needjoin) |
| 243 |
{ |
| 244 |
ChannelStatus status; |
| 245 |
|
| 246 |
status.SetFlag(CMODE_OP); |
| 247 |
bi->Join(c, &status); |
| 248 |
} |
| 249 |
|
| 250 |
IRCDProto::SendTopic(bi, c); |
| 251 |
|
| 252 |
if (needjoin) |
| 253 |
bi->Part(c); |
| 254 |
} |
| 255 |
}; |
| 256 |
|
| 257 |
struct IRCDMessageBMask : IRCDMessage |
| 258 |
{ |
| 259 |
IRCDMessageBMask() : IRCDMessage("BMASK", 4) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } |
| 260 |
|
| 261 |
/* 0 1 2 3 */ |
| 262 |
/* :0MC BMASK 1350157102 #channel b :*!*@*.test.com */ |
| 263 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 264 |
{ |
| 265 |
Channel *c = findchan(params[1]); |
| 266 |
|
| 267 |
if (c) |
| 268 |
{ |
| 269 |
ChannelMode *ban = ModeManager::FindChannelModeByName(CMODE_BAN), |
| 270 |
*except = ModeManager::FindChannelModeByName(CMODE_EXCEPT), |
| 271 |
*invex = ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE); |
| 272 |
|
| 273 |
Anope::string bans = params[3]; |
| 274 |
|
| 275 |
int count = myNumToken(bans, ' '), i; |
| 276 |
|
| 277 |
for (i = 0; i < count; ++i) |
| 278 |
{ |
| 279 |
Anope::string b = myStrGetToken(bans, ' ', i); |
| 280 |
|
| 281 |
if (ban && params[2].equals_cs("b")) |
| 282 |
c->SetModeInternal(source, ban, b); |
| 283 |
else if (except && params[2].equals_cs("e")) |
| 284 |
c->SetModeInternal(source, except, b); |
| 285 |
else if (invex && params[2].equals_cs("I")) |
| 286 |
c->SetModeInternal(source, invex, b); |
| 287 |
} |
| 288 |
} |
| 289 |
|
| 290 |
return true; |
| 291 |
} |
| 292 |
}; |
| 293 |
|
| 294 |
struct IRCDMessageJoin : CoreIRCDMessageJoin |
| 295 |
{ |
| 296 |
IRCDMessageJoin() : CoreIRCDMessageJoin("JOIN") { } |
| 297 |
|
| 298 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 299 |
{ |
| 300 |
if (params.size() < 2) |
| 301 |
return true; |
| 302 |
|
| 303 |
std::vector<Anope::string> p = params; |
| 304 |
p.erase(p.begin()); |
| 305 |
|
| 306 |
return CoreIRCDMessageJoin::Run(source, p); |
| 307 |
} |
| 308 |
}; |
| 309 |
|
| 310 |
struct IRCDMessageMode : IRCDMessage |
| 311 |
{ |
| 312 |
IRCDMessageMode(const Anope::string &n) : IRCDMessage(n, 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } |
| 313 |
|
| 314 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 315 |
{ |
| 316 |
if (params.size() > 2 && ircdproto->IsChannelValid(params[0])) |
| 317 |
{ |
| 318 |
Channel *c = findchan(params[0]); |
| 319 |
time_t ts = Anope::CurTime; |
| 320 |
|
| 321 |
try |
| 322 |
{ |
| 323 |
ts = convertTo<time_t>(params[1]); |
| 324 |
} |
| 325 |
catch (const ConvertException &) { } |
| 326 |
|
| 327 |
if (c) |
| 328 |
c->SetModesInternal(source, params[2], ts); |
| 329 |
} |
| 330 |
else |
| 331 |
{ |
| 332 |
User *u = finduser(params[0]); |
| 333 |
|
| 334 |
if (u) |
| 335 |
u->SetModesInternal("%s", params[1].c_str()); |
| 336 |
} |
| 337 |
|
| 338 |
return true; |
| 339 |
} |
| 340 |
}; |
| 341 |
|
| 342 |
struct IRCDMessageNick : IRCDMessage |
| 343 |
{ |
| 344 |
IRCDMessageNick() : IRCDMessage("NICK", 2) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } |
| 345 |
|
| 346 |
/* 0 1 */ |
| 347 |
/* :0MCAAAAAB NICK newnick 1350157102 */ |
| 348 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 349 |
{ |
| 350 |
source.GetUser()->ChangeNick(params[0], convertTo<time_t>(params[1])); |
| 351 |
return true; |
| 352 |
} |
| 353 |
}; |
| 354 |
|
| 355 |
struct IRCDMessagePass : IRCDMessage |
| 356 |
{ |
| 357 |
IRCDMessagePass() : IRCDMessage("PASS", 4) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } |
| 358 |
|
| 359 |
/* 0 1 2 3 */ |
| 360 |
/* PASS password TS 6 0MC */ |
| 361 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 362 |
{ |
| 363 |
UplinkSID = params[3]; |
| 364 |
return true; |
| 365 |
} |
| 366 |
}; |
| 367 |
|
| 368 |
struct IRCDMessagePong : IRCDMessage |
| 369 |
{ |
| 370 |
IRCDMessagePong() : IRCDMessage("PONG", 0) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } |
| 371 |
|
| 372 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 373 |
{ |
| 374 |
source.GetServer()->Sync(false); |
| 375 |
return true; |
| 376 |
} |
| 377 |
}; |
| 378 |
|
| 379 |
struct IRCDMessageServer : IRCDMessage |
| 380 |
{ |
| 381 |
IRCDMessageServer() : IRCDMessage("SERVER", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } |
| 382 |
|
| 383 |
/* 0 1 2 */ |
| 384 |
/* SERVER hades.arpa 1 :ircd-hybrid test server */ |
| 385 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 386 |
{ |
| 387 |
/* Servers other than our immediate uplink are introduced via SID */ |
| 388 |
if (params[1] != "1") |
| 389 |
return true; |
| 390 |
|
| 391 |
new Server(source.GetServer() == NULL ? Me : source.GetServer(), params[0], 1, params[2], UplinkSID); |
| 392 |
|
| 393 |
ircdproto->SendPing(Config->ServerName, params[0]); |
| 394 |
return true; |
| 395 |
} |
| 396 |
}; |
| 397 |
|
| 398 |
struct IRCDMessageSID : IRCDMessage |
| 399 |
{ |
| 400 |
IRCDMessageSID() : IRCDMessage("SID", 4) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } |
| 401 |
|
| 402 |
/* 0 1 2 3 */ |
| 403 |
/* :0MC SID hades.arpa 2 4XY :ircd-hybrid test server */ |
| 404 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 405 |
{ |
| 406 |
unsigned int hops = params[1].is_pos_number_only() ? convertTo<unsigned>(params[1]) : 0; |
| 407 |
new Server(source.GetServer() == NULL ? Me : source.GetServer(), params[0], hops, params[3], params[2]); |
| 408 |
|
| 409 |
ircdproto->SendPing(Config->ServerName, params[0]); |
| 410 |
return true; |
| 411 |
} |
| 412 |
}; |
| 413 |
|
| 414 |
struct IRCDMessageSjoin : IRCDMessage |
| 415 |
{ |
| 416 |
IRCDMessageSjoin() : IRCDMessage("SJOIN", 2) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); } |
| 417 |
|
| 418 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 419 |
{ |
| 420 |
Channel *c = findchan(params[1]); |
| 421 |
time_t ts = Anope::string(params[0]).is_pos_number_only() ? convertTo<time_t>(params[0]) : 0; |
| 422 |
bool keep_their_modes = true; |
| 423 |
|
| 424 |
if (!c) |
| 425 |
{ |
| 426 |
c = new Channel(params[1], ts); |
| 427 |
c->SetFlag(CH_SYNCING); |
| 428 |
} |
| 429 |
/* Our creation time is newer than what the server gave us */ |
| 430 |
else if (c->creation_time > ts) |
| 431 |
{ |
| 432 |
c->creation_time = ts; |
| 433 |
c->Reset(); |
| 434 |
} |
| 435 |
/* Their TS is newer than ours, our modes > theirs, unset their modes if need be */ |
| 436 |
else if (ts > c->creation_time) |
| 437 |
keep_their_modes = false; |
| 438 |
|
| 439 |
/* If we need to keep their modes, and this SJOIN string contains modes */ |
| 440 |
if (keep_their_modes && params.size() >= 3) |
| 441 |
{ |
| 442 |
Anope::string modes; |
| 443 |
|
| 444 |
for (unsigned i = 2; i < params.size() - 1; ++i) |
| 445 |
modes += " " + params[i]; |
| 446 |
|
| 447 |
if (!modes.empty()) |
| 448 |
modes.erase(modes.begin()); |
| 449 |
|
| 450 |
/* Set the modes internally */ |
| 451 |
c->SetModesInternal(source, modes); |
| 452 |
} |
| 453 |
|
| 454 |
spacesepstream sep(params[params.size() - 1]); |
| 455 |
Anope::string buf; |
| 456 |
|
| 457 |
while (sep.GetToken(buf)) |
| 458 |
{ |
| 459 |
std::list<ChannelMode *> Status; |
| 460 |
char ch; |
| 461 |
|
| 462 |
/* Get prefixes from the nick */ |
| 463 |
while ((ch = ModeManager::GetStatusChar(buf[0]))) |
| 464 |
{ |
| 465 |
buf.erase(buf.begin()); |
| 466 |
|
| 467 |
ChannelMode *cm = ModeManager::FindChannelModeByChar(ch); |
| 468 |
|
| 469 |
if (!cm) |
| 470 |
{ |
| 471 |
Log() << "Received unknown mode prefix " << ch << " in SJOIN string"; |
| 472 |
continue; |
| 473 |
} |
| 474 |
|
| 475 |
if (keep_their_modes) |
| 476 |
Status.push_back(cm); |
| 477 |
} |
| 478 |
|
| 479 |
User *u = finduser(buf); |
| 480 |
|
| 481 |
if (!u) |
| 482 |
{ |
| 483 |
Log(LOG_DEBUG) << "SJOIN for nonexistant user " << buf << " on " << c->name; |
| 484 |
continue; |
| 485 |
} |
| 486 |
|
| 487 |
EventReturn MOD_RESULT; |
| 488 |
FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); |
| 489 |
|
| 490 |
/* Add the user to the channel */ |
| 491 |
c->JoinUser(u); |
| 492 |
|
| 493 |
/* |
| 494 |
* Update their status internally on the channel |
| 495 |
* This will enforce secureops etc on the user |
| 496 |
*/ |
| 497 |
for (std::list<ChannelMode *>::iterator it = Status.begin(), it_end = Status.end(); it != it_end; ++it) |
| 498 |
c->SetModeInternal(source, *it, buf); |
| 499 |
|
| 500 |
/* Now set whatever modes this user is allowed to have on the channel */ |
| 501 |
chan_set_correct_modes(u, c, 1, true); |
| 502 |
|
| 503 |
/* |
| 504 |
* Check to see if modules want the user to join, if they do |
| 505 |
* check to see if they are allowed to join (CheckKick will kick/ban them) |
| 506 |
* Don't trigger OnJoinChannel event then as the user will be destroyed |
| 507 |
*/ |
| 508 |
if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u)) |
| 509 |
continue; |
| 510 |
|
| 511 |
FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c)); |
| 512 |
} |
| 513 |
|
| 514 |
/* Channel is done syncing */ |
| 515 |
if (c->HasFlag(CH_SYNCING)) |
| 516 |
{ |
| 517 |
/* Unset the syncing flag */ |
| 518 |
c->UnsetFlag(CH_SYNCING); |
| 519 |
c->Sync(); |
| 520 |
} |
| 521 |
|
| 522 |
return true; |
| 523 |
} |
| 524 |
}; |
| 525 |
|
| 526 |
struct IRCDMessageTBurst : IRCDMessage |
| 527 |
{ |
| 528 |
IRCDMessageTBurst() : IRCDMessage("TBURST", 5) { } |
| 529 |
|
| 530 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 531 |
{ |
| 532 |
Anope::string setter = myStrGetToken(params[3], '!', 0); |
| 533 |
time_t topic_time = Anope::string(params[2]).is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime; |
| 534 |
Channel *c = findchan(params[1]); |
| 535 |
|
| 536 |
if (c) |
| 537 |
c->ChangeTopicInternal(setter, params[4], topic_time); |
| 538 |
|
| 539 |
return true; |
| 540 |
} |
| 541 |
}; |
| 542 |
|
| 543 |
struct IRCDMessageTMode : IRCDMessage |
| 544 |
{ |
| 545 |
IRCDMessageTMode() : IRCDMessage("TMODE", 3) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } |
| 546 |
|
| 547 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 548 |
{ |
| 549 |
time_t ts = Anope::CurTime; |
| 550 |
|
| 551 |
try |
| 552 |
{ |
| 553 |
ts = convertTo<time_t>(params[0]); |
| 554 |
} |
| 555 |
catch (const ConvertException &) { } |
| 556 |
|
| 557 |
Channel *c = findchan(params[1]); |
| 558 |
Anope::string modes = params[2]; |
| 559 |
|
| 560 |
for (unsigned i = 3; i < params.size(); ++i) |
| 561 |
modes += " " + params[i]; |
| 562 |
|
| 563 |
if (c) |
| 564 |
c->SetModesInternal(source, modes, ts); |
| 565 |
|
| 566 |
return true; |
| 567 |
} |
| 568 |
}; |
| 569 |
|
| 570 |
struct IRCDMessageUID : IRCDMessage |
| 571 |
{ |
| 572 |
IRCDMessageUID() : IRCDMessage("UID", 10) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } |
| 573 |
|
| 574 |
/* 0 1 2 3 4 5 6 7 8 9 */ |
| 575 |
/* :0MC UID Steve 1 1350157102 +oi ~steve resolved.host 10.0.0.1 0MCAAAAAB 1350157108 :Mining all the time */ |
| 576 |
bool Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override |
| 577 |
{ |
| 578 |
/* Source is always the server */ |
| 579 |
User *user = new User(params[0], params[4], params[5], "", |
| 580 |
params[6], source.GetServer(), |
| 581 |
params[9], params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0, |
| 582 |
params[3], params[7]); |
| 583 |
|
| 584 |
if (user && nickserv) |
| 585 |
{ |
| 586 |
const NickAlias *na = NULL; |
| 587 |
|
| 588 |
if (params[8] != "0") |
| 589 |
na = findnick(params[8]); |
| 590 |
|
| 591 |
if (na) |
| 592 |
{ |
| 593 |
user->Login(na->nc); |
| 594 |
|
| 595 |
if (!Config->NoNicknameOwnership && na->nc->HasFlag(NI_UNCONFIRMED) == false) |
| 596 |
user->SetMode(findbot(Config->NickServ), UMODE_REGISTERED); |
| 597 |
} |
| 598 |
else |
| 599 |
nickserv->Validate(user); |
| 600 |
} |
| 601 |
|
| 602 |
return true; |
| 603 |
} |
| 604 |
}; |
| 605 |
|
| 606 |
class ProtoHybrid : public Module |
| 607 |
{ |
| 608 |
HybridProto ircd_proto; |
| 609 |
|
| 610 |
/* Core message handlers */ |
| 611 |
CoreIRCDMessageAway core_message_away; |
| 612 |
CoreIRCDMessageCapab core_message_capab; |
| 613 |
CoreIRCDMessageError core_message_error; |
| 614 |
CoreIRCDMessageKick core_message_kick; |
| 615 |
CoreIRCDMessageKill core_message_kill; |
| 616 |
CoreIRCDMessageMOTD core_message_motd; |
| 617 |
CoreIRCDMessagePart core_message_part; |
| 618 |
CoreIRCDMessagePing core_message_ping; |
| 619 |
CoreIRCDMessagePrivmsg core_message_privmsg; |
| 620 |
CoreIRCDMessageQuit core_message_quit; |
| 621 |
CoreIRCDMessageSQuit core_message_squit; |
| 622 |
CoreIRCDMessageStats core_message_stats; |
| 623 |
CoreIRCDMessageTime core_message_time; |
| 624 |
CoreIRCDMessageTopic core_message_topic; |
| 625 |
CoreIRCDMessageVersion core_message_version; |
| 626 |
CoreIRCDMessageWhois core_message_whois; |
| 627 |
|
| 628 |
/* Our message handlers */ |
| 629 |
IRCDMessageBMask message_bmask; |
| 630 |
IRCDMessageJoin message_join; |
| 631 |
IRCDMessageMode message_mode, message_svsmode; |
| 632 |
IRCDMessageNick message_nick; |
| 633 |
IRCDMessagePass message_pass; |
| 634 |
IRCDMessagePong message_pong; |
| 635 |
IRCDMessageServer message_server; |
| 636 |
IRCDMessageSID message_sid; |
| 637 |
IRCDMessageSjoin message_sjoin; |
| 638 |
IRCDMessageTBurst message_tburst; |
| 639 |
IRCDMessageTMode message_tmode; |
| 640 |
IRCDMessageUID message_uid; |
| 641 |
|
| 642 |
void AddModes() |
| 643 |
{ |
| 644 |
/* Add user modes */ |
| 645 |
ModeManager::AddUserMode(new UserMode(UMODE_ADMIN, 'a')); |
| 646 |
ModeManager::AddUserMode(new UserMode(UMODE_INVIS, 'i')); |
| 647 |
ModeManager::AddUserMode(new UserMode(UMODE_OPER, 'o')); |
| 648 |
ModeManager::AddUserMode(new UserMode(UMODE_REGISTERED, 'r')); |
| 649 |
ModeManager::AddUserMode(new UserMode(UMODE_SNOMASK, 's')); |
| 650 |
ModeManager::AddUserMode(new UserMode(UMODE_WALLOPS, 'w')); |
| 651 |
ModeManager::AddUserMode(new UserMode(UMODE_HIDEOPER, 'H')); |
| 652 |
ModeManager::AddUserMode(new UserMode(UMODE_REGPRIV, 'R')); |
| 653 |
|
| 654 |
/* b/e/I */ |
| 655 |
ModeManager::AddChannelMode(new ChannelModeList(CMODE_BAN, 'b')); |
| 656 |
ModeManager::AddChannelMode(new ChannelModeList(CMODE_EXCEPT, 'e')); |
| 657 |
ModeManager::AddChannelMode(new ChannelModeList(CMODE_INVITEOVERRIDE, 'I')); |
| 658 |
|
| 659 |
/* v/h/o/a/q */ |
| 660 |
ModeManager::AddChannelMode(new ChannelModeStatus(CMODE_VOICE, 'v', '+', 0)); |
| 661 |
ModeManager::AddChannelMode(new ChannelModeStatus(CMODE_OP, 'o', '@', 1)); |
| 662 |
|
| 663 |
/* Add channel modes */ |
| 664 |
ModeManager::AddChannelMode(new ChannelMode(CMODE_INVITE, 'i')); |
| 665 |
ModeManager::AddChannelMode(new ChannelModeKey('k')); |
| 666 |
ModeManager::AddChannelMode(new ChannelModeParam(CMODE_LIMIT, 'l')); |
| 667 |
ModeManager::AddChannelMode(new ChannelMode(CMODE_MODERATED, 'm')); |
| 668 |
ModeManager::AddChannelMode(new ChannelMode(CMODE_NOEXTERNAL, 'n')); |
| 669 |
ModeManager::AddChannelMode(new ChannelMode(CMODE_PRIVATE, 'p')); |
| 670 |
ModeManager::AddChannelMode(new ChannelModeRegistered('r')); |
| 671 |
ModeManager::AddChannelMode(new ChannelMode(CMODE_SECRET, 's')); |
| 672 |
ModeManager::AddChannelMode(new ChannelMode(CMODE_TOPIC, 't')); |
| 673 |
ModeManager::AddChannelMode(new ChannelModeOper('O')); |
| 674 |
ModeManager::AddChannelMode(new ChannelMode(CMODE_REGISTEREDONLY, 'R')); |
| 675 |
ModeManager::AddChannelMode(new ChannelMode(CMODE_SSL, 'S')); |
| 676 |
} |
| 677 |
|
| 678 |
public: |
| 679 |
ProtoHybrid(const Anope::string &modname, const Anope::string &creator) : |
| 680 |
Module(modname, creator, PROTOCOL), message_mode("MODE"), message_svsmode("SVSMODE") |
| 681 |
{ |
| 682 |
this->SetAuthor("Anope"); |
| 683 |
this->AddModes(); |
| 684 |
|
| 685 |
ModuleManager::Attach(I_OnUserNickChange, this); |
| 686 |
|
| 687 |
if (Config->Numeric.empty()) |
| 688 |
{ |
| 689 |
Anope::string numeric = ts6_sid_retrieve(); |
| 690 |
Me->SetSID(numeric); |
| 691 |
Config->Numeric = numeric; |
| 692 |
} |
| 693 |
|
| 694 |
for (botinfo_map::iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it) |
| 695 |
it->second->GenerateUID(); |
| 696 |
} |
| 697 |
|
| 698 |
void OnUserNickChange(User *u, const Anope::string &) anope_override |
| 699 |
{ |
| 700 |
u->RemoveModeInternal(ModeManager::FindUserModeByName(UMODE_REGISTERED)); |
| 701 |
ircdproto->SendLogout(u); |
| 702 |
} |
| 703 |
}; |
| 704 |
|
| 705 |
MODULE_INIT(ProtoHybrid) |