void OnUnset(User* source, Channel* chan) override { // Unset the per-membership extension when the mode is removed const Channel::MemberMap& users = chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) MemberInfoExt.unset(i->second); }
ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { ModeAction rv = ParamChannelModeHandler::OnModeChange(source, dest, channel, parameter, adding); if (rv == MODEACTION_ALLOW && !adding) ext.unset(channel); return rv; }
virtual void OnUserDisconnect(LocalUser *user) { /* User disconnect (generic socket detatch event) */ IdentRequestSocket *isock = ext.get(user); if (isock) { isock->Close(); ext.unset(user); } }
CmdResult remove_watch(User* user, const char* nick) { // removing an item from the list if (!ServerInstance->IsNick(nick)) { user->WriteNumeric(942, "%s :Invalid nickname", nick); return CMD_FAILURE; } watchlist* wl = ext.get(user); if (wl) { /* Yup, is on my list */ watchlist::iterator n = wl->find(nick); if (!wl) return CMD_FAILURE; if (n != wl->end()) { if (!n->second.empty()) user->WriteNumeric(602, "%s %s :stopped watching", n->first.c_str(), n->second.c_str()); else user->WriteNumeric(602, "%s * * 0 :stopped watching", nick); wl->erase(n); } if (wl->empty()) { ext.unset(user); } watchentries::iterator x = whos_watching_me->find(nick); if (x != whos_watching_me->end()) { /* People are watching this user, am i one of them? */ std::deque<User*>::iterator n2 = std::find(x->second.begin(), x->second.end(), user); if (n2 != x->second.end()) /* I'm no longer watching you... */ x->second.erase(n2); if (x->second.empty()) /* nobody else is, either. */ whos_watching_me->erase(nick); } } return CMD_SUCCESS; }
/* This triggers pretty regularly, we can use it in preference to * creating a Timer object and especially better than creating a * Timer per ident lookup! */ virtual ModResult OnCheckReady(LocalUser *user) { /* Does user have an ident socket attached at all? */ IdentRequestSocket *isock = ext.get(user); if (!isock) { ServerInstance->Logs->Log("m_ident",DEBUG, "No ident socket :("); return MOD_RES_PASSTHRU; } ServerInstance->Logs->Log("m_ident",DEBUG, "Has ident_socket"); time_t compare = isock->age; compare += RequestTimeout; /* Check for timeout of the socket */ if (ServerInstance->Time() >= compare) { /* Ident timeout */ user->WriteServ("NOTICE Auth :*** Ident request timed out."); ServerInstance->Logs->Log("m_ident",DEBUG, "Timeout"); } else if (!isock->HasResult()) { // time still good, no result yet... hold the registration ServerInstance->Logs->Log("m_ident",DEBUG, "No result yet"); return MOD_RES_DENY; } ServerInstance->Logs->Log("m_ident",DEBUG, "Yay, result!"); /* wooo, got a result (it will be good, or bad) */ if (isock->result.empty()) { user->ident.insert(0, 1, '~'); user->WriteServ("NOTICE Auth :*** Could not find your ident, using %s instead.", user->ident.c_str()); } else { user->ident = isock->result; user->WriteServ("NOTICE Auth :*** Found your ident, '%s'", user->ident.c_str()); } isock->Close(); ext.unset(user); return MOD_RES_PASSTHRU; }
ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { if (adding) { std::string::size_type colon = parameter.find(':'); if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str()); return MODEACTION_DENY; } /* Set up the flood parameters for this channel */ unsigned int njoins = ConvToInt(parameter.substr(0, colon)); unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); if ((njoins<1) || (nsecs<1)) { source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str()); return MODEACTION_DENY; } joinfloodsettings jfs(nsecs, njoins); joinfloodsettings* f = ext.get(channel); if ((f) && (*f == jfs)) // mode params match return MODEACTION_DENY; ext.set(channel, jfs); parameter = ConvToStr(njoins) + ":" + ConvToStr(nsecs); channel->SetModeParam(this, parameter); return MODEACTION_ALLOW; } else { if (!channel->IsModeSet(this)) return MODEACTION_DENY; joinfloodsettings* f = ext.get(channel); if (f) { ext.unset(channel); channel->SetModeParam(this, ""); return MODEACTION_ALLOW; } } return MODEACTION_DENY; }
ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { if (adding) { std::string::size_type colon = parameter.find(':'); if (colon == std::string::npos) return MODEACTION_DENY; std::string duration = parameter.substr(colon+1); if ((IS_LOCAL(source)) && ((duration.length() > 10) || (!IsValidDuration(duration)))) return MODEACTION_DENY; unsigned int len = ConvToInt(parameter.substr(0, colon)); int time = InspIRCd::Duration(duration); if (len == 0 || time < 0) return MODEACTION_DENY; if (len > maxlines && IS_LOCAL(source)) return MODEACTION_DENY; if (len > maxlines) len = maxlines; if (parameter == channel->GetModeParameter(this)) return MODEACTION_DENY; HistoryList* history = ext.get(channel); if (history) { // Shrink the list if the new line number limit is lower than the old one if (len < history->lines.size()) history->lines.erase(history->lines.begin(), history->lines.begin() + (history->lines.size() - len)); history->maxlen = len; history->maxtime = time; } else { ext.set(channel, new HistoryList(len, time)); } } else { if (!channel->IsModeSet(this)) return MODEACTION_DENY; ext.unset(channel); } return MODEACTION_ALLOW; }
ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { if (adding) { std::string::size_type colon = parameter.find(':'); if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str()); return MODEACTION_DENY; } /* Set up the flood parameters for this channel */ bool ban = (parameter[0] == '*'); unsigned int nlines = ConvToInt(parameter.substr(ban ? 1 : 0, ban ? colon-1 : colon)); unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); if ((nlines<2) || (nsecs<1)) { source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str()); return MODEACTION_DENY; } floodsettings* f = ext.get(channel); if ((f) && (nlines == f->lines) && (nsecs == f->secs) && (ban == f->ban)) // mode params match return MODEACTION_DENY; ext.set(channel, new floodsettings(ban, nsecs, nlines)); parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" + ConvToStr(nsecs); return MODEACTION_ALLOW; } else { if (!channel->IsModeSet(this)) return MODEACTION_DENY; ext.unset(channel); return MODEACTION_ALLOW; } }
ModeAction OnModeChange(User* source, User* dest, Channel* chan, std::string& parameter, bool adding) { if (adding) { std::string::size_type colon = parameter.find(':'); if (colon == std::string::npos || parameter.find('-') != std::string::npos) { source->WriteNumeric(608, "%s %s :Invalid join/part spam parameter", source->nick.c_str(), chan->name.c_str()); return MODEACTION_DENY; } unsigned int ncycles = ConvToInt(parameter.substr(0, colon)); unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); if (ncycles < 2 || nsecs < 1) { source->WriteNumeric(608, "%s %s :Invalid join/part spam parameter", source->nick.c_str(), chan->name.c_str()); return MODEACTION_DENY; } joinpartspamsettings* jpss = ext.get(chan); if (jpss && ncycles == jpss->cycles && nsecs == jpss->secs) return MODEACTION_DENY; ext.set(chan, new joinpartspamsettings(ncycles, nsecs)); parameter = ConvToStr(ncycles) + ":" + ConvToStr(nsecs); chan->SetModeParam(GetModeChar(), parameter); return MODEACTION_ALLOW; } else { if (!chan->IsModeSet(GetModeChar())) return MODEACTION_DENY; ext.unset(chan); chan->SetModeParam(GetModeChar(), ""); return MODEACTION_ALLOW; } }
CmdResult Handle (const std::vector<std::string>& parameters, User *user) { if (!parameters.size()) { // no parameters, show the current silence list. silencelist* sl = ext.get(user); // if the user has a silence list associated with their user record, show it if (sl) { for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++) { std::string decomppattern = DecompPattern(c->second); user->WriteNumeric(271, "%s %s %s %s",user->nick.c_str(), user->nick.c_str(),c->first.c_str(), decomppattern.c_str()); } } user->WriteNumeric(272, "%s :End of Silence List",user->nick.c_str()); return CMD_SUCCESS; } else if (parameters.size() > 0) { // one or more parameters, add or delete entry from the list (only the first parameter is used) std::string mask = parameters[0].substr(1); char action = parameters[0][0]; // Default is private and notice so clients do not break int pattern = CompilePattern("pn"); // if pattern supplied, use it if (parameters.size() > 1) { pattern = CompilePattern(parameters[1].c_str()); } if (pattern == 0) { user->WriteServ("NOTICE %s :Bad SILENCE pattern",user->nick.c_str()); return CMD_INVALID; } if (!mask.length()) { // 'SILENCE +' or 'SILENCE -', assume *!*@* mask = "*!*@*"; } ModeParser::CleanMask(mask); if (action == '-') { std::string decomppattern = DecompPattern(pattern); // fetch their silence list silencelist* sl = ext.get(user); // does it contain any entries and does it exist? if (sl) { for (silencelist::iterator i = sl->begin(); i != sl->end(); i++) { // search through for the item irc::string listitem = i->first.c_str(); if (listitem == mask && i->second == pattern) { sl->erase(i); user->WriteNumeric(950, "%s %s :Removed %s %s from silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str()); if (!sl->size()) { ext.unset(user); } return CMD_SUCCESS; } } } user->WriteNumeric(952, "%s %s :%s %s does not exist on your silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str()); } else if (action == '+') { // fetch the user's current silence list silencelist* sl = ext.get(user); if (!sl) { sl = new silencelist; ext.set(user, sl); } if (sl->size() > maxsilence) { user->WriteNumeric(952, "%s %s :Your silence list is full",user->nick.c_str(), user->nick.c_str()); return CMD_FAILURE; } std::string decomppattern = DecompPattern(pattern); for (silencelist::iterator n = sl->begin(); n != sl->end(); n++) { irc::string listitem = n->first.c_str(); if (listitem == mask && n->second == pattern) { user->WriteNumeric(952, "%s %s :%s %s is already on your silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str()); return CMD_FAILURE; } } if (((pattern & SILENCE_EXCLUDE) > 0)) { sl->push_front(silenceset(mask,pattern)); } else { sl->push_back(silenceset(mask,pattern)); } user->WriteNumeric(951, "%s %s :Added %s %s to silence list",user->nick.c_str(), user->nick.c_str(), mask.c_str(), decomppattern.c_str()); return CMD_SUCCESS; } } return CMD_SUCCESS; }
bool BeforeMode(User* source, User* dest, Channel* channel, std::string ¶m, bool adding) { /* nick!ident@host -> nick!ident@host * nick!ident@host#chan -> nick!ident@host#chan * nick@host#chan -> nick!*@host#chan * nick!ident#chan -> nick!ident@*#chan * nick#chan -> nick!*@*#chan */ if ((channel) && !param.empty()) { BanRedirectList* redirects; std::string mask[4]; enum { NICK, IDENT, HOST, CHAN } current = NICK; std::string::iterator start_pos = param.begin(); if (param.length() >= 2 && param[1] == ':') return true; if (param.find('#') == std::string::npos) return true; ListModeBase* banlm = static_cast<ListModeBase*>(*ban); unsigned int maxbans = banlm->GetLimit(channel); ListModeBase::ModeList* list = banlm->GetList(channel); if ((list) && (adding) && (maxbans <= list->size())) { source->WriteNumeric(ERR_BANLISTFULL, "%s :Channel ban list for %s is full (maximum entries for this channel is %u)", channel->name.c_str(), channel->name.c_str(), maxbans); return false; } for(std::string::iterator curr = start_pos; curr != param.end(); curr++) { switch(*curr) { case '!': if (current != NICK) break; mask[current].assign(start_pos, curr); current = IDENT; start_pos = curr+1; break; case '@': if (current != IDENT) break; mask[current].assign(start_pos, curr); current = HOST; start_pos = curr+1; break; case '#': if (current == CHAN) break; mask[current].assign(start_pos, curr); current = CHAN; start_pos = curr; break; } } if(mask[current].empty()) { mask[current].assign(start_pos, param.end()); } /* nick@host wants to be changed to *!nick@host rather than nick!*@host... */ if(mask[NICK].length() && mask[HOST].length() && mask[IDENT].empty()) { /* std::string::swap() is fast - it runs in constant time */ mask[NICK].swap(mask[IDENT]); } if (!mask[NICK].empty() && mask[IDENT].empty() && mask[HOST].empty()) { if (mask[NICK].find('.') != std::string::npos || mask[NICK].find(':') != std::string::npos) { mask[NICK].swap(mask[HOST]); } } for(int i = 0; i < 3; i++) { if(mask[i].empty()) { mask[i].assign("*"); } } param.assign(mask[NICK]).append(1, '!').append(mask[IDENT]).append(1, '@').append(mask[HOST]); if(mask[CHAN].length()) { if (adding && IS_LOCAL(source)) { if (!ServerInstance->IsChannel(mask[CHAN])) { source->WriteNumeric(ERR_NOSUCHCHANNEL, "%s :Invalid channel name in redirection (%s)", channel->name.c_str(), mask[CHAN].c_str()); return false; } Channel *c = ServerInstance->FindChan(mask[CHAN]); if (!c) { source->WriteNumeric(690, ":Target channel %s must exist to be set as a redirect.", mask[CHAN].c_str()); return false; } else if (adding && c->GetPrefixValue(source) < OP_VALUE) { source->WriteNumeric(690, ":You must be opped on %s to set it as a redirect.", mask[CHAN].c_str()); return false; } if (assign(channel->name) == mask[CHAN]) { source->WriteNumeric(690, "%s :You cannot set a ban redirection to the channel the ban is on", channel->name.c_str()); return false; } } if(adding) { /* It's a properly valid redirecting ban, and we're adding it */ redirects = extItem.get(channel); if (!redirects) { redirects = new BanRedirectList; extItem.set(channel, redirects); } /* Here 'param' doesn't have the channel on it yet */ redirects->push_back(BanRedirectEntry(mask[CHAN], param)); /* Now it does */ param.append(mask[CHAN]); } else { /* Removing a ban, if there's no extensible there are no redirecting bans and we're fine. */ redirects = extItem.get(channel); if (redirects) { /* But there were, so we need to remove the matching one if there is one */ for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++) { /* Ugly as f**k */ if((irc::string(redir->targetchan.c_str()) == irc::string(mask[CHAN].c_str())) && (irc::string(redir->banmask.c_str()) == irc::string(param.c_str()))) { redirects->erase(redir); if(redirects->empty()) { extItem.unset(channel); } break; } } } /* Append the channel so the default +b handler can remove the entry too */ param.append(mask[CHAN]); } } } return true; }
CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { if (parameters.empty()) { watchlist* wl = ext.get(user); if (wl) { for (watchlist::iterator q = wl->begin(); q != wl->end(); q++) { if (!q->second.empty()) user->WriteNumeric(604, "%s %s :is online", q->first.c_str(), q->second.c_str()); } } user->WriteNumeric(607, ":End of WATCH list"); } else if (parameters.size() > 0) { for (int x = 0; x < (int)parameters.size(); x++) { const char *nick = parameters[x].c_str(); if (!strcasecmp(nick,"C")) { // watch clear watchlist* wl = ext.get(user); if (wl) { for (watchlist::iterator i = wl->begin(); i != wl->end(); i++) { watchentries::iterator i2 = whos_watching_me->find(i->first); if (i2 != whos_watching_me->end()) { /* People are watching this user, am i one of them? */ std::deque<User*>::iterator n = std::find(i2->second.begin(), i2->second.end(), user); if (n != i2->second.end()) /* I'm no longer watching you... */ i2->second.erase(n); if (i2->second.empty()) /* nobody else is, either. */ whos_watching_me->erase(i2); } } ext.unset(user); } } else if (!strcasecmp(nick,"L")) { watchlist* wl = ext.get(user); if (wl) { for (watchlist::iterator q = wl->begin(); q != wl->end(); q++) { if (!q->second.empty()) { user->WriteNumeric(604, "%s %s :is online", q->first.c_str(), q->second.c_str()); User *targ = ServerInstance->FindNick(q->first.c_str()); if (targ->IsAway()) { user->WriteNumeric(609, "%s %s %s %lu :is away", targ->nick.c_str(), targ->ident.c_str(), targ->dhost.c_str(), (unsigned long) targ->awaytime); } } else user->WriteNumeric(605, "%s * * 0 :is offline", q->first.c_str()); } } user->WriteNumeric(607, ":End of WATCH list"); } else if (!strcasecmp(nick,"S")) { watchlist* wl = ext.get(user); int you_have = 0; int youre_on = 0; std::string list; if (wl) { for (watchlist::iterator q = wl->begin(); q != wl->end(); q++) list.append(q->first.c_str()).append(" "); you_have = wl->size(); } watchentries::iterator i2 = whos_watching_me->find(user->nick.c_str()); if (i2 != whos_watching_me->end()) youre_on = i2->second.size(); user->WriteNumeric(603, ":You have %d and are on %d WATCH entries", you_have, youre_on); user->WriteNumeric(606, ":%s", list.c_str()); user->WriteNumeric(607, ":End of WATCH S"); } else if (nick[0] == '-') { nick++; remove_watch(user, nick); } else if (nick[0] == '+') { nick++; add_watch(user, nick); } } } return CMD_SUCCESS; }