bool IsMatch(const CString& sChan, const CString& sHost) const { if (!sHost.WildCmp(m_sHostmaskWildcard)) return false; if (!sChan.WildCmp(m_sChannelWildcard)) return false; return true; }
void OnGetAvailableMods(set<CModInfo>& ssMods, CModInfo::EModuleType eType) override { CDir Dir; CModules::ModDirList dirs = CModules::GetModDirs(); while (!dirs.empty()) { set<CString> already; Dir.Fill(dirs.front().first); for (unsigned int a = 0; a < Dir.size(); a++) { CFile& File = *Dir[a]; CString sName = File.GetShortName(); CString sPath = File.GetLongName(); sPath.TrimSuffix(sName); if (!File.IsDir()) { if (sName.WildCmp("*.pyc")) { sName.RightChomp(4); } else if (sName.WildCmp("*.py") || sName.WildCmp("*.so")) { sName.RightChomp(3); } else { continue; } } TryAddModInfo(sPath, sName, ssMods, already, eType); } dirs.pop(); } }
bool IsMatch(const CString& sChan, const CString& sHost, const CString& sMessage) const { if (!sHost.WildCmp(m_sHostmaskWildcard)) return false; if (!sChan.WildCmp(m_sChannelWildcard)) return false; if (!sMessage.WildCmp(m_pModule->ExpandString(m_sSearchWildcard))) return false; return true; }
void CIncomingConnection::ReadLine(const CString& sLine) { bool bIsHTTP = (sLine.WildCmp("GET * HTTP/1.?\r\n") || sLine.WildCmp("POST * HTTP/1.?\r\n")); bool bAcceptHTTP = (m_eAcceptType == CListener::ACCEPT_ALL) || (m_eAcceptType == CListener::ACCEPT_HTTP); bool bAcceptIRC = (m_eAcceptType == CListener::ACCEPT_ALL) || (m_eAcceptType == CListener::ACCEPT_IRC); Csock* pSock = nullptr; if (!bIsHTTP) { // Let's assume it's an IRC connection if (!bAcceptIRC) { Write("ERROR :We don't take kindly to your types around here!\r\n"); Close(CLT_AFTERWRITE); DEBUG("Refused IRC connection to non IRC port"); return; } pSock = new CClient(); CZNC::Get().GetManager().SwapSockByAddr(pSock, this); // And don't forget to give it some sane name / timeout pSock->SetSockName("USR::???"); } else { // This is a HTTP request, let the webmods handle it if (!bAcceptHTTP) { Write( "HTTP/1.0 403 Access Denied\r\n\r\nWeb Access is not " "enabled.\r\n"); Close(CLT_AFTERWRITE); DEBUG("Refused HTTP connection to non HTTP port"); return; } pSock = new CWebSock(m_sURIPrefix); CZNC::Get().GetManager().SwapSockByAddr(pSock, this); // And don't forget to give it some sane name / timeout pSock->SetSockName("WebMod::Client"); } // TODO can we somehow get rid of this? pSock->ReadLine(sLine); pSock->PushBuff("", 0, true); }
bool IsAutoCycle(const CString& sChan) { for (unsigned int a = 0; a < m_vsNegChans.size(); a++) { if (sChan.WildCmp(m_vsNegChans[a])) { return false; } } for (unsigned int b = 0; b < m_vsChans.size(); b++) { if (sChan.WildCmp(m_vsChans[b])) { return true; } } return false; }
bool CUser::IsHostAllowed(const CString& sHostMask) const { if (m_ssAllowedHosts.empty()) { return true; } for (const CString& sHost : m_ssAllowedHosts) { if (sHostMask.WildCmp(sHost)) { return true; } } return false; }
bool CUser::IsHostAllowed(const CString& sHostMask) const { if (m_ssAllowedHosts.empty()) { return true; } for (set<CString>::const_iterator a = m_ssAllowedHosts.begin(); a != m_ssAllowedHosts.end(); ++a) { if (sHostMask.WildCmp(*a)) { return true; } } return false; }
void CModule::HandleHelpCommand(const CString& sLine) { CString sFilter = sLine.Token(1).AsLower(); CString::size_type iFilterLength = sFilter.size(); CTable Table; map<CString, CModCommand>::const_iterator it; CModCommand::InitHelp(Table); for (it = m_mCommands.begin(); it != m_mCommands.end(); ++it) { CString sCmd = it->second.GetCommand().AsLower(); if (sFilter.empty() || (sCmd.Equals(sFilter, true, iFilterLength)) || sCmd.WildCmp(sFilter)) { it->second.AddHelp(Table); } } if (Table.empty()) { PutModule("No matches for '" + sFilter + "'"); } else { PutModule(Table); } }
void CIRCSock::ReadLine(const CString& sData) { CString sLine = sData; sLine.TrimRight("\n\r"); DEBUG("(" << m_pNetwork->GetUser()->GetUserName() << "/" << m_pNetwork->GetName() << ") IRC -> ZNC [" << sLine << "]"); NETWORKMODULECALL(OnRaw(sLine), m_pNetwork->GetUser(), m_pNetwork, NULL, return); if (sLine.Equals("PING ", false, 5)) { // Generate a reply and don't forward this to any user, // we don't want any PING forwarded PutIRC("PONG " + sLine.substr(5)); return; } else if (sLine.Token(1).Equals("PONG")) { // Block PONGs, we already responded to the pings return; } else if (sLine.Equals("ERROR ", false, 6)) { //ERROR :Closing Link: nick[24.24.24.24] (Excess Flood) CString sError(sLine.substr(6)); sError.TrimPrefix(); m_pNetwork->PutStatus("Error from Server [" + sError + "]"); return; } CString sCmd = sLine.Token(1); if ((sCmd.length() == 3) && (isdigit(sCmd[0])) && (isdigit(sCmd[1])) && (isdigit(sCmd[2]))) { CString sServer = sLine.Token(0).LeftChomp_n(); unsigned int uRaw = sCmd.ToUInt(); CString sNick = sLine.Token(2); CString sRest = sLine.Token(3, true); switch (uRaw) { case 1: { // :irc.server.com 001 nick :Welcome to the Internet Relay Network nick if (m_bAuthed && sServer == "irc.znc.in") { // m_bAuthed == true => we already received another 001 => we might be in a traffic loop m_pNetwork->PutStatus("ZNC seems to be connected to itself, disconnecting..."); Quit(); return; } m_pNetwork->SetIRCServer(sServer); SetTimeout(540, TMO_READ); // Now that we are connected, let nature take its course PutIRC("WHO " + sNick); m_bAuthed = true; m_pNetwork->PutStatus("Connected!"); vector<CClient*>& vClients = m_pNetwork->GetClients(); for (unsigned int a = 0; a < vClients.size(); a++) { CClient* pClient = vClients[a]; CString sClientNick = pClient->GetNick(false); if (!sClientNick.Equals(sNick)) { // If they connected with a nick that doesn't match the one we got on irc, then we need to update them pClient->PutClient(":" + sClientNick + "!" + m_Nick.GetIdent() + "@" + m_Nick.GetHost() + " NICK :" + sNick); } } SetNick(sNick); NETWORKMODULECALL(OnIRCConnected(), m_pNetwork->GetUser(), m_pNetwork, NULL, NOTHING); m_pNetwork->ClearRawBuffer(); m_pNetwork->AddRawBuffer(":" + sServer + " " + sCmd + " ", " " + sRest); break; } case 5: ParseISupport(sRest); m_pNetwork->UpdateExactRawBuffer(":" + sServer + " " + sCmd + " ", " " + sRest); break; case 10: { // :irc.server.com 010 nick <hostname> <port> :<info> CString sHost = sRest.Token(0); CString sPort = sRest.Token(1); CString sInfo = sRest.Token(2, true).TrimPrefix_n(); m_pNetwork->PutStatus("Server [" + m_pNetwork->GetCurrentServer()->GetString(false) + "] redirects us to [" + sHost + ":" + sPort + "] with reason [" + sInfo + "]"); m_pNetwork->PutStatus("Perhaps you want to add it as a new server."); // Don't send server redirects to the client return; } case 2: case 3: case 4: case 250: // highest connection count case 251: // user count case 252: // oper count case 254: // channel count case 255: // client count case 265: // local users case 266: // global users m_pNetwork->UpdateRawBuffer(":" + sServer + " " + sCmd + " ", " " + sRest); break; case 305: m_pNetwork->SetIRCAway(false); break; case 306: m_pNetwork->SetIRCAway(true); break; case 324: { // MODE sRest.Trim(); CChan* pChan = m_pNetwork->FindChan(sRest.Token(0)); if (pChan) { pChan->SetModes(sRest.Token(1, true)); // We don't SetModeKnown(true) here, // because a 329 will follow if (!pChan->IsModeKnown()) { // When we JOIN, we send a MODE // request. This makes sure the // reply isn't forwarded. return; } } } break; case 329: { sRest.Trim(); CChan* pChan = m_pNetwork->FindChan(sRest.Token(0)); if (pChan) { unsigned long ulDate = sLine.Token(4).ToULong(); pChan->SetCreationDate(ulDate); if (!pChan->IsModeKnown()) { pChan->SetModeKnown(true); // When we JOIN, we send a MODE // request. This makes sure the // reply isn't forwarded. return; } } } break; case 331: { // :irc.server.com 331 yournick #chan :No topic is set. CChan* pChan = m_pNetwork->FindChan(sLine.Token(3)); if (pChan) { pChan->SetTopic(""); } break; } case 332: { // :irc.server.com 332 yournick #chan :This is a topic CChan* pChan = m_pNetwork->FindChan(sLine.Token(3)); if (pChan) { CString sTopic = sLine.Token(4, true); sTopic.LeftChomp(); pChan->SetTopic(sTopic); } break; } case 333: { // :irc.server.com 333 yournick #chan setternick 1112320796 CChan* pChan = m_pNetwork->FindChan(sLine.Token(3)); if (pChan) { sNick = sLine.Token(4); unsigned long ulDate = sLine.Token(5).ToULong(); pChan->SetTopicOwner(sNick); pChan->SetTopicDate(ulDate); } break; } case 352: { // :irc.yourserver.com 352 yournick #chan ident theirhost.com irc.theirserver.com theirnick H :0 Real Name sServer = sLine.Token(0); sNick = sLine.Token(7); CString sIdent = sLine.Token(4); CString sHost = sLine.Token(5); sServer.LeftChomp(); if (sNick.Equals(GetNick())) { m_Nick.SetIdent(sIdent); m_Nick.SetHost(sHost); } m_pNetwork->SetIRCNick(m_Nick); m_pNetwork->SetIRCServer(sServer); const vector<CChan*>& vChans = m_pNetwork->GetChans(); for (unsigned int a = 0; a < vChans.size(); a++) { vChans[a]->OnWho(sNick, sIdent, sHost); } break; } case 353: { // NAMES sRest.Trim(); // Todo: allow for non @+= server msgs CChan* pChan = m_pNetwork->FindChan(sRest.Token(1)); // If we don't know that channel, some client might have // requested a /names for it and we really should forward this. if (pChan) { CString sNicks = sRest.Token(2, true).TrimPrefix_n(); pChan->AddNicks(sNicks); } ForwardRaw353(sLine); // We forwarded it already, so return return; } case 366: { // end of names list m_pNetwork->PutUser(sLine); // First send them the raw // :irc.server.com 366 nick #chan :End of /NAMES list. CChan* pChan = m_pNetwork->FindChan(sRest.Token(0)); if (pChan) { if (pChan->IsOn()) { // If we are the only one in the chan, set our default modes if (pChan->GetNickCount() == 1) { CString sModes = pChan->GetDefaultModes(); if (sModes.empty()) { sModes = m_pNetwork->GetUser()->GetDefaultChanModes(); } if (!sModes.empty()) { PutIRC("MODE " + pChan->GetName() + " " + sModes); } } } } return; // return so we don't send them the raw twice } case 375: // begin motd case 422: // MOTD File is missing m_pNetwork->ClearMotdBuffer(); case 372: // motd case 376: // end motd m_pNetwork->AddMotdBuffer(":" + sServer + " " + sCmd + " ", " " + sRest); break; case 437: // :irc.server.net 437 * badnick :Nick/channel is temporarily unavailable // :irc.server.net 437 mynick badnick :Nick/channel is temporarily unavailable // :irc.server.net 437 mynick badnick :Cannot change nickname while banned on channel if (m_pNetwork->IsChan(sRest.Token(0)) || sNick != "*") break; case 432: // :irc.server.com 432 * nick :Erroneous Nickname: Illegal characters case 433: { CString sBadNick = sRest.Token(0); if (!m_bAuthed) { SendAltNick(sBadNick); return; } break; } case 451: // :irc.server.com 451 CAP :You have not registered // Servers that dont support CAP will give us this error, dont send it to the client if (sNick.Equals("CAP")) return; case 470: { // :irc.unreal.net 470 mynick [Link] #chan1 has become full, so you are automatically being transferred to the linked channel #chan2 // :mccaffrey.freenode.net 470 mynick #electronics ##electronics :Forwarding to another channel // freenode style numeric CChan* pChan = m_pNetwork->FindChan(sRest.Token(0)); if (!pChan) { // unreal style numeric pChan = m_pNetwork->FindChan(sRest.Token(1)); } if (pChan) { pChan->Disable(); m_pNetwork->PutStatus("Channel [" + pChan->GetName() + "] is linked to " "another channel and was thus disabled."); } break; } } } else { CNick Nick(sLine.Token(0).TrimPrefix_n()); sCmd = sLine.Token(1); CString sRest = sLine.Token(2, true); if (sCmd.Equals("NICK")) { CString sNewNick = sRest.TrimPrefix_n(); bool bIsVisible = false; vector<CChan*> vFoundChans; const vector<CChan*>& vChans = m_pNetwork->GetChans(); for (unsigned int a = 0; a < vChans.size(); a++) { CChan* pChan = vChans[a]; if (pChan->ChangeNick(Nick.GetNick(), sNewNick)) { vFoundChans.push_back(pChan); if (!pChan->IsDetached()) { bIsVisible = true; } } } // Todo: use nick compare function here if (Nick.GetNick().Equals(GetNick())) { // We are changing our own nick, the clients always must see this! bIsVisible = true; SetNick(sNewNick); } NETWORKMODULECALL(OnNick(Nick, sNewNick, vFoundChans), m_pNetwork->GetUser(), m_pNetwork, NULL, NOTHING); if (!bIsVisible) { return; } } else if (sCmd.Equals("QUIT")) { CString sMessage = sRest.TrimPrefix_n(); bool bIsVisible = false; // :[email protected] QUIT :message if (Nick.GetNick().Equals(GetNick())) { m_pNetwork->PutStatus("You quit [" + sMessage + "]"); // We don't call module hooks and we don't // forward this quit to clients (Some clients // disconnect if they receive such a QUIT) return; } vector<CChan*> vFoundChans; const vector<CChan*>& vChans = m_pNetwork->GetChans(); for (unsigned int a = 0; a < vChans.size(); a++) { CChan* pChan = vChans[a]; if (pChan->RemNick(Nick.GetNick())) { vFoundChans.push_back(pChan); if (!pChan->IsDetached()) { bIsVisible = true; } } } NETWORKMODULECALL(OnQuit(Nick, sMessage, vFoundChans), m_pNetwork->GetUser(), m_pNetwork, NULL, NOTHING); if (!bIsVisible) { return; } } else if (sCmd.Equals("JOIN")) { CString sChan = sRest.Token(0).TrimPrefix_n(); CChan* pChan; // Todo: use nick compare function if (Nick.GetNick().Equals(GetNick())) { m_pNetwork->AddChan(sChan, false); pChan = m_pNetwork->FindChan(sChan); if (pChan) { pChan->ResetJoinTries(); pChan->Enable(); pChan->SetIsOn(true); PutIRC("MODE " + sChan); } } else { pChan = m_pNetwork->FindChan(sChan); } if (pChan) { pChan->AddNick(Nick.GetNickMask()); NETWORKMODULECALL(OnJoin(Nick.GetNickMask(), *pChan), m_pNetwork->GetUser(), m_pNetwork, NULL, NOTHING); if (pChan->IsDetached()) { return; } } } else if (sCmd.Equals("PART")) { CString sChan = sRest.Token(0).TrimPrefix_n(); CString sMsg = sRest.Token(1, true).TrimPrefix_n(); CChan* pChan = m_pNetwork->FindChan(sChan); bool bDetached = false; if (pChan) { pChan->RemNick(Nick.GetNick()); NETWORKMODULECALL(OnPart(Nick.GetNickMask(), *pChan, sMsg), m_pNetwork->GetUser(), m_pNetwork, NULL, NOTHING); if (pChan->IsDetached()) bDetached = true; } // Todo: use nick compare function if (Nick.GetNick().Equals(GetNick())) { m_pNetwork->DelChan(sChan); } /* * We use this boolean because * m_pNetwork->DelChan() will delete this channel * and thus we would dereference an * already-freed pointer! */ if (bDetached) { return; } } else if (sCmd.Equals("MODE")) { CString sTarget = sRest.Token(0); CString sModes = sRest.Token(1, true); if (sModes.Left(1) == ":") sModes = sModes.substr(1); CChan* pChan = m_pNetwork->FindChan(sTarget); if (pChan) { pChan->ModeChange(sModes, &Nick); if (pChan->IsDetached()) { return; } } else if (sTarget == m_Nick.GetNick()) { CString sModeArg = sModes.Token(0); bool bAdd = true; /* no module call defined (yet?) MODULECALL(OnRawUserMode(*pOpNick, *this, sModeArg, sArgs), m_pNetwork->GetUser(), NULL, ); */ for (unsigned int a = 0; a < sModeArg.size(); a++) { const unsigned char& uMode = sModeArg[a]; if (uMode == '+') { bAdd = true; } else if (uMode == '-') { bAdd = false; } else { if (bAdd) { m_scUserModes.insert(uMode); } else { m_scUserModes.erase(uMode); } } } } } else if (sCmd.Equals("KICK")) { // :[email protected] KICK #chan nick :msg CString sChan = sRest.Token(0); CString sKickedNick = sRest.Token(1); CString sMsg = sRest.Token(2, true); sMsg.LeftChomp(); CChan* pChan = m_pNetwork->FindChan(sChan); if (pChan) { NETWORKMODULECALL(OnKick(Nick, sKickedNick, *pChan, sMsg), m_pNetwork->GetUser(), m_pNetwork, NULL, NOTHING); // do not remove the nick till after the OnKick call, so modules // can do Chan.FindNick or something to get more info. pChan->RemNick(sKickedNick); } if (GetNick().Equals(sKickedNick) && pChan) { pChan->SetIsOn(false); // Don't try to rejoin! pChan->Disable(); } if ((pChan) && (pChan->IsDetached())) { return; } } else if (sCmd.Equals("NOTICE")) { // :[email protected] NOTICE #chan :Message CString sTarget = sRest.Token(0); CString sMsg = sRest.Token(1, true); sMsg.LeftChomp(); if (sMsg.WildCmp("\001*\001")) { sMsg.LeftChomp(); sMsg.RightChomp(); if (sTarget.Equals(GetNick())) { if (OnCTCPReply(Nick, sMsg)) { return; } } m_pNetwork->PutUser(":" + Nick.GetNickMask() + " NOTICE " + sTarget + " :\001" + sMsg + "\001"); return; } else { if (sTarget.Equals(GetNick())) { if (OnPrivNotice(Nick, sMsg)) { return; } } else { if (OnChanNotice(Nick, sTarget, sMsg)) { return; } } } if (Nick.GetNick().Equals(m_pNetwork->GetIRCServer())) { m_pNetwork->PutUser(":" + Nick.GetNick() + " NOTICE " + sTarget + " :" + sMsg); } else { m_pNetwork->PutUser(":" + Nick.GetNickMask() + " NOTICE " + sTarget + " :" + sMsg); } return; } else if (sCmd.Equals("TOPIC")) { // :[email protected] TOPIC #chan :This is a topic CChan* pChan = m_pNetwork->FindChan(sLine.Token(2)); if (pChan) { CString sTopic = sLine.Token(3, true); sTopic.LeftChomp(); NETWORKMODULECALL(OnTopic(Nick, *pChan, sTopic), m_pNetwork->GetUser(), m_pNetwork, NULL, return); pChan->SetTopicOwner(Nick.GetNick()); pChan->SetTopicDate((unsigned long) time(NULL)); pChan->SetTopic(sTopic); if (pChan->IsDetached()) { return; // Don't forward this } sLine = ":" + Nick.GetNickMask() + " TOPIC " + pChan->GetName() + " :" + sTopic; } } else if (sCmd.Equals("PRIVMSG")) {
void CHTTPSock::ReadLine(const CString& sData) { if (m_bGotHeader) { return; } CString sLine = sData; sLine.TrimRight("\r\n"); CString sName = sLine.Token(0); if (sName.Equals("GET")) { m_bPost = false; m_sURI = sLine.Token(1); m_bHTTP10Client = sLine.Token(2).Equals("HTTP/1.0"); ParseURI(); } else if (sName.Equals("POST")) { m_bPost = true; m_sURI = sLine.Token(1); ParseURI(); } else if (sName.Equals("Cookie:")) { VCString vsNV; sLine.Token(1, true).Split(";", vsNV, false, "", "", true, true); for (const CString& s : vsNV) { m_msRequestCookies[s.Token(0, false, "=").Escape_n(CString::EURL, CString::EASCII)] = s.Token(1, true, "=").Escape_n(CString::EURL, CString::EASCII); } } else if (sName.Equals("Authorization:")) { CString sUnhashed; sLine.Token(2).Base64Decode(sUnhashed); m_sUser = sUnhashed.Token(0, false, ":"); m_sPass = sUnhashed.Token(1, true, ":"); m_bBasicAuth = true; // Postpone authorization attempt until end of headers, because cookies should be read before that, otherwise session id will be overwritten in GetSession() } else if (sName.Equals("Content-Length:")) { m_uPostLen = sLine.Token(1).ToULong(); if (m_uPostLen > MAX_POST_SIZE) PrintErrorPage(413, "Request Entity Too Large", "The request you sent was too large."); } else if (sName.Equals("X-Forwarded-For:")) { // X-Forwarded-For: client, proxy1, proxy2 if (m_sForwardedIP.empty()) { const VCString& vsTrustedProxies = CZNC::Get().GetTrustedProxies(); CString sIP = GetRemoteIP(); VCString vsIPs; sLine.Token(1, true).Split(",", vsIPs, false, "", "", false, true); while (!vsIPs.empty()) { // sIP told us that it got connection from vsIPs.back() // check if sIP is trusted proxy bool bTrusted = false; for (const CString& sTrustedProxy : vsTrustedProxies) { if (sIP.WildCmp(sTrustedProxy)) { bTrusted = true; break; } } if (bTrusted) { // sIP is trusted proxy, so use vsIPs.back() as new sIP sIP = vsIPs.back(); vsIPs.pop_back(); } else { break; } } // either sIP is not trusted proxy, or it's in the beginning of the X-Forwarded-For list // in both cases use it as the endpoind m_sForwardedIP = sIP; } } else if (sName.Equals("If-None-Match:")) { // this is for proper client cache support (HTTP 304) on static files: m_sIfNoneMatch = sLine.Token(1, true); } else if (sName.Equals("Accept-Encoding:") && !m_bHTTP10Client) { SCString ssEncodings; // trimming whitespace from the tokens is important: sLine.Token(1, true).Split(",", ssEncodings, false, "", "", false, true); m_bAcceptGzip = (ssEncodings.find("gzip") != ssEncodings.end()); } else if (sLine.empty()) { if (m_bBasicAuth && !m_bLoggedIn) { m_bLoggedIn = OnLogin(m_sUser, m_sPass, true); // After successful login ReadLine("") will be called again to trigger "else" block // Failed login sends error and closes socket, so no infinite loop here } else { m_bGotHeader = true; if (m_bPost) { m_sPostData = GetInternalReadBuffer(); CheckPost(); } else { GetPage(); } DisableReadLine(); } } }
virtual EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { if (sMessage.Equals("!dice start")) { PutIRC("PRIVMSG " + Channel.GetName() + " :!dice join"); return CONTINUE; } CNick nick = user->GetNick(); if (Nick.GetNick().Equals("Nimda3")) { if (sMessage.Token(0).Equals(nick.GetNick()+"\'s") && sMessage.Token(1).Equals("turn.")) { PutIRC("PRIVMSG " + Channel.GetName() + " :!dice roll"); lastturn = false; return CONTINUE; } if (sMessage.Token(0).Equals(nick.GetNick()) && sMessage.Token(1).Equals("rolls")) { // ravomavain rolls a 2. Points: 49 + 2 => 51 - roll again or stand? int value = sMessage.Token(3).ToInt(); if (value == 6) { return CONTINUE; } int saved = sMessage.Token(5).ToInt(); int temp = sMessage.Token(7).ToInt(); int total = saved + temp; if (lastturn) { if (total < score) { PutIRC("PRIVMSG " + Channel.GetName() + " :!dice roll"); return CONTINUE; } PutIRC("PRIVMSG " + Channel.GetName() + " :!dice stand"); return CONTINUE; } if (total == 49 || total >= HighScore) { PutIRC("PRIVMSG " + Channel.GetName() + " :!dice stand"); return CONTINUE; } if (total < 49) { if (temp >= 20) { PutIRC("PRIVMSG " + Channel.GetName() + " :!dice stand"); return CONTINUE; } } PutIRC("PRIVMSG " + Channel.GetName() + " :!dice roll"); return CONTINUE; } if (sMessage.Left(37).Equals("You broke the highest sum record with")) { HighScore = sMessage.Token(7).ToInt()+1; PutModule("HighScore: "+CString(HighScore)); return CONTINUE; } if (sMessage.Left(26).Equals("Dice game has been started")) { lastturn = false; return CONTINUE; } if (sMessage.Left(39).Equals("It is a really bad idea to \x02stand\x02 now.")) { PutIRC("PRIVMSG " + Channel.GetName() + " :!dice roll"); return CONTINUE; } if (sMessage.WildCmp("*get one more chance to beat your score*")) { lastturn = true; score = sMessage.Token(11).ToInt(); return CONTINUE; } } return CONTINUE; }
EModRet HandleMessage(const CNick& Nick, CString sMessage) { if (!Nick.NickEquals("Q") || !Nick.GetHost().Equals("CServe.quakenet.org")) return CONTINUE; sMessage.Trim(); #if Q_DEBUG_COMMUNICATION PutModule("[ZNC <-- Q] " + sMessage); #endif // WHOAMI if (sMessage.find("WHOAMI is only available to authed users") != CString::npos) { m_bAuthed = false; Auth(); m_bCatchResponse = m_bRequestedWhoami; } else if (sMessage.find("Information for user") != CString::npos) { m_bAuthed = true; m_msChanModes.clear(); m_bCatchResponse = m_bRequestedWhoami; m_bRequestedWhoami = true; } else if (m_bRequestedWhoami && sMessage.WildCmp("#*")) { CString sChannel = sMessage.Token(0); CString sFlags = sMessage.Token(1, true).Trim_n().TrimLeft_n("+"); m_msChanModes[sChannel] = sFlags; } else if (m_bRequestedWhoami && m_bCatchResponse && (sMessage.Equals("End of list.") || sMessage.Equals( "account, or HELLO to create an account."))) { m_bRequestedWhoami = m_bCatchResponse = false; return HALT; } // AUTH else if (sMessage.Equals("Username or password incorrect.")) { m_bAuthed = false; PutModule("Auth failed: " + sMessage); return HALT; } else if (sMessage.WildCmp("You are now logged in as *.")) { m_bAuthed = true; PutModule("Auth successful: " + sMessage); WhoAmI(); return HALT; } else if (m_bRequestedChallenge && sMessage.Token(0).Equals("CHALLENGE")) { m_bRequestedChallenge = false; if (sMessage.find("not available once you have authed") != CString::npos) { m_bAuthed = true; } else { if (sMessage.find("HMAC-SHA-256") != CString::npos) { ChallengeAuth(sMessage.Token(1)); } else { PutModule( "Auth failed: Q does not support HMAC-SHA-256 for " "CHALLENGEAUTH, falling back to standard AUTH."); SetUseChallenge(false); Auth(); } } return HALT; } // prevent buffering of Q's responses return !m_bCatchResponse && GetUser()->IsUserAttached() ? CONTINUE : HALT; }
bool Compare(const CString& sTarget) const { return sTarget.WildCmp(m_sRule, CString::CaseInsensitive); }
bool HostMatches(const CString& sHostmask) { return sHostmask.WildCmp(m_sHostmask, CString::CaseInsensitive); }
bool Compare(const CString& sTarget) const { return sTarget.WildCmp(m_sRule); }
bool HostMatches(const CString& sHostmask) { return sHostmask.WildCmp(m_sHostmask); }
bool CUser::IsHostAllowed(const CString& sHostMask) const { if (m_ssAllowedHosts.empty()) { return true; } for (const CString& sHost : m_ssAllowedHosts) { if (sHostMask.WildCmp(sHost)) { return true; } else { // CIDR notation checker, e.g. "192.0.2.0/24" or "2001:db8::/32" // Try to split the string into an IP and routing prefix VCString vsSplitCIDR; if (sHost.Split("/", vsSplitCIDR, false) != 2) continue; const CString sRoutingPrefix = vsSplitCIDR.back(); const int iRoutingPrefix = sRoutingPrefix.ToInt(); if (iRoutingPrefix < 0 || iRoutingPrefix > 128) continue; // If iRoutingPrefix is 0, it could be due to ToInt() failing, so // sRoutingPrefix needs to be all zeroes if (iRoutingPrefix == 0 && sRoutingPrefix != "0") continue; // Convert each IP from a numeric string to an addrinfo addrinfo aiHints; memset(&aiHints, 0, sizeof(addrinfo)); aiHints.ai_flags = AI_NUMERICHOST; addrinfo* aiHost; int iIsHostValid = getaddrinfo(sHostMask.c_str(), nullptr, &aiHints, &aiHost); if (iIsHostValid != 0) continue; aiHints.ai_family = aiHost->ai_family; // Host and range must be in // the same address family addrinfo* aiRange; int iIsRangeValid = getaddrinfo(vsSplitCIDR.front().c_str(), nullptr, &aiHints, &aiRange); if (iIsRangeValid != 0) { freeaddrinfo(aiHost); continue; } // "/0" allows all IPv[4|6] addresses if (iRoutingPrefix == 0) { freeaddrinfo(aiHost); freeaddrinfo(aiRange); return true; } // If both IPs are valid and of the same type, make a bit field mask // from the routing prefix, AND it to the host and range, and see if // they match bool bIsHostInRange = false; if (aiHost->ai_family == AF_INET) { if (iRoutingPrefix > 32) { freeaddrinfo(aiHost); freeaddrinfo(aiRange); continue; } const sockaddr_in* saHost = (sockaddr_in*)(aiHost->ai_addr); const sockaddr_in* saRange = (sockaddr_in*)(aiRange->ai_addr); // Make IPv4 bitmask const in_addr_t inBitmask = htonl((~0u) << (32 - iRoutingPrefix)); // Compare masked IPv4s bIsHostInRange = ((inBitmask & saHost->sin_addr.s_addr) == (inBitmask & saRange->sin_addr.s_addr)); } else if (aiHost->ai_family == AF_INET6) { // Make IPv6 bitmask in6_addr in6aBitmask; memset(&in6aBitmask, 0, sizeof(in6aBitmask)); for (int i = 0, iBitsLeft = iRoutingPrefix; iBitsLeft > 0; ++i, iBitsLeft -= 8) { if (iBitsLeft >= 8) { in6aBitmask.s6_addr[i] = (uint8_t)(~0u); } else { in6aBitmask.s6_addr[i] = (uint8_t)(~0u) << (8 - iBitsLeft); } } // Compare masked IPv6s bIsHostInRange = true; const sockaddr_in6* sa6Host = (sockaddr_in6*)(aiHost->ai_addr); const sockaddr_in6* sa6Range = (sockaddr_in6*)(aiRange->ai_addr); for (int i = 0; i < 16; ++i) { if ((in6aBitmask.s6_addr[i] & sa6Host->sin6_addr.s6_addr[i]) != (in6aBitmask.s6_addr[i] & sa6Range->sin6_addr.s6_addr[i])) { bIsHostInRange = false; } } } freeaddrinfo(aiHost); freeaddrinfo(aiRange); if (bIsHostInRange) return true; } } return false; }