From a44e6eaada6629721cf3fb78bb8542084650d9f6 Mon Sep 17 00:00:00 2001 From: darthgandalf Date: Tue, 7 Sep 2010 11:13:47 +0000 Subject: [PATCH] Big update of modperl module. Old modperl had several flaws and was very outdated. New modperl makes the whole ZNC API accessible from inside perl. Modperl API was changed, so old perl modules are not supported, but they weren't used much anyway. Modperl needs --enable-perl option to ./configure. This introduces new dependence on SWIG, which is needed only while compiling ZNC. So to use modperl, you need to install SWIG or to download several files and use --disable-swig option of configure. git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@2120 726aef4b-f618-498e-8847-2d620e286838 --- configure | 84 +- configure.in | 35 +- modules/Makefile.in | 33 +- modules/modperl.cpp | 1446 ++++++--------------------------- modules/modperl.pm | 447 ---------- modules/modperl/CString.i | 260 ++++++ modules/modperl/codegen.pl | 136 ++++ modules/modperl/functions.cpp | 776 ++++++++++++++++++ modules/modperl/functions.in | 65 ++ modules/modperl/modperl.i | 197 +++++ modules/modperl/module.h | 157 ++++ modules/modperl/pstring.h | 78 ++ modules/modperl/startup.pl | 458 +++++++++++ 13 files changed, 2524 insertions(+), 1648 deletions(-) delete mode 100644 modules/modperl.pm create mode 100644 modules/modperl/CString.i create mode 100755 modules/modperl/codegen.pl create mode 100644 modules/modperl/functions.cpp create mode 100644 modules/modperl/functions.in create mode 100644 modules/modperl/modperl.i create mode 100644 modules/modperl/module.h create mode 100644 modules/modperl/pstring.h create mode 100644 modules/modperl/startup.pl 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