bool CClient::OnJoinMessage(CJoinMessage& Message) { CString sChans = Message.GetTarget(); CString sKeys = Message.GetKey(); VCString vsChans; sChans.Split(",", vsChans, false); sChans.clear(); VCString vsKeys; sKeys.Split(",", vsKeys, true); sKeys.clear(); for (unsigned int a = 0; a < vsChans.size(); a++) { Message.SetTarget(vsChans[a]); Message.SetKey((a < vsKeys.size()) ? vsKeys[a] : ""); if (m_pNetwork) { // May be nullptr. Message.SetChan(m_pNetwork->FindChan(vsChans[a])); } bool bContinue = false; NETWORKMODULECALL(OnUserJoinMessage(Message), m_pUser, m_pNetwork, this, &bContinue); if (bContinue) continue; CString sChannel = Message.GetTarget(); CString sKey = Message.GetKey(); if (m_pNetwork) { CChan* pChan = m_pNetwork->FindChan(sChannel); if (pChan) { if (pChan->IsDetached()) pChan->AttachUser(this); else pChan->JoinUser(sKey); continue; } else if (!sChannel.empty()) { pChan = new CChan(sChannel, m_pNetwork, false); if (m_pNetwork->AddChan(pChan)) { pChan->SetKey(sKey); } } } if (!sChannel.empty()) { sChans += (sChans.empty()) ? sChannel : CString("," + sChannel); if (!vsKeys.empty()) { sKeys += (sKeys.empty()) ? sKey : CString("," + sKey); } } } Message.SetTarget(sChans); Message.SetKey(sKeys); return sChans.empty(); }
CString getBasePath() { CString homepath; #if defined(_WIN32) || defined(_WIN64) // Get the path. char path[MAX_PATH]; GetModuleFileNameA(0, path, MAX_PATH); // Find the program exe and remove it from the path. // Assign the path to homepath. homepath = path; int pos = homepath.findl('\\'); if (pos == -1) homepath.clear(); else if (pos != (homepath.length() - 1)) homepath.removeI(++pos, homepath.length()); #else // Get the path to the program. char path[ 260 ]; memset((void*)path, 0, 260); readlink("/proc/self/exe", path, sizeof(path)); // Assign the path to homepath. char* end = strrchr(path, '/'); if (end != 0) { end++; if (end != 0) *end = '\0'; homepath = path; } #endif return homepath; }
int CSocket::sendData(CString& data) { int intError = 0; int size = 0; // Make sure the socket is connected! if (properties.state == SOCKET_STATE_DISCONNECTED) return SOCKET_INVALID; do { // See if we can send data. // If we can't, return how many bytes we did send. fd_set set; struct timeval tm; tm.tv_sec = tm.tv_usec = 0; FD_ZERO(&set); FD_SET(properties.handle, &set); select(properties.handle + 1, 0, &set, 0, &tm); if (!FD_ISSET(properties.handle, &set)) return size; // Send our data, yay! int sent = 0; if ((sent = ::send(properties.handle, data.text(), data.length(), 0)) == SOCKET_ERROR) { intError = identifyError(); switch (intError) { case ENETDOWN: case ENETRESET: case ENOTCONN: case EHOSTUNREACH: case ECONNABORTED: case ECONNRESET: case ETIMEDOUT: // Destroy the bad socket and create a new one. disconnect(); return intError; break; } if (intError == EAGAIN || intError == EWOULDBLOCK || intError == EINPROGRESS) return size; disconnect(); return intError; } // Remove what we sent. // Increase size by how much we sent. if (sent >= data.length()) data.clear(); else if (sent > 0) data.removeI(0, sent); size += sent; // Repeat while data is still left. } while (data.length() > 0 && intError == 0); // Return how much data was ultimately sent. return size; }
bool CClient::OnPartMessage(CPartMessage& Message) { CString sChans = Message.GetTarget(); VCString vsChans; sChans.Split(",", vsChans, false); sChans.clear(); for (CString& sChan : vsChans) { bool bContinue = false; Message.SetTarget(sChan); NETWORKMODULECALL(OnUserPartMessage(Message), m_pUser, m_pNetwork, this, &bContinue); if (bContinue) continue; sChan = Message.GetTarget(); CChan* pChan = m_pNetwork ? m_pNetwork->FindChan(sChan) : nullptr; if (pChan && !pChan->IsOn()) { PutStatusNotice("Removing channel [" + sChan + "]"); m_pNetwork->DelChan(sChan); } else { sChans += (sChans.empty()) ? sChan : CString("," + sChan); } } if (sChans.empty()) { return true; } Message.SetTarget(sChans); return false; }
bool CTemplate::PrintString(CString& sRet) { sRet.clear(); stringstream sStream; bool bRet = Print(sStream); sRet = sStream.str(); return bRet; }
void reload(CWizDatabase& db) { db.DocumentFromGUID(m_data.strGUID, m_data); m_abstract = WIZABSTRACT(); m_tags.clear(); setText(""); //force repaint setText(m_data.strTitle); }
void loadServerMessage() { CStringList fileData; if(!fileData.load("servermessage.html")) return; serverMessage.clear(); for(int i = 0; i < fileData.count(); i++) serverMessage << fileData[i] << " "; }
ModHandle CModules::OpenModule(const CString& sModule, const CString& sModPath, bool &bVersionMismatch, CModInfo& Info, CString& sRetMsg) { // Some sane defaults in case anything errors out below bVersionMismatch = false; sRetMsg.clear(); for (unsigned int a = 0; a < sModule.length(); a++) { if (((sModule[a] < '0') || (sModule[a] > '9')) && ((sModule[a] < 'a') || (sModule[a] > 'z')) && ((sModule[a] < 'A') || (sModule[a] > 'Z')) && (sModule[a] != '_')) { sRetMsg = "Module names can only contain letters, numbers and underscores, [" + sModule + "] is invalid."; return NULL; } } #ifndef _WIN32 // The second argument to dlopen() has a long history. It seems clear // that (despite what the man page says) we must include either of // RTLD_NOW and RTLD_LAZY and either of RTLD_GLOBAL and RTLD_LOCAL. // // RTLD_NOW vs. RTLD_LAZY: We use RTLD_NOW to avoid znc dying due to // failed symbol lookups later on. Doesn't really seem to have much of a // performance impact. // // RTLD_GLOBAL vs. RTLD_LOCAL: If perl is loaded with RTLD_LOCAL and later on // loads own modules (which it apparently does with RTLD_LAZY), we will die in a // name lookup since one of perl's symbols isn't found. That's worse // than any theoretical issue with RTLD_GLOBAL. ModHandle p = dlopen((sModPath).c_str(), RTLD_NOW | RTLD_GLOBAL); #else ModHandle p = dlopen((sModPath).c_str(), RTLD_NOW | RTLD_LOCAL); #endif if (!p) { sRetMsg = "Unable to open module [" + sModule + "] [" + dlerror() + "]"; return NULL; } typedef bool (*InfoFP)(double, CModInfo&); InfoFP ZNCModInfo = (InfoFP) dlsym(p, "ZNCModInfo"); if (!ZNCModInfo) { dlclose(p); sRetMsg = "Could not find ZNCModInfo() in module [" + sModule + "]"; return NULL; } if (ZNCModInfo(CModule::GetCoreVersion(), Info)) { sRetMsg = ""; bVersionMismatch = false; } else { bVersionMismatch = true; sRetMsg = "Version mismatch, recompile this module."; } return p; }
void CMessage::Parse(CString sMessage) { // <tags> m_mssTags.clear(); if (sMessage.StartsWith("@")) { VCString vsTags; sMessage.Token(0).TrimPrefix_n("@").Split(";", vsTags, false); for (const CString& sTag : vsTags) { CString sKey = sTag.Token(0, false, "=", true); CString sValue = sTag.Token(1, true, "=", true); m_mssTags[sKey] = sValue.Escape(CString::EMSGTAG, CString::CString::EASCII); } sMessage = sMessage.Token(1, true); } // <message> ::= [':' <prefix> <SPACE> ] <command> <params> <crlf> // <prefix> ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ] // <command> ::= <letter> { <letter> } | <number> <number> <number> // <SPACE> ::= ' ' { ' ' } // <params> ::= <SPACE> [ ':' <trailing> | <middle> <params> ] // <middle> ::= <Any *non-empty* sequence of octets not including SPACE // or NUL or CR or LF, the first of which may not be ':'> // <trailing> ::= <Any, possibly *empty*, sequence of octets not including // NUL or CR or LF> // <prefix> if (sMessage.TrimPrefix(":")) { m_Nick.Parse(sMessage.Token(0)); sMessage = sMessage.Token(1, true); } // <command> m_sCommand = sMessage.Token(0); sMessage = sMessage.Token(1, true); // <params> m_bColon = false; m_vsParams.clear(); while (!sMessage.empty()) { m_bColon = sMessage.TrimPrefix(":"); if (m_bColon) { m_vsParams.push_back(sMessage); sMessage.clear(); } else { m_vsParams.push_back(sMessage.Token(0)); sMessage = sMessage.Token(1, true); } } InitType(); }
bool PackHex(const CString& sHex, CString& sPackedHex) { if (sHex.length() % 2) return false; sPackedHex.clear(); CString::size_type len = sHex.length() / 2; for (CString::size_type i = 0; i < len; i++) { unsigned int value; int n = sscanf(&sHex[i * 2], "%02x", &value); if (n != 1 || value > 0xff) return false; sPackedHex += (unsigned char)value; } return true; }
bool CUser::IsValid(CString& sErrMsg, bool bSkipPass) const { sErrMsg.clear(); if (!bSkipPass && m_sPass.empty()) { sErrMsg = "Pass is empty"; return false; } if (m_sUserName.empty()) { sErrMsg = "Username is empty"; return false; } if (!CUser::IsValidUserName(m_sUserName)) { sErrMsg = "Username is invalid"; return false; } return true; }
bool CFile::ReadFile(CString& sData, size_t iMaxSize) { char buff[4096]; size_t iBytesRead = 0; sData.clear(); while (iBytesRead < iMaxSize) { ssize_t iBytes = Read(buff, sizeof(buff)); if (iBytes < 0) // Error return false; if (iBytes == 0) // EOF return true; sData.append(buff, iBytes); iBytesRead += iBytes; } // Buffer limit reached return false; }
int main(int argc, char *argv[]) { // Shut down the server if we get a kill signal. signal( SIGINT, (sighandler_t) shutdownServer ); signal( SIGTERM, (sighandler_t) shutdownServer ); // Grab the base path to the server executable. getBasePath(); // Initialize data directory. filesystem[0].addDir("global"); filesystem[1].addDir("global/heads"); filesystem[2].addDir("global/bodies"); filesystem[3].addDir("global/swords"); filesystem[4].addDir("global/shields"); // Definitions CSocket playerSock, playerSockOld, serverSock; playerList.clear(); serverList.clear(); // Load Settings settings = new CSettings(homepath + "settings.ini"); if (!settings->isOpened()) { serverlog.out( "[Error] Could not load settings.\n" ); return ERR_SETTINGS; } // Load ip bans. ipBans = CString::loadToken(homepath + "ipbans.txt", "\n", true); serverlog.out("Loaded following IP bans:\n"); for (std::vector<CString>::iterator i = ipBans.begin(); i != ipBans.end(); ++i) serverlog.out("\t%s\n", i->text()); // Load server types. serverTypes = CString::loadToken("servertypes.txt", "\n", true); // Server sock. serverSock.setType( SOCKET_TYPE_SERVER ); serverSock.setProtocol( SOCKET_PROTOCOL_TCP ); serverSock.setDescription( "serverSock" ); CString serverInterface = settings->getStr("gserverInterface"); if (serverInterface == "AUTO") serverInterface.clear(); if ( serverSock.init( (serverInterface.isEmpty() ? 0 : serverInterface.text()), settings->getStr("gserverPort").text() ) ) { serverlog.out( "[Error] Could not initialize sockets.\n" ); return ERR_LISTEN; } // Player sock. playerSock.setType( SOCKET_TYPE_SERVER ); playerSock.setProtocol( SOCKET_PROTOCOL_TCP ); playerSock.setDescription( "playerSock" ); CString playerInterface = settings->getStr("clientInterface"); if (playerInterface == "AUTO") playerInterface.clear(); if ( playerSock.init( (playerInterface.isEmpty() ? 0 : playerInterface.text()), settings->getStr("clientPort").text() ) ) { serverlog.out( "[Error] Could not initialize sockets.\n" ); return ERR_LISTEN; } // Player sock. playerSockOld.setType( SOCKET_TYPE_SERVER ); playerSockOld.setProtocol( SOCKET_PROTOCOL_TCP ); playerSockOld.setDescription( "playerSockOld" ); if ( playerSockOld.init( (playerInterface.isEmpty() ? 0 : playerInterface.text()), settings->getStr("clientPortOld").text() ) ) { serverlog.out( "[Error] Could not initialize sockets.\n" ); return ERR_LISTEN; } // Connect sockets. if ( serverSock.connect() || playerSock.connect() || playerSockOld.connect() ) { serverlog.out( "[Error] Could not connect sockets.\n" ); return ERR_SOCKETS; } // MySQL-Connect #ifndef NO_MYSQL mySQL = new CMySQL(settings->getStr("server").text(), settings->getStr("user").text(), settings->getStr("password").text(), settings->getStr("database").text(), settings->getStr("sockfile").text()); vBmySQL = new CMySQL(settings->getStr("server").text(), settings->getStr("vbuser").text(), settings->getStr("vbpassword").text(), settings->getStr("vbdatabase").text(), settings->getStr("sockfile").text()); if (!mySQL->ping()) { serverlog.out( "[Error] No response from MySQL.\n" ); return ERR_MYSQL; } // Truncate servers table from MySQL. CString query; query << "TRUNCATE TABLE " << settings->getStr("serverlist"); mySQL->add_simple_query(query); query = CString("TRUNCATE TABLE ") << settings->getStr("securelogin"); mySQL->add_simple_query(query); mySQL->update(); #endif // Create Packet-Functions createPLFunctions(); createSVFunctions(); // Flavor text serverlog.out( CString() << "Graal Reborn - List Server V2\n" << "List server started..\n" << "Client port: " << CString(settings->getInt("clientport")) << "\n" << "GServer port: " << CString(settings->getInt("gserverport")) << "\n" ); #ifdef NO_MYSQL // Notify the user that they are running in No MySQL mode serverlog.out( CString() << "Running in No MySQL mode, all account and guild checks are disabled.\n"); #endif // Main Loop time_t t5min = time(0); while (running) { // Make sure MySQL is active #ifndef NO_MYSQL if (!mySQL->ping()) serverlog.out( "[Error] No response from MySQL.\n" ); mySQL->update(); #endif // Accept New Connections acceptSock(playerSock, SOCK_PLAYER); acceptSock(playerSockOld, SOCK_PLAYEROLD); acceptSock(serverSock, SOCK_SERVER); // Player Sockets for ( std::vector<TPlayer*>::iterator iter = playerList.begin(); iter != playerList.end(); ) { TPlayer* player = (TPlayer*)*iter; if ( player->doMain() == false ) { player->sendCompress(); delete player; iter = playerList.erase( iter ); } else ++iter; } // Server Sockets for ( std::vector<TServer*>::iterator iter = serverList.begin(); iter != serverList.end() ; ) { TServer* server = (TServer*)*iter; if (server == 0) { serverlog.out(CString() << "Server disconnected: [Orphaned server]\n"); iter = serverList.erase(iter); continue; } // Check for a timed out server. if ((int)server->getLastData() >= 300) { serverlog.out(CString() << "Server disconnected: " << server->getName() << " [Timed out]\n"); server->sendCompress(); delete server; iter = serverList.erase(iter); continue; } // Execute server stuff. if (server->doMain() == false) { serverlog.out(CString() << "Server disconnected: " << server->getName() << "\n"); server->sendCompress(); delete server; iter = serverList.erase(iter); continue; } ++iter; } // Every 5 minutes... // Reload ip bans. // Resync the file system. if ((int)difftime(time(0), t5min) > (5*60)) { ipBans = CString::loadToken("ipbans.txt", "\n", true); serverTypes = CString::loadToken("servertypes.txt", "\n", true); for (int i = 0; i < 5; ++i) filesystem[i].resync(); t5min = time(0); } // Wait wait(100); } // Remove all servers. // This guarantees the server deconstructors are called. for ( std::vector<TServer*>::iterator iter = serverList.begin(); iter != serverList.end() ; ) { TServer* server = (TServer*)*iter; delete server; iter = serverList.erase( iter ); } return ERR_SUCCESS; }
bool CIRCNetwork::ParseConfig(CConfig *pConfig, CString& sError, bool bUpgrade) { VCString vsList; VCString::const_iterator vit; if (!bUpgrade) { TOption<const CString&> StringOptions[] = { { "nick", &CIRCNetwork::SetNick }, { "altnick", &CIRCNetwork::SetAltNick }, { "ident", &CIRCNetwork::SetIdent }, { "realname", &CIRCNetwork::SetRealName } }; size_t numStringOptions = sizeof(StringOptions) / sizeof(StringOptions[0]); TOption<bool> BoolOptions[] = { { "ircconnectenabled", &CIRCNetwork::SetIRCConnectEnabled }, }; size_t numBoolOptions = sizeof(BoolOptions) / sizeof(BoolOptions[0]); for (size_t i = 0; i < numStringOptions; i++) { CString sValue; if (pConfig->FindStringEntry(StringOptions[i].name, sValue)) (this->*StringOptions[i].pSetter)(sValue); } for (size_t i = 0; i < numBoolOptions; i++) { CString sValue; if (pConfig->FindStringEntry(BoolOptions[i].name, sValue)) (this->*BoolOptions[i].pSetter)(sValue.ToBool()); } pConfig->FindStringVector("loadmodule", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { CString sValue = *vit; CString sModName = sValue.Token(0); // XXX Legacy crap, added in ZNC 0.203 if (sModName == "away") { CUtils::PrintMessage("NOTICE: [away] was renamed, " "loading [autoaway] instead"); sModName = "autoaway"; } CUtils::PrintAction("Loading Module [" + sModName + "]"); CString sModRet; CString sArgs = sValue.Token(1, true); bool bModRet = GetModules().LoadModule(sModName, sArgs, CModInfo::NetworkModule, GetUser(), this, sModRet); CUtils::PrintStatus(bModRet, sModRet); if (!bModRet) { sError = sModRet; return false; } } } pConfig->FindStringVector("server", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { CUtils::PrintAction("Adding Server [" + *vit + "]"); CUtils::PrintStatus(AddServer(*vit)); } pConfig->FindStringVector("chan", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { AddChan(*vit, true); } CConfig::SubConfig subConf; CConfig::SubConfig::const_iterator subIt; pConfig->FindSubConfig("chan", subConf); for (subIt = subConf.begin(); subIt != subConf.end(); ++subIt) { const CString& sChanName = subIt->first; CConfig* pSubConf = subIt->second.m_pSubConfig; CChan* pChan = new CChan(sChanName, this, true, pSubConf); if (!pSubConf->empty()) { sError = "Unhandled lines in config for User [" + m_pUser->GetUserName() + "], Network [" + GetName() + "], Channel [" + sChanName + "]!"; CUtils::PrintError(sError); CZNC::DumpConfig(pSubConf); return false; } // Save the channel name, because AddChan // deletes the CChannel*, if adding fails sError = pChan->GetName(); if (!AddChan(pChan)) { sError = "Channel [" + sError + "] defined more than once"; CUtils::PrintError(sError); return false; } sError.clear(); } return true; }
bool CUser::Clone(const CUser& User, CString& sErrorRet, bool bCloneChans) { unsigned int a = 0; sErrorRet.clear(); if (!User.IsValid(sErrorRet, true)) { return false; } // user names can only specified for the constructor, changing it later // on breaks too much stuff (e.g. lots of paths depend on the user name) if (GetUserName() != User.GetUserName()) { DEBUG("Ignoring username in CUser::Clone(), old username [" << GetUserName() << "]; New username [" << User.GetUserName() << "]"); } if (!User.GetPass().empty()) { SetPass(User.GetPass(), User.GetPassHashType(), User.GetPassSalt()); } SetNick(User.GetNick(false)); SetAltNick(User.GetAltNick(false)); SetIdent(User.GetIdent(false)); SetRealName(User.GetRealName()); SetStatusPrefix(User.GetStatusPrefix()); SetBindHost(User.GetBindHost()); SetDCCBindHost(User.GetDCCBindHost()); SetQuitMsg(User.GetQuitMsg()); SetSkinName(User.GetSkinName()); SetLanguage(User.GetLanguage()); SetDefaultChanModes(User.GetDefaultChanModes()); SetBufferCount(User.GetBufferCount(), true); SetJoinTries(User.JoinTries()); SetMaxJoins(User.MaxJoins()); // Allowed Hosts m_ssAllowedHosts.clear(); const set<CString>& ssHosts = User.GetAllowedHosts(); for (set<CString>::const_iterator it = ssHosts.begin(); it != ssHosts.end(); ++it) { AddAllowedHost(*it); } for (a = 0; a < m_vClients.size(); a++) { CClient* pSock = m_vClients[a]; if (!IsHostAllowed(pSock->GetRemoteIP())) { pSock->PutStatusNotice("You are being disconnected because your IP is no longer allowed to connect to this user"); pSock->Close(); } } // !Allowed Hosts // Networks const vector<CIRCNetwork*>& vNetworks = User.GetNetworks(); for (a = 0; a < vNetworks.size(); a++) { new CIRCNetwork(this, vNetworks[a], bCloneChans); } // !Networks // CTCP Replies m_mssCTCPReplies.clear(); const MCString& msReplies = User.GetCTCPReplies(); for (MCString::const_iterator it = msReplies.begin(); it != msReplies.end(); ++it) { AddCTCPReply(it->first, it->second); } // !CTCP Replies // Flags SetIRCConnectEnabled(User.GetIRCConnectEnabled()); SetKeepBuffer(User.KeepBuffer()); SetMultiClients(User.MultiClients()); SetDenyLoadMod(User.DenyLoadMod()); SetAdmin(User.IsAdmin()); SetDenySetBindHost(User.DenySetBindHost()); SetTimestampAppend(User.GetTimestampAppend()); SetTimestampPrepend(User.GetTimestampPrepend()); SetTimestampFormat(User.GetTimestampFormat()); SetTimezoneOffset(User.GetTimezoneOffset()); // !Flags // Modules set<CString> ssUnloadMods; CModules& vCurMods = GetModules(); const CModules& vNewMods = User.GetModules(); for (a = 0; a < vNewMods.size(); a++) { CString sModRet; CModule* pNewMod = vNewMods[a]; CModule* pCurMod = vCurMods.FindModule(pNewMod->GetModName()); if (!pCurMod) { vCurMods.LoadModule(pNewMod->GetModName(), pNewMod->GetArgs(), CModInfo::UserModule, this, NULL, sModRet); } else if (pNewMod->GetArgs() != pCurMod->GetArgs()) { vCurMods.ReloadModule(pNewMod->GetModName(), pNewMod->GetArgs(), this, NULL, sModRet); } } for (a = 0; a < vCurMods.size(); a++) { CModule* pCurMod = vCurMods[a]; CModule* pNewMod = vNewMods.FindModule(pCurMod->GetModName()); if (!pNewMod) { ssUnloadMods.insert(pCurMod->GetModName()); } } for (set<CString>::iterator it = ssUnloadMods.begin(); it != ssUnloadMods.end(); ++it) { vCurMods.UnloadModule(*it); } // !Modules return true; }
int verifyAccount(CString& pAccount, const CString& pPassword, bool fromServer) { #ifdef NO_MYSQL return ACCSTAT_NORMAL; #else // definitions CString query; std::vector<CString> result; CString password(pPassword); // make sure its not empty. if (pAccount.length() == 0) return ACCSTAT_INVALID; // See if we should try a secure login. int ret = ACCSTAT_INVALID; if (password.find("\xa7") != -1) { CString transaction = password.readString("\xa7"); CString md5password = password.readString(""); // Try our password. result.clear(); query = CString() << "SELECT activated, banned, account FROM `" << settings->getStr("userlist") << "` WHERE account='" << pAccount.escape() << "' AND transactionnr='" << transaction.escape() << "' AND password2='" << md5password.escape() << "' LIMIT 1"; int err = mySQL->try_query(query, result); // account/password correct? if (err == -1) ret = ACCSTAT_ERROR; else if (result.size() == 0) ret = ACCSTAT_INVALID; else if (result.size() >= 1 && result[0] == "0") ret = ACCSTAT_NONREG; else if (result.size() >= 2 && result[1] == "1") ret = ACCSTAT_BANNED; else ret = ACCSTAT_NORMAL; // Should we expire the password now? if (ret != ACCSTAT_INVALID && ret != ACCSTAT_ERROR) { unsigned char login_type = (char)(atoi(transaction.text()) & 0xFF); // Password expires after one server login. Remove it. if (login_type == SECURELOGIN_ONEUSE && fromServer == true) { query.clear(); query << "UPDATE `" << settings->getStr("userlist") << "` SET " << "transactionnr='0'," << "salt2=''," << "password2='' " << "WHERE account='" << pAccount.escape() << "'"; mySQL->add_simple_query(query); } } // Get the correct account name. if (result.size() == 3) pAccount = result[2]; return ret; } // If our ret is ACCSTAT_ERROR, that means there was a SQL error. if (ret == ACCSTAT_ERROR) return ret; // Either the secure login failed or we didn't try a secure login. // Try the old login method. if (ret == ACCSTAT_INVALID) { result.clear(); query = CString() << "SELECT password, salt, activated, banned, account FROM `" << settings->getStr("userlist") << "` WHERE account='" << pAccount.escape() << "' AND password="******"MD5(CONCAT(MD5('" << pPassword.escape() << "'), `salt`)) LIMIT 1"; int err = mySQL->try_query(query, result); if (err == -1) return ACCSTAT_ERROR; // account/password correct? if (result.size() == 0) return ACCSTAT_INVALID; // activated? if (result.size() < 3 || result[2] == "0") return ACCSTAT_NONREG; // banned? if (result.size() > 3 && result[3] == "1") return ACCSTAT_BANNED; // Get the case-sensitive account name. if (result.size() > 4) pAccount = result[4]; // passed all tests :) return ACCSTAT_NORMAL; } return ACCSTAT_INVALID; #endif }
void CClient::UserPortCommand(CString& sLine) { const CString sCommand = sLine.Token(0); if (sCommand.Equals("LISTPORTS")) { CTable Table; Table.AddColumn("Port"); Table.AddColumn("BindHost"); Table.AddColumn("SSL"); Table.AddColumn("Proto"); Table.AddColumn("IRC/Web"); vector<CListener*>::const_iterator it; const vector<CListener*>& vpListeners = CZNC::Get().GetListeners(); for (it = vpListeners.begin(); it < vpListeners.end(); ++it) { Table.AddRow(); Table.SetCell("Port", CString((*it)->GetPort())); Table.SetCell("BindHost", ((*it)->GetBindHost().empty() ? CString("*") : (*it)->GetBindHost())); Table.SetCell("SSL", CString((*it)->IsSSL())); EAddrType eAddr = (*it)->GetAddrType(); Table.SetCell("Proto", (eAddr == ADDR_ALL ? "All" : (eAddr == ADDR_IPV4ONLY ? "IPv4" : "IPv6"))); CListener::EAcceptType eAccept = (*it)->GetAcceptType(); Table.SetCell("IRC/Web", (eAccept == CListener::ACCEPT_ALL ? "All" : (eAccept == CListener::ACCEPT_IRC ? "IRC" : "Web"))); } PutStatus(Table); return; } CString sPort = sLine.Token(1); CString sAddr = sLine.Token(2); EAddrType eAddr = ADDR_ALL; if (sAddr.Equals("IPV4")) { eAddr = ADDR_IPV4ONLY; } else if (sAddr.Equals("IPV6")) { eAddr = ADDR_IPV6ONLY; } else if (sAddr.Equals("ALL")) { eAddr = ADDR_ALL; } else { sAddr.clear(); } unsigned short uPort = sPort.ToUShort(); if (sCommand.Equals("ADDPORT")) { CListener::EAcceptType eAccept = CListener::ACCEPT_ALL; CString sAccept = sLine.Token(3); if (sAccept.Equals("WEB")) { eAccept = CListener::ACCEPT_HTTP; } else if (sAccept.Equals("IRC")) { eAccept = CListener::ACCEPT_IRC; } else if (sAccept.Equals("ALL")) { eAccept = CListener::ACCEPT_ALL; } else { sAccept.clear(); } if (sPort.empty() || sAddr.empty() || sAccept.empty()) { PutStatus("Usage: AddPort <[+]port> <ipv4|ipv6|all> <web|irc|all> [bindhost]"); } else { bool bSSL = (sPort.Left(1).Equals("+")); const CString sBindHost = sLine.Token(4); CListener* pListener = new CListener(uPort, sBindHost, bSSL, eAddr, eAccept); if (!pListener->Listen()) { delete pListener; PutStatus("Unable to bind [" + CString(strerror(errno)) + "]"); } else { if (CZNC::Get().AddListener(pListener)) PutStatus("Port Added"); else PutStatus("Error?!"); } } } else if (sCommand.Equals("DELPORT")) { if (sPort.empty() || sAddr.empty()) { PutStatus("Usage: DelPort <port> <ipv4|ipv6|all> [bindhost]"); } else { const CString sBindHost = sLine.Token(3); CListener* pListener = CZNC::Get().FindListener(uPort, sBindHost, eAddr); if (pListener) { CZNC::Get().DelListener(pListener); PutStatus("Deleted Port"); } else { PutStatus("Unable to find a matching port"); } } } }
void CDaemonApp::handleIpcMessage(const CEvent& e, void*) { CIpcMessage* m = static_cast<CIpcMessage*>(e.getDataObject()); switch (m->type()) { case kIpcCommand: { CIpcCommandMessage* cm = static_cast<CIpcCommandMessage*>(m); CString command = cm->command(); // if empty quotes, clear. if (command == "\"\"") { command.clear(); } if (!command.empty()) { LOG((CLOG_DEBUG "new command, elevate=%d command=%s", cm->elevate(), command.c_str())); CString debugArg("--debug"); UInt32 debugArgPos = static_cast<UInt32>(command.find(debugArg)); if (debugArgPos != CString::npos) { UInt32 from = debugArgPos + static_cast<UInt32>(debugArg.size()) + 1; UInt32 nextSpace = static_cast<UInt32>(command.find(" ", from)); CString logLevel(command.substr(from, nextSpace - from)); try { // change log level based on that in the command string // and change to that log level now. ARCH->setting("LogLevel", logLevel); CLOG->setFilter(logLevel.c_str()); } catch (XArch& e) { LOG((CLOG_ERR "failed to save LogLevel setting, %s", e.what().c_str())); } } } else { LOG((CLOG_DEBUG "empty command, elevate=%d", cm->elevate())); } try { // store command in system settings. this is used when the daemon // next starts. ARCH->setting("Command", command); // TODO: it would be nice to store bools/ints... ARCH->setting("Elevate", CString(cm->elevate() ? "1" : "0")); } catch (XArch& e) { LOG((CLOG_ERR "failed to save settings, %s", e.what().c_str())); } #if SYSAPI_WIN32 // tell the relauncher about the new command. this causes the // relauncher to stop the existing command and start the new // command. m_watchdog->setCommand(command, cm->elevate()); #endif break; } case kIpcHello: CIpcHelloMessage* hm = static_cast<CIpcHelloMessage*>(m); CString type; switch (hm->clientType()) { case kIpcClientGui: type = "gui"; break; case kIpcClientNode: type = "node"; break; default: type = "unknown"; break; } LOG((CLOG_DEBUG "ipc hello, type=%s", type.c_str())); #if SYSAPI_WIN32 CString watchdogStatus = m_watchdog->isProcessActive() ? "ok" : "error"; LOG((CLOG_INFO "watchdog status: %s", watchdogStatus.c_str())); #endif m_ipcLogOutputter->notifyBuffer(); break; } }
bool CTemplate::Print(const CString& sFileName, ostream& oOut) { if (sFileName.empty()) { DEBUG("Empty filename in CTemplate::Print()"); return false; } CFile File(sFileName); if (!File.Open()) { DEBUG("Unable to open file [" + sFileName + "] in CTemplate::Print()"); return false; } CString sLine; CString sSetBlockVar; bool bValidLastIf = false; bool bInSetBlock = false; unsigned long uFilePos = 0; unsigned long uCurPos = 0; unsigned int uLineNum = 0; unsigned int uNestedIfs = 0; unsigned int uSkip = 0; bool bLoopCont = false; bool bLoopBreak = false; bool bExit = false; while (File.ReadLine(sLine)) { CString sOutput; bool bFoundATag = false; bool bTmplLoopHasData = false; uLineNum++; CString::size_type iPos = 0; uCurPos = uFilePos; unsigned int uLineSize = sLine.size(); bool bBroke = false; while (1) { iPos = sLine.find("<?"); if (iPos == CString::npos) { break; } uCurPos += iPos; bFoundATag = true; if (!uSkip) { sOutput += sLine.substr(0, iPos); } sLine = sLine.substr(iPos +2); CString::size_type iPos2 = sLine.find("?>"); // Make sure our tmpl tag is ended properly if (iPos2 == CString::npos) { DEBUG("Template tag not ended properly in file [" + sFileName + "] [<?" + sLine + "]"); return false; } uCurPos += iPos2 +4; CString sMid = CString(sLine.substr(0, iPos2)).Trim_n(); // Make sure we don't have a nested tag if (sMid.find("<?") == CString::npos) { sLine = sLine.substr(iPos2 +2); CString sAction = sMid.Token(0); CString sArgs = sMid.Token(1, true); bool bNotFound = false; // If we're breaking or continuing from within a loop, skip all tags that aren't ENDLOOP if ((bLoopCont || bLoopBreak) && !sAction.Equals("ENDLOOP")) { continue; } if (!uSkip) { if (sAction.Equals("INC")) { if (!Print(ExpandFile(sArgs, true), oOut)) { DEBUG("Unable to print INC'd file [" + sArgs + "]"); return false; } } else if (sAction.Equals("SETOPTION")) { m_spOptions->Parse(sArgs); } else if (sAction.Equals("ADDROW")) { CString sLoopName = sArgs.Token(0); MCString msRow; if (sArgs.Token(1, true, " ").OptionSplit(msRow)) { CTemplate& NewRow = AddRow(sLoopName); for (MCString::iterator it = msRow.begin(); it != msRow.end(); ++it) { NewRow[it->first] = it->second; } } } else if (sAction.Equals("SET")) { CString sName = sArgs.Token(0); CString sValue = sArgs.Token(1, true); (*this)[sName] = sValue; } else if (sAction.Equals("JOIN")) { VCString vsArgs; //sArgs.Split(" ", vsArgs, false, "\"", "\""); sArgs.QuoteSplit(vsArgs); if (vsArgs.size() > 1) { CString sDelim = vsArgs[0]; bool bFoundOne = false; CString::EEscape eEscape = CString::EASCII; for (unsigned int a = 1; a < vsArgs.size(); a++) { const CString& sArg = vsArgs[a]; if (sArg.Equals("ESC=", false, 4)) { eEscape = CString::ToEscape(sArg.LeftChomp_n(4)); } else { CString sValue = GetValue(sArg); if (!sValue.empty()) { if (bFoundOne) { sOutput += sDelim; } sOutput += sValue.Escape_n(eEscape); bFoundOne = true; } } } } } else if (sAction.Equals("SETBLOCK")) { sSetBlockVar = sArgs; bInSetBlock = true; } else if (sAction.Equals("EXPAND")) { sOutput += ExpandFile(sArgs, true); } else if (sAction.Equals("VAR")) { sOutput += GetValue(sArgs); } else if (sAction.Equals("LT")) { sOutput += "<?"; } else if (sAction.Equals("GT")) { sOutput += "?>"; } else if (sAction.Equals("CONTINUE")) { CTemplateLoopContext* pContext = GetCurLoopContext(); if (pContext) { uSkip++; bLoopCont = true; break; } else { DEBUG("[" + sFileName + ":" + CString(uCurPos - iPos2 -4) + "] <? CONTINUE ?> must be used inside of a loop!"); } } else if (sAction.Equals("BREAK")) { // break from loop CTemplateLoopContext* pContext = GetCurLoopContext(); if (pContext) { uSkip++; bLoopBreak = true; break; } else { DEBUG("[" + sFileName + ":" + CString(uCurPos - iPos2 -4) + "] <? BREAK ?> must be used inside of a loop!"); } } else if (sAction.Equals("EXIT")) { bExit = true; } else if (sAction.Equals("DEBUG")) { DEBUG("CTemplate DEBUG [" + sFileName + "@" + CString(uCurPos - iPos2 -4) + "b] -> [" + sArgs + "]"); } else if (sAction.Equals("LOOP")) { CTemplateLoopContext* pContext = GetCurLoopContext(); if (!pContext || pContext->GetFilePosition() != uCurPos) { // we are at a brand new loop (be it new or a first pass at an inner loop) CString sLoopName = sArgs.Token(0); bool bReverse = (sArgs.Token(1).Equals("REVERSE")); bool bSort = (sArgs.Token(1).Left(4).Equals("SORT")); vector<CTemplate*>* pvLoop = GetLoop(sLoopName); if (bSort && pvLoop != NULL && pvLoop->size() > 1) { CString sKey; if(sArgs.Token(1).TrimPrefix_n("SORT").Left(4).Equals("ASC=")) { sKey = sArgs.Token(1).TrimPrefix_n("SORTASC="); } else if(sArgs.Token(1).TrimPrefix_n("SORT").Left(5).Equals("DESC=")) { sKey = sArgs.Token(1).TrimPrefix_n("SORTDESC="); bReverse = true; } if (!sKey.empty()) { std::sort(pvLoop->begin(), pvLoop->end(), CLoopSorter(sKey)); } } if (pvLoop) { // If we found data for this loop, add it to our context vector //unsigned long uBeforeLoopTag = uCurPos - iPos2 - 4; unsigned long uAfterLoopTag = uCurPos; for (CString::size_type t = 0; t < sLine.size(); t++) { char c = sLine[t]; if (c == '\r' || c == '\n') { uAfterLoopTag++; } else { break; } } m_vLoopContexts.push_back(new CTemplateLoopContext(uAfterLoopTag, sLoopName, bReverse, pvLoop)); } else { // If we don't have data, just skip this loop and everything inside uSkip++; } } } else if (sAction.Equals("IF")) { if (ValidIf(sArgs)) { uNestedIfs++; bValidLastIf = true; } else { uSkip++; bValidLastIf = false; } } else if (sAction.Equals("REM")) { uSkip++; } else { bNotFound = true; } } else if (sAction.Equals("REM")) { uSkip++; } else if (sAction.Equals("IF")) { uSkip++; } else if (sAction.Equals("LOOP")) { uSkip++; } if (sAction.Equals("ENDIF")) { if (uSkip) { uSkip--; } else { uNestedIfs--; } } else if (sAction.Equals("ENDREM")) { if (uSkip) { uSkip--; } } else if (sAction.Equals("ENDSETBLOCK")) { bInSetBlock = false; sSetBlockVar = ""; } else if (sAction.Equals("ENDLOOP")) { if (bLoopCont && uSkip == 1) { uSkip--; bLoopCont = false; } if (bLoopBreak && uSkip == 1) { uSkip--; } if (uSkip) { uSkip--; } else { // We are at the end of the loop so we need to inc the index CTemplateLoopContext* pContext = GetCurLoopContext(); if (pContext) { pContext->IncRowIndex(); // If we didn't go out of bounds we need to seek back to the top of our loop if (!bLoopBreak && pContext->GetCurRow()) { uCurPos = pContext->GetFilePosition(); uFilePos = uCurPos; uLineSize = 0; File.Seek(uCurPos); bBroke = true; if (!sOutput.Trim_n().empty()) { pContext->SetHasData(); } break; } else { if (sOutput.Trim_n().empty()) { sOutput.clear(); } bTmplLoopHasData = pContext->HasData(); DelCurLoopContext(); bLoopBreak = false; } } } } else if (sAction.Equals("ELSE")) { if (!bValidLastIf && uSkip == 1) { CString sArg = sArgs.Token(0); if (sArg.empty() || (sArg.Equals("IF") && ValidIf(sArgs.Token(1, true)))) { uSkip = 0; bValidLastIf = true; } } else if (!uSkip) { uSkip = 1; } } else if (bNotFound) { // Unknown tag that isn't being skipped... vector<CSmartPtr<CTemplateTagHandler> >& vspTagHandlers = GetTagHandlers(); if (!vspTagHandlers.empty()) { // @todo this should go up to the top to grab handlers CTemplate* pTmpl = GetCurTemplate(); CString sCustomOutput; for (unsigned int j = 0; j < vspTagHandlers.size(); j++) { CSmartPtr<CTemplateTagHandler> spTagHandler = vspTagHandlers[j]; if (spTagHandler->HandleTag(*pTmpl, sAction, sArgs, sCustomOutput)) { sOutput += sCustomOutput; bNotFound = false; break; } } if (bNotFound) { DEBUG("Unknown/Unhandled tag [" + sAction + "]"); } } } continue; } DEBUG("Malformed tag on line " + CString(uLineNum) + " of [" << File.GetLongName() + "]"); DEBUG("--------------- [" + sLine + "]"); } if (!bBroke) { uFilePos += uLineSize; if (!uSkip) { sOutput += sLine; } } if (!bFoundATag || bTmplLoopHasData || sOutput.find_first_not_of(" \t\r\n") != CString::npos) { if (bInSetBlock) { CString sName = sSetBlockVar.Token(0); //CString sValue = sSetBlockVar.Token(1, true); (*this)[sName] += sOutput; } else { oOut << sOutput; } } if (bExit) { break; } } oOut.flush(); return true; }
bool CUser::Clone(const CUser& User, CString& sErrorRet, bool bCloneNetworks) { sErrorRet.clear(); if (!User.IsValid(sErrorRet, true)) { return false; } // user names can only specified for the constructor, changing it later // on breaks too much stuff (e.g. lots of paths depend on the user name) if (GetUserName() != User.GetUserName()) { DEBUG("Ignoring username in CUser::Clone(), old username [" << GetUserName() << "]; New username [" << User.GetUserName() << "]"); } if (!User.GetPass().empty()) { SetPass(User.GetPass(), User.GetPassHashType(), User.GetPassSalt()); } SetNick(User.GetNick(false)); SetAltNick(User.GetAltNick(false)); SetIdent(User.GetIdent(false)); SetRealName(User.GetRealName()); SetStatusPrefix(User.GetStatusPrefix()); SetBindHost(User.GetBindHost()); SetDCCBindHost(User.GetDCCBindHost()); SetQuitMsg(User.GetQuitMsg()); SetSkinName(User.GetSkinName()); SetDefaultChanModes(User.GetDefaultChanModes()); SetChanBufferSize(User.GetChanBufferSize(), true); SetQueryBufferSize(User.GetQueryBufferSize(), true); SetJoinTries(User.JoinTries()); SetMaxNetworks(User.MaxNetworks()); SetMaxQueryBuffers(User.MaxQueryBuffers()); SetMaxJoins(User.MaxJoins()); SetClientEncoding(User.GetClientEncoding()); // Allowed Hosts m_ssAllowedHosts.clear(); const set<CString>& ssHosts = User.GetAllowedHosts(); for (const CString& sHost : ssHosts) { AddAllowedHost(sHost); } for (CClient* pSock : m_vClients) { if (!IsHostAllowed(pSock->GetRemoteIP())) { pSock->PutStatusNotice( "You are being disconnected because your IP is no longer " "allowed to connect to this user"); pSock->Close(); } } // !Allowed Hosts // Networks if (bCloneNetworks) { CloneNetworks(User); } // !Networks // CTCP Replies m_mssCTCPReplies.clear(); const MCString& msReplies = User.GetCTCPReplies(); for (const auto& it : msReplies) { AddCTCPReply(it.first, it.second); } // !CTCP Replies // Flags SetAutoClearChanBuffer(User.AutoClearChanBuffer()); SetAutoClearQueryBuffer(User.AutoClearQueryBuffer()); SetMultiClients(User.MultiClients()); SetDenyLoadMod(User.DenyLoadMod()); SetAdmin(User.IsAdmin()); SetDenySetBindHost(User.DenySetBindHost()); SetTimestampAppend(User.GetTimestampAppend()); SetTimestampPrepend(User.GetTimestampPrepend()); SetTimestampFormat(User.GetTimestampFormat()); SetTimezone(User.GetTimezone()); // !Flags // Modules set<CString> ssUnloadMods; CModules& vCurMods = GetModules(); const CModules& vNewMods = User.GetModules(); for (CModule* pNewMod : vNewMods) { CString sModRet; CModule* pCurMod = vCurMods.FindModule(pNewMod->GetModName()); if (!pCurMod) { vCurMods.LoadModule(pNewMod->GetModName(), pNewMod->GetArgs(), CModInfo::UserModule, this, nullptr, sModRet); } else if (pNewMod->GetArgs() != pCurMod->GetArgs()) { vCurMods.ReloadModule(pNewMod->GetModName(), pNewMod->GetArgs(), this, nullptr, sModRet); } } for (CModule* pCurMod : vCurMods) { CModule* pNewMod = vNewMods.FindModule(pCurMod->GetModName()); if (!pNewMod) { ssUnloadMods.insert(pCurMod->GetModName()); } } for (const CString& sMod : ssUnloadMods) { vCurMods.UnloadModule(sMod); } // !Modules return true; }
bool CUser::Clone(const CUser& User, CString& sErrorRet, bool bCloneChans) { unsigned int a = 0; sErrorRet.clear(); if (!User.IsValid(sErrorRet, true)) { return false; } // user names can only specified for the constructor, changing it later // on breaks too much stuff (e.g. lots of paths depend on the user name) if (GetUserName() != User.GetUserName()) { DEBUG("Ignoring username in CUser::Clone(), old username [" << GetUserName() << "]; New username [" << User.GetUserName() << "]"); } if (!User.GetPass().empty()) { SetPass(User.GetPass(), User.GetPassHashType(), User.GetPassSalt()); } SetNick(User.GetNick(false)); SetAltNick(User.GetAltNick(false)); SetIdent(User.GetIdent(false)); SetRealName(User.GetRealName()); SetStatusPrefix(User.GetStatusPrefix()); SetBindHost(User.GetBindHost()); SetDCCBindHost(User.GetDCCBindHost()); SetQuitMsg(User.GetQuitMsg()); SetSkinName(User.GetSkinName()); SetDefaultChanModes(User.GetDefaultChanModes()); SetBufferCount(User.GetBufferCount(), true); SetJoinTries(User.JoinTries()); SetMaxJoins(User.MaxJoins()); // Allowed Hosts m_ssAllowedHosts.clear(); const set<CString>& ssHosts = User.GetAllowedHosts(); for (set<CString>::const_iterator it = ssHosts.begin(); it != ssHosts.end(); ++it) { AddAllowedHost(*it); } for (a = 0; a < m_vClients.size(); a++) { CClient* pSock = m_vClients[a]; if (!IsHostAllowed(pSock->GetRemoteIP())) { pSock->PutStatusNotice("You are being disconnected because your IP is no longer allowed to connect to this user"); pSock->Close(); } } // !Allowed Hosts // Servers const vector<CServer*>& vServers = User.GetServers(); CString sServer; CServer* pCurServ = GetCurrentServer(); if (pCurServ) { sServer = pCurServ->GetName(); } DelServers(); for (a = 0; a < vServers.size(); a++) { CServer* pServer = vServers[a]; AddServer(pServer->GetName(), pServer->GetPort(), pServer->GetPass(), pServer->IsSSL()); } m_uServerIdx = 0; for (a = 0; a < m_vServers.size(); a++) { if (sServer.Equals(m_vServers[a]->GetName())) { m_uServerIdx = a + 1; break; } } if (m_uServerIdx == 0) { m_uServerIdx = m_vServers.size(); CIRCSock* pSock = GetIRCSock(); if (pSock) { PutStatus("Jumping servers because this server is no longer in the list"); pSock->Quit(); } } // !Servers // Chans const vector<CChan*>& vChans = User.GetChans(); for (a = 0; a < vChans.size(); a++) { CChan* pNewChan = vChans[a]; CChan* pChan = FindChan(pNewChan->GetName()); if (pChan) { pChan->SetInConfig(pNewChan->InConfig()); } else { AddChan(pNewChan->GetName(), pNewChan->InConfig()); } } for (a = 0; a < m_vChans.size(); a++) { CChan* pChan = m_vChans[a]; CChan* pNewChan = User.FindChan(pChan->GetName()); if (!pNewChan) { pChan->SetInConfig(false); } else { if (bCloneChans) pChan->Clone(*pNewChan); } } // !Chans // CTCP Replies m_mssCTCPReplies.clear(); const MCString& msReplies = User.GetCTCPReplies(); for (MCString::const_iterator it = msReplies.begin(); it != msReplies.end(); ++it) { AddCTCPReply(it->first, it->second); } // !CTCP Replies // Flags SetIRCConnectEnabled(User.GetIRCConnectEnabled()); SetKeepBuffer(User.KeepBuffer()); SetMultiClients(User.MultiClients()); SetBounceDCCs(User.BounceDCCs()); SetUseClientIP(User.UseClientIP()); SetDenyLoadMod(User.DenyLoadMod()); SetAdmin(User.IsAdmin()); SetDenySetBindHost(User.DenySetBindHost()); SetTimestampAppend(User.GetTimestampAppend()); SetTimestampPrepend(User.GetTimestampPrepend()); SetTimestampFormat(User.GetTimestampFormat()); SetTimezoneOffset(User.GetTimezoneOffset()); // !Flags // Modules set<CString> ssUnloadMods; CModules& vCurMods = GetModules(); const CModules& vNewMods = User.GetModules(); for (a = 0; a < vNewMods.size(); a++) { CString sModRet; CModule* pNewMod = vNewMods[a]; CModule* pCurMod = vCurMods.FindModule(pNewMod->GetModName()); if (!pCurMod) { vCurMods.LoadModule(pNewMod->GetModName(), pNewMod->GetArgs(), this, sModRet); } else if (pNewMod->GetArgs() != pCurMod->GetArgs()) { vCurMods.ReloadModule(pNewMod->GetModName(), pNewMod->GetArgs(), this, sModRet); } } for (a = 0; a < vCurMods.size(); a++) { CModule* pCurMod = vCurMods[a]; CModule* pNewMod = vNewMods.FindModule(pCurMod->GetModName()); if (!pNewMod) { ssUnloadMods.insert(pCurMod->GetModName()); } } for (set<CString>::iterator it = ssUnloadMods.begin(); it != ssUnloadMods.end(); ++it) { vCurMods.UnloadModule(*it); } // !Modules return true; }
void CLanguage::LoadFile ( const CString& szLangName, const CString& szEntryName ) { CString szPath ( "../lang/%s/%s.txt", szLangName.c_str (), szEntryName.c_str () ); FILE* fp; #ifdef WIN32 fopen_s ( &fp, szPath.c_str (), "r" ); #else fp = fopen ( szPath.c_str (), "r" ); #endif if ( !fp ) return; CString szCurTopic; CString szCurTopicName; char szBuffer [ 4096 ]; char* p; t_topicMap* map = new t_topicMap ( ); map->set_deleted_key ( (char*)HASH_STRING_DELETED ); map->set_empty_key ( (char*)HASH_STRING_EMPTY ); char* szKey = strdup ( szEntryName.c_str () ); m_entriesMap.insert ( t_entriesMap::value_type ( szKey, map ) ); while ( !feof ( fp ) ) { fgets ( szBuffer, sizeof ( szBuffer ), fp ); p = szBuffer + strlen ( szBuffer ) - 1; while ( p >= szBuffer && ( *p == '\r' || *p == '\n' ) ) { *p = '\0'; --p; } if ( *p == '#' ) { // Es un comentario continue; } if ( *p == '%' && szBuffer [ 0 ] == '%' ) { if ( p > szBuffer + 1 ) { // Inicio de un tema szCurTopic.clear (); *p = '\0'; szCurTopicName = szBuffer + 1; } else { // Fin de un tema if ( szCurTopicName.length () > 0 ) { char* szKey = strdup ( szCurTopicName.c_str () ); map->insert ( t_topicMap::value_type ( szKey, szCurTopic ) ); } szCurTopicName.clear (); } } else { szCurTopic.append ( szBuffer ); szCurTopic.append ( "\n" ); } } fclose ( fp ); }
void CDaemonApp::handleIpcMessage(const CEvent& e, void*) { CIpcMessage* m = static_cast<CIpcMessage*>(e.getDataObject()); switch (m->type()) { case kIpcCommand: { CIpcCommandMessage* cm = static_cast<CIpcCommandMessage*>(m); CString command = cm->command(); // if empty quotes, clear. if (command == "\"\"") { command.clear(); } if (!command.empty()) { LOG((CLOG_DEBUG "new command, elevate=%d command=%s", cm->elevate(), command.c_str())); std::vector<CString> argsArray; CArgParser::splitCommandString(command, argsArray); CArgParser argParser(NULL); const char** argv = argParser.getArgv(argsArray); CServerArgs serverArgs; CClientArgs clientArgs; int argc = static_cast<int>(argsArray.size()); bool server = argsArray[0].find("synergys") != CString::npos ? true : false; CArgsBase* argBase = NULL; if (server) { argParser.parseServerArgs(serverArgs, argc, argv); argBase = &serverArgs; } else { argParser.parseClientArgs(clientArgs, argc, argv); argBase = &clientArgs; } delete[] argv; CString logLevel(argBase->m_logFilter); if (!logLevel.empty()) { try { // change log level based on that in the command string // and change to that log level now. ARCH->setting("LogLevel", logLevel); CLOG->setFilter(logLevel.c_str()); } catch (XArch& e) { LOG((CLOG_ERR "failed to save LogLevel setting, %s", e.what())); } } #if SYSAPI_WIN32 CString logFilename; if (argBase->m_logFile != NULL) { logFilename = CString(argBase->m_logFile); ARCH->setting("LogFilename", logFilename); m_watchdog->setFileLogOutputter(m_fileLogOutputter); command = CArgParser::assembleCommand(argsArray, "--log", 1); LOG((CLOG_DEBUG "removed log file argument and filename %s from command ", logFilename.c_str())); LOG((CLOG_DEBUG "new command, elevate=%d command=%s", cm->elevate(), command.c_str())); } else { m_watchdog->setFileLogOutputter(NULL); } m_fileLogOutputter->setLogFilename(logFilename.c_str()); #endif } else { LOG((CLOG_DEBUG "empty command, elevate=%d", cm->elevate())); } try { // store command in system settings. this is used when the daemon // next starts. ARCH->setting("Command", command); // TODO: it would be nice to store bools/ints... ARCH->setting("Elevate", CString(cm->elevate() ? "1" : "0")); } catch (XArch& e) { LOG((CLOG_ERR "failed to save settings, %s", e.what())); } #if SYSAPI_WIN32 // tell the relauncher about the new command. this causes the // relauncher to stop the existing command and start the new // command. m_watchdog->setCommand(command, cm->elevate()); #endif break; } case kIpcHello: CIpcHelloMessage* hm = static_cast<CIpcHelloMessage*>(m); CString type; switch (hm->clientType()) { case kIpcClientGui: type = "gui"; break; case kIpcClientNode: type = "node"; break; default: type = "unknown"; break; } LOG((CLOG_DEBUG "ipc hello, type=%s", type.c_str())); #if SYSAPI_WIN32 CString watchdogStatus = m_watchdog->isProcessActive() ? "ok" : "error"; LOG((CLOG_INFO "watchdog status: %s", watchdogStatus.c_str())); #endif m_ipcLogOutputter->notifyBuffer(); break; } }
ModHandle CModules::OpenModule(const CString& sModule, const CString& sModPath, bool &bVersionMismatch, bool &bIsGlobal, CString& sDesc, CString& sRetMsg) { // Some sane defaults in case anything errors out below bVersionMismatch = false; bIsGlobal = false; sDesc.clear(); sRetMsg.clear(); for (unsigned int a = 0; a < sModule.length(); a++) { if (((sModule[a] < '0') || (sModule[a] > '9')) && ((sModule[a] < 'a') || (sModule[a] > 'z')) && ((sModule[a] < 'A') || (sModule[a] > 'Z')) && (sModule[a] != '_')) { sRetMsg = "Module names can only contain letters, numbers and underscores, [" + sModule + "] is invalid."; return NULL; } } #ifndef _WIN32 // The second argument to dlopen() has a long history. It seems clear // that (despite what the man page says) we must include either of // RTLD_NOW and RTLD_LAZY and either of RTLD_GLOBAL and RTLD_LOCAL. // // RTLD_NOW vs. RTLD_LAZY: We use RTLD_NOW to avoid znc dying due to // failed symbol lookups later on. Doesn't really seem to have much of a // performance impact. // // RTLD_GLOBAL vs. RTLD_LOCAL: If perl is loaded with RTLD_LOCAL and later on // loads own modules (which it apparently does with RTLD_LAZY), we will die in a // name lookup since one of perl's symbols isn't found. That's worse // than any theoretical issue with RTLD_LOCAL. ModHandle p = dlopen((sModPath).c_str(), RTLD_NOW | RTLD_GLOBAL); #else ModHandle p = dlopen((sModPath).c_str(), RTLD_NOW | RTLD_LOCAL); #endif if (!p) { sRetMsg = "Unable to open module [" + sModule + "] [" + dlerror() + "]"; return NULL; } typedef double (*dFP)(); dFP Version = (dFP) dlsym(p, "ZNCModVersion"); if (!Version) { dlclose(p); sRetMsg = "Could not find ZNCModVersion() in module [" + sModule + "]"; return NULL; } typedef bool (*bFP)(); bFP IsGlobal = (bFP) dlsym(p, "ZNCModGlobal"); if (!IsGlobal) { dlclose(p); sRetMsg = "Could not find ZNCModGlobal() in module [" + sModule + "]"; return NULL; } typedef const char *(*sFP)(); sFP GetDesc = (sFP) dlsym(p, "ZNCModDescription"); if (!GetDesc) { dlclose(p); sRetMsg = "Could not find ZNCModDescription() in module [" + sModule + "]"; return false; } if (CModule::GetCoreVersion() != Version()) { bVersionMismatch = true; #ifndef _WIN32 sRetMsg = "Version mismatch, recompile this module."; #else sRetMsg = "Module version is '" + CString(Version(), 3) + "', but core expects '" + CString(CModule::GetCoreVersion(), 3) + "'. Please re-download/re-install/re-compile the module."; #endif } else { sRetMsg = ""; bVersionMismatch = false; bIsGlobal = IsGlobal(); sDesc = GetDesc(); } return p; }
bool CUser::ParseConfig(CConfig* pConfig, CString& sError) { TOption<const CString&> StringOptions[] = { { "nick", &CUser::SetNick }, { "quitmsg", &CUser::SetQuitMsg }, { "altnick", &CUser::SetAltNick }, { "ident", &CUser::SetIdent }, { "realname", &CUser::SetRealName }, { "chanmodes", &CUser::SetDefaultChanModes }, { "bindhost", &CUser::SetBindHost }, { "vhost", &CUser::SetBindHost }, { "dccbindhost", &CUser::SetDCCBindHost }, { "dccvhost", &CUser::SetDCCBindHost }, { "timestampformat", &CUser::SetTimestampFormat }, { "skin", &CUser::SetSkinName }, }; size_t numStringOptions = sizeof(StringOptions) / sizeof(StringOptions[0]); TOption<unsigned int> UIntOptions[] = { { "jointries", &CUser::SetJoinTries }, { "maxjoins", &CUser::SetMaxJoins }, }; size_t numUIntOptions = sizeof(UIntOptions) / sizeof(UIntOptions[0]); TOption<bool> BoolOptions[] = { { "keepbuffer", &CUser::SetKeepBuffer }, { "multiclients", &CUser::SetMultiClients }, { "bouncedccs", &CUser::SetBounceDCCs }, { "denyloadmod", &CUser::SetDenyLoadMod }, { "admin", &CUser::SetAdmin }, { "denysetbindhost", &CUser::SetDenySetBindHost }, { "denysetvhost", &CUser::SetDenySetBindHost }, { "appendtimestamp", &CUser::SetTimestampAppend }, { "prependtimestamp", &CUser::SetTimestampPrepend }, { "ircconnectenabled", &CUser::SetIRCConnectEnabled }, }; size_t numBoolOptions = sizeof(BoolOptions) / sizeof(BoolOptions[0]); for (size_t i = 0; i < numStringOptions; i++) { CString sValue; if (pConfig->FindStringEntry(StringOptions[i].name, sValue)) (this->*StringOptions[i].pSetter)(sValue); } for (size_t i = 0; i < numUIntOptions; i++) { CString sValue; if (pConfig->FindStringEntry(UIntOptions[i].name, sValue)) (this->*UIntOptions[i].pSetter)(sValue.ToUInt()); } for (size_t i = 0; i < numBoolOptions; i++) { CString sValue; if (pConfig->FindStringEntry(BoolOptions[i].name, sValue)) (this->*BoolOptions[i].pSetter)(sValue.ToBool()); } VCString vsList; VCString::const_iterator vit; pConfig->FindStringVector("allow", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { AddAllowedHost(*vit); } pConfig->FindStringVector("ctcpreply", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { const CString& sValue = *vit; AddCTCPReply(sValue.Token(0), sValue.Token(1, true)); } pConfig->FindStringVector("server", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { CUtils::PrintAction("Adding Server [" + *vit + "]"); CUtils::PrintStatus(AddServer(*vit)); } pConfig->FindStringVector("chan", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { AddChan(*vit, true); } CString sValue; if (pConfig->FindStringEntry("buffer", sValue)) SetBufferCount(sValue.ToUInt(), true); if (pConfig->FindStringEntry("awaysuffix", sValue)) { CUtils::PrintMessage("WARNING: AwaySuffix has been depricated, instead try -> LoadModule = awaynick %nick%_" + sValue); } if (pConfig->FindStringEntry("autocycle", sValue)) { if (sValue.Equals("true")) CUtils::PrintError("WARNING: AutoCycle has been removed, instead try -> LoadModule = autocycle"); } if (pConfig->FindStringEntry("keepnick", sValue)) { if (sValue.Equals("true")) CUtils::PrintError("WARNING: KeepNick has been deprecated, instead try -> LoadModule = keepnick"); } if (pConfig->FindStringEntry("statusprefix", sValue)) { if (!SetStatusPrefix(sValue)) { sError = "Invalid StatusPrefix [" + sValue + "] Must be 1-5 chars, no spaces."; CUtils::PrintError(sError); return false; } } if (pConfig->FindStringEntry("timezoneoffset", sValue)) { SetTimezoneOffset(sValue.ToDouble()); } if (pConfig->FindStringEntry("timestamp", sValue)) { if (!sValue.Trim_n().Equals("true")) { if (sValue.Trim_n().Equals("append")) { SetTimestampAppend(true); SetTimestampPrepend(false); } else if (sValue.Trim_n().Equals("prepend")) { SetTimestampAppend(false); SetTimestampPrepend(true); } else if (sValue.Trim_n().Equals("false")) { SetTimestampAppend(false); SetTimestampPrepend(false); } else { SetTimestampFormat(sValue); } } } if (pConfig->FindStringEntry("dcclookupmethod", sValue)) SetUseClientIP(sValue.Equals("Client")); pConfig->FindStringEntry("pass", sValue); // There are different formats for this available: // Pass = <plain text> // Pass = <md5 hash> - // Pass = plain#<plain text> // Pass = <hash name>#<hash> // Pass = <hash name>#<salted hash>#<salt># // 'Salted hash' means hash of 'password' + 'salt' // Possible hashes are md5 and sha256 if (sValue.Right(1) == "-") { sValue.RightChomp(); sValue.Trim(); SetPass(sValue, CUser::HASH_MD5); } else { CString sMethod = sValue.Token(0, false, "#"); CString sPass = sValue.Token(1, true, "#"); if (sMethod == "md5" || sMethod == "sha256") { CUser::eHashType type = CUser::HASH_MD5; if (sMethod == "sha256") type = CUser::HASH_SHA256; CString sSalt = sPass.Token(1, false, "#"); sPass = sPass.Token(0, false, "#"); SetPass(sPass, type, sSalt); } else if (sMethod == "plain") { SetPass(sPass, CUser::HASH_NONE); } else { SetPass(sValue, CUser::HASH_NONE); } } CConfig::SubConfig subConf; CConfig::SubConfig::const_iterator subIt; pConfig->FindSubConfig("chan", subConf); for (subIt = subConf.begin(); subIt != subConf.end(); ++subIt) { const CString& sChanName = subIt->first; CConfig* pSubConf = subIt->second.m_pSubConfig; CChan* pChan = new CChan(sChanName, this, true, pSubConf); if (!pSubConf->empty()) { sError = "Unhandled lines in config for User [" + GetUserName() + "], Channel [" + sChanName + "]!"; CUtils::PrintError(sError); CZNC::DumpConfig(pSubConf); return false; } // Save the channel name, because AddChan // deletes the CChannel*, if adding fails sError = pChan->GetName(); if (!AddChan(pChan)) { sError = "Channel [" + sError + "] defined more than once"; CUtils::PrintError(sError); return false; } sError.clear(); } pConfig->FindStringVector("loadmodule", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { sValue = *vit; CString sModName = sValue.Token(0); // XXX Legacy crap, added in znc 0.089 if (sModName == "discon_kick") { CUtils::PrintMessage("NOTICE: [discon_kick] was renamed, loading [disconkick] instead"); sModName = "disconkick"; } CUtils::PrintAction("Loading Module [" + sModName + "]"); CString sModRet; CString sArgs = sValue.Token(1, true); bool bModRet = GetModules().LoadModule(sModName, sArgs, this, sModRet); CUtils::PrintStatus(bModRet, sModRet); if (!bModRet) { sError = sModRet; return false; } continue; } return true; }
bool CIRCNetwork::ParseConfig(CConfig *pConfig, CString& sError, bool bUpgrade) { VCString vsList; if (!bUpgrade) { TOption<const CString&> StringOptions[] = { { "nick", &CIRCNetwork::SetNick }, { "altnick", &CIRCNetwork::SetAltNick }, { "ident", &CIRCNetwork::SetIdent }, { "realname", &CIRCNetwork::SetRealName }, { "bindhost", &CIRCNetwork::SetBindHost }, { "encoding", &CIRCNetwork::SetEncoding }, { "quitmsg", &CIRCNetwork::SetQuitMsg }, }; TOption<bool> BoolOptions[] = { { "ircconnectenabled", &CIRCNetwork::SetIRCConnectEnabled }, }; TOption<double> DoubleOptions[] = { { "floodrate", &CIRCNetwork::SetFloodRate }, }; TOption<short unsigned int> SUIntOptions[] = { { "floodburst", &CIRCNetwork::SetFloodBurst }, { "joindelay", &CIRCNetwork::SetJoinDelay }, }; for (const auto& Option : StringOptions) { CString sValue; if (pConfig->FindStringEntry(Option.name, sValue)) (this->*Option.pSetter)(sValue); } for (const auto& Option : BoolOptions) { CString sValue; if (pConfig->FindStringEntry(Option.name, sValue)) (this->*Option.pSetter)(sValue.ToBool()); } for (const auto& Option : DoubleOptions) { double fValue; if (pConfig->FindDoubleEntry(Option.name, fValue)) (this->*Option.pSetter)(fValue); } for (const auto& Option : SUIntOptions) { unsigned short value; if (pConfig->FindUShortEntry(Option.name, value)) (this->*Option.pSetter)(value); } pConfig->FindStringVector("loadmodule", vsList); for (const CString& sValue : vsList) { CString sModName = sValue.Token(0); CString sNotice = "Loading network module [" + sModName + "]"; // XXX Legacy crap, added in ZNC 0.203, modified in 0.207 // Note that 0.203 == 0.207 if (sModName == "away") { sNotice = "NOTICE: [away] was renamed, loading [awaystore] instead"; sModName = "awaystore"; } // XXX Legacy crap, added in ZNC 0.207 if (sModName == "autoaway") { sNotice = "NOTICE: [autoaway] was renamed, loading [awaystore] instead"; sModName = "awaystore"; } // XXX Legacy crap, added in 1.1; fakeonline module was dropped in 1.0 and returned in 1.1 if (sModName == "fakeonline") { sNotice = "NOTICE: [fakeonline] was renamed, loading [modules_online] instead"; sModName = "modules_online"; } CString sModRet; CString sArgs = sValue.Token(1, true); bool bModRet = LoadModule(sModName, sArgs, sNotice, sModRet); if (!bModRet) { // XXX The awaynick module was retired in 1.6 (still available as external module) if (sModName == "awaynick") { // load simple_away instead, unless it's already on the list if (std::find(vsList.begin(), vsList.end(), "simple_away") == vsList.end()) { sNotice = "Loading network module [simple_away] instead"; sModName = "simple_away"; // not a fatal error if simple_away is not available LoadModule(sModName, sArgs, sNotice, sModRet); } } else { sError = sModRet; return false; } } } } pConfig->FindStringVector("server", vsList); for (const CString& sServer : vsList) { CUtils::PrintAction("Adding server [" + sServer + "]"); CUtils::PrintStatus(AddServer(sServer)); } pConfig->FindStringVector("trustedserverfingerprint", vsList); for (const CString& sFP : vsList) { AddTrustedFingerprint(sFP); } pConfig->FindStringVector("chan", vsList); for (const CString& sChan : vsList) { AddChan(sChan, true); } CConfig::SubConfig subConf; CConfig::SubConfig::const_iterator subIt; pConfig->FindSubConfig("chan", subConf); for (subIt = subConf.begin(); subIt != subConf.end(); ++subIt) { const CString& sChanName = subIt->first; CConfig* pSubConf = subIt->second.m_pSubConfig; CChan* pChan = new CChan(sChanName, this, true, pSubConf); if (!pSubConf->empty()) { sError = "Unhandled lines in config for User [" + m_pUser->GetUserName() + "], Network [" + GetName() + "], Channel [" + sChanName + "]!"; CUtils::PrintError(sError); CZNC::DumpConfig(pSubConf); return false; } // Save the channel name, because AddChan // deletes the CChannel*, if adding fails sError = pChan->GetName(); if (!AddChan(pChan)) { sError = "Channel [" + sError + "] defined more than once"; CUtils::PrintError(sError); return false; } sError.clear(); } return true; }
void ListServer_Main() { static CBuffer packetBuffer; CStringList lines; if ( listServerFields[5] == "localhost" ) return; if (!lsConnected) return; // Read any new data into the socket. if ( listServer.getData() == -1 ) { errorOut( "serverlog.txt", "Disconnected from list server." ); lsConnected = false; return; } // Grab all the data from the socket buffer. packetBuffer << listServer.getBuffer(); listServer.getBuffer().clear(); // Search for a packet. If none is found, break out of the loop. while (packetBuffer.length() != 0) { CPacket line; if (!nextIsRaw) { int lineEnd = packetBuffer.find( '\n' ); if ( lineEnd == -1 ) return; // Copy the packet out and remove the \n line = packetBuffer.copy( 0, lineEnd + 1 ); packetBuffer.remove(0, line.length()); line.remove(line.length() - 1, 1); } else { if (packetBuffer.length() < rawPacketSize) return; line.writeBytes(packetBuffer.readChars(rawPacketSize), rawPacketSize); packetBuffer.remove(0, line.length()); line.remove(line.length() - 1, 1); nextIsRaw = false; } packetBuffer.setRead(0); int messageId = line.readByte1(); switch (messageId) { case GSVOLD: { printf("[%s] SERVER VERSION CHECK - Current: %i, Latest: %i - Old version, please upgrade.\n", getTimeStr(1).text(), GSERVER_BUILD, line.readByte2()); break; } case GSVCURRENT: { printf("[%s] SERVER VERSION CHECK - Current: %i, Latest: %i - You are up to date :)\n", getTimeStr(1).text(), GSERVER_BUILD, GSERVER_BUILD); break; } case GSVACCOUNT: { CString accountName = line.readChars(line.readByte1()); CString errorMsg = line.readString(""); for (int i = 0; i < newPlayers.count(); i++) { CPlayer *player = (CPlayer *)newPlayers[i]; if (player->accountName.comparei(accountName) == 0) { // The serverlist will return case sensitive account names. // This helps case sensitive file systems open/save the correct // acount. player->accountName = accountName; if (errorMsg == "SUCCESS") { player->sendAccount(); } else { player->sendPacket(CPacket() << (char)DISMESSAGE << errorMsg); player->deleteMe = true; } break; } } break; } case GSVGUILD: { int playerId = line.readByte2(); CPlayer *player = (CPlayer *)playerIds[playerId]; if (player != NULL) { CString nick = line.readChars((unsigned char)line.readByte1()); CString guild = nick.copy( nick.findl( '(' ) ).remove( ")" ); if ( globalGuilds == false ) { if ( globalGuildList.find( guild ) != -1 ) player->setNick(nick, false); } else player->setNick(nick, false); } break; } case GSVPROFILE: /* Unsure if this works, temp */ { CPacket profile; CPlayer *player1 = (CPlayer *)playerIds[line.readByte2()]; CPlayer *player2 = findPlayerId(line.readChars(line.readByte1())); if (player1 == NULL || player2 == NULL) return; profile << (char)player2->accountName.length() << player2->accountName << line.readString(""); int time = player2->onlineSecs; CString line2; //Online time line2 << toString((int)time/3600) << " hrs "; line2 << toString((int)(time/60)%60) << " mins "; line2 << toString((int)time%60) << " secs"; profile << (char)line2.length() << line2; for (int i = 0; i < profileList.count(); i++) { CStringList a; a.load(profileList[i].text(), ":="); if (a[0].length() < 1) continue; CString n; if (a[1] == "playerkills") n = toString(player2->kills); else if (a[1] == "playerdeaths") n = toString(player2->deaths); else if (a[1] == "playerfullhearts") { if ( (float)(int)player2->maxPower == (float)player2->maxPower ) n = toString((int)player2->maxPower); else { n = toString(player2->maxPower); n = n.copy( 0, n.length() - 1 ); } } else if (a[1] == "playerrating") n = toString((int)player2->rating) << "/" << toString((int)player2->deviation); else if (a[1] == "playerap") n = toString(player2->ap); else if (a[1] == "playerrupees") n = toString(player2->rubins); else if (a[1] == "playerswordpower") n = toString(player2->swordPower); else if (a[1] == "canspin") n = (player2->status & 64 ? "true" : "false"); else if (a[1] == "playerhearts") { if ( (float)(int)player2->power == (float)player2->power ) n = toString((int)player2->power); else { n = toString(player2->power); n = n.copy( 0, n.length() - 1 ); } } else if (a[1] == "playerdarts") n = toString(player2->darts); else if (a[1] == "playerbombs") n = toString(player2->bombs); else if (a[1] == "playermp") n = toString(player2->magicPoints); else if (a[1] == "playershieldpower") n = toString(player2->shieldPower); else if (a[1] == "playerglovepower") n = toString(player2->glovePower); else { for (int i = 0; i < player2->myFlags.count(); i++) { CStringList b; b.load(player2->myFlags[i].text(), "="); if (b[0] == a[1]) { n = b[1]; break; } } } profile << (char)(a[0].length() + n.length() + 2) << a[0] << ":=" << n; } player1->sendPacket(CPacket() << (char)DPROFILE << profile); break; } case GSVMSG: printf("[%s] %s\n", getTimeStr(1).text(), line.readString("")); break; case GSVFILESTART3: { unsigned char pTy = (unsigned char)line.readByte1(); CString fileData, fileName = CString() << dataDir << "global" << fSep; switch (pTy) { case 0: // head fileName << "heads" << fSep; break; case 1: // body fileName << "bodies" << fSep; break; case 2: // sword fileName << "swords" << fSep; break; case 3: // shield fileName << "shields" << fSep; break; } fileName << line.readChars(line.readByte1()); fileData.save(fileName.text()); break; } case GSVFILEDATA3: { unsigned char pTy = (unsigned char)line.readByte1(); CString fileData, fileName, newData, shortName; shortName = line.readChars(line.readByte1()); fileName = CString() << dataDir << "global" << fSep; switch (pTy) { case 0: // head fileName << "heads" << fSep; break; case 1: // body fileName << "bodies" << fSep; break; case 2: // sword fileName << "swords" << fSep; break; case 3: // shield fileName << "shields" << fSep; break; } fileName << shortName.text(); newData.writeBytes(line.readChars(line.bytesLeft()), line.bytesLeft()); fileData.load(fileName.text()); fileData << newData; fileData.save(fileName.text()); break; } case GSVFILEEND3: { CPlayer *player = (CPlayer *)playerIds[line.readByte2()]; int type = line.readByte1(); char doCompress = line.readByte1(); time_t modTime = line.readByte5(); int fileLength = line.readByte5(); CString shortName = line.readString(""); CString fileName = CString() << dataDir << "global" << fSep; switch (type) { case 0: // head fileName << "heads" << fSep; break; case 1: // body fileName << "bodies" << fSep; break; case 2: // sword fileName << "swords" << fSep; break; case 3: // shield fileName << "shields" << fSep; break; } fileName << shortName.text(); // If the file was sent compressed, we need to uncompress it. if (doCompress == 1) { // Open the file so we can uncompress it. CString fileData; fileData.load(fileName.text()); // Uncompress the file. char* buffer = new char[fileLength]; memset((void*)buffer, 0, fileLength); int cLen = fileLength; int error = uncompress((Bytef*)buffer,(uLongf*)&cLen,(const Bytef*)fileData.text(), fileData.length()); if (error != Z_OK) printf("Failed to decompress file: %s\n", shortName.text()); // Save the file now. fileData.clear(); fileData.writeBytes(buffer, cLen); fileData.save(fileName.text()); delete [] buffer; } // Set the file mod time. if (setFileModTime(fileName.text(), modTime) == false) printf("** [WARNING] Could not set modification time on file %s\n", shortName.text()); if (player) { player->fileList.add(new COutFile(shortName, 0)); switch (type) { case 0: // head player->headImage = shortName; player->updateProp(HEADGIF); break; case 1: // body player->bodyImage = shortName; player->updateProp(BODYIMG); break; case 2: // sword player->swordImage = shortName; player->updateProp(SWORDPOWER); break; case 3: // shield player->shieldImage = shortName; player->updateProp(SHIELDPOWER); break; } } break; } case GSVPING: // Sent every 60 seconds, do nothing. break; case GSVRAWDATA: nextIsRaw = true; rawPacketSize = line.readByte3(); break; default: printf("[%s] Invalid List Server Message: %i\n", getTimeStr(1).text(), messageId); break; } } }