mirror of
https://github.com/znc/znc.git
synced 2026-08-06 17:03:14 +02:00
Merge pull request #1651 from Zarthus/remove_partyline
modules: Remove partyline
This commit is contained in:
@@ -1,739 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2019 ZNC, see the NOTICE file for details.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <znc/User.h>
|
||||
#include <znc/IRCNetwork.h>
|
||||
|
||||
using std::set;
|
||||
using std::vector;
|
||||
using std::map;
|
||||
|
||||
// If you change these and it breaks, you get to keep the pieces
|
||||
#define CHAN_PREFIX_1 "~"
|
||||
#define CHAN_PREFIX_1C '~'
|
||||
#define CHAN_PREFIX CHAN_PREFIX_1 "#"
|
||||
|
||||
#define NICK_PREFIX CString("?")
|
||||
#define NICK_PREFIX_C '?'
|
||||
|
||||
class CPartylineChannel {
|
||||
public:
|
||||
CPartylineChannel(const CString& sName) { m_sName = sName.AsLower(); }
|
||||
~CPartylineChannel() {}
|
||||
|
||||
const CString& GetTopic() const { return m_sTopic; }
|
||||
const CString& GetName() const { return m_sName; }
|
||||
const set<CString>& GetNicks() const { return m_ssNicks; }
|
||||
|
||||
void SetTopic(const CString& s) { m_sTopic = s; }
|
||||
|
||||
void AddNick(const CString& s) { m_ssNicks.insert(s); }
|
||||
void DelNick(const CString& s) { m_ssNicks.erase(s); }
|
||||
|
||||
bool IsInChannel(const CString& s) {
|
||||
return m_ssNicks.find(s) != m_ssNicks.end();
|
||||
}
|
||||
|
||||
protected:
|
||||
CString m_sTopic;
|
||||
CString m_sName;
|
||||
set<CString> m_ssNicks;
|
||||
};
|
||||
|
||||
class CPartylineMod : public CModule {
|
||||
public:
|
||||
void ListChannelsCommand(const CString& sLine) {
|
||||
if (m_ssChannels.empty()) {
|
||||
PutModule(t_s("There are no open channels."));
|
||||
return;
|
||||
}
|
||||
|
||||
CTable Table;
|
||||
|
||||
Table.AddColumn(t_s("Channel"));
|
||||
Table.AddColumn(t_s("Users"));
|
||||
|
||||
for (set<CPartylineChannel*>::const_iterator a = m_ssChannels.begin();
|
||||
a != m_ssChannels.end(); ++a) {
|
||||
Table.AddRow();
|
||||
|
||||
Table.SetCell(t_s("Channel"), (*a)->GetName());
|
||||
Table.SetCell(t_s("Users"), CString((*a)->GetNicks().size()));
|
||||
}
|
||||
|
||||
PutModule(Table);
|
||||
}
|
||||
|
||||
MODCONSTRUCTOR(CPartylineMod) {
|
||||
AddHelpCommand();
|
||||
AddCommand("List", "", t_d("List all open channels"),
|
||||
[=](const CString& sLine) { ListChannelsCommand(sLine); });
|
||||
}
|
||||
|
||||
~CPartylineMod() override {
|
||||
// Kick all clients who are in partyline channels
|
||||
for (set<CPartylineChannel*>::iterator it = m_ssChannels.begin();
|
||||
it != m_ssChannels.end(); ++it) {
|
||||
set<CString> ssNicks = (*it)->GetNicks();
|
||||
|
||||
for (set<CString>::const_iterator it2 = ssNicks.begin();
|
||||
it2 != ssNicks.end(); ++it2) {
|
||||
CUser* pUser = CZNC::Get().FindUser(*it2);
|
||||
vector<CClient*> vClients = pUser->GetAllClients();
|
||||
|
||||
for (vector<CClient*>::const_iterator it3 = vClients.begin();
|
||||
it3 != vClients.end(); ++it3) {
|
||||
CClient* pClient = *it3;
|
||||
pClient->PutClient(":*" + GetModName() +
|
||||
"!znc@znc.in KICK " + (*it)->GetName() +
|
||||
" " + pClient->GetNick() + " :" +
|
||||
GetModName() + " unloaded");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!m_ssChannels.empty()) {
|
||||
delete *m_ssChannels.begin();
|
||||
m_ssChannels.erase(m_ssChannels.begin());
|
||||
}
|
||||
}
|
||||
|
||||
bool OnBoot() override {
|
||||
// The config is now read completely, so all Users are set up
|
||||
Load();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnLoad(const CString& sArgs, CString& sMessage) override {
|
||||
const map<CString, CUser*>& msUsers = CZNC::Get().GetUserMap();
|
||||
|
||||
for (map<CString, CUser*>::const_iterator it = msUsers.begin();
|
||||
it != msUsers.end(); ++it) {
|
||||
CUser* pUser = it->second;
|
||||
for (CClient* pClient : pUser->GetAllClients()) {
|
||||
CIRCNetwork* pNetwork = pClient->GetNetwork();
|
||||
if (!pNetwork || !pNetwork->IsIRCConnected() ||
|
||||
!pNetwork->GetChanPrefixes().Contains(CHAN_PREFIX_1)) {
|
||||
pClient->PutClient(
|
||||
":" + GetIRCServer(pNetwork) + " 005 " +
|
||||
pClient->GetNick() + " CHANTYPES=" +
|
||||
(pNetwork ? pNetwork->GetChanPrefixes() : "") +
|
||||
CHAN_PREFIX_1 " :are supported by this server.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VCString vsChans;
|
||||
VCString::const_iterator it;
|
||||
sArgs.Split(" ", vsChans, false);
|
||||
|
||||
for (it = vsChans.begin(); it != vsChans.end(); ++it) {
|
||||
if (it->Left(2) == CHAN_PREFIX) {
|
||||
m_ssDefaultChans.insert(it->Left(32));
|
||||
}
|
||||
}
|
||||
|
||||
Load();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Load() {
|
||||
CString sAction, sKey;
|
||||
CPartylineChannel* pChannel;
|
||||
for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) {
|
||||
if (it->first.find(":") != CString::npos) {
|
||||
sAction = it->first.Token(0, false, ":");
|
||||
sKey = it->first.Token(1, true, ":");
|
||||
} else {
|
||||
// backwards compatibility for older NV data
|
||||
sAction = "fixedchan";
|
||||
sKey = it->first;
|
||||
}
|
||||
|
||||
if (sAction == "fixedchan") {
|
||||
// Sorry, this was removed
|
||||
}
|
||||
|
||||
if (sAction == "topic") {
|
||||
pChannel = FindChannel(sKey);
|
||||
if (pChannel && !(it->second).empty()) {
|
||||
PutChan(pChannel->GetNicks(), ":irc.znc.in TOPIC " +
|
||||
pChannel->GetName() +
|
||||
" :" + it->second);
|
||||
pChannel->SetTopic(it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void SaveTopic(CPartylineChannel* pChannel) {
|
||||
if (!pChannel->GetTopic().empty())
|
||||
SetNV("topic:" + pChannel->GetName(), pChannel->GetTopic());
|
||||
else
|
||||
DelNV("topic:" + pChannel->GetName());
|
||||
}
|
||||
|
||||
EModRet OnDeleteUser(CUser& User) override {
|
||||
// Loop through each chan
|
||||
for (set<CPartylineChannel*>::iterator it = m_ssChannels.begin();
|
||||
it != m_ssChannels.end();) {
|
||||
CPartylineChannel* pChan = *it;
|
||||
// RemoveUser() might delete channels, so make sure our
|
||||
// iterator doesn't break.
|
||||
++it;
|
||||
RemoveUser(&User, pChan, "KICK", "User deleted", true);
|
||||
}
|
||||
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
EModRet OnNumericMessage(CNumericMessage& Msg) override {
|
||||
if (Msg.GetCode() == 5) {
|
||||
for (int i = 0; i < Msg.GetParams().size(); ++i) {
|
||||
if (Msg.GetParams()[i].StartsWith("CHANTYPES=")) {
|
||||
Msg.SetParam(i, Msg.GetParam(i) + CHAN_PREFIX_1);
|
||||
m_spInjectedPrefixes.insert(GetNetwork());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
void OnIRCDisconnected() override {
|
||||
m_spInjectedPrefixes.erase(GetNetwork());
|
||||
}
|
||||
|
||||
void OnClientLogin() override {
|
||||
CUser* pUser = GetUser();
|
||||
CClient* pClient = GetClient();
|
||||
CIRCNetwork* pNetwork = GetNetwork();
|
||||
if (!pNetwork || !pNetwork->IsIRCConnected()) {
|
||||
pClient->PutClient(":" + GetIRCServer(pNetwork) + " 005 " +
|
||||
pClient->GetNick() + " CHANTYPES=" +
|
||||
CHAN_PREFIX_1 " :are supported by this server.");
|
||||
}
|
||||
|
||||
// Make sure this user is in the default channels
|
||||
for (set<CString>::iterator a = m_ssDefaultChans.begin();
|
||||
a != m_ssDefaultChans.end(); ++a) {
|
||||
CPartylineChannel* pChannel = GetChannel(*a);
|
||||
const CString& sNick = pUser->GetUsername();
|
||||
|
||||
if (pChannel->IsInChannel(sNick)) continue;
|
||||
|
||||
CString sHost = pUser->GetBindHost();
|
||||
const set<CString>& ssNicks = pChannel->GetNicks();
|
||||
|
||||
if (sHost.empty()) {
|
||||
sHost = "znc.in";
|
||||
}
|
||||
PutChan(ssNicks,
|
||||
":" + NICK_PREFIX + sNick + "!" + pUser->GetIdent() + "@" +
|
||||
sHost + " JOIN " + *a,
|
||||
false);
|
||||
pChannel->AddNick(sNick);
|
||||
}
|
||||
|
||||
CString sNickMask = pClient->GetNickMask();
|
||||
|
||||
for (set<CPartylineChannel*>::iterator it = m_ssChannels.begin();
|
||||
it != m_ssChannels.end(); ++it) {
|
||||
const set<CString>& ssNicks = (*it)->GetNicks();
|
||||
|
||||
if ((*it)->IsInChannel(pUser->GetUsername())) {
|
||||
pClient->PutClient(":" + sNickMask + " JOIN " +
|
||||
(*it)->GetName());
|
||||
|
||||
if (!(*it)->GetTopic().empty()) {
|
||||
pClient->PutClient(":" + GetIRCServer(pNetwork) + " 332 " +
|
||||
pClient->GetNickMask() + " " +
|
||||
(*it)->GetName() + " :" +
|
||||
(*it)->GetTopic());
|
||||
}
|
||||
|
||||
SendNickList(pUser, pNetwork, ssNicks, (*it)->GetName());
|
||||
PutChan(ssNicks, ":*" + GetModName() + "!znc@znc.in MODE " +
|
||||
(*it)->GetName() + " +" +
|
||||
CString(pUser->IsAdmin() ? "o" : "v") +
|
||||
" " + NICK_PREFIX + pUser->GetUsername(),
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnClientDisconnect() override {
|
||||
CUser* pUser = GetUser();
|
||||
if (!pUser->IsUserAttached() && !pUser->IsBeingDeleted()) {
|
||||
for (set<CPartylineChannel*>::iterator it = m_ssChannels.begin();
|
||||
it != m_ssChannels.end(); ++it) {
|
||||
const set<CString>& ssNicks = (*it)->GetNicks();
|
||||
|
||||
if (ssNicks.find(pUser->GetUsername()) != ssNicks.end()) {
|
||||
PutChan(ssNicks,
|
||||
":*" + GetModName() + "!znc@znc.in MODE " +
|
||||
(*it)->GetName() + " -ov " + NICK_PREFIX +
|
||||
pUser->GetUsername() + " " + NICK_PREFIX +
|
||||
pUser->GetUsername(),
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EModRet OnUserRawMessage(CMessage& Msg) override {
|
||||
if ((Msg.GetCommand().Equals("WHO") ||
|
||||
Msg.GetCommand().Equals("MODE")) &&
|
||||
Msg.GetParam(0).StartsWith(CHAN_PREFIX_1)) {
|
||||
return HALT;
|
||||
} else if (Msg.GetCommand().Equals("TOPIC") &&
|
||||
Msg.GetParam(0).StartsWith(CHAN_PREFIX)) {
|
||||
const CString sChannel = Msg.As<CTopicMessage>().GetTarget();
|
||||
CString sTopic = Msg.As<CTopicMessage>().GetText();
|
||||
|
||||
sTopic.TrimPrefix(":");
|
||||
|
||||
CUser* pUser = GetUser();
|
||||
CClient* pClient = GetClient();
|
||||
CPartylineChannel* pChannel = FindChannel(sChannel);
|
||||
|
||||
if (pChannel && pChannel->IsInChannel(pUser->GetUsername())) {
|
||||
const set<CString>& ssNicks = pChannel->GetNicks();
|
||||
if (!sTopic.empty()) {
|
||||
if (pUser->IsAdmin()) {
|
||||
PutChan(ssNicks, ":" + pClient->GetNickMask() +
|
||||
" TOPIC " + sChannel + " :" +
|
||||
sTopic);
|
||||
pChannel->SetTopic(sTopic);
|
||||
SaveTopic(pChannel);
|
||||
} else {
|
||||
pUser->PutUser(":irc.znc.in 482 " + pClient->GetNick() +
|
||||
" " + sChannel +
|
||||
" :You're not channel operator");
|
||||
}
|
||||
} else {
|
||||
sTopic = pChannel->GetTopic();
|
||||
|
||||
if (sTopic.empty()) {
|
||||
pUser->PutUser(":irc.znc.in 331 " + pClient->GetNick() +
|
||||
" " + sChannel + " :No topic is set.");
|
||||
} else {
|
||||
pUser->PutUser(":irc.znc.in 332 " + pClient->GetNick() +
|
||||
" " + sChannel + " :" + sTopic);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pUser->PutUser(":irc.znc.in 442 " + pClient->GetNick() + " " +
|
||||
sChannel + " :You're not on that channel");
|
||||
}
|
||||
return HALT;
|
||||
}
|
||||
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
EModRet OnUserPart(CString& sChannel, CString& sMessage) override {
|
||||
if (sChannel.Left(1) != CHAN_PREFIX_1) {
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
if (sChannel.Left(2) != CHAN_PREFIX) {
|
||||
GetClient()->PutClient(":" + GetIRCServer(GetNetwork()) + " 401 " +
|
||||
GetClient()->GetNick() + " " + sChannel +
|
||||
" :No such channel");
|
||||
return HALT;
|
||||
}
|
||||
|
||||
CPartylineChannel* pChannel = FindChannel(sChannel);
|
||||
|
||||
PartUser(GetUser(), pChannel);
|
||||
|
||||
return HALT;
|
||||
}
|
||||
|
||||
void PartUser(CUser* pUser, CPartylineChannel* pChannel,
|
||||
const CString& sMessage = "") {
|
||||
RemoveUser(pUser, pChannel, "PART", sMessage);
|
||||
}
|
||||
|
||||
void RemoveUser(CUser* pUser, CPartylineChannel* pChannel,
|
||||
const CString& sCommand, const CString& sMessage = "",
|
||||
bool bNickAsTarget = false) {
|
||||
if (!pChannel || !pChannel->IsInChannel(pUser->GetUsername())) {
|
||||
return;
|
||||
}
|
||||
|
||||
vector<CClient*> vClients = pUser->GetAllClients();
|
||||
|
||||
CString sCmd = " " + sCommand + " ";
|
||||
CString sMsg = sMessage;
|
||||
if (!sMsg.empty()) sMsg = " :" + sMsg;
|
||||
|
||||
pChannel->DelNick(pUser->GetUsername());
|
||||
|
||||
const set<CString>& ssNicks = pChannel->GetNicks();
|
||||
CString sHost = pUser->GetBindHost();
|
||||
|
||||
if (sHost.empty()) {
|
||||
sHost = "znc.in";
|
||||
}
|
||||
|
||||
if (bNickAsTarget) {
|
||||
for (vector<CClient*>::const_iterator it = vClients.begin();
|
||||
it != vClients.end(); ++it) {
|
||||
CClient* pClient = *it;
|
||||
|
||||
pClient->PutClient(":" + pClient->GetNickMask() + sCmd +
|
||||
pChannel->GetName() + " " +
|
||||
pClient->GetNick() + sMsg);
|
||||
}
|
||||
|
||||
PutChan(ssNicks, ":" + NICK_PREFIX + pUser->GetUsername() + "!" +
|
||||
pUser->GetIdent() + "@" + sHost + sCmd +
|
||||
pChannel->GetName() + " " + NICK_PREFIX +
|
||||
pUser->GetUsername() + sMsg,
|
||||
false, true, pUser);
|
||||
} else {
|
||||
for (vector<CClient*>::const_iterator it = vClients.begin();
|
||||
it != vClients.end(); ++it) {
|
||||
CClient* pClient = *it;
|
||||
|
||||
pClient->PutClient(":" + pClient->GetNickMask() + sCmd +
|
||||
pChannel->GetName() + sMsg);
|
||||
}
|
||||
|
||||
PutChan(ssNicks, ":" + NICK_PREFIX + pUser->GetUsername() + "!" +
|
||||
pUser->GetIdent() + "@" + sHost + sCmd +
|
||||
pChannel->GetName() + sMsg,
|
||||
false, true, pUser);
|
||||
}
|
||||
|
||||
if (!pUser->IsBeingDeleted() &&
|
||||
m_ssDefaultChans.find(pChannel->GetName()) !=
|
||||
m_ssDefaultChans.end()) {
|
||||
JoinUser(pUser, pChannel);
|
||||
}
|
||||
|
||||
if (ssNicks.empty()) {
|
||||
delete pChannel;
|
||||
m_ssChannels.erase(pChannel);
|
||||
}
|
||||
}
|
||||
|
||||
EModRet OnUserJoin(CString& sChannel, CString& sKey) override {
|
||||
if (sChannel.Left(1) != CHAN_PREFIX_1) {
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
if (sChannel.Left(2) != CHAN_PREFIX) {
|
||||
GetClient()->PutClient(":" + GetIRCServer(GetNetwork()) + " 403 " +
|
||||
GetClient()->GetNick() + " " + sChannel +
|
||||
" :Channels look like " CHAN_PREFIX "znc");
|
||||
return HALT;
|
||||
}
|
||||
|
||||
sChannel = sChannel.Left(32);
|
||||
CPartylineChannel* pChannel = GetChannel(sChannel);
|
||||
|
||||
JoinUser(GetUser(), pChannel);
|
||||
|
||||
return HALT;
|
||||
}
|
||||
|
||||
void JoinUser(CUser* pUser, CPartylineChannel* pChannel) {
|
||||
if (pChannel && !pChannel->IsInChannel(pUser->GetUsername())) {
|
||||
vector<CClient*> vClients = pUser->GetAllClients();
|
||||
|
||||
const set<CString>& ssNicks = pChannel->GetNicks();
|
||||
const CString& sNick = pUser->GetUsername();
|
||||
pChannel->AddNick(sNick);
|
||||
|
||||
CString sHost = pUser->GetBindHost();
|
||||
|
||||
if (sHost.empty()) {
|
||||
sHost = "znc.in";
|
||||
}
|
||||
|
||||
for (vector<CClient*>::const_iterator it = vClients.begin();
|
||||
it != vClients.end(); ++it) {
|
||||
CClient* pClient = *it;
|
||||
pClient->PutClient(":" + pClient->GetNickMask() + " JOIN " +
|
||||
pChannel->GetName());
|
||||
}
|
||||
|
||||
PutChan(ssNicks,
|
||||
":" + NICK_PREFIX + sNick + "!" + pUser->GetIdent() + "@" +
|
||||
sHost + " JOIN " + pChannel->GetName(),
|
||||
false, true, pUser);
|
||||
|
||||
if (!pChannel->GetTopic().empty()) {
|
||||
for (vector<CClient*>::const_iterator it = vClients.begin();
|
||||
it != vClients.end(); ++it) {
|
||||
CClient* pClient = *it;
|
||||
pClient->PutClient(
|
||||
":" + GetIRCServer(pClient->GetNetwork()) + " 332 " +
|
||||
pClient->GetNickMask() + " " + pChannel->GetName() +
|
||||
" :" + pChannel->GetTopic());
|
||||
}
|
||||
}
|
||||
|
||||
SendNickList(pUser, nullptr, ssNicks, pChannel->GetName());
|
||||
|
||||
/* Tell the other clients we have op or voice, the current user's
|
||||
* clients already know from NAMES list */
|
||||
|
||||
if (pUser->IsAdmin()) {
|
||||
PutChan(ssNicks, ":*" + GetModName() + "!znc@znc.in MODE " +
|
||||
pChannel->GetName() + " +o " +
|
||||
NICK_PREFIX + pUser->GetUsername(),
|
||||
false, false, pUser);
|
||||
}
|
||||
|
||||
PutChan(ssNicks, ":*" + GetModName() + "!znc@znc.in MODE " +
|
||||
pChannel->GetName() + " +v " + NICK_PREFIX +
|
||||
pUser->GetUsername(),
|
||||
false, false, pUser);
|
||||
}
|
||||
}
|
||||
|
||||
EModRet HandleMessage(const CString& sCmd, const CString& sTarget,
|
||||
const CString& sMessage) {
|
||||
if (sTarget.empty()) {
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
char cPrefix = sTarget[0];
|
||||
|
||||
if (cPrefix != CHAN_PREFIX_1C && cPrefix != NICK_PREFIX_C) {
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
CUser* pUser = GetUser();
|
||||
CClient* pClient = GetClient();
|
||||
CIRCNetwork* pNetwork = GetNetwork();
|
||||
CString sHost = pUser->GetBindHost();
|
||||
|
||||
if (sHost.empty()) {
|
||||
sHost = "znc.in";
|
||||
}
|
||||
|
||||
if (cPrefix == CHAN_PREFIX_1C) {
|
||||
if (FindChannel(sTarget) == nullptr) {
|
||||
pClient->PutClient(":" + GetIRCServer(pNetwork) + " 401 " +
|
||||
pClient->GetNick() + " " + sTarget +
|
||||
" :No such channel");
|
||||
return HALT;
|
||||
}
|
||||
|
||||
PutChan(sTarget, ":" + NICK_PREFIX + pUser->GetUsername() + "!" +
|
||||
pUser->GetIdent() + "@" + sHost + " " + sCmd +
|
||||
" " + sTarget + " :" + sMessage,
|
||||
true, false);
|
||||
} else {
|
||||
CString sNick = sTarget.LeftChomp_n(1);
|
||||
CUser* pTargetUser = CZNC::Get().FindUser(sNick);
|
||||
|
||||
if (pTargetUser) {
|
||||
vector<CClient*> vClients = pTargetUser->GetAllClients();
|
||||
|
||||
if (vClients.empty()) {
|
||||
pClient->PutClient(":" + GetIRCServer(pNetwork) + " 401 " +
|
||||
pClient->GetNick() + " " + sTarget +
|
||||
" :User is not attached: " + sNick + "");
|
||||
return HALT;
|
||||
}
|
||||
|
||||
for (vector<CClient*>::const_iterator it = vClients.begin();
|
||||
it != vClients.end(); ++it) {
|
||||
CClient* pTarget = *it;
|
||||
|
||||
pTarget->PutClient(
|
||||
":" + NICK_PREFIX + pUser->GetUsername() + "!" +
|
||||
pUser->GetIdent() + "@" + sHost + " " + sCmd + " " +
|
||||
pTarget->GetNick() + " :" + sMessage);
|
||||
}
|
||||
} else {
|
||||
pClient->PutClient(":" + GetIRCServer(pNetwork) + " 401 " +
|
||||
pClient->GetNick() + " " + sTarget +
|
||||
" :No such znc user: " + sNick + "");
|
||||
}
|
||||
}
|
||||
|
||||
return HALT;
|
||||
}
|
||||
|
||||
EModRet OnUserMsg(CString& sTarget, CString& sMessage) override {
|
||||
return HandleMessage("PRIVMSG", sTarget, sMessage);
|
||||
}
|
||||
|
||||
EModRet OnUserNotice(CString& sTarget, CString& sMessage) override {
|
||||
return HandleMessage("NOTICE", sTarget, sMessage);
|
||||
}
|
||||
|
||||
EModRet OnUserCTCP(CString& sTarget, CString& sMessage) override {
|
||||
return HandleMessage("PRIVMSG", sTarget, "\001" + sMessage + "\001");
|
||||
}
|
||||
|
||||
EModRet OnUserCTCPReply(CString& sTarget, CString& sMessage) override {
|
||||
return HandleMessage("NOTICE", sTarget, "\001" + sMessage + "\001");
|
||||
}
|
||||
|
||||
const CString GetIRCServer(CIRCNetwork* pNetwork) {
|
||||
if (!pNetwork) {
|
||||
return "irc.znc.in";
|
||||
}
|
||||
|
||||
const CString& sServer = pNetwork->GetIRCServer();
|
||||
if (!sServer.empty()) return sServer;
|
||||
return "irc.znc.in";
|
||||
}
|
||||
|
||||
bool PutChan(const CString& sChan, const CString& sLine,
|
||||
bool bIncludeCurUser = true, bool bIncludeClient = true,
|
||||
CUser* pUser = nullptr, CClient* pClient = nullptr) {
|
||||
CPartylineChannel* pChannel = FindChannel(sChan);
|
||||
|
||||
if (pChannel != nullptr) {
|
||||
PutChan(pChannel->GetNicks(), sLine, bIncludeCurUser,
|
||||
bIncludeClient, pUser, pClient);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PutChan(const set<CString>& ssNicks, const CString& sLine,
|
||||
bool bIncludeCurUser = true, bool bIncludeClient = true,
|
||||
CUser* pUser = nullptr, CClient* pClient = nullptr) {
|
||||
const map<CString, CUser*>& msUsers = CZNC::Get().GetUserMap();
|
||||
|
||||
if (!pUser) pUser = GetUser();
|
||||
if (!pClient) pClient = GetClient();
|
||||
|
||||
for (map<CString, CUser*>::const_iterator it = msUsers.begin();
|
||||
it != msUsers.end(); ++it) {
|
||||
if (ssNicks.find(it->first) != ssNicks.end()) {
|
||||
if (it->second == pUser) {
|
||||
if (bIncludeCurUser) {
|
||||
it->second->PutAllUser(
|
||||
sLine, nullptr,
|
||||
(bIncludeClient ? nullptr : pClient));
|
||||
}
|
||||
} else {
|
||||
it->second->PutAllUser(sLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PutUserIRCNick(CUser* pUser, const CString& sPre,
|
||||
const CString& sPost) {
|
||||
const vector<CClient*>& vClients = pUser->GetAllClients();
|
||||
vector<CClient*>::const_iterator it;
|
||||
for (it = vClients.begin(); it != vClients.end(); ++it) {
|
||||
(*it)->PutClient(sPre + (*it)->GetNick() + sPost);
|
||||
}
|
||||
}
|
||||
|
||||
void SendNickList(CUser* pUser, CIRCNetwork* pNetwork,
|
||||
const set<CString>& ssNicks, const CString& sChan) {
|
||||
CString sNickList;
|
||||
|
||||
for (set<CString>::const_iterator it = ssNicks.begin();
|
||||
it != ssNicks.end(); ++it) {
|
||||
CUser* pChanUser = CZNC::Get().FindUser(*it);
|
||||
|
||||
if (pChanUser == pUser) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pChanUser && pChanUser->IsUserAttached()) {
|
||||
sNickList += (pChanUser->IsAdmin()) ? "@" : "+";
|
||||
}
|
||||
|
||||
sNickList += NICK_PREFIX + (*it) + " ";
|
||||
|
||||
if (sNickList.size() >= 500) {
|
||||
PutUserIRCNick(pUser, ":" + GetIRCServer(pNetwork) + " 353 ",
|
||||
" @ " + sChan + " :" + sNickList);
|
||||
sNickList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (sNickList.size()) {
|
||||
PutUserIRCNick(pUser, ":" + GetIRCServer(pNetwork) + " 353 ",
|
||||
" @ " + sChan + " :" + sNickList);
|
||||
}
|
||||
|
||||
vector<CClient*> vClients = pUser->GetAllClients();
|
||||
for (vector<CClient*>::const_iterator it = vClients.begin();
|
||||
it != vClients.end(); ++it) {
|
||||
CClient* pClient = *it;
|
||||
pClient->PutClient(":" + GetIRCServer(pNetwork) + " 353 " +
|
||||
pClient->GetNick() + " @ " + sChan + " :" +
|
||||
((pUser->IsAdmin()) ? "@" : "+") +
|
||||
pClient->GetNick());
|
||||
}
|
||||
|
||||
PutUserIRCNick(pUser, ":" + GetIRCServer(pNetwork) + " 366 ",
|
||||
" " + sChan + " :End of /NAMES list.");
|
||||
}
|
||||
|
||||
CPartylineChannel* FindChannel(const CString& sChan) {
|
||||
CString sChannel = sChan.AsLower();
|
||||
|
||||
for (set<CPartylineChannel*>::iterator it = m_ssChannels.begin();
|
||||
it != m_ssChannels.end(); ++it) {
|
||||
if ((*it)->GetName().AsLower() == sChannel) return *it;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CPartylineChannel* GetChannel(const CString& sChannel) {
|
||||
CPartylineChannel* pChannel = FindChannel(sChannel);
|
||||
|
||||
if (!pChannel) {
|
||||
pChannel = new CPartylineChannel(sChannel.AsLower());
|
||||
m_ssChannels.insert(pChannel);
|
||||
}
|
||||
|
||||
return pChannel;
|
||||
}
|
||||
|
||||
private:
|
||||
set<CPartylineChannel*> m_ssChannels;
|
||||
set<CIRCNetwork*> m_spInjectedPrefixes;
|
||||
set<CString> m_ssDefaultChans;
|
||||
};
|
||||
|
||||
template <>
|
||||
void TModInfo<CPartylineMod>(CModInfo& Info) {
|
||||
Info.SetWikiPage("partyline");
|
||||
Info.SetHasArgs(true);
|
||||
Info.SetArgsHelpText(
|
||||
Info.t_s("You may enter a list of channels the user joins, when "
|
||||
"entering the internal partyline."));
|
||||
}
|
||||
|
||||
GLOBALMODULEDEFS(
|
||||
CPartylineMod,
|
||||
t_s("Internal channels and queries for users connected to ZNC"))
|
||||
@@ -1,41 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: crowdin.com\n"
|
||||
"X-Crowdin-Project: znc-bouncer\n"
|
||||
"X-Crowdin-Language: de\n"
|
||||
"X-Crowdin-File: /master/modules/po/partyline.pot\n"
|
||||
"Project-Id-Version: znc-bouncer\n"
|
||||
"Last-Translator: DarthGandalf <alexey+crowdin@asokolov.org>\n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de_DE\n"
|
||||
|
||||
#: partyline.cpp:60
|
||||
msgid "There are no open channels."
|
||||
msgstr "Es gibt keine offenen Kanäle."
|
||||
|
||||
#: partyline.cpp:66 partyline.cpp:73
|
||||
msgid "Channel"
|
||||
msgstr "Kanal"
|
||||
|
||||
#: partyline.cpp:67 partyline.cpp:74
|
||||
msgid "Users"
|
||||
msgstr "Benutzer"
|
||||
|
||||
#: partyline.cpp:82
|
||||
msgid "List all open channels"
|
||||
msgstr "Liste alle offenen Kanäle auf"
|
||||
|
||||
#: partyline.cpp:733
|
||||
msgid ""
|
||||
"You may enter a list of channels the user joins, when entering the internal "
|
||||
"partyline."
|
||||
msgstr ""
|
||||
"Du kannst eine Liste von Kanälen angeben, die der Benutzer betritt, wenn er "
|
||||
"die interne Partyline betritt."
|
||||
|
||||
#: partyline.cpp:739
|
||||
msgid "Internal channels and queries for users connected to ZNC"
|
||||
msgstr "Interne Kanäle und Queries für mit ZNC verbundene Benutzer"
|
||||
@@ -1,41 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: crowdin.com\n"
|
||||
"X-Crowdin-Project: znc-bouncer\n"
|
||||
"X-Crowdin-Language: es-ES\n"
|
||||
"X-Crowdin-File: /master/modules/po/partyline.pot\n"
|
||||
"Project-Id-Version: znc-bouncer\n"
|
||||
"Last-Translator: DarthGandalf <alexey+crowdin@asokolov.org>\n"
|
||||
"Language-Team: Spanish\n"
|
||||
"Language: es_ES\n"
|
||||
|
||||
#: partyline.cpp:60
|
||||
msgid "There are no open channels."
|
||||
msgstr "No hay canales abiertos."
|
||||
|
||||
#: partyline.cpp:66 partyline.cpp:73
|
||||
msgid "Channel"
|
||||
msgstr "Canal"
|
||||
|
||||
#: partyline.cpp:67 partyline.cpp:74
|
||||
msgid "Users"
|
||||
msgstr "Usuarios"
|
||||
|
||||
#: partyline.cpp:82
|
||||
msgid "List all open channels"
|
||||
msgstr "Mostrar canales abiertos"
|
||||
|
||||
#: partyline.cpp:733
|
||||
msgid ""
|
||||
"You may enter a list of channels the user joins, when entering the internal "
|
||||
"partyline."
|
||||
msgstr ""
|
||||
"Puedes añadir una lista de canales a los que el usuario se meterá cuando se "
|
||||
"conecte a la partyline."
|
||||
|
||||
#: partyline.cpp:739
|
||||
msgid "Internal channels and queries for users connected to ZNC"
|
||||
msgstr "Privados y canales internos para usuarios conectados a ZNC"
|
||||
@@ -1,39 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Generator: crowdin.com\n"
|
||||
"X-Crowdin-Project: znc-bouncer\n"
|
||||
"X-Crowdin-Language: fr\n"
|
||||
"X-Crowdin-File: /master/modules/po/partyline.pot\n"
|
||||
"Project-Id-Version: znc-bouncer\n"
|
||||
"Last-Translator: DarthGandalf <alexey+crowdin@asokolov.org>\n"
|
||||
"Language-Team: French\n"
|
||||
"Language: fr_FR\n"
|
||||
|
||||
#: partyline.cpp:60
|
||||
msgid "There are no open channels."
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:66 partyline.cpp:73
|
||||
msgid "Channel"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:67 partyline.cpp:74
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:82
|
||||
msgid "List all open channels"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:733
|
||||
msgid ""
|
||||
"You may enter a list of channels the user joins, when entering the internal "
|
||||
"partyline."
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:739
|
||||
msgid "Internal channels and queries for users connected to ZNC"
|
||||
msgstr ""
|
||||
@@ -1,39 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: crowdin.com\n"
|
||||
"X-Crowdin-Project: znc-bouncer\n"
|
||||
"X-Crowdin-Language: id\n"
|
||||
"X-Crowdin-File: /master/modules/po/partyline.pot\n"
|
||||
"Project-Id-Version: znc-bouncer\n"
|
||||
"Last-Translator: DarthGandalf <alexey+crowdin@asokolov.org>\n"
|
||||
"Language-Team: Indonesian\n"
|
||||
"Language: id_ID\n"
|
||||
|
||||
#: partyline.cpp:60
|
||||
msgid "There are no open channels."
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:66 partyline.cpp:73
|
||||
msgid "Channel"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:67 partyline.cpp:74
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:82
|
||||
msgid "List all open channels"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:733
|
||||
msgid ""
|
||||
"You may enter a list of channels the user joins, when entering the internal "
|
||||
"partyline."
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:739
|
||||
msgid "Internal channels and queries for users connected to ZNC"
|
||||
msgstr ""
|
||||
@@ -1,42 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: crowdin.com\n"
|
||||
"X-Crowdin-Project: znc-bouncer\n"
|
||||
"X-Crowdin-Language: nl\n"
|
||||
"X-Crowdin-File: /master/modules/po/partyline.pot\n"
|
||||
"Project-Id-Version: znc-bouncer\n"
|
||||
"Last-Translator: DarthGandalf <alexey+crowdin@asokolov.org>\n"
|
||||
"Language-Team: Dutch\n"
|
||||
"Language: nl_NL\n"
|
||||
|
||||
#: partyline.cpp:60
|
||||
msgid "There are no open channels."
|
||||
msgstr "Er zijn geen open kanalen."
|
||||
|
||||
#: partyline.cpp:66 partyline.cpp:73
|
||||
msgid "Channel"
|
||||
msgstr "Kanaal"
|
||||
|
||||
#: partyline.cpp:67 partyline.cpp:74
|
||||
msgid "Users"
|
||||
msgstr "Gebruikers"
|
||||
|
||||
#: partyline.cpp:82
|
||||
msgid "List all open channels"
|
||||
msgstr "Laat alle open kanalen zien"
|
||||
|
||||
#: partyline.cpp:733
|
||||
msgid ""
|
||||
"You may enter a list of channels the user joins, when entering the internal "
|
||||
"partyline."
|
||||
msgstr ""
|
||||
"Je mag een lijst van kanalen toevoegen wanneer een gebruiker toetreed tot de "
|
||||
"interne partijlijn."
|
||||
|
||||
#: partyline.cpp:739
|
||||
msgid "Internal channels and queries for users connected to ZNC"
|
||||
msgstr ""
|
||||
"Interne kanalen en privé berichten voor gebruikers die verbonden zijn met ZNC"
|
||||
@@ -1,30 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: partyline.cpp:60
|
||||
msgid "There are no open channels."
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:66 partyline.cpp:73
|
||||
msgid "Channel"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:67 partyline.cpp:74
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:82
|
||||
msgid "List all open channels"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:733
|
||||
msgid ""
|
||||
"You may enter a list of channels the user joins, when entering the internal "
|
||||
"partyline."
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:739
|
||||
msgid "Internal channels and queries for users connected to ZNC"
|
||||
msgstr ""
|
||||
@@ -1,39 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: crowdin.com\n"
|
||||
"X-Crowdin-Project: znc-bouncer\n"
|
||||
"X-Crowdin-Language: pt-BR\n"
|
||||
"X-Crowdin-File: /master/modules/po/partyline.pot\n"
|
||||
"Project-Id-Version: znc-bouncer\n"
|
||||
"Last-Translator: DarthGandalf <alexey+crowdin@asokolov.org>\n"
|
||||
"Language-Team: Portuguese, Brazilian\n"
|
||||
"Language: pt_BR\n"
|
||||
|
||||
#: partyline.cpp:60
|
||||
msgid "There are no open channels."
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:66 partyline.cpp:73
|
||||
msgid "Channel"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:67 partyline.cpp:74
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:82
|
||||
msgid "List all open channels"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:733
|
||||
msgid ""
|
||||
"You may enter a list of channels the user joins, when entering the internal "
|
||||
"partyline."
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:739
|
||||
msgid "Internal channels and queries for users connected to ZNC"
|
||||
msgstr ""
|
||||
@@ -1,41 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 "
|
||||
"&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 "
|
||||
"&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
|
||||
"X-Generator: crowdin.com\n"
|
||||
"X-Crowdin-Project: znc-bouncer\n"
|
||||
"X-Crowdin-Language: ru\n"
|
||||
"X-Crowdin-File: /master/modules/po/partyline.pot\n"
|
||||
"Project-Id-Version: znc-bouncer\n"
|
||||
"Last-Translator: DarthGandalf <alexey+crowdin@asokolov.org>\n"
|
||||
"Language-Team: Russian\n"
|
||||
"Language: ru_RU\n"
|
||||
|
||||
#: partyline.cpp:60
|
||||
msgid "There are no open channels."
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:66 partyline.cpp:73
|
||||
msgid "Channel"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:67 partyline.cpp:74
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:82
|
||||
msgid "List all open channels"
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:733
|
||||
msgid ""
|
||||
"You may enter a list of channels the user joins, when entering the internal "
|
||||
"partyline."
|
||||
msgstr ""
|
||||
|
||||
#: partyline.cpp:739
|
||||
msgid "Internal channels and queries for users connected to ZNC"
|
||||
msgstr ""
|
||||
@@ -470,6 +470,21 @@ bool CIRCNetwork::ParseConfig(CConfig* pConfig, CString& sError,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Partyline is removed in znc 1.8
|
||||
if (sModName == "partyline") {
|
||||
CUtils::PrintError(
|
||||
"NOTICE: [partyline] is unavailable, cannot load.");
|
||||
CUtils::PrintError(
|
||||
"NOTICE: [partyline] is removed in this release"
|
||||
" of ZNC. Please either remove it from your config or "
|
||||
"install it as a third party module with the same "
|
||||
"name.");
|
||||
CUtils::PrintError(
|
||||
"NOTICE: More info can be found on "
|
||||
"https://wiki.znc.in/Partyline");
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXX The awaynick module was retired in 1.6 (still available
|
||||
// as external module)
|
||||
if (sModName == "awaynick") {
|
||||
|
||||
Reference in New Issue
Block a user