diff --git a/include/znc/Message.h b/include/znc/Message.h index eb3f5cb4..1981d312 100644 --- a/include/znc/Message.h +++ b/include/znc/Message.h @@ -30,6 +30,12 @@ #define ZNC_LVREFQUAL #endif +#ifdef SWIG +#define ZNC_MSG_DEPRECATED(msg) +#else +#define ZNC_MSG_DEPRECATED(msg) __attribute__((deprecated(msg))) +#endif + #include #include #include @@ -55,7 +61,8 @@ class CIRCNetwork; * - `nick` is the sender, which can be obtained with GetNick() * - `cmd` is command, which is obtained via GetCommand() * - `0`, `1`, ... are parameters, available via GetParam(n), which removes the - * leading colon (:). If you don't want to remove the colon, use GetParams(). + * leading colon (:). If you don't want to remove the colon, use + * GetParamsColon(). * * For certain events, like a PRIVMSG, convienience commands like GetChan() and * GetNick() are available, this is not true for all CMessage extensions. @@ -114,9 +121,15 @@ class CMessage { void SetCommand(const CString& sCommand); const VCString& GetParams() const { return m_vsParams; } - CString GetParams(unsigned int uIdx, unsigned int uLen = -1) const; void SetParams(const VCString& vsParams); + /// @deprecated use GetParamsColon() instead. + CString GetParams(unsigned int uIdx, unsigned int uLen = -1) const + ZNC_MSG_DEPRECATED("Use GetParamsColon() instead") { + return GetParamsColon(uIdx, uLen); + } + CString GetParamsColon(unsigned int uIdx, unsigned int uLen = -1) const; + CString GetParam(unsigned int uIdx) const; void SetParam(unsigned int uIdx, const CString& sParam); @@ -244,7 +257,7 @@ REGISTER_ZNC_MESSAGE(CJoinMessage); class CModeMessage : public CTargetMessage { public: - CString GetModes() const { return GetParams(1).TrimPrefix_n(":"); } + CString GetModes() const { return GetParamsColon(1).TrimPrefix_n(":"); } }; REGISTER_ZNC_MESSAGE(CModeMessage); diff --git a/modules/adminlog.cpp b/modules/adminlog.cpp index 19c79586..bd172813 100644 --- a/modules/adminlog.cpp +++ b/modules/adminlog.cpp @@ -76,7 +76,7 @@ class CAdminLogMod : public CModule { Log("[" + GetUser()->GetUserName() + "/" + GetNetwork()->GetName() + "] disconnected from IRC: " + GetNetwork()->GetCurrentServer()->GetName() + " [" + - Message.GetParams(1) + "]", + Message.GetParamsColon(1) + "]", LOG_NOTICE); } return CONTINUE; diff --git a/modules/flooddetach.cpp b/modules/flooddetach.cpp index f58dfb09..946c6029 100644 --- a/modules/flooddetach.cpp +++ b/modules/flooddetach.cpp @@ -32,9 +32,12 @@ class CFloodDetachMod : public CModule { AddCommand("Secs", t_d("[]"), t_d("Show or set number of seconds in the time interval"), [=](const CString& sLine) { SecsCommand(sLine); }); - AddCommand("Lines", t_d("[]"), t_d("blahblah: description"), + AddCommand("Lines", t_d("[]"), + t_d("Show or set number of lines in the time interval"), [=](const CString& sLine) { LinesCommand(sLine); }); - AddCommand("Silent", t_d("[yes|no]"), t_d("blahblah: description"), + AddCommand("Silent", "[yes|no]", + t_d("Show or set whether to notify you about detaching and " + "attaching back"), [=](const CString& sLine) { SilentCommand(sLine); }); } diff --git a/modules/modperl/modperl.i b/modules/modperl/modperl.i index dcf7dd42..4992b740 100644 --- a/modules/modperl/modperl.i +++ b/modules/modperl/modperl.i @@ -73,21 +73,24 @@ namespace std { }; } %include "modperl/CString.i" -%template(_stringlist) std::list; -%typemap(out) std::list { - std::list::const_iterator i; - unsigned int j; - int len = $1.size(); - SV **svs = new SV*[len]; - for (i=$1.begin(), j=0; i!=$1.end(); i++, j++) { - svs[j] = sv_newmortal(); - SwigSvFromString(svs[j], *i); - } - AV *myav = av_make(len, svs); - delete[] svs; - $result = newRV_noinc((SV*) myav); - sv_2mortal($result); - argvi++; + +%typemap(out) VCString { + EXTEND(sp, $1.size()); + for (int i = 0; i < $1.size(); ++i) { + SV* x = newSV(0); + SwigSvFromString(x, $1[i]); + $result = sv_2mortal(x); + argvi++; + } +} +%typemap(out) const VCString& { + EXTEND(sp, $1->size()); + for (int i = 0; i < $1->size(); ++i) { + SV* x = newSV(0); + SwigSvFromString(x, (*$1)[i]); + $result = sv_2mortal(x); + argvi++; + } } %template(VIRCNetworks) std::vector; @@ -176,26 +179,18 @@ class MCString : public std::map {}; %} %extend CModule { - std::list _GetNVKeys() { - std::list res; - for (MCString::iterator i = $self->BeginNV(); i != $self->EndNV(); ++i) { - res.push_back(i->first); - } - return res; - } + VCString GetNVKeys() { + VCString result; + for (auto i = $self->BeginNV(); i != $self->EndNV(); ++i) { + result.push_back(i->first); + } + return result; + } bool ExistsNV(const CString& sName) { return $self->EndNV() != $self->FindNV(sName); } } -%perlcode %{ - package ZNC::CModule; - sub GetNVKeys { - my $result = _GetNVKeys(@_); - return @$result; - } -%} - %extend CModules { void push_back(CModule* p) { $self->push_back(p); diff --git a/modules/modpython/cstring.i b/modules/modpython/cstring.i index bc081f7e..f73e6176 100644 --- a/modules/modpython/cstring.i +++ b/modules/modpython/cstring.i @@ -7,6 +7,7 @@ Remove unrelated stuff from top of file which is included by default s/std::string/CString/g s/std_string/CString/g + Add "%traits_ptypen(CString);" */ // @@ -17,6 +18,7 @@ %feature("naturalvar") CString; class CString; +%traits_ptypen(CString); /*@SWIG:/swig/3.0.8/typemaps/CStrings.swg,70,%typemaps_CString@*/ @@ -74,7 +76,7 @@ SWIG_AsVal_CString (PyObject * obj, CString *val) } /*@SWIG@*/ /*@SWIG:/swig/3.0.8/typemaps/CStrings.swg,38,%CString_from@*/ -%fragment("SWIG_" "From" "_" {CString},"header",fragment="SWIG_FromCharPtrAndSize") { +%fragment("SWIG_" "From" "_" {CString},"header",fragment="SWIG_FromCharPtrAndSize", fragment="StdTraits") { SWIGINTERNINLINE PyObject * SWIG_From_CString (const CString& s) { diff --git a/modules/route_replies.cpp b/modules/route_replies.cpp index 7bb65f2f..786c7d71 100644 --- a/modules/route_replies.cpp +++ b/modules/route_replies.cpp @@ -304,7 +304,7 @@ class CRouteRepliesMod : public CModule { // If there are arguments to a mode change, // we must not route it. - if (!Message.GetParams(2).empty()) return CONTINUE; + if (!Message.GetParamsColon(2).empty()) return CONTINUE; // Grab the mode change parameter CString sMode = Message.GetParam(1); diff --git a/modules/schat.cpp b/modules/schat.cpp index daf26c59..713023aa 100644 --- a/modules/schat.cpp +++ b/modules/schat.cpp @@ -144,7 +144,7 @@ class CSChat : public CModule { EModRet OnUserRawMessage(CMessage& msg) override { if (!msg.GetCommand().Equals("schat")) return CONTINUE; - const CString sParams = msg.GetParams(0); + const CString sParams = msg.GetParamsColon(0); if (sParams.empty()) { PutModule("SChat User Area ..."); OnModCommand("help"); diff --git a/src/Client.cpp b/src/Client.cpp index ac210f3b..82164986 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -1204,7 +1204,7 @@ bool CClient::OnPingMessage(CMessage& Message) { // All PONGs are generated by ZNC. We will still forward this to // the ircd, but all PONGs from irc will be blocked. if (!Message.GetParams().empty()) - PutClient(":irc.znc.in PONG irc.znc.in " + Message.GetParams(0)); + PutClient(":irc.znc.in PONG irc.znc.in " + Message.GetParamsColon(0)); else PutClient(":irc.znc.in PONG irc.znc.in"); return false; @@ -1305,10 +1305,10 @@ bool CClient::OnOtherMessage(CMessage& Message) { CString sModCommand; if (sTarget.TrimPrefix(m_pUser->GetStatusPrefix())) { - sModCommand = Message.GetParams(1); + sModCommand = Message.GetParamsColon(1); } else { sTarget = "status"; - sModCommand = Message.GetParams(0); + sModCommand = Message.GetParamsColon(0); } if (sTarget.Equals("status")) { @@ -1330,7 +1330,7 @@ bool CClient::OnOtherMessage(CMessage& Message) { return true; } - CString sPatterns = Message.GetParams(0); + CString sPatterns = Message.GetParamsColon(0); if (sPatterns.empty()) { PutStatusNotice(t_s("Usage: /attach <#chans>")); @@ -1352,7 +1352,7 @@ bool CClient::OnOtherMessage(CMessage& Message) { return true; } - CString sPatterns = Message.GetParams(0); + CString sPatterns = Message.GetParamsColon(0); if (sPatterns.empty()) { PutStatusNotice(t_s("Usage: /detach <#chans>")); diff --git a/src/IRCSock.cpp b/src/IRCSock.cpp index 2518d36f..e9db5447 100644 --- a/src/IRCSock.cpp +++ b/src/IRCSock.cpp @@ -761,7 +761,7 @@ bool CIRCSock::OnNumericMessage(CNumericMessage& Message) { CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { - pChan->SetModes(Message.GetParams(2)); + pChan->SetModes(Message.GetParamsColon(2)); // We don't SetModeKnown(true) here, // because a 329 will follow diff --git a/src/Message.cpp b/src/Message.cpp index d0696ffa..6242e428 100644 --- a/src/Message.cpp +++ b/src/Message.cpp @@ -48,7 +48,7 @@ void CMessage::SetCommand(const CString& sCommand) { InitType(); } -CString CMessage::GetParams(unsigned int uIdx, unsigned int uLen) const { +CString CMessage::GetParamsColon(unsigned int uIdx, unsigned int uLen) const { if (m_vsParams.empty() || uLen == 0) { return ""; } @@ -151,7 +151,7 @@ CString CMessage::ToString(unsigned int uFlags) const { if (!sMessage.empty()) { sMessage += " "; } - sMessage += GetParams(0); + sMessage += GetParamsColon(0); } return sMessage; diff --git a/test/integration/tests/scripting.cpp b/test/integration/tests/scripting.cpp index 304b88f9..9dd68d8f 100644 --- a/test/integration/tests/scripting.cpp +++ b/test/integration/tests/scripting.cpp @@ -152,5 +152,89 @@ TEST_F(ZNCTest, ModperlSocket) { client.ReadUntil("received 4 bytes"); } +TEST_F(ZNCTest, ModpythonVCString) { + if (QProcessEnvironment::systemEnvironment().value( + "DISABLED_ZNC_PERL_PYTHON_TEST") == "1") { + return; + } + auto znc = Run(); + znc->CanLeak(); + + InstallModule("test.py", R"( + import znc + + class test(znc.Module): + def OnUserRawMessage(self, msg): + self.PutModule(str(msg.GetParams())) + return znc.CONTINUE + )"); + + auto ircd = ConnectIRCd(); + auto client = LoginClient(); + client.Write("znc loadmod modpython"); + client.Write("znc loadmod test"); + client.Write("PRIVMSG *test :foo"); + client.ReadUntil("'*test', 'foo'"); +} + +TEST_F(ZNCTest, ModperlVCString) { + if (QProcessEnvironment::systemEnvironment().value( + "DISABLED_ZNC_PERL_PYTHON_TEST") == "1") { + return; + } + auto znc = Run(); + znc->CanLeak(); + + InstallModule("test.pm", R"( + package test; + use base 'ZNC::Module'; + sub OnUserRawMessage { + my ($self, $msg) = @_; + my @params = $msg->GetParams; + $self->PutModule("@params"); + return $ZNC::CONTINUE; + } + + 1; + )"); + + auto ircd = ConnectIRCd(); + auto client = LoginClient(); + client.Write("znc loadmod modperl"); + client.Write("znc loadmod test"); + client.Write("PRIVMSG *test :foo"); + client.ReadUntil(":*test foo"); +} + +TEST_F(ZNCTest, ModperlNV) { + if (QProcessEnvironment::systemEnvironment().value( + "DISABLED_ZNC_PERL_PYTHON_TEST") == "1") { + return; + } + auto znc = Run(); + znc->CanLeak(); + + InstallModule("test.pm", R"( + package test; + use base 'ZNC::Module'; + sub OnLoad { + my $self = shift; + $self->SetNV('a', 'X'); + $self->NV->{b} = 'Y'; + my @k = keys %{$self->NV}; + $self->PutModule("@k"); + return $ZNC::CONTINUE; + } + + 1; + )"); + + auto ircd = ConnectIRCd(); + auto client = LoginClient(); + client.Write("znc loadmod modperl"); + client.Write("znc loadmod test"); + client.ReadUntil(":a b"); +} + } // namespace } // namespace znc_inttest diff --git a/translations/id-ID b/translations/id-ID new file mode 100644 index 00000000..5083107b --- /dev/null +++ b/translations/id-ID @@ -0,0 +1 @@ +SelfName Indonesian