diff --git a/configure b/configure index 963e20b4..b5daa318 100755 --- a/configure +++ b/configure @@ -568,6 +568,7 @@ MODLINK LIBZNCDIR LIBZNC MODFLAGS +SWIG_BINARY PERL_BINARY openssl_LIBS openssl_CFLAGS @@ -642,6 +643,7 @@ enable_debug enable_ipv6 enable_openssl enable_perl +enable_swig enable_sasl enable_optimization enable_c_ares @@ -1288,7 +1290,13 @@ Optional Features: --enable-debug enable debugging --disable-ipv6 disable ipv6 support --disable-openssl disable openssl - --disable-perl disable perl + --enable-perl enable perl + --disable-swig Disable automatic generation of source files needed + for modperl. This value is ignored if perl is + disabled or not found. If you disable swig, but + still want to use modperl, please download the + necessary files to modules/modperl. Check + http://en.znc.in/wiki/Modperl for details. --enable-sasl enable sasl --disable-optimization Disable some compiler optimizations to decrease memory usage while compiling @@ -2913,7 +2921,14 @@ fi if test "${enable_perl+set}" = set; then : enableval=$enable_perl; PERL="$enableval" else - PERL="auto" + PERL="no" +fi + +# Check whether --enable-swig was given. +if test "${enable_swig+set}" = set; then : + enableval=$enable_swig; SWIG="$enableval" +else + SWIG="auto" fi # Check whether --enable-sasl was given. @@ -3649,6 +3664,7 @@ fi if test "x$PERL" != "xno"; then old_PERL="$PERL" + old_SWIG="$SWIG" # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -3734,6 +3750,53 @@ else PERL="no" fi + if test "x$PERL" != "xno"; then + if test "x$SWIG" != "xno"; then + # Extract the first word of "swig", so it can be a program name with args. +set dummy swig; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_SWIG_BINARY+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $SWIG_BINARY in + [\\/]* | ?:[\\/]*) + ac_cv_path_SWIG_BINARY="$SWIG_BINARY" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_SWIG_BINARY="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +SWIG_BINARY=$ac_cv_path_SWIG_BINARY +if test -n "$SWIG_BINARY"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SWIG_BINARY" >&5 +$as_echo "$SWIG_BINARY" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -z "$SWIG_BINARY"; then + SWIG="no" + fi + fi + fi LDFLAGS="$my_saved_LDFLAGS" else PERL="no" @@ -3751,7 +3814,22 @@ $as_echo "$as_me: WARNING: perl was not found and thus disabled" >&2;} PERL_BINARY="" else - PERL=yes + if test "x$SWIG" = "xno"; then + SWIG_BINARY="" + if test "x$old_SWIG" = "xno"; then + PERL="yes, but with manual download" + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: swig was disabled, so you should put needed sources for modperl to modules/modperl. + Please check http://en.znc.in/wiki/Modperl for details." >&5 +$as_echo "$as_me: WARNING: swig was disabled, so you should put needed sources for modperl to modules/modperl. + Please check http://en.znc.in/wiki/Modperl for details." >&2;} + else + as_fn_error $? "swig was not found. Try --disable-perl, or download the necessary sources and use --disable-swig. + Please check http://en.znc.in/wiki/Modperl for details." "$LINENO" 5 + fi + else + PERL="yes" + SWIG="yes" + fi fi fi diff --git a/configure.in b/configure.in index 4942bf8f..a711e78b 100644 --- a/configure.in +++ b/configure.in @@ -93,9 +93,16 @@ AC_ARG_ENABLE( [openssl], [SSL="$enableval"], [SSL="auto"]) AC_ARG_ENABLE( [perl], - AS_HELP_STRING([--disable-perl], [disable perl]), + AS_HELP_STRING([--enable-perl], [enable perl]), [PERL="$enableval"], - [PERL="auto"]) + [PERL="no"]) +AC_ARG_ENABLE( [swig], + AS_HELP_STRING([--disable-swig], [Disable automatic generation of source files needed for modperl. + This value is ignored if perl is disabled or not found. If you disable swig, + but still want to use modperl, please download the necessary files to modules/modperl. + Check http://en.znc.in/wiki/Modperl for details.]), + [SWIG="$enableval"], + [SWIG="auto"]) AC_ARG_ENABLE( [sasl], AS_HELP_STRING([--enable-sasl], [enable sasl]), [if test "$enableval" = "yes" ; then SASL=1; fi],) @@ -257,6 +264,7 @@ fi if test "x$PERL" != "xno"; then old_PERL="$PERL" + old_SWIG="$SWIG" AC_PATH_PROG([PERL_BINARY], [perl], []) if test -n "$PERL_BINARY"; then my_saved_LDFLAGS="$LDFLAGS" @@ -264,6 +272,14 @@ if test "x$PERL" != "xno"; then AC_CHECK_LIB(perl, perl_alloc, [: No, we do not want autoconf to do sth automatically], PERL="no") + if test "x$PERL" != "xno"; then + if test "x$SWIG" != "xno"; then + AC_PATH_PROG([SWIG_BINARY], [swig], []) + if test -z "$SWIG_BINARY"; then + SWIG="no" + fi + fi + fi LDFLAGS="$my_saved_LDFLAGS" else PERL="no" @@ -274,7 +290,20 @@ if test "x$PERL" != "xno"; then [perl was not found and thus disabled]) PERL_BINARY="" else - PERL=yes + if test "x$SWIG" = "xno"; then + SWIG_BINARY="" + if test "x$old_SWIG" = "xno"; then + PERL="yes, but with manual download" + AC_MSG_WARN([swig was disabled, so you should put needed sources for modperl to modules/modperl. + Please check http://en.znc.in/wiki/Modperl for details.]) + else + AC_MSG_ERROR([swig was not found. Try --disable-perl, or download the necessary sources and use --disable-swig. + Please check http://en.znc.in/wiki/Modperl for details.]) + fi + else + PERL="yes" + SWIG="yes" + fi fi fi diff --git a/modules/Makefile.in b/modules/Makefile.in index c96a309d..d9579493 100644 --- a/modules/Makefile.in +++ b/modules/Makefile.in @@ -22,6 +22,7 @@ LDFLAGS := @LDFLAGS@ # The znc binary links already against those. # LIBS := @LIBS@ PERL := @PERL_BINARY@ +SWIG := @SWIG_BINARY@ MODDIR := @MODDIR@ DATADIR := @DATADIR@ LIBZNC := @LIBZNC@ @@ -69,6 +70,10 @@ ifneq "$(PERL)" "" modperlFLAGS := $(shell $(PERL) -MExtUtils::Embed -e perl_inc -e ldopts) # Perl API is ugly, casting string literals to char* and redeclaring functions :( modperlFLAGS += -Wno-write-strings -Wno-redundant-decls -Wno-missing-declarations +# This is for SWIG +modperlFLAGS += -DSWIG_TYPE_TABLE=znc +# Find additional headers for out-of-tree build +modperlFLAGS += -I. PERLHOOK := modperl_install else FILES := $(shell echo $(FILES) | sed -e "s/modperl//") @@ -94,7 +99,7 @@ modtclFLAGS := $(TCL_FLAGS) TARGETS := $(addsuffix .so, $(FILES)) -CLEAN := *.so extra/*.so +CLEAN := *.so extra/*.so modperl/ZNC.so modperl/modperl_wrap.cxx modperl/ZNC.pm .PHONY: all clean install modperl_install @@ -125,10 +130,34 @@ clean: $(E) Building $(if $(filter %extra/,$(dir $<)),extra )module $(notdir $(basename $@))... $(Q)$(CXX) $(MODFLAGS) $(LDFLAGS) $(MODLINK) -o $@ $< $($(notdir $(basename $@))FLAGS) -MMD -MF .depend/$(notdir $@).dep -modperl_install: create_install_dir +modperl.so: modperl/ZNC.so +modperl/ZNC.so: modperl/modperl_wrap.cxx Makefile + $(E) Building ZNC perl bindings library... + $(Q)$(CXX) $(MODFLAGS) $(LDFLAGS) $(MODLINK) -I$(srcdir) -DSWIG_TYPE_TABLE=znc $(shell $(PERL) -MExtUtils::Embed -e perl_inc -e ldopts) -o $@ $< +ifneq "$(SWIG)" "" +modperl/modperl_wrap.cxx: modperl/modperl.i Makefile modperl/module.h modperl/CString.i + $(E) Generating ZNC API for perl... + @mkdir -p modperl + $(Q)$(SWIG) -perl5 -c++ -shadow -outdir modperl -I$(srcdir) -w362,315,401,402 -o $@.warn $< + $(Q)$(PERL) -pe '$$x==2 and print "items+=0;" and $$x=3;/^XS\(SWIG_init\)/ and $$x=1;$$x==1 and /dXSARGS/ and $$x=2' $@.warn > $@ + $(Q)rm -rf $@.warn + $(Q)$(SWIG) -perl5 -c++ -shadow -external-runtime modperl/swigperlrun.h +endif + +modperl_install: create_install_dir install_metadirs for i in $(srcdir)/*.pm; do \ $(INSTALL_DATA) $$i $(DESTDIR)$(MODDIR); \ done + for a in $(srcdir)/*; do \ + if [ -d $$a ] && [ -f $${a}.pm ]; then \ + cp -Rp $$a $(DESTDIR)$(DATADIR); \ + fi \ + done + rm -rf $(DESTDIR)$(DATADIR)/modperl + mkdir -p $(DESTDIR)$(MODDIR)/modperl + $(INSTALL_PROGRAM) $(srcdir)/modperl/ZNC.so $(DESTDIR)$(MODDIR)/modperl + $(INSTALL_DATA) $(srcdir)/modperl/ZNC.pm $(DESTDIR)$(MODDIR)/modperl + $(INSTALL_DATA) $(srcdir)/modperl/startup.pl $(DESTDIR)$(MODDIR)/modperl modtcl_install: mkdir -p $(DESTDIR)$(DATADIR)/modtcl/ diff --git a/modules/modperl.cpp b/modules/modperl.cpp index 069b2d24..2e892c14 100644 --- a/modules/modperl.cpp +++ b/modules/modperl.cpp @@ -4,1231 +4,291 @@ * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. - * - * @author imaginos@imaginos.net - * - * NOTE, the proper way to valgrind this module is to compile znc with debug, and do the following ... - * - * PERL_DESTRUCT_LEVEL=2 GLIBCPP_FORCE_NEW=1 valgrind --leak-check=full /path/to/znc - * - * GLIBCPP_FORCE_NEW is an STL env flag to turn of mem pooling, and stops false alarms within stl - * PERL_DESTRUCT_LEVEL is a perl env flag to force the VM to cleanup, this also stops false alarms, but within perl */ -#include "Chan.h" +#include "Modules.h" #include "User.h" +#include "Chan.h" +#include "Nick.h" #include "znc.h" +#include "IRCSock.h" -// perl stuff +#include "modperl/module.h" +#include "modperl/swigperlrun.h" #include #include #include -#define NICK(a) a.GetNickMask() -#define CHAN(a) a.GetName() -#define ZNCEvalCB "ZNC::COREEval" -#define ZNCCallFuncCB "ZNC::CORECallFunc" -#define ZNCCallTimerCB "ZNC::CORECallTimer" -#define ZNCCallSockCB "ZNC::CORECallSock" -#define ZNCSOCK ":::ZncSock:::" +#include "modperl/pstring.h" -class PString : public CString -{ +// Allows perl to load .so files when needed by .pm +// For example, it needs to load ZNC.so +extern "C" { + void boot_DynaLoader (pTHX_ CV* cv); + static void xs_init(pTHX) { + newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__); + } +} + +class CModPerl: public CGlobalModule { + PerlInterpreter *m_pPerl; public: - enum EType - { - STRING, - INT, - UINT, - NUM, - BOOL - }; - - PString() : CString() { m_eType = STRING; } - PString(const char* c) : CString(c) { m_eType = STRING; } - PString(const CString& s) : CString(s) { m_eType = STRING; } - PString(int i) : CString(i) { m_eType = INT; } - PString(u_int i) : CString(i) { m_eType = UINT; } - PString(long i) : CString(i) { m_eType = INT; } - PString(u_long i) : CString(i) { m_eType = UINT; } - PString(long long i) : CString(i) { m_eType = INT; } - PString(unsigned long long i) : CString(i) { m_eType = UINT; } - PString(double i) : CString(i) { m_eType = NUM; } - PString(bool b) : CString((b ? "1" : "0")) { m_eType = BOOL; } - - virtual ~PString() {} - - EType GetType() const { return(m_eType); } - void SetType(EType e) { m_eType = e; } - - SV * GetSV(bool bMakeMortal = true) const - { - SV *pSV = NULL; - switch(GetType()) - { - case NUM: - pSV = newSVnv(ToDouble()); - break; - case INT: - pSV = newSViv(ToLongLong()); - break; - case UINT: - case BOOL: - pSV = newSVuv(ToULongLong()); - break; - case STRING: - default: - pSV = newSVpv(data(), length()); - break; - } - - if (bMakeMortal) - pSV = sv_2mortal(pSV); - - return(pSV); - } - -private: - EType m_eType; -}; - - -class CPerlHash : public map< CString, PString > -{ -public: - - HV *GetHash() - { - HV *pHash = newHV(); - sv_2mortal((SV *) pHash); - for (CPerlHash::iterator it = this->begin(); it != this->end(); it++) - { - SV *pSV = it->second.GetSV(false); - hv_store(pHash, it->first.c_str(), it->first.length(), pSV, 0); - } - - return(pHash); - } -}; - -typedef vector< PString > VPString; - -class CModPerl; -static CModPerl *g_ModPerl = NULL; - -class CPerlSock : public CZNCSock -{ -public: - CPerlSock() : CZNCSock() - { - m_iParentFD = -1; - SetSockName(ZNCSOCK); - } - CPerlSock(const CS_STRING & sHost, u_short iPort, int iTimeout = 60) - : CZNCSock(sHost, iPort, iTimeout) - { - m_iParentFD = -1; - SetSockName(ZNCSOCK); - } - - -// # OnSockDestroy($sockhandle) - virtual ~CPerlSock(); - - virtual Csock *GetSockObj(const CS_STRING & sHostname, u_short iPort); - - void SetParentFD(int iFD) { m_iParentFD = iFD; } - void SetUsername(const CString & sUsername) { m_sUsername = sUsername; } - void SetModuleName(const CString & sModuleName) { m_sModuleName = sModuleName; } - - const CString & GetUsername() { return(m_sUsername); } - const CString & GetModuleName() { return(m_sModuleName); } - -// # OnConnect($sockhandle, $parentsockhandle) - virtual void Connected(); -// # OnConnectionFrom($sockhandle, $remotehost, $remoteport) - virtual bool ConnectionFrom(const CS_STRING & sHost, u_short iPort); -// # OnError($sockhandle, $errno) - virtual void SockError(int iErrno); -// # OnConnectionRefused($sockhandle) - virtual void ConnectionRefused(); -// # OnTimeout($sockhandle) - virtual void Timeout(); -// # OnDisconnect($sockhandle) - virtual void Disconnected(); -// # OnData($sockhandle, $bytes, $length) - virtual void ReadData(const char *data, size_t len); -// # OnReadLine($sockhandle, $line) - virtual void ReadLine(const CS_STRING & sLine); - - -private: - CString m_sModuleName; - CString m_sUsername; // NEED these so we can send the signal to the right guy - int m_iParentFD; - VPString m_vArgs; - - void SetupArgs() - { - m_vArgs.clear(); - m_vArgs.push_back(m_sModuleName); - m_vArgs.push_back(GetRSock()); - } - - void AddArg(const PString & sArg) - { - m_vArgs.push_back(sArg); - } - - int CallBack(const PString & sFuncName); -}; - -class CPerlTimer : public CTimer -{ -public: - CPerlTimer(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) - : CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {} - - virtual ~CPerlTimer() {} - - void SetFuncName(const CString & sFuncName) { m_sFuncName = sFuncName; } - void SetUserName(const CString & sUserName) { m_sUserName = sUserName; } - void SetModuleName(const CString & sModuleName) { m_sModuleName = sModuleName; } - -protected: - virtual void RunJob(); - - CString m_sFuncName; - CString m_sUserName; - CString m_sModuleName; -}; - -class CModPerl : public CGlobalModule -{ -public: - GLOBALMODCONSTRUCTOR(CModPerl) - { - g_ModPerl = this; + GLOBALMODCONSTRUCTOR(CModPerl) { m_pPerl = NULL; } - virtual ~CModPerl() - { - DestroyAllSocks(); - if (m_pPerl) - { - const map & msUsers = CZNC::Get().GetUserMap(); +#define PSTART dSP; I32 ax; int ret = 0; ENTER; SAVETMPS; PUSHMARK(SP) +#define PCALL(name) PUTBACK; ret = call_pv(name, G_EVAL|G_ARRAY); SPAGAIN; SP -= ret; ax = (SP - PL_stack_base) + 1 +#define PEND PUTBACK; FREETMPS; LEAVE +#define PUSH_STR(s) XPUSHs(PString(s).GetSV()) +#define PUSH_PTR(type, p) XPUSHs(SWIG_NewInstanceObj(const_cast(p), SWIG_TypeQuery(#type), SWIG_SHADOW)) - for (map::const_iterator it = msUsers.begin(); it != msUsers.end(); it++) - { // need to set it on all of these - m_pUser = it->second; - CBNone("OnShutdown"); - m_pUser = NULL; - } - PerlInterpShutdown(); + bool OnLoad(const CString& sArgsi, CString& sMessage) { + CString sModPath, sTmp; + if (!CModules::FindModPath("modperl/startup.pl", sModPath, sTmp)) { + sMessage = "startup.pl not found."; + return false; } - g_ModPerl = NULL; - } - - void PerlInterpShutdown() - { - perl_destruct(m_pPerl); - perl_free(m_pPerl); - PERL_SYS_TERM(); - m_pPerl = NULL; - } - - bool SetupZNCScript() - { - CString sModule, sTmp; - - if (!CModules::FindModPath("modperl.pm", sModule, sTmp)) + sTmp = CDir::ChangeDir(sModPath, ".."); + int argc = 6; + char *pArgv[] = {"", "-T", "-w", + "-I", const_cast(sTmp.c_str()), + const_cast(sModPath.c_str()), NULL}; + char **argv = pArgv; + PERL_SYS_INIT3(&argc, &argv, &environ); + m_pPerl = perl_alloc(); + perl_construct(m_pPerl); + if (perl_parse(m_pPerl, xs_init, argc, argv, environ)) { + perl_free(m_pPerl); + PERL_SYS_TERM(); + m_pPerl = NULL; + sMessage = "Can't initialize perl."; return false; - - CString sBuffer, sScript; - CFile cFile(sModule); - if (!cFile.Exists() || !cFile.Open()) - return false; - - while (cFile.ReadLine(sBuffer)) - sScript += sBuffer; - cFile.Close(); - - eval_pv(sScript.c_str(), FALSE); + } + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + PSTART; + PCALL("ZNC::Core::Init"); + PEND; return true; } - virtual EModRet OnConfigLine(const CString& sName, const CString& sValue, CUser* pUser, CChan* pChan) - { - if (sName.Equals("loadperlmodule") && pUser) - { - m_pUser = pUser; - if (sValue.Right(3) == ".pm") - LoadPerlMod(sValue); - else - LoadPerlMod(sValue + ".pm"); - m_pUser = NULL; - return(HALT); + ELoadPerlMod LoadPerlModule(const CString& sModule, const CString& sArgs, CUser* pUser, CString& sRetMsg) { + ELoadPerlMod result = Perl_LoadError; + PSTART; + PUSH_STR(sModule); + PUSH_STR(sArgs); + PUSH_PTR(CUser*, pUser); + PCALL("ZNC::Core::LoadModule"); + + if (SvTRUE(ERRSV)) { + sRetMsg = PString(ERRSV); + } else if (2 == ret) { + result = static_cast(SvUV(ST(0))); + sRetMsg = PString(ST(1)); } - return(CONTINUE); + + PEND; + return result; } - void DumpError(const CString & sError) - { - CString sTmp = sError; - for (CString::size_type a = 0; a < sTmp.size(); a++) - { - if (isspace(sTmp[a])) - sTmp[a] = ' '; + virtual EModRet OnModuleLoading(const CString& sModName, const CString& sArgs, + bool& bSuccess, CString& sRetMsg) { + switch (LoadPerlModule(sModName, sArgs, GetUser(), sRetMsg)) { + case Perl_NotFound: + return CONTINUE; + case Perl_Loaded: + bSuccess = true; + return HALT; + case Perl_LoadError: + bSuccess = false; + return HALT; } - PutModule(sTmp); - DEBUG(sTmp); + sRetMsg = "Something weird happened"; + bSuccess = false; + return HALT; } - CSockManager * GetSockManager() { return(m_pManager); } - void DestroyAllSocks(const CString & sModuleName = ""); - - CUser * GetUser(const CString & sUsername = "", bool bSetUserContext = false) - { - if (sUsername.empty()) - return(m_pUser); - - CUser *pUser = CZNC::Get().FindUser(sUsername); - if (bSetUserContext) - m_pUser = pUser; - - return(pUser); - } - void UnSetUser() { m_pUser = NULL; } - - virtual bool OnLoad(const CString & sArgs, CString & sMessage); - virtual void OnClientLogin() { CBNone("OnClientLogin"); } - virtual void OnClientDisconnect() { CBNone("OnClientDisconnect"); } - virtual void OnIRCDisconnected() { CBNone("OnIRCDisconnected"); } - virtual void OnIRCConnected() { CBNone("OnIRCConnected"); } - - virtual EModRet OnDCCUserSend(const CNick& RemoteNick, unsigned long uLongIP, unsigned short uPort, - const CString& sFile, unsigned long uFileSize); - - virtual void OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) - { - CBFour("OnOp", NICK(OpNick), NICK(Nick), CHAN(Channel), bNoChange); - } - virtual void OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) - { - CBFour("OnDeop", NICK(OpNick), NICK(Nick), CHAN(Channel), bNoChange); - } - virtual void OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) - { - CBFour("OnVoice", NICK(OpNick), NICK(Nick), CHAN(Channel), bNoChange); - } - virtual void OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) - { - CBFour("OnDevoice", NICK(OpNick), NICK(Nick), CHAN(Channel), bNoChange); - } - virtual void OnRawMode(const CNick& Nick, CChan& Channel, const CString& sModes, const CString& sArgs) - { - CBFour("OnRawMode", NICK(Nick), CHAN(Channel), sModes, sArgs); - } - virtual EModRet OnUserRaw(CString& sLine) { return(CBSingle("OnUserRaw", sLine)); } - virtual EModRet OnRaw(CString& sLine) { return(CBSingle("OnRaw", sLine)); } - - virtual EModRet OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) { - return(CBFour("OnIRCRegistration", sPass, sNick, sIdent, sRealName)); - } - virtual EModRet OnTimerAutoJoin(CChan& Channel) { return(CBSingle("OnTimerAutoJoin", CHAN(Channel))); } - - virtual void OnModCommand(const CString& sCommand) - { - if (CBSingle("OnModCommand", sCommand) == 0) - Eval(sCommand); - } - virtual void OnModNotice(const CString& sMessage) { CBSingle("OnModNotice", sMessage); } - virtual void OnModCTCP(const CString& sMessage) { CBSingle("OnModCTCP", sMessage); } - - virtual void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) - { - VPString vsArgs; - vsArgs.push_back(Nick.GetNickMask()); - vsArgs.push_back(sMessage); - for (vector::size_type a = 0; a < vChans.size(); a++) - vsArgs.push_back(vChans[a]->GetName()); - - CallBack("OnQuit", vsArgs); - } - - virtual void OnNick(const CNick& Nick, const CString& sNewNick, const vector& vChans) - { - VPString vsArgs; - vsArgs.push_back(Nick.GetNickMask()); - vsArgs.push_back(sNewNick); - for (vector::size_type a = 0; a < vChans.size(); a++) - vsArgs.push_back(vChans[a]->GetName()); - - CallBack("OnNick", vsArgs); - } - - virtual void OnKick(const CNick& Nick, const CString& sOpNick, CChan& Channel, const CString& sMessage) - { - CBFour("OnKick", NICK(Nick), sOpNick, CHAN(Channel), sMessage); - } - - virtual void OnJoin(const CNick& Nick, CChan& Channel) { CBDouble("OnJoin", NICK(Nick), CHAN(Channel)); } - virtual void OnPart(const CNick& Nick, CChan& Channel) { CBDouble("OnPart", NICK(Nick), CHAN(Channel)); } - - virtual EModRet OnUserCTCPReply(CString& sTarget, CString& sMessage) - { - return CBDouble("OnUserCTCPReply", sTarget, sMessage); - } - virtual EModRet OnCTCPReply(CNick& Nick, CString& sMessage) - { - return CBDouble("OnCTCPReply", NICK(Nick), sMessage); - } - virtual EModRet OnUserCTCP(CString& sTarget, CString& sMessage) - { - return CBDouble("OnUserCTCP", sTarget, sMessage); - } - virtual EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) - { - return CBDouble("OnPrivCTCP", NICK(Nick), sMessage); - } - virtual EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) - { - return CBTriple("OnChanCTCP", NICK(Nick), CHAN(Channel), sMessage); - } - virtual EModRet OnUserMsg(CString& sTarget, CString& sMessage) - { - return CBDouble("OnUserMsg", sTarget, sMessage); - } - virtual EModRet OnPrivMsg(CNick& Nick, CString& sMessage) - { - return CBDouble("OnPrivMsg", NICK(Nick), sMessage); - } - - virtual EModRet OnChanMsg(CNick& Nick, CChan & Channel, CString & sMessage) - { - return(CBTriple("OnChanMsg", NICK(Nick), CHAN(Channel), sMessage)); - } - virtual EModRet OnUserNotice(CString& sTarget, CString& sMessage) - { - return CBDouble("OnUserNotice", sTarget, sMessage); - } - virtual EModRet OnPrivNotice(CNick& Nick, CString& sMessage) - { - return CBDouble("OnPrivNotice", NICK(Nick), sMessage); - } - virtual EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) - { - return(CBTriple("OnChanNotice", NICK(Nick), CHAN(Channel), sMessage)); - } - - enum ECBTYPES - { - CB_LOCAL = 1, - CB_ONHOOK = 2, - CB_TIMER = 3, - CB_SOCK = 4 - }; - - EModRet CallBack(const PString & sHookName, const VPString & vsArgs, - ECBTYPES eCBType = CB_ONHOOK, const PString & sUsername = ""); - - EModRet CBNone(const PString & sHookName) - { - VPString vsArgs; - return(CallBack(sHookName, vsArgs)); - } - - template - inline EModRet CBSingle(const PString & sHookName, const A & a) - { - VPString vsArgs; - vsArgs.push_back(a); - return(CallBack(sHookName, vsArgs)); - } - template - inline EModRet CBDouble(const PString & sHookName, const A & a, const B & b) - { - VPString vsArgs; - vsArgs.push_back(a); - vsArgs.push_back(b); - return(CallBack(sHookName, vsArgs)); - } - template - inline EModRet CBTriple(const PString & sHookName, const A & a, const B & b, const C & c) - { - VPString vsArgs; - vsArgs.push_back(a); - vsArgs.push_back(b); - vsArgs.push_back(c); - return(CallBack(sHookName, vsArgs)); - } - template - inline EModRet CBFour(const PString & sHookName, const A & a, const B & b, const C & c, const D & d) - { - VPString vsArgs; - vsArgs.push_back(a); - vsArgs.push_back(b); - vsArgs.push_back(c); - vsArgs.push_back(d); - return(CallBack(sHookName, vsArgs)); - } - - bool Eval(const CString & sScript, const CString & sFuncName = ZNCEvalCB); - - virtual EModRet OnStatusCommand(CString& sLine) - { - CString sCommand = sLine.Token(0); - - if (sCommand.Equals("loadperlmod", false, 11) || sCommand.Equals("unloadperlmod", false, 13) || sCommand.Equals("reloadperlmod", false, 13)) - { - CString sModule = sLine.Token(1); - if (sModule.Right(3) != ".pm") - sModule += ".pm"; - if (sCommand.Equals("loadperlmod", false, 11)) - LoadPerlMod(sModule); - else if (sCommand.Equals("unloadperlmod", false, 13)) - UnloadPerlMod(sModule); - else - { - UnloadPerlMod(sModule); - LoadPerlMod(sModule); + virtual EModRet OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) { + CPerlModule* pMod = AsPerlModule(pModule); + if (pMod) { + CString sModName = pMod->GetModName(); + PSTART; + PUSH_PTR(CPerlModule*, pMod); + PCALL("ZNC::Core::UnloadModule"); + if (SvTRUE(ERRSV)) { + bSuccess = false; + sRetMsg = PString(ERRSV); + } else { + bSuccess = true; + sRetMsg = "Module [" + sModName + "] unloaded"; } - return(HALT); + return HALT; } - return(CONTINUE); + return CONTINUE; } - void LoadPerlMod(const CString & sModule); - void UnloadPerlMod(const CString & sModule); + virtual EModRet OnGetModInfo(CModInfo& ModInfo, const CString& sModule, + bool& bSuccess, CString& sRetMsg) { + PSTART; + PUSH_STR(sModule); + PCALL("ZNC::Core::GetModInfo"); + EModRet result = CONTINUE; + if (SvTRUE(ERRSV)) { + bSuccess = false; + sRetMsg = PString(ERRSV); + } else if (0 < ret) { + switch(static_cast(SvUV(ST(0)))) { + case Perl_NotFound: + result = CONTINUE; + break; + case Perl_Loaded: + result = HALT; + if (3 == ret) { + ModInfo.SetGlobal(false); + ModInfo.SetDescription(PString(ST(2))); + ModInfo.SetName(sModule); + ModInfo.SetPath(PString(ST(1))); + bSuccess = true; + } else { + bSuccess = false; + sRetMsg = "Something weird happened"; + } + break; + case Perl_LoadError: + result = HALT; + bSuccess = false; + if (2 == ret) { + sRetMsg = PString(ST(1)); + } else { + sRetMsg = "Something weird happened"; + } + } + } else { + result = HALT; + bSuccess = false; + sRetMsg = "Something weird happened"; + } + PEND; + return result; + } -private: - PerlInterpreter *m_pPerl; + virtual void OnGetAvailableMods(set& ssMods, bool bGlobal) { + if (bGlobal) { + return; + } + + unsigned int a = 0; + CDir Dir; + + CModules::ModDirList dirs = CModules::GetModDirs(); + + while (!dirs.empty()) { + Dir.FillByWildcard(dirs.front().first, "*.pm"); + dirs.pop(); + + for (a = 0; a < Dir.size(); a++) { + CFile& File = *Dir[a]; + CString sName = File.GetShortName(); + CString sPath = File.GetLongName(); + CModInfo ModInfo; + sName.RightChomp(3); + PSTART; + PUSH_STR(sPath); + PUSH_STR(sName); + PCALL("ZNC::Core::ModInfoByPath"); + if (!SvTRUE(ERRSV) && ret == 1) { + ModInfo.SetGlobal(false); + ModInfo.SetDescription(PString(ST(0))); + ModInfo.SetName(sName); + ModInfo.SetPath(sPath); + ssMods.insert(ModInfo); + } + PEND; + } + } + } + + virtual ~CModPerl() { + if (m_pPerl) { + PSTART; + PCALL("ZNC::Core::UnloadAll"); + PEND; + perl_destruct(m_pPerl); + perl_free(m_pPerl); + PERL_SYS_TERM(); + } + } }; +#include "modperl/functions.cpp" + +VWebSubPages& CPerlModule::GetSubPages() { + VWebSubPages* result = _GetSubPages(); + if (!result) { + return CModule::GetSubPages(); + } + return *result; +} + +void CPerlTimer::RunJob() { + CPerlModule* pMod = AsPerlModule(GetModule()); + if (pMod) { + PSTART; + PUSH_STR(pMod->GetPerlID()); + PUSH_STR(GetPerlID()); + PCALL("ZNC::Core::CallTimer"); + PEND; + } +} + +#define SOCKSTART PSTART; PUSH_STR(pMod->GetPerlID()); PUSH_STR(GetPerlID()) +#define SOCKCBCHECK(OnSuccess) PCALL("ZNC::Core::CallSocket"); if (SvTRUE(ERRSV)) { Close(); DEBUG("Perl socket hook died with: " + PString(ERRSV)); } else { OnSuccess; } PEND +#define CBSOCK(Func) void CPerlSocket::Func() {\ + CPerlModule* pMod = AsPerlModule(GetModule());\ + if (pMod) {\ + SOCKSTART;\ + PUSH_STR("On" #Func);\ + SOCKCBCHECK();\ + }\ +} +CBSOCK(Connected); +CBSOCK(Disconnected); +CBSOCK(Timeout); +CBSOCK(ConnectionRefused); + +void CPerlSocket::ReadData(const char *data, size_t len) { + CPerlModule* pMod = AsPerlModule(GetModule()); + if (pMod) { + SOCKSTART; + PUSH_STR("OnReadData"); + XPUSHs(sv_2mortal(newSVpvn(data, len))); + mXPUSHi(len); + SOCKCBCHECK(); + } +} +void CPerlSocket::ReadLine(const CString& sLine) { + CPerlModule* pMod = AsPerlModule(GetModule()); + if (pMod) { + SOCKSTART; + PUSH_STR("OnReadLine"); + PUSH_STR(sLine); + SOCKCBCHECK(); + } +} +Csock* CPerlSocket::GetSockObj(const CString& sHost, unsigned short uPort) { + CPerlModule* pMod = AsPerlModule(GetModule()); + Csock* result = NULL; + if (pMod) { + SOCKSTART; + PUSH_STR("_Accepted"); + PUSH_STR(sHost); + mXPUSHi(uPort); + SOCKCBCHECK( + result = SvToPtr("CPerlSocket*")(ST(0)); + ); + } + return result; +} + GLOBALMODULEDEFS(CModPerl, "Loads perl scripts as ZNC modules") - - - -//////////////////////////////// PERL GUTS ////////////////////////////// - -XS(XS_ZNC_COREAddTimer) -{ - dXSARGS; - if (items != 5) - Perl_croak(aTHX_ "Usage: COREAddTimer(modname, funcname, description, interval, cycles)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if ((g_ModPerl) && (g_ModPerl->GetUser())) - { - CString sModName = (char *)SvPV(ST(0),PL_na); - CString sFuncName = (char *)SvPV(ST(1),PL_na); - CString sDesc = (char *)SvPV(ST(2),PL_na); - u_int iInterval = (u_int)SvUV(ST(3)); - u_int iCycles = (u_int)SvUV(ST(4)); - CString sUserName = g_ModPerl->GetUser()->GetUserName(); - CString sLabel = sUserName + sModName + sFuncName; - CPerlTimer *pTimer = new CPerlTimer(g_ModPerl, iInterval, iCycles, sLabel, sDesc); - pTimer->SetFuncName(sFuncName); - pTimer->SetUserName(sUserName); - pTimer->SetModuleName(sModName); - g_ModPerl->AddTimer(pTimer); - } - PUTBACK; - } -} - -XS(XS_ZNC_CORERemTimer) -{ - dXSARGS; - if (items != 2) - Perl_croak(aTHX_ "Usage: CORERemTimer(modname, funcname)"); - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if ((g_ModPerl) && (g_ModPerl->GetUser())) - { - CString sModName = (char *)SvPV(ST(0),PL_na); - CString sFuncName = (char *)SvPV(ST(1),PL_na); - CString sUserName = g_ModPerl->GetUser()->GetUserName(); - CString sLabel = sUserName + sModName + sFuncName; - CTimer *pTimer = g_ModPerl->FindTimer(sLabel); - if (pTimer) - pTimer->Stop(); - else - g_ModPerl->PutModule("Unable to find Timer!"); - } - PUTBACK; - } -} -XS(XS_ZNC_COREPuts) -{ - dXSARGS; - if (items != 2) - Perl_croak(aTHX_ "Usage: COREPuts(sWHich, sLine)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if ((g_ModPerl) && (g_ModPerl->GetUser())) - { - CString sWhich = (char *)SvPV(ST(0),PL_na); - CString sLine = (char *)SvPV(ST(1),PL_na); - - if (sWhich == "IRC") - g_ModPerl->PutIRC(sLine); - else if (sWhich == "Status") - g_ModPerl->PutStatus(sLine); - else if (sWhich == "User") - g_ModPerl->PutUser(sLine); - } - PUTBACK; - } -} - -XS(XS_ZNC_LoadMod) -{ - dXSARGS; - if (items != 1) - Perl_croak(aTHX_ "Usage: LoadMod(module)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if (g_ModPerl) - { - CString sModule = (char *)SvPV(ST(0),PL_na); - g_ModPerl->LoadPerlMod(sModule); - } - PUTBACK; - } -} - -XS(XS_ZNC_UnloadMod) -{ - dXSARGS; - if (items != 1) - Perl_croak(aTHX_ "Usage: UnloadMod(module)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if (g_ModPerl) - { - CString sModule = (char *)SvPV(ST(0),PL_na); - g_ModPerl->UnloadPerlMod(sModule); - } - PUTBACK; - } -} - -XS(XS_ZNC_COREPutModule) -{ - dXSARGS; - if (items != 4) - Perl_croak(aTHX_ "Usage: COREPutModule(sWhich sLine, sIdent, sHost)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if (g_ModPerl) - { - CString sWhich = (char *)SvPV(ST(0),PL_na); - CString sLine = (char *)SvPV(ST(1),PL_na); - CString sIdent = (char *)SvPV(ST(2),PL_na); - CString sHost = (char *)SvPV(ST(3),PL_na); - if (sWhich == "Module") - g_ModPerl->PutModule(sLine, sIdent, sHost); - else - g_ModPerl->PutModNotice(sLine, sIdent, sHost); - } - PUTBACK; - } -} - -XS(XS_ZNC_GetNicks) -{ - dXSARGS; - if (items != 1) - Perl_croak(aTHX_ "Usage: GetNicks(sChan)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if ((g_ModPerl) && (g_ModPerl->GetUser())) - { - CString sChan = (char *)SvPV(ST(0),PL_na); - CUser * pUser = g_ModPerl->GetUser(); - CChan * pChan = pUser->FindChan(sChan); - if (!pChan) - XSRETURN(0); - - const map< CString,CNick* > & mscNicks = pChan->GetNicks(); - - for (map< CString,CNick* >::const_iterator it = mscNicks.begin(); it != mscNicks.end(); it++) - { - CNick & cNick = *(it->second); - CPerlHash cHash; - cHash["Nick"] = cNick.GetNick(); - cHash["Ident"] = cNick.GetIdent(); - cHash["Host"] = cNick.GetHost(); - cHash["Perms"] = cNick.GetPermStr(); - XPUSHs(newRV_noinc((SV*)cHash.GetHash())); - } - } - PUTBACK; - } -} - -XS(XS_ZNC_GetString) -{ - dXSARGS; - - if (items != 1) - Perl_croak(aTHX_ "Usage: GetString(sName)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if ((g_ModPerl) && (g_ModPerl->GetUser())) - { - CUser * pUser = g_ModPerl->GetUser(); - PString sReturn; - CString sName = (char *)SvPV(ST(0),PL_na); - - if (sName == "UserName") sReturn = pUser->GetUserName(); - else if (sName == "Nick") sReturn = pUser->GetNick(); - else if (sName == "AltNick") sReturn = pUser->GetAltNick(); - else if (sName == "Ident") sReturn = pUser->GetIdent(); - else if (sName == "RealName") sReturn = pUser->GetRealName(); - else if (sName == "VHost" || sName == "BindHost") sReturn = pUser->GetBindHost(); - else if (sName == "Pass") sReturn = pUser->GetPass(); - else if (sName == "CurPath") sReturn = CZNC::Get().GetCurPath(); - else if (sName == "DLPath") sReturn = pUser->GetDLPath(); - else if (sName == "ModPath") sReturn = CZNC::Get().GetModPath(); - else if (sName == "HomePath") sReturn = CZNC::Get().GetHomePath(); - else if (sName == "SavePath") sReturn = g_ModPerl->GetSavePath(); - else if (sName == "StatusPrefix") sReturn = pUser->GetStatusPrefix(); - else if (sName == "DefaultChanModes") sReturn = pUser->GetDefaultChanModes(); - else if (sName == "IRCServer") sReturn = pUser->GetIRCServer(); - else - XSRETURN(0); - - XPUSHs(sReturn.GetSV()); - } - PUTBACK; - } -} - -////////////// Perl SOCKET guts ///////////// -#define MANAGER g_ModPerl->GetSockManager() -XS(XS_ZNC_WriteSock) -{ - dXSARGS; - if (items != 3) - Perl_croak(aTHX_ "Usage: ZNC::WriteSock(sockhandle, bytes, len)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if (g_ModPerl) - { - PString sReturn = false; - int iSockFD = SvIV(ST(0)); - STRLEN iLen = SvUV(ST(2)); - if (iLen > 0) - { - PString sData; - STRLEN iLen2 = iLen; - sData.append(SvPV(ST(1), iLen), iLen2); - CPerlSock *pSock = (CPerlSock *)MANAGER->FindSockByFD(iSockFD); - if ((pSock) && (pSock->GetSockName() == ZNCSOCK)) - sReturn = pSock->Write(sData.data(), sData.length()); - } - XPUSHs(sReturn.GetSV()); - } - PUTBACK; - } -} - -XS(XS_ZNC_CloseSock) -{ - dXSARGS; - if (items != 1) - Perl_croak(aTHX_ "Usage: ZNC::CloseSock(sockhandle)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if (g_ModPerl) - { - int iSockFD = SvIV(ST(0)); - CPerlSock *pSock = (CPerlSock *)MANAGER->FindSockByFD(iSockFD); - if ((pSock) && (pSock->GetSockName() == ZNCSOCK)) - pSock->Close(); - } - PUTBACK; - } -} - -XS(XS_ZNC_SetSockValue) -{ - dXSARGS; - if (items < 3) - Perl_croak(aTHX_ "Usage: ZNC::SetSockValue(sockhandle, what, value)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if (g_ModPerl) - { - int iSockFD = SvIV(ST(0)); - PString sWhat = (char *)SvPV(ST(1),PL_na); - CPerlSock *pSock = (CPerlSock *)MANAGER->FindSockByFD(iSockFD); - if ((pSock) && (pSock->GetSockName() == ZNCSOCK)) - { - if (sWhat == "timeout") - { - u_int iTimeout = SvUV(ST(2)); - pSock->SetTimeout(iTimeout); - } - } - } - PUTBACK; - } -} - -XS(XS_ZNC_COREConnect) -{ - dXSARGS; - if (items != 6) - Perl_croak(aTHX_ "Usage: ZNC::COREConnect($modname, $host, $port, $timeout, $bEnableReadline, $bUseSSL)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if ((g_ModPerl) && (g_ModPerl->GetUser())) - { - PString sReturn = -1; - PString sModuleName = (char *)SvPV(ST(0),PL_na); - PString sHostname = (char *)SvPV(ST(1),PL_na); - int iPort = SvIV(ST(2)); - u_int iTimeout = SvUV(ST(3)); - u_int iEnableReadline = SvUV(ST(4)); - u_int iUseSSL = SvUV(ST(5)); - CPerlSock *pSock = new CPerlSock(sHostname, iPort, iTimeout); - pSock->SetSockName(ZNCSOCK); - pSock->SetUsername(g_ModPerl->GetUser()->GetUserName()); - pSock->SetModuleName(sModuleName); - if (iEnableReadline) - pSock->EnableReadLine(); - - if (MANAGER->Connect(sHostname, iPort, ZNCSOCK, iTimeout, (iUseSSL != 0), "", pSock)) - sReturn = pSock->GetRSock(); - - XPUSHs(sReturn.GetSV()); - } - PUTBACK; - } -} - -XS(XS_ZNC_COREListen) -{ - dXSARGS; - if (items != 5) - Perl_croak(aTHX_ "Usage: ZNC::COREListen($modname, $port, $bindhost, $bEnableReadline, $bUseSSL)"); - - SP -= items; - ax = (SP - PL_stack_base) + 1 ; - { - if ((g_ModPerl) && (g_ModPerl->GetUser())) - { - PString sReturn = -1; - PString sModuleName = (char *)SvPV(ST(0),PL_na); - int iPort = SvIV(ST(1)); - PString sHostname = (char *)SvPV(ST(2),PL_na); - u_int iEnableReadline = SvUV(ST(3)); - u_int iUseSSL = SvUV(ST(4)); - - CPerlSock *pSock = new CPerlSock(); - pSock->SetSockName(ZNCSOCK); - pSock->SetUsername(g_ModPerl->GetUser()->GetUserName()); - pSock->SetModuleName(sModuleName); - - if (iEnableReadline) - pSock->EnableReadLine(); - - bool bContinue = true; - -#ifdef HAVE_LIBSSL - if (iUseSSL != 0) - { - if (CFile::Exists(CZNC::Get().GetPemLocation())) - pSock->SetPemLocation(CZNC::Get().GetPemLocation()); - else - { - g_ModPerl->PutModule("PEM File does not exist! (looking for " + CZNC::Get().GetPemLocation() + ")"); - bContinue = false; - } - } -#endif /* HAVE_LIBSSL */ - - if (bContinue) - { - if (MANAGER->ListenHost(iPort, ZNCSOCK, sHostname, (iUseSSL != 0), SOMAXCONN, pSock)) - sReturn = pSock->GetRSock(); - } - else - sReturn = -1; - - XPUSHs(sReturn.GetSV()); - - } - PUTBACK; - } -} - -/////////// supporting functions from within module - -bool CModPerl::Eval(const CString & sScript, const CString & sFuncName) -{ - dSP; - SAVETMPS; - - PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVpv(sScript.c_str(), sScript.length()))); - PUTBACK; - - SPAGAIN; - - call_pv(sFuncName.c_str(), G_EVAL|G_KEEPERR|G_VOID|G_DISCARD); - - bool bReturn = true; - - if (SvTRUE(ERRSV)) - { - DumpError(SvPV(ERRSV, PL_na)); - bReturn = false; - } - PUTBACK; - FREETMPS; - - return(bReturn); -} - -CModPerl::EModRet CModPerl::CallBack(const PString & sHookName, const VPString & vsArgs, - ECBTYPES eCBType, const PString & sUsername) -{ - if (!m_pPerl) - return(CONTINUE); - - dSP; - ENTER; - SAVETMPS; - - PUSHMARK(SP); - - CString sFuncToCall; - if (eCBType == CB_LOCAL) - sFuncToCall = sHookName; - else - { - if (sUsername.empty()) - { - if (!m_pUser) - return(CONTINUE); - - XPUSHs(PString(m_pUser->GetUserName()).GetSV()); - } - else - XPUSHs(sUsername.GetSV()); - XPUSHs(sHookName.GetSV()); - if (eCBType == CB_ONHOOK) - sFuncToCall = ZNCCallFuncCB; - else if (eCBType == CB_TIMER) - sFuncToCall = ZNCCallTimerCB; - else - sFuncToCall = ZNCCallSockCB; - } - for (VPString::size_type a = 0; a < vsArgs.size(); a++) - XPUSHs(vsArgs[a].GetSV()); - - PUTBACK; - - int iCount = call_pv(sFuncToCall.c_str(), G_EVAL|G_SCALAR|G_KEEPERR); - - SPAGAIN; - int iRet = CONTINUE; - - if (SvTRUE(ERRSV)) - { - CString sError = SvPV(ERRSV, PL_na); - DumpError(sHookName + ": " + sError); - - if (eCBType == CB_TIMER) - iRet = HALT; - POPs; - } else - { - if (iCount == 1) - iRet = POPi; - } - - PUTBACK; - FREETMPS; - LEAVE; - - return((CModPerl::EModRet)iRet); -} - -////////////////////// Events /////////////////// - -// special case this, required for perl modules that are dynamic -EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); - -bool CModPerl::OnLoad(const CString & sArgs, CString & sMessage) -{ - int iArgc = 5; - char *p[] = { "", "-e", "0", "-T", "-w", NULL }; - char **pArgv = static_cast(p); - PERL_SYS_INIT3( &iArgc, &pArgv, &environ ); - - m_pPerl = perl_alloc(); - perl_construct(m_pPerl); - - if (perl_parse(m_pPerl, NULL, iArgc, (char **)pArgv, (char **)NULL) != 0) - { - perl_free(m_pPerl); - PERL_SYS_TERM(); - m_pPerl = NULL; - return(false); - } - -#ifdef PERL_EXIT_DESTRUCT_END - PL_exit_flags |= PERL_EXIT_DESTRUCT_END; -#endif /* PERL_EXIT_DESTRUCT_END */ - - /* system functions */ - newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, "modperl"); - newXS("ZNC::COREPutModule", XS_ZNC_COREPutModule, "modperl"); - newXS("ZNC::COREAddTimer", XS_ZNC_COREAddTimer, "modperl"); - newXS("ZNC::CORERemTimer", XS_ZNC_CORERemTimer, "modperl"); - newXS("ZNC::COREPuts", XS_ZNC_COREPuts, "modperl"); - newXS("ZNC::COREConnect", XS_ZNC_COREConnect, "modperl"); - newXS("ZNC::COREListen", XS_ZNC_COREListen, "modperl"); - - /* user functions */ - newXS("ZNC::GetNicks", XS_ZNC_GetNicks, "modperl"); - newXS("ZNC::GetString", XS_ZNC_GetString, "modperl"); - newXS("ZNC::LoadMod", XS_ZNC_LoadMod, "modperl"); - newXS("ZNC::UnloadMod", XS_ZNC_UnloadMod, "modperl"); - newXS("ZNC::WriteSock", XS_ZNC_WriteSock, "modperl"); - newXS("ZNC::CloseSock", XS_ZNC_CloseSock, "modperl"); - newXS("ZNC::SetSockValue", XS_ZNC_SetSockValue, "modperl"); - - // this sets up the eval CB that we call from here on out. this way we can grab the error produced - if (!SetupZNCScript()) { - sMessage = "Failed to load modperl.pm"; - return false; - } - - HV *pZNCSpace = get_hv("ZNC::", TRUE); - - if (!pZNCSpace) - return(false); - - sv_2mortal((SV*)pZNCSpace); - - newCONSTSUB(pZNCSpace, "CONTINUE", PString(CONTINUE).GetSV(false)); - newCONSTSUB(pZNCSpace, "HALT", PString(HALT).GetSV(false)); - newCONSTSUB(pZNCSpace, "HALTMODS", PString(HALTMODS).GetSV(false)); - newCONSTSUB(pZNCSpace, "HALTCORE", PString(HALTCORE).GetSV(false)); - - return(true); -} - -void CModPerl::LoadPerlMod(const CString & sModule) -{ - if (!m_pUser) - { - DEBUG("LoadPerlMod: No User is set!!!"); - return; - } - - CString sModPath, sTmp; - - if (!CModules::FindModPath(sModule, sModPath, sTmp)) - PutStatus("No such module " + sModule); - else - { - PutStatus("Using " + sModPath); - Eval("ZNC::CORELoadMod('" + m_pUser->GetUserName() + "', '" + sModPath + "');"); - } -} - -void CModPerl::DestroyAllSocks(const CString & sModuleName) -{ - for (u_int a = 0; a < m_pManager->size(); a++) - { - if ((*m_pManager)[a]->GetSockName() == ZNCSOCK) - { - if ((sModuleName.empty()) || (sModuleName == ((CPerlSock *)(*m_pManager)[a])->GetModuleName())) - m_pManager->DelSock(a--); - } - } -} -void CModPerl::UnloadPerlMod(const CString & sModule) -{ - DestroyAllSocks(sModule); - if (!m_pUser) - { - DEBUG("UnloadPerlMod: No User is set!!!"); - return; - } - Eval("ZNC::COREUnloadMod('" + m_pUser->GetUserName() + "', '" + sModule + "');"); -} - - -CModPerl::EModRet CModPerl::OnDCCUserSend(const CNick& RemoteNick, unsigned long uLongIP, unsigned short uPort, - const CString& sFile, unsigned long uFileSize) -{ - VPString vsArgs; - vsArgs.push_back(NICK(RemoteNick)); - vsArgs.push_back(uLongIP); - vsArgs.push_back(uPort); - vsArgs.push_back(sFile); - - return(CallBack("OnDCCUserSend", vsArgs)); -} - -void CPerlTimer::RunJob() -{ - if (!((CModPerl *)m_pModule)->GetUser(m_sUserName, true)) - { - Stop(); - return; - } - - VPString vArgs; - vArgs.push_back(m_sModuleName); - if (((CModPerl *)m_pModule)->CallBack(m_sFuncName, vArgs, CModPerl::CB_TIMER) != CModPerl::CONTINUE) - Stop(); - - ((CModPerl *)m_pModule)->UnSetUser(); -} - -/////////////////////////// CPerlSock stuff //////////////////// -#define SOCKCB(a) if (CallBack(a) != CModPerl::CONTINUE) { Close(); } -int CPerlSock::CallBack(const PString & sFuncName) -{ - if (!g_ModPerl->GetUser(m_sUsername, true)) - { - Close(); - return(CModPerl::HALT); - } - int i = g_ModPerl->CallBack(sFuncName, m_vArgs, CModPerl::CB_SOCK, m_sUsername); - g_ModPerl->UnSetUser(); - return(i); -} - -// # OnConnect($sockhandle, $parentsockhandle) -void CPerlSock::Connected() -{ - if (GetType() == INBOUND) - { - m_vArgs.clear(); - m_vArgs.push_back(m_sModuleName); - m_vArgs.push_back(m_iParentFD); - m_vArgs.push_back(GetRSock()); - SOCKCB("OnNewSock"); - } - SetupArgs(); - if (GetType() == INBOUND) - AddArg(m_iParentFD); - - SOCKCB("OnConnect") -} - -// # OnConnectionFrom($sockhandle, $remotehost, $remoteport) -bool CPerlSock::ConnectionFrom(const CS_STRING & sHost, u_short iPort) -{ - SetupArgs(); - AddArg(sHost); - AddArg(iPort); - - // special case here - if (CallBack("OnConnectionFrom") != CModPerl::CONTINUE) - return(false); - - return(true); -} - - -// # OnError($sockhandle, $errno) -void CPerlSock::SockError(int iErrno) -{ - SetupArgs(); - AddArg(iErrno); - SOCKCB("OnError") -} - -// # OnConnectionRefused($sockhandle) -void CPerlSock::ConnectionRefused() -{ - SetupArgs(); - SOCKCB("OnConnectionRefused") -} - -// # OnTimeout($sockhandle) -void CPerlSock::Timeout() -{ - SetupArgs(); - SOCKCB("OnTimeout") -} - -// # OnDisconnect($sockhandle) -void CPerlSock::Disconnected() -{ - SetupArgs(); - SOCKCB("OnDisconnect"); -} -// # OnData($sockhandle, $bytes, $length) -void CPerlSock::ReadData(const char *data, size_t len) -{ - SetupArgs(); - PString sData; - sData.append(data, len); - AddArg(sData); - AddArg(len); - SOCKCB("OnData") -} -// # OnReadLine($sockhandle, $line) -void CPerlSock::ReadLine(const CS_STRING & sLine) -{ - SetupArgs(); - AddArg(sLine); - SOCKCB("OnReadLine"); -} - -// # OnSockDestroy($sockhandle) -CPerlSock::~CPerlSock() -{ - SetupArgs(); - CallBack("OnSockDestroy"); -} - -Csock *CPerlSock::GetSockObj(const CS_STRING & sHostname, u_short iPort) -{ - CPerlSock *p = new CPerlSock(sHostname, iPort); - p->SetParentFD(GetRSock()); - p->SetUsername(m_sUsername); - p->SetModuleName(m_sModuleName); - p->SetSockName(ZNCSOCK); - if (HasReadLine()) - p->EnableReadLine(); - - return(p); -} diff --git a/modules/modperl.pm b/modules/modperl.pm deleted file mode 100644 index 9403fdb5..00000000 --- a/modules/modperl.pm +++ /dev/null @@ -1,447 +0,0 @@ -# TODO need Close() - -package ZNC; -use strict; - -my @MODS = (); - -sub COREEval -{ - my $arg = shift; - eval $arg; -} - -sub CORECallFunc -{ - my ( $Username, $Func, @args ) = @_; - my $FinalRet = CONTINUE(); - - foreach( @MODS ) - { - next if ( $_->{ZNC_Username} ne $Username ); - - if ( $_->can( $Func ) ) - { - my $Ret = $_->$Func( @args ); - - if ( $Ret == HALT() ) - { - return( $Ret ); - } - - if ( $Ret == HALTMODS() ) - { - return( $Ret ); - } - - if ( $Ret == HALTCORE() ) - { - $FinalRet = $Ret; - } - } - } - - return( $FinalRet ); -} - -sub CORELoadMod -{ - my ( $Username, $ModPath ) = @_; - - my $Module; - if ( $ModPath =~ /\/([^\/.]+)\.pm/ ) - { - $Module = $1; - } - if ( !$Module ) - { - ZNC::PutModule( "Invalid Module requested!" ); - return( HALTMODS() ); - } - - my $DPath = GetString( "SavePath" ); - my $FileName = $DPath . "/." . $Username . $Module . ".pm"; - - if ( !open( INMOD, $ModPath ) ) - { - ZNC::PutModule( "Unable to open module $ModPath!" ); - return( HALTMODS() ); - } - if ( !open( OUTMOD, ">$FileName" ) ) - { - ZNC::PutModule( "Unable to write to Module cache $FileName!" ); - close( INMOD ); - return( HALTMODS() ); - } - - foreach( @MODS ) - { - if ( ( $_->{ZNC_Username} eq $Username ) && ( $_->{ZNC_Name} eq $Module ) ) - { - ZNC::PutModule( "$Module Already Loaded" ); - return( HALTMODS() ); - } - } - - my $bFoundPackage = 0; - while( ) - { - if ( $_ =~ /^\s*package\s*$Module\s*;/ ) - { - print OUTMOD "package $Username$Module;\n"; - $bFoundPackage = 1; - } - else - { - print OUTMOD $_; - } - } - close( INMOD ); - close( OUTMOD ); - - if( !$bFoundPackage ) - { - ZNC::PutModule( "Warning, did not find 'package $Module;' in $FileName" ); - } - - if ( $INC{$FileName} ) - { # force a delete on this guy - delete $INC{$FileName}; - } - - require $FileName; - - my $NewMod = $Username . $Module; - my $obj = new $NewMod(); - if ( !$obj ) - { - ZNC::PutModule( "$Module Failed to load" ); - return( HALTMODS() ); - } - - $obj->{ZNC_Username} = $Username; - $obj->{ZNC_Name} = $Module; - $obj->{ZNC_ModPath} = $FileName; - @{$obj->{socks}} = (); - - push( @MODS, $obj ); - ZNC::PutModule( "Loaded $Module" ); -} - -sub COREUnloadMod -{ - my ( $Username, $Module ) = @_; - - $Module =~ s/(.+?)\.pm/$1/; - - if ( !$Module ) - { - ZNC::PutModule( "Invalid Module requested!" ); - return( HALTMODS() ); - } - - for( my $i = 0; $i < @MODS; $i++ ) - { - if ( ( $MODS[$i]->{ZNC_Username} eq $Username ) && ( $MODS[$i]->{ZNC_Name} eq $Module ) ) - { - my $filename = $MODS[$i]->{ZNC_ModPath}; - undef $MODS[$i]; - splice( @MODS, $i, 1 ); - if ( $INC{$filename} ) - { # remove the $INC instantiation - delete $INC{$filename}; - } - ZNC::PutModule( "Unloaded $Module" ); - return( CONTINUE() ); - } - } - ZNC::PutModule( "$Module Isn't Loaded" ); - -} - -# the timer is inserted, it just calls this guy and expects it to be here -sub CORECallTimer -{ - my ( $Username, $Func, $ModName ) = @_; - - for( my $i = 0; $i < @MODS; $i++ ) - { - if ( ( $MODS[$i]->{ZNC_Username} eq $Username ) && ( $MODS[$i]->{ZNC_Name} eq $ModName ) ) - { - return( $MODS[$i]->$Func() ); - } - } - return( HALTMODS() ); -} - -sub CORECallSock -{ - my ( $Username, $Func, $ModName, $fd, @args ) = @_; - - for( my $i = 0; $i < @MODS; $i++ ) - { - if ( ( $MODS[$i]->{ZNC_Username} eq $Username ) && ( $MODS[$i]->{ZNC_Name} eq $ModName ) ) - { - ######### Sock methods are in the module directly - if ( @{$MODS[$i]->{socks}} == 0 ) - { # ok, try simple manner, overloads in this here class - if ( $MODS[$i]->can( $Func ) ) - { - my $ret = $MODS[$i]->$Func( $fd, @args ); - if ( $Func eq "OnConnectionFrom" ) - { # special case this for now, requires a return value - return( $ret ); - } - } - return( CONTINUE() ); - } - - ########## they sent us a socket to look at, we'll use it - for( my $a = 0; $a < @{$MODS[$i]->{socks}}; $a++ ) - { - my $obj = ${$MODS[$i]->{socks}}[$a]; - - if ( $obj->{fd} == $fd ) - { - if ( $obj->can( $Func ) ) - { - my $ret = $obj->$Func( @args ); - if ( $Func eq "OnConnectionFrom" ) - { # special case this for now, requires a return value - return( $ret ); - } - elsif ( $Func eq "OnSockDestroy" ) - { - splice( @{$MODS[$i]->{socks}}, $a, 1 ); - } - } - return( CONTINUE() ); - } - } - last; #no point in checking further - } - } - return( HALTMODS() ); -} - -###################### -# Ease Of use USER functions -sub AddTimer -{ - my ( $mod, $funcname, $description, $interval, $cycles ) = @_; - - COREAddTimer( $mod->{ZNC_Name}, $funcname, $description, $interval, $cycles ); -} - -sub RemTimer -{ - my ( $mod, $funcname ) = @_; - CORERemTimer( $mod->{ZNC_Name}, $funcname ); -} - -sub PutModule -{ - my ( $line, $ident, $host ) = @_; - - if ( !$ident ) - { - $ident = "znc"; - } - if ( !$host ) - { - $host = "znc.in"; - } - - COREPutModule( "Module", $line, $ident, $host ); -} - -sub PutModNotice -{ - my ( $line, $ident, $host ) = @_; - - if ( !$ident ) - { - $ident = "znc"; - } - if ( !$host ) - { - $host = "znc.in"; - } - - COREPutModule( "ModNotice", $line, $ident, $host ); -} - -sub PutIRC -{ - my ( $line ) = @_; - COREPuts( "IRC", $line ); -} - -sub PutStatus -{ - my ( $line ) = @_; - COREPuts( "Status", $line ); -} - -sub PutUser -{ - my ( $line ) = @_; - COREPuts( "User", $line ); -} - -sub PutTarget -{ - my ( $target, $line ) = @_; - PutIRC( "PRIVMSG $target :$line" ); -} - -sub Connect -{ - my ( $obj, $host, $port, $timeout, $bEnableReadline, $bUseSSL ) = @_; - if ( ( !$host ) || ( !$port ) ) - { - return( -1 ); - } - - if ( !$timeout ) - { - $timeout = 60; - } - - if ( !$bEnableReadline ) - { - $bEnableReadline = 0; - } - - if ( !$bUseSSL ) - { - $bUseSSL = 0; - } - - return( COREConnect( $obj->{ZNC_Name}, $host, $port, $timeout, $bEnableReadline, $bUseSSL ) ); -} - -sub ConnectSSL -{ - my ( $obj, $host, $port, $timeout, $bEnableReadline, $bUseSSL ) = @_; - - return( Connect( $obj, $host, $port, $timeout, $bEnableReadline, $bUseSSL, 1 ) ); -} - -sub Listen -{ - my ( $obj, $port, $bindhost, $bEnableReadline, $bUseSSL ) = @_; - - if ( !$port ) - { - return( -1 ); - } - - if ( !$bindhost ) - { - $bindhost = ""; - } - - if ( !$bEnableReadline ) - { - $bEnableReadline = 0; - } - - if ( !$bUseSSL ) - { - $bUseSSL = 0; - } - - return( COREListen( $obj->{ZNC_Name}, $port, $bindhost, $bEnableReadline, $bUseSSL ) ); -} - -sub ListenSSL -{ - my ( $obj, $port, $bindhost, $bEnableReadline ) = @_; - return( Listen( $obj, $port, $bindhost, $bEnableReadline, 1 ) ); -} - -1; - - -###################### -## use this if you really want to have fun. be sure you don't leave a reference to the -## handle laying around! ZNC will deal with that inside your module, so its properly closed -package ZNCSocket; - -sub new -{ - my ( $classname, $modobj, $fd ) = @_; - - if ( !defined( $fd ) ) - { - $fd = -1; - } - - my $self = - { - modobj => $modobj, - fd => $fd - }; - - bless( $self, $classname ); - return( $self ); -} - -sub AddSock -{ - my ( $me ) = @_; - push( @{$me->{modobj}->{socks}}, $me ); -} - -sub Connect -{ - my ( $me, $host, $port, $timeout, $bEnableReadline, $bUseSSL ) = @_; - $me->{fd} = ZNC::Connect( $me->{modobj}, $host, $port, $timeout, $bEnableReadline, $bUseSSL ); - return( ( $me->{fd} >= 0 ) ); -} - -sub ConnectSSL -{ - my ( $me, $host, $port, $timeout, $bEnableReadline ) = @_; - $me->{fd} = ZNC::ConnectSSL( $me->{modobj}, $host, $port, $timeout, $bEnableReadline ); - return( ( $me->{fd} >= 0 ) ); -} - -sub Write -{ - my ( $me, $data ) = @_; - return( ZNC::WriteSock( $me->{fd}, $data, length( $data ) ) ); -} - -sub Close -{ - my ( $me ) = @_; - ZNC::CloseSock( $me->{fd} ); -} - -sub SetTimeout -{ - my ( $me, $timeout ) = @_; - ZNC::SetSockValue( $me->{fd}, "timeout", $timeout ); -} - -sub Listen -{ - my ( $me, $port, $bindhost, $bEnableReadline, $bUseSSL ) = @_; - $me->{fd} = ZNC::Listen( $me->{modobj}, $port, $bindhost, $bEnableReadline, $bUseSSL ); - return( ( $me->{fd} >= 0 ) ); -} - -sub ListenSSL -{ - my ( $me, $port, $bindhost, $bEnableReadline ) = @_; - $me->{fd} = ZNC::ListenSSL( $me->{modobj}, $port, $bindhost, $bEnableReadline ); - return( ( $me->{fd} >= 0 ) ); -} - -1; - - - - diff --git a/modules/modperl/CString.i b/modules/modperl/CString.i new file mode 100644 index 00000000..e7ab6344 --- /dev/null +++ b/modules/modperl/CString.i @@ -0,0 +1,260 @@ + +%{ +#include +%} + + + + +%feature("naturalvar") CString; +class CString; + + +/*@SWIG:/usr/share/swig1.3/typemaps/std_strings.swg,74,%typemaps_std_string@*/ + +/*@SWIG:/usr/share/swig1.3/typemaps/std_strings.swg,4,%std_string_asptr@*/ +%fragment("SWIG_" "AsPtr" "_" {CString},"header",fragment="SWIG_AsCharPtrAndSize") { +SWIGINTERN int +SWIG_AsPtr_std_string SWIG_PERL_DECL_ARGS_2(SV * obj, CString **val) +{ + char* buf = 0 ; size_t size = 0; int alloc = SWIG_OLDOBJ; + if (SWIG_IsOK((SWIG_AsCharPtrAndSize(obj, &buf, &size, &alloc)))) { + if (buf) { + if (val) *val = new CString(buf, size - 1); + if (alloc == SWIG_NEWOBJ) free((char*)buf); + return SWIG_NEWOBJ; + } else { + if (val) *val = 0; + return SWIG_OLDOBJ; + } + } else { + static int init = 0; + static swig_type_info* descriptor = 0; + if (!init) { + descriptor = SWIG_TypeQuery("CString" " *"); + init = 1; + } + if (descriptor) { + CString *vptr; + int res = SWIG_ConvertPtr(obj, (void**)&vptr, descriptor, 0); + if (SWIG_IsOK(res) && val) *val = vptr; + return res; + } + } + return SWIG_ERROR; +} +} +/*@SWIG@*/ +/*@SWIG:/usr/share/swig1.3/typemaps/std_strings.swg,52,%std_string_asval@*/ +%fragment("SWIG_" "AsVal" "_" {CString},"header", fragment="SWIG_" "AsPtr" "_" {CString}) { +SWIGINTERN int +SWIG_AsVal_std_string SWIG_PERL_DECL_ARGS_2(SV * obj, CString *val) +{ + CString* v = (CString *) 0; + int res = SWIG_AsPtr_std_string SWIG_PERL_CALL_ARGS_2(obj, &v); + if (!SWIG_IsOK(res)) return res; + if (v) { + if (val) *val = *v; + if (SWIG_IsNewObj(res)) { + free((char*)v); + res = SWIG_DelNewMask(res); + } + return res; + } + return SWIG_ERROR; +} +} +/*@SWIG@*/ +/*@SWIG:/usr/share/swig1.3/typemaps/std_strings.swg,38,%std_string_from@*/ +%fragment("SWIG_" "From" "_" {CString},"header",fragment="SWIG_FromCharPtrAndSize") { +SWIGINTERNINLINE SV * +SWIG_From_std_string SWIG_PERL_DECL_ARGS_1(const CString& s) +{ + if (s.size()) { + return SWIG_FromCharPtrAndSize(s.data(), s.size()); + } else { + return SWIG_FromCharPtrAndSize(s.c_str(), 0); + } +} +} +/*@SWIG@*/ + +/*@SWIG:/usr/share/swig1.3/typemaps/ptrtypes.swg,201,%typemaps_asptrfromn@*/ +/*@SWIG:/usr/share/swig1.3/typemaps/ptrtypes.swg,190,%typemaps_asptrfrom@*/ + /*@SWIG:/usr/share/swig1.3/typemaps/ptrtypes.swg,160,%typemaps_asptr@*/ + %fragment("SWIG_" "AsVal" "_" {CString},"header",fragment="SWIG_" "AsPtr" "_" {CString}) { + SWIGINTERNINLINE int + SWIG_AsVal_std_string SWIG_PERL_CALL_ARGS_2(SV * obj, CString *val) + { + CString *v = (CString *)0; + int res = SWIG_AsPtr_std_string SWIG_PERL_CALL_ARGS_2(obj, &v); + if (!SWIG_IsOK(res)) return res; + if (v) { + if (val) *val = *v; + if (SWIG_IsNewObj(res)) { + free((char*)v); + res = SWIG_DelNewMask(res); + } + return res; + } + return SWIG_ERROR; + } + } + /*@SWIG:/usr/share/swig1.3/typemaps/ptrtypes.swg,28,%ptr_in_typemap@*/ + %typemap(in,fragment="SWIG_" "AsPtr" "_" {CString}) CString { + CString *ptr = (CString *)0; + int res = SWIG_AsPtr_std_string SWIG_PERL_CALL_ARGS_2($input, &ptr); + if (!SWIG_IsOK(res) || !ptr) { + SWIG_exception_fail(SWIG_ArgError((ptr ? res : SWIG_TypeError)), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); + } + $1 = *ptr; + if (SWIG_IsNewObj(res)) free((char*)ptr); + } + %typemap(freearg) CString ""; + %typemap(in,fragment="SWIG_" "AsPtr" "_" {CString}) const CString & (int res = SWIG_OLDOBJ) { + CString *ptr = (CString *)0; + res = SWIG_AsPtr_std_string SWIG_PERL_CALL_ARGS_2($input, &ptr); + if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } + if (!ptr) { SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } + $1 = ptr; + } + %typemap(freearg,noblock=1) const CString & { + if (SWIG_IsNewObj(res$argnum)) free((char*)$1); + } +/*@SWIG@*/; + /*@SWIG:/usr/share/swig1.3/typemaps/ptrtypes.swg,53,%ptr_varin_typemap@*/ + %typemap(varin,fragment="SWIG_" "AsPtr" "_" {CString}) CString { + CString *ptr = (CString *)0; + int res = SWIG_AsPtr_std_string SWIG_PERL_CALL_ARGS_2($input, &ptr); + if (!SWIG_IsOK(res) || !ptr) { + SWIG_exception_fail(SWIG_ArgError((ptr ? res : SWIG_TypeError)), "in variable '""$name""' of type '""$type""'"); + } + $1 = *ptr; + if (SWIG_IsNewObj(res)) free((char*)ptr); + } +/*@SWIG@*/; + ; + /*@SWIG:/usr/share/swig1.3/typemaps/ptrtypes.swg,143,%ptr_typecheck_typemap@*/ +%typemap(typecheck,noblock=1,precedence=135,fragment="SWIG_" "AsPtr" "_" {CString}) CString * { + int res = SWIG_AsPtr_std_string SWIG_PERL_CALL_ARGS_2($input, (CString**)(0)); + $1 = SWIG_CheckState(res); +} + +%typemap(typecheck,noblock=1,precedence=135,fragment="SWIG_" "AsPtr" "_" {CString}) CString, const CString& { + int res = SWIG_AsPtr_std_string SWIG_PERL_CALL_ARGS_2($input, (CString**)(0)); + $1 = SWIG_CheckState(res); +} +/*@SWIG@*/; + /*@SWIG:/usr/share/swig1.3/typemaps/inoutlist.swg,254,%ptr_input_typemap@*/ + /*@SWIG:/usr/share/swig1.3/typemaps/inoutlist.swg,117,%_ptr_input_typemap@*/ + %typemap(in,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString}) CString *INPUT(int res = 0) { + res = SWIG_AsPtr_std_string SWIG_PERL_CALL_ARGS_2($input, &$1); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); + } + res = SWIG_AddTmpMask(res); + } + %typemap(in,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString}) CString &INPUT(int res = 0) { + res = SWIG_AsPtr_std_string SWIG_PERL_CALL_ARGS_2($input, &$1); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); + } + if (!$1) { + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); + } + res = SWIG_AddTmpMask(res); + } + %typemap(freearg,noblock=1,match="in") CString *INPUT, CString &INPUT { + if (SWIG_IsNewObj(res$argnum)) free((char*)$1); + } + %typemap(typecheck,noblock=1,precedence=135,fragment="SWIG_" "AsPtr" "_" {CString}) CString *INPUT, CString &INPUT { + int res = SWIG_AsPtr_std_string SWIG_PERL_CALL_ARGS_2($input, (CString**)0); + $1 = SWIG_CheckState(res); + } +/*@SWIG@*/ +/*@SWIG@*/; +/*@SWIG@*/ + /*@SWIG:/usr/share/swig1.3/typemaps/valtypes.swg,184,%typemaps_from@*/ + /*@SWIG:/usr/share/swig1.3/typemaps/valtypes.swg,55,%value_out_typemap@*/ + %typemap(out,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString, const CString { + $result = SWIG_From_std_string SWIG_PERL_CALL_ARGS_1((CString)($1)); argvi++ ; + } + %typemap(out,noblock=1,fragment="SWIG_" "From" "_" {CString}) const CString& { + $result = SWIG_From_std_string SWIG_PERL_CALL_ARGS_1((CString)(*$1)); argvi++ ; + } +/*@SWIG@*/; + /*@SWIG:/usr/share/swig1.3/typemaps/valtypes.swg,79,%value_varout_typemap@*/ + %typemap(varout,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString, const CString& { + sv_setsv($result,SWIG_From_std_string SWIG_PERL_CALL_ARGS_1((CString)($1))) ; + } +/*@SWIG@*/; + /*@SWIG:/usr/share/swig1.3/typemaps/valtypes.swg,87,%value_constcode_typemap@*/ + %typemap(constcode,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString { + /*@SWIG:/usr/share/swig1.3/perl5/perltypemaps.swg,65,%set_constant@*/ do { + SV *sv = get_sv((char*) SWIG_prefix "$symname", TRUE | 0x2 | GV_ADDMULTI); + sv_setsv(sv, SWIG_From_std_string SWIG_PERL_CALL_ARGS_1((CString)($value))); + SvREADONLY_on(sv); +} while(0) /*@SWIG@*/; + } +/*@SWIG@*/; + ; + /*@SWIG:/usr/share/swig1.3/typemaps/valtypes.swg,154,%value_throws_typemap@*/ + %typemap(throws,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString { + sv_setsv(GvSV(PL_errgv), SWIG_From_std_string SWIG_PERL_CALL_ARGS_1((CString)($1))); SWIG_fail ; + } +/*@SWIG@*/; + /*@SWIG:/usr/share/swig1.3/typemaps/inoutlist.swg,258,%value_output_typemap@*/ + /*@SWIG:/usr/share/swig1.3/typemaps/inoutlist.swg,175,%_value_output_typemap@*/ + %typemap(in,numinputs=0,noblock=1) + CString *OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ), + CString &OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ) { + $1 = &temp; + } + %typemap(argout,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString *OUTPUT, CString &OUTPUT { + if (SWIG_IsTmpObj(res$argnum)) { + if (argvi >= items) EXTEND(sp,1); $result = SWIG_From_std_string SWIG_PERL_CALL_ARGS_1((*$1)); argvi++ ; + } else { + int new_flags = SWIG_IsNewObj(res$argnum) ? (SWIG_POINTER_OWN | $shadow) : $shadow; + if (argvi >= items) EXTEND(sp,1); $result = SWIG_NewPointerObj((void*)($1), $1_descriptor, new_flags); argvi++ ; + } + } +/*@SWIG@*/ +/*@SWIG@*/; +/*@SWIG@*/; + /*@SWIG:/usr/share/swig1.3/typemaps/inoutlist.swg,258,%value_output_typemap@*/ + /*@SWIG:/usr/share/swig1.3/typemaps/inoutlist.swg,175,%_value_output_typemap@*/ + %typemap(in,numinputs=0,noblock=1) + CString *OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ), + CString &OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ) { + $1 = &temp; + } + %typemap(argout,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString *OUTPUT, CString &OUTPUT { + if (SWIG_IsTmpObj(res$argnum)) { + if (argvi >= items) EXTEND(sp,1); $result = SWIG_From_std_string SWIG_PERL_CALL_ARGS_1((*$1)); argvi++ ; + } else { + int new_flags = SWIG_IsNewObj(res$argnum) ? (SWIG_POINTER_OWN | $shadow) : $shadow; + if (argvi >= items) EXTEND(sp,1); $result = SWIG_NewPointerObj((void*)($1), $1_descriptor, new_flags); argvi++ ; + } + } +/*@SWIG@*/ +/*@SWIG@*/; + /*@SWIG:/usr/share/swig1.3/typemaps/inoutlist.swg,240,%_ptr_inout_typemap@*/ + /*@SWIG:/usr/share/swig1.3/typemaps/inoutlist.swg,230,%_value_inout_typemap@*/ + %typemap(in) CString *INOUT = CString *INPUT; + %typemap(in) CString &INOUT = CString &INPUT; + %typemap(typecheck) CString *INOUT = CString *INPUT; + %typemap(typecheck) CString &INOUT = CString &INPUT; + %typemap(argout) CString *INOUT = CString *OUTPUT; + %typemap(argout) CString &INOUT = CString &OUTPUT; +/*@SWIG@*/ + %typemap(typecheck) CString *INOUT = CString *INPUT; + %typemap(typecheck) CString &INOUT = CString &INPUT; + %typemap(freearg) CString *INOUT = CString *INPUT; + %typemap(freearg) CString &INOUT = CString &INPUT; +/*@SWIG@*/; +/*@SWIG@*/; +/*@SWIG@*/; + +/*@SWIG@*/; + + diff --git a/modules/modperl/codegen.pl b/modules/modperl/codegen.pl new file mode 100755 index 00000000..6f5c2ea8 --- /dev/null +++ b/modules/modperl/codegen.pl @@ -0,0 +1,136 @@ +#!/usr/bin/env perl +# +# Copyright (C) 2004-2010 See the AUTHORS file for details. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 as published +# by the Free Software Foundation. +# + +use strict; +use warnings; +use IO::File; +use feature 'switch', 'say'; + +open my $in, "functions.in" or die; +open my $out, "> functions.cpp" or die; + +print $out <<'EOF'; +/* + * Copyright (C) 2004-2010 See the AUTHORS file for details. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +/*************************************************************************** + * This file is generated automatically using codegen.pl from functions.in * + * Don't change it manually. * + ***************************************************************************/ + +/*#include "module.h" +#include "swigperlrun.h" +#include +#include +#include +#include "pstring.h"*/ + +namespace { + template + struct SvToPtr { + CString m_sType; + SvToPtr(const CString& sType) { + m_sType = sType; + } + T* operator()(SV* sv) { + T* result; + int res = SWIG_ConvertPtr(sv, (void**)&result, SWIG_TypeQuery(m_sType.c_str()), 0); + if (SWIG_IsOK(res)) { + return result; + } + return NULL; + } + }; + + CModule::EModRet SvToEModRet(SV* sv) { + return static_cast(SvUV(sv)); + } +} +/* +#define PSTART dSP; I32 ax; int ret = 0; ENTER; SAVETMPS; PUSHMARK(SP) +#define PCALL(name) PUTBACK; ret = call_pv(name, G_EVAL|G_ARRAY); SPAGAIN; SP -= ret; ax = (SP - PL_stack_base) + 1 +#define PEND PUTBACK; FREETMPS; LEAVE +#define PUSH_STR(s) XPUSHs(PString(s).GetSV()) +#define PUSH_PTR(type, p) XPUSHs(SWIG_NewInstanceObj(const_cast(p), SWIG_TypeQuery(#type), SWIG_SHADOW)) +*/ +#define PSTART_IDF(Func) PSTART; PUSH_STR(GetPerlID()); PUSH_STR(#Func) +#define PCALLMOD(Error, Success) PCALL("ZNC::Core::CallModFunc"); if (SvTRUE(ERRSV)) { DEBUG("Perl hook died with: " + PString(ERRSV)); Error; } else { Success; } PEND + +EOF + +while (<$in>) { + my ($type, $name, $args, $default) = /(\S+)\s+(\w+)\((.*)\)(?:=(\w+))?/ or next; + $type =~ s/(EModRet)/CModule::$1/; + $type =~ s/^\s*(.*?)\s*$/$1/; + unless (defined $default) { + given ($type) { + when ('bool') { $default = 'true' } + when ('CModule::EModRet') { $default = 'CONTINUE' } + when ('CString') { $default = '""' } + when (/\*$/) { $default = "($type)NULL" } + } + } + my @arg = map { + my ($t, $v) = /^\s*(.*\W)\s*(\w+)\s*$/; + $t =~ s/^\s*(.*?)\s*$/$1/; + my ($tt, $tm) = $t =~ /^(.*?)\s*?(\*|&)?$/; + {type=>$t, var=>$v, base=>$tt, mod=>$tm//''} + } split /,/, $args; + say $out "$type CPerlModule::$name($args) {"; + say $out "\t$type result = $default;" if $type ne 'void'; + say $out "\tPSTART_IDF($name);"; + given ($type) { + when ('CString') { print $out "\tPUSH_STR($default);" } + when (/\*$/) { my $t=$type; $t=~s/^const//; print $out "\tPUSH_PTR($t, $default);" } + when ('void') { print $out "\tmXPUSHi(0);" } + default { print $out "\tmXPUSHi(static_cast($default));" } + } + say $out " // Default value"; + for my $a (@arg) { + given ($a->{type}) { + when (/(vector\s*<\s*(.*)\*\s*>)/) { + my ($vec, $sub) = ($1, $2); + my $dot = '.'; + $dot = '->' if $a->{mod} eq '*'; + say $out "\tfor (${vec}::const_iterator i = $a->{var}${dot}begin(); i != $a->{var}${dot}end(); ++i) {"; +#atm sub is always "...*" so... + say $out "\t\tPUSH_PTR($sub*, *i);"; + say $out "\t}"; + } + when (/CString/) { say $out "\tPUSH_STR($a->{var});" } + when (/\*$/) { my $t=$a->{type}; $t=~s/^const//; say $out "\tPUSH_PTR($t, $a->{var});" } + when (/&$/) { my $b=$a->{base}; $b=~s/^const//; say $out "\tPUSH_PTR($b*, &$a->{var});" } + } + } + say $out "\tPCALLMOD(,"; + my $x = 0; + say $out "\t\tresult = ".sv($type)."(ST(0));" if $type ne 'void'; + for my $a (@arg) { + $x++; + say $out "\t\t$a->{var} = PString(ST($x));" if $a->{base} eq 'CString' && $a->{mod} eq '&'; + } + say $out "\t);"; + say $out "\treturn result;" if $type ne 'void'; + say $out "}\n"; +} + +sub sv { + my $type = shift; + given ($type) { + when (/^(.*)\*$/) { return "SvToPtr<$1>(\"$type\")" } + when ('CString') { return 'PString' } + when ('CModule::EModRet') { return 'SvToEModRet' } + default { return 'SvUV' } + } +} diff --git a/modules/modperl/functions.cpp b/modules/modperl/functions.cpp new file mode 100644 index 00000000..a7739666 --- /dev/null +++ b/modules/modperl/functions.cpp @@ -0,0 +1,776 @@ +/* + * Copyright (C) 2004-2010 See the AUTHORS file for details. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +/*************************************************************************** + * This file is generated automatically using codegen.pl from functions.in * + * Don't change it manually. * + ***************************************************************************/ + +/*#include "module.h" +#include "swigperlrun.h" +#include +#include +#include +#include "pstring.h"*/ + +namespace { + template + struct SvToPtr { + CString m_sType; + SvToPtr(const CString& sType) { + m_sType = sType; + } + T* operator()(SV* sv) { + T* result; + int res = SWIG_ConvertPtr(sv, (void**)&result, SWIG_TypeQuery(m_sType.c_str()), 0); + if (SWIG_IsOK(res)) { + return result; + } + return NULL; + } + }; + + CModule::EModRet SvToEModRet(SV* sv) { + return static_cast(SvUV(sv)); + } +} +/* +#define PSTART dSP; I32 ax; int ret = 0; ENTER; SAVETMPS; PUSHMARK(SP) +#define PCALL(name) PUTBACK; ret = call_pv(name, G_EVAL|G_ARRAY); SPAGAIN; SP -= ret; ax = (SP - PL_stack_base) + 1 +#define PEND PUTBACK; FREETMPS; LEAVE +#define PUSH_STR(s) XPUSHs(PString(s).GetSV()) +#define PUSH_PTR(type, p) XPUSHs(SWIG_NewInstanceObj(const_cast(p), SWIG_TypeQuery(#type), SWIG_SHADOW)) +*/ +#define PSTART_IDF(Func) PSTART; PUSH_STR(GetPerlID()); PUSH_STR(#Func) +#define PCALLMOD(Error, Success) PCALL("ZNC::Core::CallModFunc"); if (SvTRUE(ERRSV)) { DEBUG("Perl hook died with: " + PString(ERRSV)); Error; } else { Success; } PEND + +bool CPerlModule::OnBoot() { + bool result = true; + PSTART_IDF(OnBoot); + mXPUSHi(static_cast(true)); // Default value + PCALLMOD(, + result = SvUV(ST(0)); + ); + return result; +} + +bool CPerlModule::WebRequiresLogin() { + bool result = true; + PSTART_IDF(WebRequiresLogin); + mXPUSHi(static_cast(true)); // Default value + PCALLMOD(, + result = SvUV(ST(0)); + ); + return result; +} + +bool CPerlModule::WebRequiresAdmin() { + bool result = false; + PSTART_IDF(WebRequiresAdmin); + mXPUSHi(static_cast(false)); // Default value + PCALLMOD(, + result = SvUV(ST(0)); + ); + return result; +} + +CString CPerlModule::GetWebMenuTitle() { + CString result = ""; + PSTART_IDF(GetWebMenuTitle); + PUSH_STR(""); // Default value + PCALLMOD(, + result = PString(ST(0)); + ); + return result; +} + +bool CPerlModule::OnWebPreRequest(CWebSock& WebSock, const CString& sPageName) { + bool result = false; + PSTART_IDF(OnWebPreRequest); + mXPUSHi(static_cast(false)); // Default value + PUSH_PTR(CWebSock*, &WebSock); + PUSH_STR(sPageName); + PCALLMOD(, + result = SvUV(ST(0)); + ); + return result; +} + +bool CPerlModule::OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) { + bool result = false; + PSTART_IDF(OnWebRequest); + mXPUSHi(static_cast(false)); // Default value + PUSH_PTR(CWebSock*, &WebSock); + PUSH_STR(sPageName); + PUSH_PTR(CTemplate*, &Tmpl); + PCALLMOD(, + result = SvUV(ST(0)); + ); + return result; +} + +VWebSubPages* CPerlModule::_GetSubPages() { + VWebSubPages* result = (VWebSubPages*)NULL; + PSTART_IDF(_GetSubPages); + PUSH_PTR(VWebSubPages*, (VWebSubPages*)NULL); // Default value + PCALLMOD(, + result = SvToPtr("VWebSubPages*")(ST(0)); + ); + return result; +} + +void CPerlModule::OnPreRehash() { + PSTART_IDF(OnPreRehash); + mXPUSHi(0); // Default value + PCALLMOD(, + ); +} + +void CPerlModule::OnPostRehash() { + PSTART_IDF(OnPostRehash); + mXPUSHi(0); // Default value + PCALLMOD(, + ); +} + +void CPerlModule::OnIRCDisconnected() { + PSTART_IDF(OnIRCDisconnected); + mXPUSHi(0); // Default value + PCALLMOD(, + ); +} + +void CPerlModule::OnIRCConnected() { + PSTART_IDF(OnIRCConnected); + mXPUSHi(0); // Default value + PCALLMOD(, + ); +} + +CModule::EModRet CPerlModule::OnIRCConnecting(CIRCSock *pIRCSock) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnIRCConnecting); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CIRCSock *, pIRCSock); + PCALLMOD(, + result = SvToEModRet(ST(0)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnIRCRegistration); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sPass); + PUSH_STR(sNick); + PUSH_STR(sIdent); + PUSH_STR(sRealName); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sPass = PString(ST(1)); + sNick = PString(ST(2)); + sIdent = PString(ST(3)); + sRealName = PString(ST(4)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnBroadcast(CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnBroadcast); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sMessage = PString(ST(1)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnConfigLine(const CString& sName, const CString& sValue, CUser* pUser, CChan* pChan) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnConfigLine); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sName); + PUSH_STR(sValue); + PUSH_PTR(CUser*, pUser); + PUSH_PTR(CChan*, pChan); + PCALLMOD(, + result = SvToEModRet(ST(0)); + ); + return result; +} + +void CPerlModule::OnWriteUserConfig(CFile& Config) { + PSTART_IDF(OnWriteUserConfig); + mXPUSHi(0); // Default value + PUSH_PTR(CFile*, &Config); + PCALLMOD(, + ); +} + +void CPerlModule::OnWriteChanConfig(CFile& Config, CChan& Chan) { + PSTART_IDF(OnWriteChanConfig); + mXPUSHi(0); // Default value + PUSH_PTR(CFile*, &Config); + PUSH_PTR(CChan*, &Chan); + PCALLMOD(, + ); +} + +CModule::EModRet CPerlModule::OnDCCUserSend(const CNick& RemoteNick, unsigned long uLongIP, unsigned short uPort, const CString& sFile, unsigned long uFileSize) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnDCCUserSend); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR( CNick*, &RemoteNick); + PUSH_STR(sFile); + PCALLMOD(, + result = SvToEModRet(ST(0)); + ); + return result; +} + +void CPerlModule::OnChanPermission(const CNick& OpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) { + PSTART_IDF(OnChanPermission); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &OpNick); + PUSH_PTR( CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PCALLMOD(, + ); +} + +void CPerlModule::OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { + PSTART_IDF(OnOp); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &OpNick); + PUSH_PTR( CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PCALLMOD(, + ); +} + +void CPerlModule::OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { + PSTART_IDF(OnDeop); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &OpNick); + PUSH_PTR( CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PCALLMOD(, + ); +} + +void CPerlModule::OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { + PSTART_IDF(OnVoice); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &OpNick); + PUSH_PTR( CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PCALLMOD(, + ); +} + +void CPerlModule::OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { + PSTART_IDF(OnDevoice); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &OpNick); + PUSH_PTR( CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PCALLMOD(, + ); +} + +void CPerlModule::OnMode(const CNick& OpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) { + PSTART_IDF(OnMode); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &OpNick); + PUSH_PTR(CChan*, &Channel); + PUSH_STR(sArg); + PCALLMOD(, + ); +} + +void CPerlModule::OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) { + PSTART_IDF(OnRawMode); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &OpNick); + PUSH_PTR(CChan*, &Channel); + PUSH_STR(sModes); + PUSH_STR(sArgs); + PCALLMOD(, + ); +} + +CModule::EModRet CPerlModule::OnRaw(CString& sLine) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnRaw); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sLine); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sLine = PString(ST(1)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnStatusCommand(CString& sCommand) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnStatusCommand); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sCommand); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sCommand = PString(ST(1)); + ); + return result; +} + +void CPerlModule::OnModCommand(const CString& sCommand) { + PSTART_IDF(OnModCommand); + mXPUSHi(0); // Default value + PUSH_STR(sCommand); + PCALLMOD(, + ); +} + +void CPerlModule::OnModNotice(const CString& sMessage) { + PSTART_IDF(OnModNotice); + mXPUSHi(0); // Default value + PUSH_STR(sMessage); + PCALLMOD(, + ); +} + +void CPerlModule::OnModCTCP(const CString& sMessage) { + PSTART_IDF(OnModCTCP); + mXPUSHi(0); // Default value + PUSH_STR(sMessage); + PCALLMOD(, + ); +} + +void CPerlModule::OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) { + PSTART_IDF(OnQuit); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &Nick); + PUSH_STR(sMessage); + for (vector::const_iterator i = vChans.begin(); i != vChans.end(); ++i) { + PUSH_PTR(CChan*, *i); + } + PCALLMOD(, + ); +} + +void CPerlModule::OnNick(const CNick& Nick, const CString& sNewNick, const vector& vChans) { + PSTART_IDF(OnNick); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &Nick); + PUSH_STR(sNewNick); + for (vector::const_iterator i = vChans.begin(); i != vChans.end(); ++i) { + PUSH_PTR(CChan*, *i); + } + PCALLMOD(, + ); +} + +void CPerlModule::OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) { + PSTART_IDF(OnKick); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &OpNick); + PUSH_STR(sKickedNick); + PUSH_PTR(CChan*, &Channel); + PUSH_STR(sMessage); + PCALLMOD(, + ); +} + +void CPerlModule::OnJoin(const CNick& Nick, CChan& Channel) { + PSTART_IDF(OnJoin); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PCALLMOD(, + ); +} + +void CPerlModule::OnPart(const CNick& Nick, CChan& Channel) { + PSTART_IDF(OnPart); + mXPUSHi(0); // Default value + PUSH_PTR( CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PCALLMOD(, + ); +} + +CModule::EModRet CPerlModule::OnChanBufferStarting(CChan& Chan, CClient& Client) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnChanBufferStarting); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CChan*, &Chan); + PUSH_PTR(CClient*, &Client); + PCALLMOD(, + result = SvToEModRet(ST(0)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnChanBufferEnding(CChan& Chan, CClient& Client) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnChanBufferEnding); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CChan*, &Chan); + PUSH_PTR(CClient*, &Client); + PCALLMOD(, + result = SvToEModRet(ST(0)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnChanBufferPlayLine); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CChan*, &Chan); + PUSH_PTR(CClient*, &Client); + PUSH_STR(sLine); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sLine = PString(ST(3)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnPrivBufferPlayLine(CClient& Client, CString& sLine) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnPrivBufferPlayLine); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CClient*, &Client); + PUSH_STR(sLine); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sLine = PString(ST(2)); + ); + return result; +} + +void CPerlModule::OnClientLogin() { + PSTART_IDF(OnClientLogin); + mXPUSHi(0); // Default value + PCALLMOD(, + ); +} + +void CPerlModule::OnClientDisconnect() { + PSTART_IDF(OnClientDisconnect); + mXPUSHi(0); // Default value + PCALLMOD(, + ); +} + +CModule::EModRet CPerlModule::OnUserRaw(CString& sLine) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnUserRaw); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sLine); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sLine = PString(ST(1)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnUserCTCPReply(CString& sTarget, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnUserCTCPReply); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sTarget); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sTarget = PString(ST(1)); + sMessage = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnUserCTCP(CString& sTarget, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnUserCTCP); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sTarget); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sTarget = PString(ST(1)); + sMessage = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnUserAction(CString& sTarget, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnUserAction); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sTarget); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sTarget = PString(ST(1)); + sMessage = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnUserMsg(CString& sTarget, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnUserMsg); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sTarget); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sTarget = PString(ST(1)); + sMessage = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnUserNotice(CString& sTarget, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnUserNotice); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sTarget); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sTarget = PString(ST(1)); + sMessage = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnUserJoin(CString& sChannel, CString& sKey) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnUserJoin); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sChannel); + PUSH_STR(sKey); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sChannel = PString(ST(1)); + sKey = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnUserPart(CString& sChannel, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnUserPart); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sChannel); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sChannel = PString(ST(1)); + sMessage = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnUserTopic(CString& sChannel, CString& sTopic) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnUserTopic); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sChannel); + PUSH_STR(sTopic); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sChannel = PString(ST(1)); + sTopic = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnUserTopicRequest(CString& sChannel) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnUserTopicRequest); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_STR(sChannel); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sChannel = PString(ST(1)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnCTCPReply(CNick& Nick, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnCTCPReply); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CNick*, &Nick); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sMessage = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnPrivCTCP(CNick& Nick, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnPrivCTCP); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CNick*, &Nick); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sMessage = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnChanCTCP); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sMessage = PString(ST(3)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnPrivAction(CNick& Nick, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnPrivAction); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CNick*, &Nick); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sMessage = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnChanAction); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sMessage = PString(ST(3)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnPrivMsg(CNick& Nick, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnPrivMsg); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CNick*, &Nick); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sMessage = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnChanMsg); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sMessage = PString(ST(3)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnPrivNotice(CNick& Nick, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnPrivNotice); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CNick*, &Nick); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sMessage = PString(ST(2)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnChanNotice); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PUSH_STR(sMessage); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sMessage = PString(ST(3)); + ); + return result; +} + +CModule::EModRet CPerlModule::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnTopic); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CNick*, &Nick); + PUSH_PTR(CChan*, &Channel); + PUSH_STR(sTopic); + PCALLMOD(, + result = SvToEModRet(ST(0)); + sTopic = PString(ST(3)); + ); + return result; +} + +bool CPerlModule::OnServerCapAvailable(const CString& sCap) { + bool result = false; + PSTART_IDF(OnServerCapAvailable); + mXPUSHi(static_cast(false)); // Default value + PUSH_STR(sCap); + PCALLMOD(, + result = SvUV(ST(0)); + ); + return result; +} + +void CPerlModule::OnServerCapResult(const CString& sCap, bool bSuccess) { + PSTART_IDF(OnServerCapResult); + mXPUSHi(0); // Default value + PUSH_STR(sCap); + PCALLMOD(, + ); +} + +CModule::EModRet CPerlModule::OnTimerAutoJoin(CChan& Channel) { + CModule::EModRet result = CONTINUE; + PSTART_IDF(OnTimerAutoJoin); + mXPUSHi(static_cast(CONTINUE)); // Default value + PUSH_PTR(CChan*, &Channel); + PCALLMOD(, + result = SvToEModRet(ST(0)); + ); + return result; +} + diff --git a/modules/modperl/functions.in b/modules/modperl/functions.in new file mode 100644 index 00000000..fbdb7e91 --- /dev/null +++ b/modules/modperl/functions.in @@ -0,0 +1,65 @@ +bool OnBoot()=true +bool WebRequiresLogin()=true +bool WebRequiresAdmin()=false +CString GetWebMenuTitle() +bool OnWebPreRequest(CWebSock& WebSock, const CString& sPageName)=false +bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl)=false +VWebSubPages* _GetSubPages() +void OnPreRehash() +void OnPostRehash() +void OnIRCDisconnected() +void OnIRCConnected() +EModRet OnIRCConnecting(CIRCSock *pIRCSock) +EModRet OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) +EModRet OnBroadcast(CString& sMessage) +EModRet OnConfigLine(const CString& sName, const CString& sValue, CUser* pUser, CChan* pChan) +void OnWriteUserConfig(CFile& Config) +void OnWriteChanConfig(CFile& Config, CChan& Chan) +EModRet OnDCCUserSend(const CNick& RemoteNick, unsigned long uLongIP, unsigned short uPort, const CString& sFile, unsigned long uFileSize) +void OnChanPermission(const CNick& OpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) +void OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) +void OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) +void OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) +void OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) +void OnMode(const CNick& OpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) +void OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) +EModRet OnRaw(CString& sLine) +EModRet OnStatusCommand(CString& sCommand) +void OnModCommand(const CString& sCommand) +void OnModNotice(const CString& sMessage) +void OnModCTCP(const CString& sMessage) +void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) +void OnNick(const CNick& Nick, const CString& sNewNick, const vector& vChans) +void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) +void OnJoin(const CNick& Nick, CChan& Channel) +void OnPart(const CNick& Nick, CChan& Channel) +EModRet OnChanBufferStarting(CChan& Chan, CClient& Client) +EModRet OnChanBufferEnding(CChan& Chan, CClient& Client) +EModRet OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) +EModRet OnPrivBufferPlayLine(CClient& Client, CString& sLine) +void OnClientLogin() +void OnClientDisconnect() +EModRet OnUserRaw(CString& sLine) +EModRet OnUserCTCPReply(CString& sTarget, CString& sMessage) +EModRet OnUserCTCP(CString& sTarget, CString& sMessage) +EModRet OnUserAction(CString& sTarget, CString& sMessage) +EModRet OnUserMsg(CString& sTarget, CString& sMessage) +EModRet OnUserNotice(CString& sTarget, CString& sMessage) +EModRet OnUserJoin(CString& sChannel, CString& sKey) +EModRet OnUserPart(CString& sChannel, CString& sMessage) +EModRet OnUserTopic(CString& sChannel, CString& sTopic) +EModRet OnUserTopicRequest(CString& sChannel) +EModRet OnCTCPReply(CNick& Nick, CString& sMessage) +EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) +EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) +EModRet OnPrivAction(CNick& Nick, CString& sMessage) +EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) +EModRet OnPrivMsg(CNick& Nick, CString& sMessage) +EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) +EModRet OnPrivNotice(CNick& Nick, CString& sMessage) +EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) +EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) +bool OnServerCapAvailable(const CString& sCap)=false +void OnServerCapResult(const CString& sCap, bool bSuccess) +EModRet OnTimerAutoJoin(CChan& Channel) + diff --git a/modules/modperl/modperl.i b/modules/modperl/modperl.i new file mode 100644 index 00000000..55f43189 --- /dev/null +++ b/modules/modperl/modperl.i @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2004-2010 See the AUTHORS file for details. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +%module ZNC %{ +#ifdef Copy +# undef Copy +#endif +#include +#include "../Utils.h" +#include "../Socket.h" +#include "../Modules.h" +#include "../Nick.h" +#include "../Chan.h" +#include "../User.h" +#include "../Client.h" +#include "../IRCSock.h" +#include "../Listener.h" +#include "../HTTPSock.h" +#include "../Template.h" +#include "../WebModules.h" +#include "../znc.h" +#include "../Server.h" +#include "../ZNCString.h" +#include "../DCCBounce.h" +#include "../DCCSock.h" +#include "../FileUtils.h" +#include "modperl/module.h" +#define stat struct stat +%} + +%include +%include +%include + +namespace std { + template class set { + public: + set(); + set(const set&); + }; +} +%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++; +} + +#define u_short unsigned short +#define u_int unsigned int +#include "../ZNCString.h" +%include "../defines.h" +%include "../Utils.h" +%include "../Csocket.h" +%template(ZNCSocketManager) TSocketManager; +%include "../Socket.h" +%include "../DCCBounce.h" +%include "../DCCSock.h" +%include "../FileUtils.h" +%include "../Modules.h" +%include "../Nick.h" +%include "../Chan.h" +%include "../User.h" +%include "../Client.h" +%include "../IRCSock.h" +%include "../Listener.h" +%include "../HTTPSock.h" +%include "../Template.h" +%include "../WebModules.h" +%include "../znc.h" +%include "../Server.h" + +%include "modperl/module.h" + +%inline %{ + class String : public CString { + public: + String() {} + String(const CString& s) : CString(s) {} + String(double d, int prec=2): CString(d, prec) {} + String(float f, int prec=2) : CString(f, prec) {} + String(int i) : CString(i) {} + String(unsigned int i) : CString(i) {} + String(long int i) : CString(i) {} + String(unsigned long int i) : CString(i) {} + String(char c) : CString(c) {} + String(unsigned char c) : CString(c) {} + String(short int i) : CString(i) {} + String(unsigned short int i): CString(i) {} + String(bool b) : CString(b) {} + CString GetPerlStr() { + return *this; + } + }; +%} + +%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; + } + 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); + } + bool removeModule(CModule* p) { + for (CModules::iterator i = $self->begin(); $self->end() != i; ++i) { + if (*i == p) { + $self->erase(i); + return true; + } + } + return false; + } +} + +/* Web */ + +%template(StrPair) pair; +%template(VPair) vector >; +typedef vector > VPair; +%template(VWebSubPages) vector; + +%inline %{ + void _VPair_Add2Str(VPair* self, const CString& a, const CString& b) { + self->push_back(std::make_pair(a, b)); + } +%} + +%extend CTemplate { + void set(const CString& key, const CString& value) { + (*$self)[key] = value; + } +} + +%inline %{ + TWebSubPage _CreateWebSubPage(const CString& sName, const CString& sTitle, const VPair& vParams, unsigned int uFlags) { + return new CWebSubPage(sName, sTitle, vParams, uFlags); + } +%} + +%perlcode %{ + package ZNC; + sub CreateWebSubPage { + my ($name, %arg) = @_; + my $params = $arg{params}//{}; + my $vpair = ZNC::VPair->new; + while (my ($key, $val) = each %$params) { + ZNC::_VPair_Add2Str($vpair, $key, $val); + } + my $flags = 0; + $flags |= $ZNC::CWebSubPage::F_ADMIN if $arg{admin}//0; + return _CreateWebSubPage($name, $arg{title}//'', $vpair, $flags); + } +%} + +%perlcode %{ + package ZNC; + *CONTINUE = *ZNC::CModule::CONTINUE; + *HALT = *ZNC::CModule::HALT; + *HALTMODS = *ZNC::CModule::HALTMODS; + *HALTCORE = *ZNC::CModule::HALTCORE; + *UNLOAD = *ZNC::CModule::UNLOAD; +%} + diff --git a/modules/modperl/module.h b/modules/modperl/module.h new file mode 100644 index 00000000..c62c6afd --- /dev/null +++ b/modules/modperl/module.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2004-2010 See the AUTHORS file for details. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#pragma once + +#include "Modules.h" + +class CPerlModule : public CModule { + CString m_sPerlID; + VWebSubPages* _GetSubPages(); +public: + CPerlModule(CUser* pUser, const CString& sModName, const CString& sDataPath, + const CString& sPerlID) + : CModule(NULL, pUser, sModName, sDataPath) { + m_sPerlID = sPerlID; + } + CString GetPerlID() { return m_sPerlID; } + + virtual bool OnBoot(); + virtual bool WebRequiresLogin(); + virtual bool WebRequiresAdmin(); + virtual CString GetWebMenuTitle(); + virtual bool OnWebPreRequest(CWebSock& WebSock, const CString& sPageName); + virtual bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl); + virtual VWebSubPages& GetSubPages(); + virtual void OnPreRehash(); + virtual void OnPostRehash(); + virtual void OnIRCDisconnected(); + virtual void OnIRCConnected(); + virtual EModRet OnIRCConnecting(CIRCSock *pIRCSock); + virtual EModRet OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName); + virtual EModRet OnBroadcast(CString& sMessage); + virtual EModRet OnConfigLine(const CString& sName, const CString& sValue, CUser* pUser, CChan* pChan); + virtual void OnWriteUserConfig(CFile& Config); + virtual void OnWriteChanConfig(CFile& Config, CChan& Chan); + virtual EModRet OnDCCUserSend(const CNick& RemoteNick, unsigned long uLongIP, unsigned short uPort, const CString& sFile, unsigned long uFileSize); + virtual void OnChanPermission(const CNick& OpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange); + virtual void OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange); + virtual void OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange); + virtual void OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange); + virtual void OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange); + virtual void OnMode(const CNick& OpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange); + virtual void OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs); + virtual EModRet OnRaw(CString& sLine); + virtual EModRet OnStatusCommand(CString& sCommand); + virtual void OnModCommand(const CString& sCommand); + virtual void OnModNotice(const CString& sMessage); + virtual void OnModCTCP(const CString& sMessage); + virtual void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans); + virtual void OnNick(const CNick& Nick, const CString& sNewNick, const vector& vChans); + virtual void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage); + virtual void OnJoin(const CNick& Nick, CChan& Channel); + virtual void OnPart(const CNick& Nick, CChan& Channel); + virtual EModRet OnChanBufferStarting(CChan& Chan, CClient& Client); + virtual EModRet OnChanBufferEnding(CChan& Chan, CClient& Client); + virtual EModRet OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine); + virtual EModRet OnPrivBufferPlayLine(CClient& Client, CString& sLine); + virtual void OnClientLogin(); + virtual void OnClientDisconnect(); + virtual EModRet OnUserRaw(CString& sLine); + virtual EModRet OnUserCTCPReply(CString& sTarget, CString& sMessage); + virtual EModRet OnUserCTCP(CString& sTarget, CString& sMessage); + virtual EModRet OnUserAction(CString& sTarget, CString& sMessage); + virtual EModRet OnUserMsg(CString& sTarget, CString& sMessage); + virtual EModRet OnUserNotice(CString& sTarget, CString& sMessage); + virtual EModRet OnUserJoin(CString& sChannel, CString& sKey); + virtual EModRet OnUserPart(CString& sChannel, CString& sMessage); + virtual EModRet OnUserTopic(CString& sChannel, CString& sTopic); + virtual EModRet OnUserTopicRequest(CString& sChannel); + virtual EModRet OnCTCPReply(CNick& Nick, CString& sMessage); + virtual EModRet OnPrivCTCP(CNick& Nick, CString& sMessage); + virtual EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage); + virtual EModRet OnPrivAction(CNick& Nick, CString& sMessage); + virtual EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage); + virtual EModRet OnPrivMsg(CNick& Nick, CString& sMessage); + virtual EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage); + virtual EModRet OnPrivNotice(CNick& Nick, CString& sMessage); + virtual EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage); + virtual EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic); + virtual bool OnServerCapAvailable(const CString& sCap); + virtual void OnServerCapResult(const CString& sCap, bool bSuccess); + virtual EModRet OnTimerAutoJoin(CChan& Channel); +}; + +static inline CPerlModule* AsPerlModule(CModule* p) { + return dynamic_cast(p); +} + +enum ELoadPerlMod { + Perl_NotFound, + Perl_Loaded, + Perl_LoadError, +}; + +class CPerlTimer : public CTimer { + CString m_sPerlID; +public: + CPerlTimer(CPerlModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription, const CString& sPerlID) + : CTimer (pModule, uInterval, uCycles, sLabel, sDescription), m_sPerlID(sPerlID) { + pModule->AddTimer(this); + } + virtual void RunJob(); + CString GetPerlID() { return m_sPerlID; } +}; + +inline CPerlTimer* CreatePerlTimer(CPerlModule* pModule, unsigned int uInterval, unsigned int uCycles, + const CString& sLabel, const CString& sDescription, const CString& sPerlID) { + return new CPerlTimer(pModule, uInterval, uCycles, sLabel, sDescription, sPerlID); +} + +class CPerlSocket : public CSocket { + CString m_sPerlID; +public: + CPerlSocket(CPerlModule* pModule, const CString& sPerlID) : CSocket(pModule), m_sPerlID(sPerlID) {} + CString GetPerlID() { return m_sPerlID; } + virtual void Connected(); + virtual void Disconnected(); + virtual void Timeout(); + virtual void ConnectionRefused(); + virtual void ReadData(const char *data, size_t len); + virtual void ReadLine(const CString& sLine); + virtual Csock* GetSockObj(const CString& sHost, unsigned short uPort); +}; + +inline CPerlSocket* CreatePerlSocket(CPerlModule* pModule, const CString& sPerlID) { + return new CPerlSocket(pModule, sPerlID); +} + +inline bool HaveIPv6() { +#ifdef HAVE_IPV6 + return true; +#endif + return false; +} + +inline bool HaveSSL() { +#ifdef HAVE_LIBSSL + return true; +#endif + return false; +} + +inline bool HaveCAres() { +#ifdef HAVE_C_ARES + return true; +#endif + return false; +} + +inline int _GetSOMAXCONN() { + return SOMAXCONN; +} diff --git a/modules/modperl/pstring.h b/modules/modperl/pstring.h new file mode 100644 index 00000000..80e650d2 --- /dev/null +++ b/modules/modperl/pstring.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2004-2010 See the AUTHORS file for details. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#pragma once + +class PString : public CString { + public: + enum EType { + STRING, + INT, + UINT, + NUM, + BOOL + }; + + PString() : CString() { m_eType = STRING; } + PString(const char* c) : CString(c) { m_eType = STRING; } + PString(const CString& s) : CString(s) { m_eType = STRING; } + PString(int i) : CString(i) { m_eType = INT; } + PString(u_int i) : CString(i) { m_eType = UINT; } + PString(long i) : CString(i) { m_eType = INT; } + PString(u_long i) : CString(i) { m_eType = UINT; } + PString(long long i) : CString(i) { m_eType = INT; } + PString(unsigned long long i) : CString(i) { m_eType = UINT; } + PString(double i) : CString(i) { m_eType = NUM; } + PString(bool b) : CString((b ? "1" : "0")) { m_eType = BOOL; } + PString(SV* sv) { + STRLEN len = SvCUR(sv); + char* c = SvPV(sv, len); + char* c2 = new char[len+1]; + memcpy(c2, c, len); + c2[len] = 0; + *this = c2; + delete[] c2; + } + + virtual ~PString() {} + + EType GetType() const { return m_eType; } + void SetType(EType e) { m_eType = e; } + + SV* GetSV(bool bMakeMortal = true) const + { + SV* pSV = NULL; + switch (GetType()) { + case NUM: + pSV = newSVnv(ToDouble()); + break; + case INT: + pSV = newSViv(ToLongLong()); + break; + case UINT: + case BOOL: + pSV = newSVuv(ToULongLong()); + break; + case STRING: + default: + pSV = newSVpv(data(), length()); + break; + } + + if (bMakeMortal) { + pSV = sv_2mortal(pSV); + } + + return pSV; + } + + private: + EType m_eType; +}; + + diff --git a/modules/modperl/startup.pl b/modules/modperl/startup.pl new file mode 100644 index 00000000..b8cf665e --- /dev/null +++ b/modules/modperl/startup.pl @@ -0,0 +1,458 @@ +# +# Copyright (C) 2004-2010 See the AUTHORS file for details. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 as published +# by the Free Software Foundation. +# + +use strict; +use warnings; +use ZNC; +use Data::UUID; +use IO::File; +use feature 'switch'; + +package ZNC::Core; + +my $uuidgen; +our %pmods; + +sub Init { + $uuidgen = new Data::UUID; +} + +sub CreateUUID { + $uuidgen->create_str; +} + +sub unloadByIDUser { + my ($id, $user) = @_; + $pmods{$id}->OnShutdown; + $user->GetModules->removeModule($pmods{$id}{_cmod}); + delete $pmods{$id}{_cmod};# Just for the case + delete $pmods{$id}{_nv}; + delete $pmods{$id}{_ptimers}; + delete $pmods{$id}{_sockets}; + delete $pmods{$id}; +} + +sub UnloadModule { + my ($cmod) = @_; + unloadByIDUser($cmod->GetPerlID, $cmod->GetUser); +} + +sub UnloadAll { + while (my ($id, $pmod) = each %pmods) { + unloadByIDUser($id, $pmod->{_cmod}->GetUser); + } +} + +sub IsModule { + my $path = shift; + my $modname = shift; + my $f = IO::File->new($path); + grep {/package\s+$modname\s*;/} <$f>; +} + +sub LoadModule { + my ($modname, $args, $user) = @_; + $modname =~ /^\w+$/ or return ($ZNC::Perl_LoadError, "Module names can only contain letters, numbers and underscores, [$modname] is invalid."); + return ($ZNC::Perl_LoadError, "Module [$modname] already loaded.") if defined $user->GetModules->FindModule($modname); + my $modpath = ZNC::String->new; + my $datapath = ZNC::String->new; + ZNC::CModules::FindModPath("$modname.pm", $modpath, $datapath) or return ($ZNC::Perl_NotFound, "Unable to find module [$modname]"); + $modpath = $modpath->GetPerlStr; + return ($ZNC::Perl_LoadError, "Incorrect perl module.") unless IsModule $modpath, $modname; + require $modpath; + my $id = CreateUUID; + $datapath = $datapath->GetPerlStr; + $datapath =~ s/\.pm$//; + my $cmod = ZNC::CPerlModule->new($user, $modname, $datapath, $id); + my %nv; + tie %nv, 'ZNC::ModuleNV', $cmod; + my $pmod = bless { + _cmod=>$cmod, + _nv=>\%nv + }, $modname; + $cmod->SetDescription($pmod->description); + $cmod->SetArgs($args); + $cmod->SetModPath($modpath); + $pmods{$id} = $pmod; + $user->GetModules->push_back($cmod); + my $x = ''; + my $loaded = 0; + eval { + $loaded = $pmod->OnLoad($args, $x); + }; + if ($@) { + $x .= ' ' if '' ne $x; + $x .= $@; + } + if (!$loaded) { + unloadByIDUser($id, $user); + if ($x) { + return ($ZNC::Perl_LoadError, "Module [$modname] aborted: $x"); + } + return ($ZNC::Perl_LoadError, "Module [$modname] aborted."); + } + if ($x) { + return ($ZNC::Perl_Loaded, "Loaded module [$modname] [$x] [$modpath]"); + } + return ($ZNC::Perl_Loaded, "Loaded module [$modname] [$modpath]") +} + +sub GetModInfo { + my ($modname) = @_; + $modname =~ /^\w+$/ or return ($ZNC::Perl_LoadError, "Module names can only contain letters, numbers and underscores, [$modname] is invalid."); + my $modpath = ZNC::String->new; + my $datapath = ZNC::String->new; + ZNC::CModules::FindModPath("$modname.pm", $modpath, $datapath) or return ($ZNC::Perl_NotFound, "Unable to find module [$modname]"); + $modpath = $modpath->GetPerlStr; + return ($ZNC::Perl_LoadError, "Incorrect perl module.") unless IsModule $modpath, $modname; + require $modpath; + my $pmod = bless {}, $modname; + return ($ZNC::Perl_Loaded, $modpath->GetPerlStr, $pmod->description) +} + +sub ModInfoByPath { + my ($modpath, $modname) = @_; + die "Incorrect perl module." unless IsModule $modpath, $modname; + require $modpath; + my $pmod = bless {}, $modname; + return ($pmod->description) +} + +sub CallModFunc { + my $id = shift; + my $func = shift; + my $default = shift; + my @arg = @_; + my $res = $pmods{$id}->$func(@arg); +# print "Returned from $func(@_): $res, (@arg)\n"; + unless (defined $res) { + $res = $default if defined $default; + } + ($res, @arg) +} + +sub CallTimer { + my $modid = shift; + my $timerid = shift; + $pmods{$modid}->_CallTimer($timerid) +} + +sub CallSocket { + my $modid = shift; + $pmods{$modid}->_CallSocket(@_) +} + +package ZNC::ModuleNV; + +sub TIEHASH { + my $name = shift; + my $cmod = shift; + bless {cmod=>$cmod, last=>-1}, $name +} + +sub FETCH { + my $self = shift; + my $key = shift; + return $self->{cmod}->GetNV($key) if $self->{cmod}->ExistsNV($key); + return undef +} + +sub STORE { + my $self = shift; + my $key = shift; + my $value = shift; + $self->{cmod}->SetNV($key, $value); +} + +sub DELETE { + my $self = shift; + my $key = shift; + $self->{cmod}->DelNV($key); +} + +sub CLEAR { + my $self = shift; + $self->{cmod}->ClearNV; +} + +sub EXISTS { + my $self = shift; + my $key = shift; + $self->{cmod}->ExistsNV($key) +} + +sub FIRSTKEY { + my $self = shift; + my @keys = $self->{cmod}->GetNVKeys; + $self->{last} = 0; + return $keys[0]; + return undef; +} + +sub NEXTKEY { + my $self = shift; + my $last = shift; + my @keys = $self->{cmod}->GetNVKeys; + if ($#keys < $self->{last}) { + $self->{last} = -1; + return undef + } + # Probably caller called delete on last key? + if ($last eq $keys[$self->{last}]) { + $self->{last}++ + } + if ($#keys < $self->{last}) { + $self->{last} = -1; + return undef + } + return $keys[$self->{last}] +} + +sub SCALAR { + my $self = shift; + my @keys = $self->{cmod}->GetNVKeys; + return $#keys + 1 +} + +package ZNC::Module; + +sub description { + "< Placeholder for a description >" +} + +# Default implementations for module hooks. They can be overriden in derived modules. +sub OnLoad {1} +sub OnBoot {} +sub OnShutdown {} +sub WebRequiresLogin {} +sub WebRequiresAdmin {} +sub GetWebMenuTitle {} +sub OnWebPreRequest {} +sub OnWebRequest {} +sub GetSubPages {} +sub _GetSubPages { my $self = shift; $self->GetSubPages } +sub OnPreRehash {} +sub OnPostRehash {} +sub OnIRCDisconnected {} +sub OnIRCConnected {} +sub OnIRCConnecting {} +sub OnIRCRegistration {} +sub OnBroadcast {} +sub OnConfigLine {} +sub OnWriteUserConfig {} +sub OnWriteChanConfig {} +sub OnDCCUserSend {} +sub OnChanPermission {} +sub OnOp {} +sub OnDeop {} +sub OnVoice {} +sub OnDevoice {} +sub OnMode {} +sub OnRawMode {} +sub OnRaw {} +sub OnStatusCommand {} +sub OnModCommand {} +sub OnModNotice {} +sub OnModCTCP {} +sub OnQuit {} +sub OnNick {} +sub OnKick {} +sub OnJoin {} +sub OnPart {} +sub OnChanBufferStarting {} +sub OnChanBufferEnding {} +sub OnChanBufferPlayLine {} +sub OnPrivBufferPlayLine {} +sub OnClientLogin {} +sub OnClientDisconnect {} +sub OnUserRaw {} +sub OnUserCTCPReply {} +sub OnUserCTCP {} +sub OnUserAction {} +sub OnUserMsg {} +sub OnUserNotice {} +sub OnUserJoin {} +sub OnUserPart {} +sub OnUserTopic {} +sub OnUserTopicRequest {} +sub OnCTCPReply {} +sub OnPrivCTCP {} +sub OnChanCTCP {} +sub OnPrivAction {} +sub OnChanAction {} +sub OnPrivMsg {} +sub OnChanMsg {} +sub OnPrivNotice {} +sub OnChanNotice {} +sub OnTopic {} +sub OnServerCapAvailable {} +sub OnServerCapResult {} +sub OnTimerAutoJoin {} + + +# Functions of CModule will be usable from perl modules. +our $AUTOLOAD; + +sub AUTOLOAD { + my $name = $AUTOLOAD; + $name =~ s/^.*:://; # Strip fully-qualified portion. + my $sub = sub { + my $self = shift; + $self->{_cmod}->$name(@_) + }; + no strict 'refs'; + *{$AUTOLOAD} = $sub; + use strict 'refs'; + goto &{$sub}; +} + +sub DESTROY {} + +sub BeginNV { + die "Don't use BeginNV from perl modules, use GetNVKeys or NV instead!"; +} +sub EndNV { + die "Don't use EndNV from perl modules, use GetNVKeys or NV instead!"; +} +sub FindNV { + die "Don't use FindNV from perl modules, use GetNVKeys/ExistsNV or NV instead!"; +} + +sub NV { + my $self = shift; + $self->{_nv} +} + +sub CreateTimer { + my ($self, $job, $interval, $cycles, $description) = @_; + my $id = ZNC::Core::CreateUUID; + my $ctimer = ZNC::CreatePerlTimer($self->{_cmod}, $interval, $cycles, "perl-timer-$id", $description, $id); + $self->{_ptimers}{$id}{job} = $job; + $self->{_ptimers}{$id}{cobj} = $ctimer; +} + +sub _CallTimer { + my $self = shift; + my $id = shift; + &{$self->{_ptimers}{$id}{job}}($self, $self->{_ptimers}{$id}{obj}); +} + +sub CreateSocket { + my $self = shift; + my $class = shift; + my $id = ZNC::Core::CreateUUID; + my $csock = ZNC::CreatePerlSocket($self->{_cmod}, $id); + my $psock = bless { + _csock=>$csock, + _modid=>$self->GetPerlID + }, $class; + $self->{_sockets}{$id} = $psock; + $psock->Init(@_); + $psock; +} + +sub _CallSocket { + my $self = shift; + my $id = shift; + my $func = shift; + $self->{_sockets}{$id}->$func(@_) +} + +package ZNC::Socket; + +sub GetModule { + my $self = shift; + $ZNC::Core::pmods{$self->{_modid}}; +} + +sub Init {} +sub OnConnected {} +sub OnDisconnected {} +sub OnTimeout {} +sub OnConnectionRefused {} +sub OnReadData {} +sub OnReadLine {} +sub OnAccepted {} + +sub _Accepted { + my $self = shift; + my $psock = $self->OnAccepted(@_); + return $psock->{_csock} if defined $psock; + return undef; +} + +our $AUTOLOAD; + +sub AUTOLOAD { + my $name = $AUTOLOAD; + $name =~ s/^.*:://; # Strip fully-qualified portion. + my $sub = sub { + my $self = shift; + $self->{_csock}->$name(@_) + }; + no strict 'refs'; + *{$AUTOLOAD} = $sub; + use strict 'refs'; + goto &{$sub}; +} + +sub DESTROY {} + +sub Connect { + my $self = shift; + my $host = shift; + my $port = shift; + my %arg = @_; + $self->GetModule->GetManager->Connect( + $host, + $port, + "perl-socket-".$self->GetPerlID, + $arg{timeout}//60, + $arg{ssl}//0, + $arg{bindhost}//'', + $self->{_csock} + ); +} + +sub Listen { + my $self = shift; + my %arg = @_; + my $addrtype = $ZNC::ADDR_ALL; + if (defined $arg{addrtype}) { + given ($arg{addrtype}) { + when (/^ipv4$/i) { $addrtype = $ZNC::ADDR_IPV4ONLY } + when (/^ipv6$/i) { $addrtype = $ZNC::ADDR_IPV6ONLY } + when (/^all$/i) { } + default { die "Specified addrtype [$arg{addrtype}] isn't supported" } + } + } + if (defined $arg{port}) { + return $arg{port} if $self->GetModule->GetManager->ListenHost( + $arg{port}, + "perl-socket-".$self->GetPerlID, + $arg{bindhost}//'', + $arg{ssl}//0, + $arg{maxconns}//ZNC::_GetSOMAXCONN, + $self->{_csock}, + $arg{timeout}//0, + $addrtype + ); + return 0; + } + $self->GetModule->GetManager->ListenRand( + "perl-socket-".$self->GetPerlID, + $arg{bindhost}//'', + $arg{ssl}//0, + $arg{maxconns}//ZNC::_GetSOMAXCONN, + $self->{_csock}, + $arg{timeout}//0, + $addrtype + ); +} + +1