Merge pull request #1651 from Zarthus/remove_partyline

modules: Remove partyline
This commit is contained in:
Alexey Sokolov
2019-06-11 23:40:07 +01:00
committed by GitHub
10 changed files with 15 additions and 1051 deletions
-739
View File
@@ -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"))
-41
View File
@@ -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"
-41
View File
@@ -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"
-39
View File
@@ -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 ""
-39
View File
@@ -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 ""
-42
View File
@@ -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"
-30
View File
@@ -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 ""
-39
View File
@@ -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 ""
-41
View File
@@ -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 ""
+15
View File
@@ -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") {