2011-02-24 04:14:30 +01:00
/* X-Chat 2.0 PERL Plugin
* Copyright (C) 1998-2002 Peter Zelezny.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
2012-12-23 11:36:54 -08:00
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
2011-02-24 04:14:30 +01:00
*/
2014-12-28 06:08:20 -05:00
#include "config.h"
2011-02-24 04:14:30 +01:00
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef ENABLE_NLS
#include <locale.h>
#endif
#ifdef WIN32
#include <windows.h>
2016-09-07 04:00:10 -07:00
#include <stdbool.h>
2011-02-28 18:59:32 +01:00
#else
#include <dirent.h>
2026-03-12 22:33:28 -06:00
#include <strings.h>
2011-02-24 04:14:30 +01:00
#endif
2014-12-28 06:08:20 -05:00
#include <glib.h>
2011-02-24 04:14:30 +01:00
#undef PACKAGE
2014-06-04 10:30:18 -04:00
2026-01-05 23:12:38 -07:00
#include "zoitechat-plugin.h"
2011-02-24 04:14:30 +01:00
2026-01-05 23:12:38 -07:00
static zoitechat_plugin * ph ; /* plugin handle */
2011-02-24 04:14:30 +01:00
static int perl_load_file ( char * script_name );
#ifdef WIN32
/* STRINGIFY is from perl's CORE/config.h */
#ifndef PERL_REQUIRED_VERSION
#define PERL_REQUIRED_VERSION STRINGIFY(PERL_REVISION) "." STRINGIFY(PERL_VERSION)
#endif
#ifndef PERL_DLL
#define PERL_DLL "perl" STRINGIFY(PERL_REVISION) STRINGIFY(PERL_VERSION) ".dll"
#endif
static DWORD
child ( char * str )
{
MessageBoxA ( 0 , str , "Perl DLL Error" ,
MB_OK | MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL );
return 0 ;
}
static void
thread_mbox ( char * str )
{
DWORD tid ;
CloseHandle ( CreateThread ( NULL , 0 , ( LPTHREAD_START_ROUTINE ) child ,
str , 0 , & tid ));
}
#endif
/* leave this before XSUB.h, to avoid readdir() being redefined */
2012-07-13 20:07:47 +02:00
#ifdef WIN32
static void
perl_auto_load_from_path ( const char * path )
{
2014-12-28 06:08:20 -05:00
char * search_path = g_build_filename ( path , "*.pl" , NULL );
WIN32_FIND_DATAA find_data ;
HANDLE find_handle = FindFirstFileA ( search_path , & find_data );
2012-07-13 20:07:47 +02:00
if ( find_handle != INVALID_HANDLE_VALUE )
{
do
{
2014-12-28 06:08:20 -05:00
if (( find_data . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 && ( find_data . dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) == 0 )
2012-07-13 20:07:47 +02:00
{
2014-12-28 06:08:20 -05:00
char * full_path = g_build_filename ( path , find_data . cFileName , NULL );
2012-07-13 20:07:47 +02:00
perl_load_file ( full_path );
2014-12-28 06:08:20 -05:00
g_free ( full_path );
2012-07-13 20:07:47 +02:00
}
}
2014-12-28 06:08:20 -05:00
while ( FindNextFileA ( find_handle , & find_data ) != 0 );
2012-07-13 20:07:47 +02:00
FindClose ( find_handle );
}
2014-12-28 06:08:20 -05:00
g_free ( search_path );
2012-07-13 20:07:47 +02:00
}
#else
2011-02-24 04:14:30 +01:00
static void
perl_auto_load_from_path ( const char * path )
{
DIR * dir ;
struct dirent * ent ;
dir = opendir ( path );
2014-12-28 06:08:20 -05:00
if ( dir )
{
while (( ent = readdir ( dir )))
{
2011-02-24 04:14:30 +01:00
int len = strlen ( ent -> d_name );
2014-12-28 06:08:20 -05:00
if ( len > 3 && strcasecmp ( ".pl" , ent -> d_name + len - 3 ) == 0 )
{
char * file = g_build_filename ( path , ent -> d_name , NULL );
2011-02-24 04:14:30 +01:00
perl_load_file ( file );
2014-12-28 06:08:20 -05:00
g_free ( file );
2011-02-24 04:14:30 +01:00
}
}
closedir ( dir );
}
}
2012-07-13 20:07:47 +02:00
#endif
2011-02-24 04:14:30 +01:00
static int
perl_auto_load ( void * unused )
{
const char * xdir ;
char * sub_dir ;
#ifdef WIN32
int copied = 0 ;
char * slash = NULL ;
#endif
/* get the dir in local filesystem encoding (what opendir() expects!) */
2026-01-05 23:12:38 -07:00
xdir = zoitechat_get_info ( ph , "configdir" );
2011-02-24 04:14:30 +01:00
2012-07-21 19:16:31 +02:00
/* don't pollute the filesystem with script files, this only causes misuse of the folders
2026-01-05 23:12:38 -07:00
* only use ~/.config/zoitechat/addons/ and %APPDATA%\ZoiteChat\addons */
2014-12-28 06:08:20 -05:00
sub_dir = g_build_filename ( xdir , "addons" , NULL );
2011-02-24 04:14:30 +01:00
perl_auto_load_from_path ( sub_dir );
2014-12-28 06:08:20 -05:00
g_free ( sub_dir );
2011-02-24 04:14:30 +01:00
return 0 ;
}
#include <EXTERN.h>
#define WIN32IOP_H
#include <perl.h>
#include <XSUB.h>
typedef struct
{
SV * callback ;
SV * userdata ;
2026-01-05 23:12:38 -07:00
zoitechat_hook * hook ; /* required for timers */
zoitechat_context * ctx ; /* allow timers to remember their context */
2011-02-24 04:14:30 +01:00
SV * package ; /* need to track the package name when removing hooks
by returning REMOVE
*/
unsigned int depth ;
} HookData ;
static PerlInterpreter * my_perl = NULL ;
extern void boot_DynaLoader ( pTHX_ CV * cv );
/*
this is used for autoload and shutdown callbacks
*/
static int
execute_perl ( SV * function , char * args )
{
int count , ret_value = 1 ;
dSP ;
ENTER ;
SAVETMPS ;
PUSHMARK ( SP );
XPUSHs ( sv_2mortal ( newSVpv ( args , 0 )));
PUTBACK ;
count = call_sv ( function , G_EVAL | G_SCALAR );
SPAGAIN ;
if ( SvTRUE ( ERRSV )) {
2026-01-05 23:12:38 -07:00
zoitechat_printf ( ph , "Perl error: %s \n " , SvPV_nolen ( ERRSV ));
2011-02-24 04:14:30 +01:00
if ( ! SvOK ( POPs )) {} /* remove undef from the top of the stack */
} else if ( count != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_printf ( ph , "Perl error: expected 1 value from %s, "
2011-02-24 04:14:30 +01:00
"got: %d \n " , SvPV_nolen ( function ), count );
} else {
ret_value = POPi ;
}
PUTBACK ;
FREETMPS ;
LEAVE ;
return ret_value ;
}
static char *
get_filename ( char * word [], char * word_eol [])
{
int len ;
char * file ;
/* if called as /load "filename.pl" the only difference between word and
* word_eol will be the two quotes
*/
if ( strchr ( word [ 2 ], ' ' ) != NULL
|| ( strlen ( word_eol [ 2 ]) - strlen ( word [ 2 ])) == 2 )
{
file = word [ 2 ];
} else {
file = word_eol [ 2 ];
}
len = strlen ( file );
if ( len > 3 && strncasecmp ( ".pl" , file + len - 3 , 3 ) == 0 ) {
return file ;
}
return NULL ;
}
static SV *
2026-01-05 23:12:38 -07:00
list_item_to_sv ( zoitechat_list * list , const char * const * fields )
2011-02-24 04:14:30 +01:00
{
HV * hash = newHV ();
SV * field_value ;
const char * field ;
int field_index = 0 ;
const char * field_name ;
int name_len ;
while ( fields [ field_index ] != NULL ) {
field_name = fields [ field_index ] + 1 ;
name_len = strlen ( field_name );
switch ( fields [ field_index ][ 0 ]) {
case 's' :
2026-01-05 23:12:38 -07:00
field = zoitechat_list_str ( ph , list , field_name );
2011-02-24 04:14:30 +01:00
if ( field != NULL ) {
field_value = newSVpvn ( field , strlen ( field ));
} else {
field_value = & PL_sv_undef ;
}
break ;
case 'p' :
2026-01-05 23:12:38 -07:00
field_value = newSViv ( PTR2IV ( zoitechat_list_str ( ph , list ,
2011-02-24 04:14:30 +01:00
field_name )));
break ;
case 'i' :
2026-01-05 23:12:38 -07:00
field_value = newSVuv ( zoitechat_list_int ( ph , list , field_name ));
2011-02-24 04:14:30 +01:00
break ;
case 't' :
2014-12-14 13:31:19 -08:00
/* From perldoc for Perl's own timelocal() and timegm():
* <quote>
* On perl versions older than 5.12.0, the range of dates that can be actually be handled depends on the size of time_t (usually a signed integer) on the given platform.
* As of version 5.12.0, perl has stopped using the underlying time library of the operating system it's running on and has its own implementation of those routines with a
* safe range of at least +/ 2**52 (about 142 million years).
* </quote>
*
* This is further confirmed from looking at the source for Time::Local - it's a Perl module and the implementations of timelocal() and timegm() use simple addition and
* subtraction of numbers. Perl automatically promotes numbers from int32_t (IV) to uint32_t (UV) to 64-bit IEEE754 double (NV) as required.
*
* This means that using a double (NV) for our own time_t suffers from the same assumptions that Perl's own functions do.
*/
2026-01-05 23:12:38 -07:00
field_value = newSVnv (( const NV ) zoitechat_list_time ( ph , list , field_name ));
2011-02-24 04:14:30 +01:00
break ;
default :
field_value = & PL_sv_undef ;
}
2013-04-23 12:09:05 -07:00
( void ) hv_store ( hash , field_name , name_len , field_value , 0 );
2011-02-24 04:14:30 +01:00
field_index ++ ;
}
return sv_2mortal ( newRV_noinc (( SV * ) hash ));
}
2020-09-21 11:22:50 -07:00
#define WORD_ARRAY_LEN 32
2020-09-17 15:50:28 -07:00
2011-02-24 04:14:30 +01:00
static AV *
array2av ( char * array [])
{
int count = 0 ;
SV * temp = NULL ;
AV * av = newAV ();
sv_2mortal (( SV * ) av );
for (
count = 1 ;
2020-09-17 15:50:28 -07:00
count < WORD_ARRAY_LEN && array [ count ] != NULL && array [ count ][ 0 ] != 0 ;
2011-02-24 04:14:30 +01:00
count ++
) {
temp = newSVpv ( array [ count ], 0 );
SvUTF8_on ( temp );
av_push ( av , temp );
}
return av ;
}
2026-01-05 23:12:38 -07:00
/* sets $ZoiteChat::Embed::current_package */
2012-07-13 20:16:10 +02:00
static void
set_current_package ( SV * package )
{
2026-01-05 23:12:38 -07:00
SV * current_package = get_sv ( "ZoiteChat::Embed::current_package" , 1 );
2012-07-13 20:16:10 +02:00
SvSetSV_nosteal ( current_package , package );
}
2011-02-24 04:14:30 +01:00
static int
fd_cb ( int fd , int flags , void * userdata )
{
HookData * data = ( HookData * ) userdata ;
int retVal = 0 ;
int count = 0 ;
dSP ;
ENTER ;
SAVETMPS ;
PUSHMARK ( SP );
XPUSHs ( data -> userdata );
PUTBACK ;
2012-07-13 20:16:10 +02:00
set_current_package ( data -> package );
2011-02-24 04:14:30 +01:00
count = call_sv ( data -> callback , G_EVAL );
2012-07-13 20:16:10 +02:00
set_current_package ( & PL_sv_undef );
2011-02-24 04:14:30 +01:00
SPAGAIN ;
if ( SvTRUE ( ERRSV )) {
2026-01-05 23:12:38 -07:00
zoitechat_printf ( ph , "Error in fd callback %s" , SvPV_nolen ( ERRSV ));
2011-02-24 04:14:30 +01:00
if ( ! SvOK ( POPs )) {} /* remove undef from the top of the stack */
2026-01-25 16:13:47 -07:00
retVal = ZOITECHAT_EAT_ALL ;
2011-02-24 04:14:30 +01:00
} else {
if ( count != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Fd handler should only return 1 value." );
2026-01-25 16:13:47 -07:00
retVal = ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
} else {
retVal = POPi ;
if ( retVal == 0 ) {
/* if 0 is returned, the fd is going to get unhooked */
PUSHMARK ( SP );
XPUSHs ( sv_2mortal ( newSViv ( PTR2IV ( data -> hook ))));
PUTBACK ;
2026-01-05 23:12:38 -07:00
call_pv ( "ZoiteChat::unhook" , G_EVAL );
2011-02-24 04:14:30 +01:00
SPAGAIN ;
SvREFCNT_dec ( data -> callback );
if ( data -> userdata ) {
SvREFCNT_dec ( data -> userdata );
}
2014-12-28 06:08:20 -05:00
g_free ( data );
2011-02-24 04:14:30 +01:00
}
}
}
PUTBACK ;
FREETMPS ;
LEAVE ;
return retVal ;
}
static int
timer_cb ( void * userdata )
{
HookData * data = ( HookData * ) userdata ;
int retVal = 0 ;
int count = 0 ;
dSP ;
ENTER ;
SAVETMPS ;
PUSHMARK ( SP );
XPUSHs ( data -> userdata );
PUTBACK ;
if ( data -> ctx ) {
2026-01-05 23:12:38 -07:00
zoitechat_set_context ( ph , data -> ctx );
2011-02-24 04:14:30 +01:00
}
2012-07-13 20:16:10 +02:00
set_current_package ( data -> package );
2013-10-09 11:33:10 +03:00
count = call_sv ( data -> callback , G_EVAL | G_KEEPERR );
2012-07-13 20:16:10 +02:00
set_current_package ( & PL_sv_undef );
2011-02-24 04:14:30 +01:00
SPAGAIN ;
if ( SvTRUE ( ERRSV )) {
2026-01-05 23:12:38 -07:00
zoitechat_printf ( ph , "Error in timer callback %s" , SvPV_nolen ( ERRSV ));
2011-02-24 04:14:30 +01:00
if ( ! SvOK ( POPs )) {} /* remove undef from the top of the stack */
2026-01-25 16:13:47 -07:00
retVal = ZOITECHAT_EAT_ALL ;
2011-02-24 04:14:30 +01:00
} else {
if ( count != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Timer handler should only return 1 value." );
2026-01-25 16:13:47 -07:00
retVal = ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
} else {
retVal = POPi ;
if ( retVal == 0 ) {
/* if 0 is return the timer is going to get unhooked */
PUSHMARK ( SP );
XPUSHs ( sv_2mortal ( newSViv ( PTR2IV ( data -> hook ))));
XPUSHs ( sv_mortalcopy ( data -> package ));
PUTBACK ;
2026-01-05 23:12:38 -07:00
call_pv ( "ZoiteChat::unhook" , G_EVAL );
2011-02-24 04:14:30 +01:00
SPAGAIN ;
}
}
}
PUTBACK ;
FREETMPS ;
LEAVE ;
return retVal ;
}
static int
server_cb ( char * word [], char * word_eol [], void * userdata )
{
HookData * data = ( HookData * ) userdata ;
int retVal = 0 ;
int count = 0 ;
dSP ;
ENTER ;
SAVETMPS ;
if ( data -> depth )
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
PUSHMARK ( SP );
XPUSHs ( newRV_noinc (( SV * ) array2av ( word )));
XPUSHs ( newRV_noinc (( SV * ) array2av ( word_eol )));
XPUSHs ( data -> userdata );
PUTBACK ;
data -> depth ++ ;
2012-07-13 20:16:10 +02:00
set_current_package ( data -> package );
2013-10-09 11:33:10 +03:00
count = call_sv ( data -> callback , G_EVAL | G_KEEPERR );
2012-07-13 20:16:10 +02:00
set_current_package ( & PL_sv_undef );
2011-02-24 04:14:30 +01:00
data -> depth -- ;
SPAGAIN ;
if ( SvTRUE ( ERRSV )) {
2026-01-05 23:12:38 -07:00
zoitechat_printf ( ph , "Error in server callback %s" , SvPV_nolen ( ERRSV ));
2011-02-24 04:14:30 +01:00
if ( ! SvOK ( POPs )) {} /* remove undef from the top of the stack */
2026-01-25 16:13:47 -07:00
retVal = ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
} else {
if ( count != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Server handler should only return 1 value." );
2026-01-25 16:13:47 -07:00
retVal = ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
} else {
retVal = POPi ;
}
}
PUTBACK ;
FREETMPS ;
LEAVE ;
return retVal ;
}
static int
command_cb ( char * word [], char * word_eol [], void * userdata )
{
HookData * data = ( HookData * ) userdata ;
int retVal = 0 ;
int count = 0 ;
dSP ;
ENTER ;
SAVETMPS ;
if ( data -> depth )
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
PUSHMARK ( SP );
XPUSHs ( newRV_noinc (( SV * ) array2av ( word )));
XPUSHs ( newRV_noinc (( SV * ) array2av ( word_eol )));
XPUSHs ( data -> userdata );
PUTBACK ;
data -> depth ++ ;
2012-07-13 20:16:10 +02:00
set_current_package ( data -> package );
2013-10-09 11:33:10 +03:00
count = call_sv ( data -> callback , G_EVAL | G_KEEPERR );
2012-07-13 20:16:10 +02:00
set_current_package ( & PL_sv_undef );
2011-02-24 04:14:30 +01:00
data -> depth -- ;
SPAGAIN ;
if ( SvTRUE ( ERRSV )) {
2026-01-05 23:12:38 -07:00
zoitechat_printf ( ph , "Error in command callback %s" , SvPV_nolen ( ERRSV ));
2011-02-24 04:14:30 +01:00
if ( ! SvOK ( POPs )) {} /* remove undef from the top of the stack */
2026-01-25 16:13:47 -07:00
retVal = ZOITECHAT_EAT_ZOITECHAT ;
2011-02-24 04:14:30 +01:00
} else {
if ( count != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Command handler should only return 1 value." );
2026-01-25 16:13:47 -07:00
retVal = ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
} else {
retVal = POPi ;
}
}
PUTBACK ;
FREETMPS ;
LEAVE ;
return retVal ;
}
static int
print_cb ( char * word [], void * userdata )
{
HookData * data = ( HookData * ) userdata ;
SV * temp = NULL ;
int retVal = 0 ;
int count = 1 ;
int last_index = 31 ;
/* must be initialized after SAVETMPS */
AV * wd = NULL ;
dSP ;
ENTER ;
SAVETMPS ;
if ( data -> depth )
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
wd = newAV ();
sv_2mortal (( SV * ) wd );
/* need to scan backwards to find the index of the last element since some
events such as "DCC Timeout" can have NULL elements in between non NULL
elements */
while ( last_index >= 0
&& ( word [ last_index ] == NULL || word [ last_index ][ 0 ] == 0 )) {
last_index -- ;
}
for ( count = 1 ; count <= last_index ; count ++ ) {
if ( word [ count ] == NULL ) {
av_push ( wd , & PL_sv_undef );
} else if ( word [ count ][ 0 ] == 0 ) {
av_push ( wd , newSVpvn ( "" , 0 ));
} else {
temp = newSVpv ( word [ count ], 0 );
SvUTF8_on ( temp );
av_push ( wd , temp );
}
}
PUSHMARK ( SP );
XPUSHs ( newRV_noinc (( SV * ) wd ));
XPUSHs ( data -> userdata );
PUTBACK ;
data -> depth ++ ;
2012-07-13 20:16:10 +02:00
set_current_package ( data -> package );
2013-10-09 11:33:10 +03:00
count = call_sv ( data -> callback , G_EVAL | G_KEEPERR );
2012-07-13 20:16:10 +02:00
set_current_package ( & PL_sv_undef );
2011-02-24 04:14:30 +01:00
data -> depth -- ;
SPAGAIN ;
if ( SvTRUE ( ERRSV )) {
2026-01-05 23:12:38 -07:00
zoitechat_printf ( ph , "Error in print callback %s" , SvPV_nolen ( ERRSV ));
2011-02-24 04:14:30 +01:00
if ( ! SvOK ( POPs )) {} /* remove undef from the top of the stack */
2026-01-25 16:13:47 -07:00
retVal = ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
} else {
if ( count != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Print handler should only return 1 value." );
2026-01-25 16:13:47 -07:00
retVal = ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
} else {
retVal = POPi ;
}
}
PUTBACK ;
FREETMPS ;
LEAVE ;
return retVal ;
}
/* custom IRC perl functions for scripting */
2026-01-05 23:12:38 -07:00
/* ZoiteChat::Internal::register (scriptname, version, desc, shutdowncallback, filename)
2011-02-24 04:14:30 +01:00
*
*/
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_register )
2011-02-24 04:14:30 +01:00
{
char * name , * version , * desc , * filename ;
void * gui_entry ;
dXSARGS ;
if ( items != 4 ) {
2026-01-05 23:12:38 -07:00
zoitechat_printf ( ph ,
"Usage: ZoiteChat::Internal::register(scriptname, version, desc, filename)" );
2011-02-24 04:14:30 +01:00
} else {
name = SvPV_nolen ( ST ( 0 ));
version = SvPV_nolen ( ST ( 1 ));
desc = SvPV_nolen ( ST ( 2 ));
filename = SvPV_nolen ( ST ( 3 ));
2026-01-05 23:12:38 -07:00
gui_entry = zoitechat_plugingui_add ( ph , filename , name ,
2011-02-24 04:14:30 +01:00
desc , version , NULL );
XSRETURN_IV ( PTR2IV ( gui_entry ));
}
}
2026-01-05 23:12:38 -07:00
/* ZoiteChat::print(output) */
2011-02-24 04:14:30 +01:00
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_print )
2011-02-24 04:14:30 +01:00
{
char * text = NULL ;
dXSARGS ;
if ( items != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::Internal::print(text)" );
2011-02-24 04:14:30 +01:00
} else {
text = SvPV_nolen ( ST ( 0 ));
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , text );
2011-02-24 04:14:30 +01:00
}
XSRETURN_EMPTY ;
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_emit_print )
2011-02-24 04:14:30 +01:00
{
char * event_name ;
int RETVAL ;
int count ;
dXSARGS ;
if ( items < 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::emit_print(event_name, ...)" );
2011-02-24 04:14:30 +01:00
} else {
event_name = ( char * ) SvPV_nolen ( ST ( 0 ));
RETVAL = 0 ;
/* we need to figure out the number of defined values passed in */
for ( count = 0 ; count < items ; count ++ ) {
if ( ! SvOK ( ST ( count ))) {
break ;
}
}
switch ( count ) {
case 1 :
2026-01-05 23:12:38 -07:00
RETVAL = zoitechat_emit_print ( ph , event_name , NULL );
2011-02-24 04:14:30 +01:00
break ;
case 2 :
2026-01-05 23:12:38 -07:00
RETVAL = zoitechat_emit_print ( ph , event_name ,
2011-02-24 04:14:30 +01:00
SvPV_nolen ( ST ( 1 )), NULL );
break ;
case 3 :
2026-01-05 23:12:38 -07:00
RETVAL = zoitechat_emit_print ( ph , event_name ,
2011-02-24 04:14:30 +01:00
SvPV_nolen ( ST ( 1 )),
SvPV_nolen ( ST ( 2 )), NULL );
break ;
case 4 :
2026-01-05 23:12:38 -07:00
RETVAL = zoitechat_emit_print ( ph , event_name ,
2011-02-24 04:14:30 +01:00
SvPV_nolen ( ST ( 1 )),
SvPV_nolen ( ST ( 2 )),
SvPV_nolen ( ST ( 3 )), NULL );
break ;
case 5 :
2026-01-05 23:12:38 -07:00
RETVAL = zoitechat_emit_print ( ph , event_name ,
2011-02-24 04:14:30 +01:00
SvPV_nolen ( ST ( 1 )),
SvPV_nolen ( ST ( 2 )),
SvPV_nolen ( ST ( 3 )),
SvPV_nolen ( ST ( 4 )), NULL );
break ;
}
XSRETURN_IV ( RETVAL );
}
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_send_modes )
2011-02-24 04:14:30 +01:00
{
AV * p_targets = NULL ;
int modes_per_line = 0 ;
char sign ;
char mode ;
int i = 0 ;
const char ** targets ;
int target_count = 0 ;
SV ** elem ;
dXSARGS ;
if ( items < 3 || items > 4 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph ,
"Usage: ZoiteChat::send_modes( targets, sign, mode, modes_per_line)"
2011-02-24 04:14:30 +01:00
);
} else {
if ( SvROK ( ST ( 0 ))) {
p_targets = ( AV * ) SvRV ( ST ( 0 ));
target_count = av_len ( p_targets ) + 1 ;
2014-12-28 06:08:20 -05:00
targets = g_new ( const char * , target_count );
2011-02-24 04:14:30 +01:00
for ( i = 0 ; i < target_count ; i ++ ) {
elem = av_fetch ( p_targets , i , 0 );
if ( elem != NULL ) {
targets [ i ] = SvPV_nolen ( * elem );
} else {
targets [ i ] = "" ;
}
}
} else {
2014-12-28 06:08:20 -05:00
targets = g_new ( const char * , 1 );
2011-02-24 04:14:30 +01:00
targets [ 0 ] = SvPV_nolen ( ST ( 0 ));
target_count = 1 ;
}
if ( target_count == 0 ) {
2014-12-28 06:08:20 -05:00
g_free (( char ** ) targets );
2011-02-24 04:14:30 +01:00
XSRETURN_EMPTY ;
}
sign = ( SvPV_nolen ( ST ( 1 )))[ 0 ];
mode = ( SvPV_nolen ( ST ( 2 )))[ 0 ];
if ( items == 4 ) {
modes_per_line = ( int ) SvIV ( ST ( 3 ));
}
2026-01-05 23:12:38 -07:00
zoitechat_send_modes ( ph , targets , target_count , modes_per_line , sign , mode );
2014-12-28 06:08:20 -05:00
g_free (( char ** ) targets );
2011-02-24 04:14:30 +01:00
}
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_get_info )
2011-02-24 04:14:30 +01:00
{
SV * temp = NULL ;
dXSARGS ;
if ( items != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::get_info(id)" );
2011-02-24 04:14:30 +01:00
} else {
SV * id = ST ( 0 );
const char * RETVAL ;
2026-01-05 23:12:38 -07:00
RETVAL = zoitechat_get_info ( ph , SvPV_nolen ( id ));
2011-02-24 04:14:30 +01:00
if ( RETVAL == NULL ) {
XSRETURN_UNDEF ;
}
if ( ! strncmp ( "win_ptr" , SvPV_nolen ( id ), 7 )
|| ! strncmp ( "gtkwin_ptr" , SvPV_nolen ( id ), 10 ))
{
XSRETURN_IV ( PTR2IV ( RETVAL ));
} else {
if (
! strncmp ( "libdirfs" , SvPV_nolen ( id ), 8 ) ||
2012-11-04 23:55:36 +01:00
! strncmp ( "xchatdirfs" , SvPV_nolen ( id ), 10 ) ||
! strncmp ( "configdir" , SvPV_nolen ( id ), 9 )
2011-02-24 04:14:30 +01:00
) {
XSRETURN_PV ( RETVAL );
} else {
temp = newSVpv ( RETVAL , 0 );
SvUTF8_on ( temp );
PUSHMARK ( SP );
XPUSHs ( sv_2mortal ( temp ));
PUTBACK ;
}
}
}
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_context_info )
2011-02-24 04:14:30 +01:00
{
const char * const * fields ;
dXSARGS ;
if ( items > 0 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::Internal::context_info()" );
2011-02-24 04:14:30 +01:00
}
2026-01-05 23:12:38 -07:00
fields = zoitechat_list_fields ( ph , "channels" );
2011-02-24 04:14:30 +01:00
XPUSHs ( list_item_to_sv ( NULL , fields ));
XSRETURN ( 1 );
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_get_prefs )
2011-02-24 04:14:30 +01:00
{
const char * str ;
int integer ;
SV * temp = NULL ;
dXSARGS ;
if ( items != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::get_prefs(name)" );
2011-02-24 04:14:30 +01:00
} else {
2026-01-05 23:12:38 -07:00
switch ( zoitechat_get_prefs ( ph , SvPV_nolen ( ST ( 0 )), & str , & integer )) {
2011-02-24 04:14:30 +01:00
case 0 :
XSRETURN_UNDEF ;
break ;
case 1 :
temp = newSVpv ( str , 0 );
SvUTF8_on ( temp );
SP -= items ;
sp = mark ;
XPUSHs ( sv_2mortal ( temp ));
PUTBACK ;
break ;
case 2 :
XSRETURN_IV ( integer );
break ;
case 3 :
if ( integer ) {
XSRETURN_YES ;
} else {
XSRETURN_NO ;
}
}
}
}
2026-01-05 23:12:38 -07:00
/* ZoiteChat::Internal::hook_server(name, priority, callback, userdata) */
2011-02-24 04:14:30 +01:00
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_hook_server )
2011-02-24 04:14:30 +01:00
{
char * name ;
int pri ;
SV * callback ;
SV * userdata ;
2012-07-13 20:16:10 +02:00
SV * package ;
2026-01-05 23:12:38 -07:00
zoitechat_hook * hook ;
2011-02-24 04:14:30 +01:00
HookData * data ;
dXSARGS ;
2012-07-13 20:16:10 +02:00
if ( items != 5 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph ,
"Usage: ZoiteChat::Internal::hook_server(name, priority, callback, userdata, package)" );
2011-02-24 04:14:30 +01:00
} else {
name = SvPV_nolen ( ST ( 0 ));
pri = ( int ) SvIV ( ST ( 1 ));
callback = ST ( 2 );
userdata = ST ( 3 );
2012-07-13 20:16:10 +02:00
package = ST ( 4 );
2011-02-24 04:14:30 +01:00
data = NULL ;
2014-12-28 06:08:20 -05:00
data = g_new ( HookData , 1 );
2012-07-13 20:16:10 +02:00
data -> callback = newSVsv ( callback );
data -> userdata = newSVsv ( userdata );
2011-02-24 04:14:30 +01:00
data -> depth = 0 ;
2012-07-13 20:16:10 +02:00
data -> package = newSVsv ( package );
2026-01-05 23:12:38 -07:00
hook = zoitechat_hook_server ( ph , name , pri , server_cb , data );
2011-02-24 04:14:30 +01:00
XSRETURN_IV ( PTR2IV ( hook ));
}
}
2026-01-05 23:12:38 -07:00
/* ZoiteChat::Internal::hook_command(name, priority, callback, help_text, userdata) */
2011-02-24 04:14:30 +01:00
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_hook_command )
2011-02-24 04:14:30 +01:00
{
char * name ;
int pri ;
SV * callback ;
char * help_text = NULL ;
SV * userdata ;
2012-07-13 20:16:10 +02:00
SV * package ;
2026-01-05 23:12:38 -07:00
zoitechat_hook * hook ;
2011-02-24 04:14:30 +01:00
HookData * data ;
dXSARGS ;
2012-07-13 20:16:10 +02:00
if ( items != 6 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph ,
"Usage: ZoiteChat::Internal::hook_command(name, priority, callback, help_text, userdata, package)" );
2011-02-24 04:14:30 +01:00
} else {
name = SvPV_nolen ( ST ( 0 ));
pri = ( int ) SvIV ( ST ( 1 ));
callback = ST ( 2 );
2012-07-13 20:16:10 +02:00
/* leave the help text as NULL if the help text is undefined to avoid
2011-02-24 04:14:30 +01:00
* overriding the default help message for builtin commands */
if ( SvOK ( ST ( 3 ))) {
help_text = SvPV_nolen ( ST ( 3 ));
}
userdata = ST ( 4 );
2012-07-13 20:16:10 +02:00
package = ST ( 5 );
2011-02-24 04:14:30 +01:00
data = NULL ;
2014-12-28 06:08:20 -05:00
data = g_new ( HookData , 1 );
2012-07-13 20:16:10 +02:00
data -> callback = newSVsv ( callback );
data -> userdata = newSVsv ( userdata );
2011-02-24 04:14:30 +01:00
data -> depth = 0 ;
2012-07-13 20:16:10 +02:00
data -> package = newSVsv ( package );
2026-01-05 23:12:38 -07:00
hook = zoitechat_hook_command ( ph , name , pri , command_cb , help_text , data );
2011-02-24 04:14:30 +01:00
XSRETURN_IV ( PTR2IV ( hook ));
}
}
2026-01-05 23:12:38 -07:00
/* ZoiteChat::Internal::hook_print(name, priority, callback, [userdata]) */
2011-02-24 04:14:30 +01:00
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_hook_print )
2011-02-24 04:14:30 +01:00
{
char * name ;
int pri ;
SV * callback ;
SV * userdata ;
2012-07-13 20:16:10 +02:00
SV * package ;
2026-01-05 23:12:38 -07:00
zoitechat_hook * hook ;
2011-02-24 04:14:30 +01:00
HookData * data ;
dXSARGS ;
2012-07-13 20:16:10 +02:00
if ( items != 5 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph ,
"Usage: ZoiteChat::Internal::hook_print(name, priority, callback, userdata, package)" );
2011-02-24 04:14:30 +01:00
} else {
name = SvPV_nolen ( ST ( 0 ));
pri = ( int ) SvIV ( ST ( 1 ));
callback = ST ( 2 );
data = NULL ;
userdata = ST ( 3 );
2012-07-13 20:16:10 +02:00
package = ST ( 4 );
2011-02-24 04:14:30 +01:00
2014-12-28 06:08:20 -05:00
data = g_new ( HookData , 1 );
2012-07-13 20:16:10 +02:00
data -> callback = newSVsv ( callback );
data -> userdata = newSVsv ( userdata );
2011-02-24 04:14:30 +01:00
data -> depth = 0 ;
2012-07-13 20:16:10 +02:00
data -> package = newSVsv ( package );
2026-01-05 23:12:38 -07:00
hook = zoitechat_hook_print ( ph , name , pri , print_cb , data );
2011-02-24 04:14:30 +01:00
XSRETURN_IV ( PTR2IV ( hook ));
}
}
2026-01-05 23:12:38 -07:00
/* ZoiteChat::Internal::hook_timer(timeout, callback, userdata) */
2011-02-24 04:14:30 +01:00
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_hook_timer )
2011-02-24 04:14:30 +01:00
{
int timeout ;
SV * callback ;
SV * userdata ;
2026-01-05 23:12:38 -07:00
zoitechat_hook * hook ;
2011-02-24 04:14:30 +01:00
SV * package ;
HookData * data ;
dXSARGS ;
if ( items != 4 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph ,
"Usage: ZoiteChat::Internal::hook_timer(timeout, callback, userdata, package)" );
2011-02-24 04:14:30 +01:00
} else {
timeout = ( int ) SvIV ( ST ( 0 ));
callback = ST ( 1 );
data = NULL ;
userdata = ST ( 2 );
package = ST ( 3 );
2014-12-28 06:08:20 -05:00
data = g_new ( HookData , 1 );
2012-07-13 20:16:10 +02:00
data -> callback = newSVsv ( callback );
data -> userdata = newSVsv ( userdata );
2026-01-05 23:12:38 -07:00
data -> ctx = zoitechat_get_context ( ph );
2012-07-13 20:16:10 +02:00
data -> package = newSVsv ( package );
2026-01-05 23:12:38 -07:00
hook = zoitechat_hook_timer ( ph , timeout , timer_cb , data );
2011-02-24 04:14:30 +01:00
data -> hook = hook ;
XSRETURN_IV ( PTR2IV ( hook ));
}
}
2026-01-05 23:12:38 -07:00
/* ZoiteChat::Internal::hook_fd(fd, callback, flags, userdata) */
2011-02-24 04:14:30 +01:00
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_hook_fd )
2011-02-24 04:14:30 +01:00
{
int fd ;
SV * callback ;
int flags ;
SV * userdata ;
2012-07-13 20:16:10 +02:00
SV * package ;
2026-01-05 23:12:38 -07:00
zoitechat_hook * hook ;
2011-02-24 04:14:30 +01:00
HookData * data ;
dXSARGS ;
2013-03-16 22:41:40 +01:00
if ( items != 5 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph ,
"Usage: ZoiteChat::Internal::hook_fd(fd, callback, flags, userdata)" );
2011-02-24 04:14:30 +01:00
} else {
fd = ( int ) SvIV ( ST ( 0 ));
callback = ST ( 1 );
flags = ( int ) SvIV ( ST ( 2 ));
userdata = ST ( 3 );
2012-07-13 20:16:10 +02:00
package = ST ( 4 );
2011-02-24 04:14:30 +01:00
data = NULL ;
#ifdef WIN32
2026-01-25 16:13:47 -07:00
if (( flags & ZOITECHAT_FD_NOTSOCKET ) == 0 ) {
2011-02-24 04:14:30 +01:00
/* this _get_osfhandle if from win32iop.h in the perl distribution,
* not the one provided by Windows
*/
fd = _get_osfhandle ( fd );
if ( fd < 0 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Invalid file descriptor" );
2011-02-24 04:14:30 +01:00
XSRETURN_UNDEF ;
}
}
#endif
2014-12-28 06:08:20 -05:00
data = g_new ( HookData , 1 );
2012-07-13 20:16:10 +02:00
data -> callback = newSVsv ( callback );
data -> userdata = newSVsv ( userdata );
data -> depth = 0 ;
data -> package = newSVsv ( package );
2026-01-05 23:12:38 -07:00
hook = zoitechat_hook_fd ( ph , fd , flags , fd_cb , data );
2011-02-24 04:14:30 +01:00
data -> hook = hook ;
XSRETURN_IV ( PTR2IV ( hook ));
}
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_unhook )
2011-02-24 04:14:30 +01:00
{
2026-01-05 23:12:38 -07:00
zoitechat_hook * hook ;
2011-02-24 04:14:30 +01:00
HookData * userdata ;
int retCount = 0 ;
dXSARGS ;
if ( items != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::unhook(hook)" );
2011-02-24 04:14:30 +01:00
} else {
2026-01-05 23:12:38 -07:00
hook = INT2PTR ( zoitechat_hook * , SvUV ( ST ( 0 )));
userdata = ( HookData * ) zoitechat_unhook ( ph , hook );
2011-02-24 04:14:30 +01:00
if ( userdata != NULL ) {
if ( userdata -> callback != NULL ) {
SvREFCNT_dec ( userdata -> callback );
}
if ( userdata -> userdata != NULL ) {
XPUSHs ( sv_mortalcopy ( userdata -> userdata ));
SvREFCNT_dec ( userdata -> userdata );
retCount = 1 ;
}
if ( userdata -> package != NULL ) {
SvREFCNT_dec ( userdata -> package );
}
2012-07-13 20:16:10 +02:00
2014-12-28 06:08:20 -05:00
g_free ( userdata );
2011-02-24 04:14:30 +01:00
}
XSRETURN ( retCount );
}
XSRETURN_EMPTY ;
}
2026-01-05 23:12:38 -07:00
/* ZoiteChat::Internal::command(command) */
2011-02-24 04:14:30 +01:00
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_command )
2011-02-24 04:14:30 +01:00
{
char * cmd = NULL ;
dXSARGS ;
if ( items != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::Internal::command(command)" );
2011-02-24 04:14:30 +01:00
} else {
cmd = SvPV_nolen ( ST ( 0 ));
2026-01-05 23:12:38 -07:00
zoitechat_command ( ph , cmd );
2011-02-24 04:14:30 +01:00
}
XSRETURN_EMPTY ;
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_find_context )
2011-02-24 04:14:30 +01:00
{
char * server = NULL ;
char * chan = NULL ;
2026-01-05 23:12:38 -07:00
zoitechat_context * RETVAL ;
2011-02-24 04:14:30 +01:00
dXSARGS ;
if ( items > 2 )
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::find_context ([channel, [server]])" );
2011-02-24 04:14:30 +01:00
{
switch ( items ) {
case 0 : /* no server name and no channel name */
/* nothing to do, server and chan are already NULL */
break ;
case 1 : /* channel name only */
/* change channel value only if it is true or 0 */
/* otherwise leave it as null */
if ( SvTRUE ( ST ( 0 )) || SvNIOK ( ST ( 0 ))) {
chan = SvPV_nolen ( ST ( 0 ));
2026-01-05 23:12:38 -07:00
/* zoitechat_printf( ph, "XSUB - find_context( %s, NULL )", chan ); */
2011-02-24 04:14:30 +01:00
}
2026-01-05 23:12:38 -07:00
/* else { zoitechat_print( ph, "XSUB - find_context( NULL, NULL )" ); } */
2011-02-24 04:14:30 +01:00
/* chan is already NULL */
break ;
case 2 : /* server and channel */
/* change channel value only if it is true or 0 */
/* otherwise leave it as NULL */
if ( SvTRUE ( ST ( 0 )) || SvNIOK ( ST ( 0 ))) {
chan = SvPV_nolen ( ST ( 0 ));
2026-01-05 23:12:38 -07:00
/* zoitechat_printf( ph, "XSUB - find_context( %s, NULL )", SvPV_nolen(ST(0) )); */
2011-02-24 04:14:30 +01:00
}
2026-01-05 23:12:38 -07:00
/* else { zoitechat_print( ph, "XSUB - 2 arg NULL chan" ); } */
2011-02-24 04:14:30 +01:00
/* change server value only if it is true or 0 */
/* otherwise leave it as NULL */
if ( SvTRUE ( ST ( 1 )) || SvNIOK ( ST ( 1 ))) {
server = SvPV_nolen ( ST ( 1 ));
2026-01-05 23:12:38 -07:00
/* zoitechat_printf( ph, "XSUB - find_context( NULL, %s )", SvPV_nolen(ST(1) )); */
2011-02-24 04:14:30 +01:00
}
2026-01-05 23:12:38 -07:00
/* else { zoitechat_print( ph, "XSUB - 2 arg NULL server" ); } */
2011-02-24 04:14:30 +01:00
break ;
}
2026-01-05 23:12:38 -07:00
RETVAL = zoitechat_find_context ( ph , server , chan );
2011-02-24 04:14:30 +01:00
if ( RETVAL != NULL ) {
2026-01-05 23:12:38 -07:00
/* zoitechat_print (ph, "XSUB - context found"); */
2011-02-24 04:14:30 +01:00
XSRETURN_IV ( PTR2IV ( RETVAL ));
} else {
2026-01-05 23:12:38 -07:00
/* zoitechat_print (ph, "XSUB - context not found"); */
2011-02-24 04:14:30 +01:00
XSRETURN_UNDEF ;
}
}
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_get_context )
2011-02-24 04:14:30 +01:00
{
dXSARGS ;
if ( items != 0 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::get_context()" );
2011-02-24 04:14:30 +01:00
} else {
2026-01-05 23:12:38 -07:00
XSRETURN_IV ( PTR2IV ( zoitechat_get_context ( ph )));
2011-02-24 04:14:30 +01:00
}
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_set_context )
2011-02-24 04:14:30 +01:00
{
2026-01-05 23:12:38 -07:00
zoitechat_context * ctx ;
2011-02-24 04:14:30 +01:00
dXSARGS ;
if ( items != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::set_context(ctx)" );
2011-02-24 04:14:30 +01:00
} else {
2026-01-05 23:12:38 -07:00
ctx = INT2PTR ( zoitechat_context * , SvUV ( ST ( 0 )));
XSRETURN_IV (( IV ) zoitechat_set_context ( ph , ctx ));
2011-02-24 04:14:30 +01:00
}
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_nickcmp )
2011-02-24 04:14:30 +01:00
{
dXSARGS ;
if ( items != 2 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::nickcmp(s1, s2)" );
2011-02-24 04:14:30 +01:00
} else {
2026-01-05 23:12:38 -07:00
XSRETURN_IV (( IV ) zoitechat_nickcmp ( ph , SvPV_nolen ( ST ( 0 )),
2011-02-24 04:14:30 +01:00
SvPV_nolen ( ST ( 1 ))));
}
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_get_list )
2011-02-24 04:14:30 +01:00
{
SV * name ;
2026-01-05 23:12:38 -07:00
zoitechat_list * list ;
2011-02-24 04:14:30 +01:00
const char * const * fields ;
int count = 0 ; /* return value for scalar context */
dXSARGS ;
if ( items != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::get_list(name)" );
2011-02-24 04:14:30 +01:00
} else {
SP -= items ; /*remove the argument list from the stack */
name = ST ( 0 );
2026-01-05 23:12:38 -07:00
list = zoitechat_list_get ( ph , SvPV_nolen ( name ));
2011-02-24 04:14:30 +01:00
if ( list == NULL ) {
XSRETURN_EMPTY ;
}
if ( GIMME_V == G_SCALAR ) {
2026-01-05 23:12:38 -07:00
while ( zoitechat_list_next ( ph , list )) {
2011-02-24 04:14:30 +01:00
count ++ ;
}
2026-01-05 23:12:38 -07:00
zoitechat_list_free ( ph , list );
2011-02-24 04:14:30 +01:00
XSRETURN_IV (( IV ) count );
}
2026-01-05 23:12:38 -07:00
fields = zoitechat_list_fields ( ph , SvPV_nolen ( name ));
while ( zoitechat_list_next ( ph , list )) {
2011-02-24 04:14:30 +01:00
XPUSHs ( list_item_to_sv ( list , fields ));
}
2026-01-05 23:12:38 -07:00
zoitechat_list_free ( ph , list );
2011-02-24 04:14:30 +01:00
PUTBACK ;
return ;
}
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_Embed_plugingui_remove )
2011-02-24 04:14:30 +01:00
{
void * gui_entry ;
dXSARGS ;
if ( items != 1 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Usage: ZoiteChat::Embed::plugingui_remove(handle)" );
2011-02-24 04:14:30 +01:00
} else {
gui_entry = INT2PTR ( void * , SvUV ( ST ( 0 )));
2026-01-05 23:12:38 -07:00
zoitechat_plugingui_remove ( ph , gui_entry );
2011-02-24 04:14:30 +01:00
}
XSRETURN_EMPTY ;
}
2013-10-02 17:47:56 +03:00
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_plugin_pref_set )
2013-10-02 17:47:56 +03:00
{
dMARK ;
dAX ;
2026-01-05 23:12:38 -07:00
XSRETURN_IV (( IV ) zoitechat_pluginpref_set_str ( ph , SvPV_nolen ( ST ( 0 )),
2013-10-02 17:47:56 +03:00
SvPV_nolen ( ST ( 1 ))));
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_plugin_pref_get )
2013-10-02 17:47:56 +03:00
{
int result ;
char value [ 512 ];
dMARK ;
dAX ;
2026-01-05 23:12:38 -07:00
result = zoitechat_pluginpref_get_str ( ph , SvPV_nolen ( ST ( 0 )), value );
2013-10-02 17:47:56 +03:00
if ( result )
XSRETURN_PV ( value );
XSRETURN_UNDEF ;
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_plugin_pref_delete )
2013-10-02 17:47:56 +03:00
{
dMARK ;
dAX ;
2026-01-05 23:12:38 -07:00
XSRETURN_IV (( IV ) zoitechat_pluginpref_delete ( ph , SvPV_nolen ( ST ( 0 ))));
2013-10-02 17:47:56 +03:00
}
static
2026-01-05 23:12:38 -07:00
XS ( XS_ZoiteChat_plugin_pref_list )
2013-10-02 17:47:56 +03:00
{
char list [ 4096 ];
char value [ 512 ];
char * token ;
dSP ;
dMARK ;
dAX ;
2026-01-05 23:12:38 -07:00
if ( ! zoitechat_pluginpref_list ( ph , list ))
2013-10-02 17:47:56 +03:00
XSRETURN_EMPTY ;
PUSHMARK ( SP );
token = strtok ( list , "," );
while ( token != NULL )
{
2026-01-05 23:12:38 -07:00
zoitechat_pluginpref_get_str ( ph , token , value );
2013-10-02 17:47:56 +03:00
XPUSHs ( sv_2mortal ( newSVpv ( token , 0 )));
XPUSHs ( sv_2mortal ( newSVpv ( value , 0 )));
token = strtok ( NULL , "," );
}
PUTBACK ;
}
2011-02-24 04:14:30 +01:00
/* xs_init is the second argument perl_parse. As the name hints, it
initializes XS subroutines (see the perlembed manpage) */
static void
xs_init ( pTHX )
{
HV * stash ;
SV * version ;
/* This one allows dynamic loading of perl modules in perl
scripts by the 'use perlmod;' construction */
newXS ( "DynaLoader::boot_DynaLoader" , boot_DynaLoader , __FILE__ );
/* load up all the custom IRC perl functions */
2026-01-05 23:12:38 -07:00
newXS ( "ZoiteChat::Internal::register" , XS_ZoiteChat_register , __FILE__ );
newXS ( "ZoiteChat::Internal::hook_server" , XS_ZoiteChat_hook_server , __FILE__ );
newXS ( "ZoiteChat::Internal::hook_command" , XS_ZoiteChat_hook_command , __FILE__ );
newXS ( "ZoiteChat::Internal::hook_print" , XS_ZoiteChat_hook_print , __FILE__ );
newXS ( "ZoiteChat::Internal::hook_timer" , XS_ZoiteChat_hook_timer , __FILE__ );
newXS ( "ZoiteChat::Internal::hook_fd" , XS_ZoiteChat_hook_fd , __FILE__ );
newXS ( "ZoiteChat::Internal::unhook" , XS_ZoiteChat_unhook , __FILE__ );
newXS ( "ZoiteChat::Internal::print" , XS_ZoiteChat_print , __FILE__ );
newXS ( "ZoiteChat::Internal::command" , XS_ZoiteChat_command , __FILE__ );
newXS ( "ZoiteChat::Internal::set_context" , XS_ZoiteChat_set_context , __FILE__ );
newXS ( "ZoiteChat::Internal::get_info" , XS_ZoiteChat_get_info , __FILE__ );
newXS ( "ZoiteChat::Internal::context_info" , XS_ZoiteChat_context_info , __FILE__ );
newXS ( "ZoiteChat::Internal::get_list" , XS_ZoiteChat_get_list , __FILE__ );
newXS ( "ZoiteChat::Internal::plugin_pref_set" , XS_ZoiteChat_plugin_pref_set , __FILE__ );
newXS ( "ZoiteChat::Internal::plugin_pref_get" , XS_ZoiteChat_plugin_pref_get , __FILE__ );
newXS ( "ZoiteChat::Internal::plugin_pref_delete" , XS_ZoiteChat_plugin_pref_delete , __FILE__ );
newXS ( "ZoiteChat::Internal::plugin_pref_list" , XS_ZoiteChat_plugin_pref_list , __FILE__ );
2011-02-24 04:14:30 +01:00
2026-01-05 23:12:38 -07:00
newXS ( "ZoiteChat::find_context" , XS_ZoiteChat_find_context , __FILE__ );
newXS ( "ZoiteChat::get_context" , XS_ZoiteChat_get_context , __FILE__ );
newXS ( "ZoiteChat::get_prefs" , XS_ZoiteChat_get_prefs , __FILE__ );
newXS ( "ZoiteChat::emit_print" , XS_ZoiteChat_emit_print , __FILE__ );
newXS ( "ZoiteChat::send_modes" , XS_ZoiteChat_send_modes , __FILE__ );
newXS ( "ZoiteChat::nickcmp" , XS_ZoiteChat_nickcmp , __FILE__ );
newXS ( "ZoiteChat::Embed::plugingui_remove" , XS_ZoiteChat_Embed_plugingui_remove ,
2011-02-24 04:14:30 +01:00
__FILE__ );
2026-01-05 23:12:38 -07:00
stash = get_hv ( "ZoiteChat::" , TRUE );
2011-02-24 04:14:30 +01:00
if ( stash == NULL ) {
exit ( 1 );
}
2026-01-25 16:13:47 -07:00
newCONSTSUB ( stash , "PRI_HIGHEST" , newSViv ( ZOITECHAT_PRI_HIGHEST ));
newCONSTSUB ( stash , "PRI_HIGH" , newSViv ( ZOITECHAT_PRI_HIGH ));
newCONSTSUB ( stash , "PRI_NORM" , newSViv ( ZOITECHAT_PRI_NORM ));
newCONSTSUB ( stash , "PRI_LOW" , newSViv ( ZOITECHAT_PRI_LOW ));
newCONSTSUB ( stash , "PRI_LOWEST" , newSViv ( ZOITECHAT_PRI_LOWEST ));
newCONSTSUB ( stash , "EAT_NONE" , newSViv ( ZOITECHAT_EAT_NONE ));
newCONSTSUB ( stash , "EAT_ZOITECHAT" , newSViv ( ZOITECHAT_EAT_ZOITECHAT ));
newCONSTSUB ( stash , "EAT_XCHAT" , newSViv ( ZOITECHAT_EAT_ZOITECHAT )); /* for compatibility */
2026-02-23 19:09:09 -07:00
newCONSTSUB ( stash , "EAT_HEXCHAT" , newSViv ( ZOITECHAT_EAT_ZOITECHAT )); /* for compatibility */
2026-01-25 16:13:47 -07:00
newCONSTSUB ( stash , "EAT_PLUGIN" , newSViv ( ZOITECHAT_EAT_PLUGIN ));
newCONSTSUB ( stash , "EAT_ALL" , newSViv ( ZOITECHAT_EAT_ALL ));
newCONSTSUB ( stash , "FD_READ" , newSViv ( ZOITECHAT_FD_READ ));
newCONSTSUB ( stash , "FD_WRITE" , newSViv ( ZOITECHAT_FD_WRITE ));
newCONSTSUB ( stash , "FD_EXCEPTION" , newSViv ( ZOITECHAT_FD_EXCEPTION ));
newCONSTSUB ( stash , "FD_NOTSOCKET" , newSViv ( ZOITECHAT_FD_NOTSOCKET ));
2011-02-24 04:14:30 +01:00
newCONSTSUB ( stash , "KEEP" , newSViv ( 1 ));
newCONSTSUB ( stash , "REMOVE" , newSViv ( 0 ));
2026-01-05 23:12:38 -07:00
version = get_sv ( "ZoiteChat::VERSION" , 1 );
2011-02-24 04:14:30 +01:00
sv_setpv ( version , PACKAGE_VERSION );
}
static void
perl_init ( void )
{
int warn ;
int arg_count ;
char * perl_args [] = { "" , "-e" , "0" , "-w" };
char * env [] = { "" };
static const char xchat_definitions [] = {
2026-01-05 23:12:38 -07:00
/* Redefine the $SIG{__WARN__} handler to have ZoiteChat
2011-02-24 04:14:30 +01:00
printing warnings in the main window. (TheHobbit) */
2026-01-05 23:12:38 -07:00
#include "zoitechat.pm.h"
2011-02-24 04:14:30 +01:00
};
#ifdef OLD_PERL
static const char irc_definitions [] = {
#include "irc.pm.h"
};
#endif
#ifdef ENABLE_NLS
/* Problem is, dynamicaly loaded modules check out the $]
var. It appears that in the embedded interpreter we get
5,00503 as soon as the LC_NUMERIC locale calls for a comma
instead of a point in separating integer and decimal
parts. I realy can't understant why... The following
appears to be an awful workaround... But it'll do until I
(or someone else :)) found the "right way" to solve this
nasty problem. (TheHobbit <thehobbit@altern.org>) */
setlocale ( LC_NUMERIC , "C" );
#endif
warn = 0 ;
2026-01-05 23:12:38 -07:00
zoitechat_get_prefs ( ph , "perl_warnings" , NULL , & warn );
2011-02-24 04:14:30 +01:00
arg_count = warn ? 4 : 3 ;
PERL_SYS_INIT3 ( & arg_count , ( char *** ) & perl_args , ( char *** ) & env );
my_perl = perl_alloc ();
perl_construct ( my_perl );
PL_exit_flags |= PERL_EXIT_DESTRUCT_END ;
perl_parse ( my_perl , xs_init , arg_count , perl_args , ( char ** ) NULL );
/*
Now initialising the perl interpreter by loading the
perl_definition array.
*/
eval_pv ( xchat_definitions , TRUE );
#ifdef OLD_PERL
eval_pv ( irc_definitions , TRUE );
#endif
}
static int
perl_load_file ( char * filename )
{
#ifdef WIN32
static HMODULE lib = NULL ;
if ( ! lib ) {
lib = LoadLibraryA ( PERL_DLL );
if ( ! lib ) {
if ( GetLastError () == ERROR_BAD_EXE_FORMAT )
/* http://forum.xchat.org/viewtopic.php?t=3277 */
thread_mbox ( "Cannot use this " PERL_DLL " \n\n "
2011-02-28 18:59:32 +01:00
#ifdef _WIN64
2026-01-05 23:12:38 -07:00
"64-bit ZoiteChat Perl is required." );
2011-02-28 18:59:32 +01:00
#else
2026-01-05 23:12:38 -07:00
"32-bit ZoiteChat Perl is required." );
2011-02-28 18:59:32 +01:00
#endif
2011-02-24 04:14:30 +01:00
else {
/* a lot of people install this old version */
lib = LoadLibraryA ( "perl56.dll" );
if ( lib ) {
FreeLibrary ( lib );
lib = NULL ;
2012-11-12 02:24:19 +01:00
thread_mbox ( "Cannot open " PERL_DLL "! \n\n "
"You must have a Visual C++ build of Perl "
PERL_REQUIRED_VERSION " installed in order to \n "
2013-03-24 18:49:45 -03:00
"run Perl scripts. A reboot may be required. \n\n "
2026-03-30 18:25:26 -06:00
"http://zoitechat.org/downloads.html \n\n "
2011-02-24 04:14:30 +01:00
"I have found Perl 5.6, but that is too old." );
} else {
2012-11-12 02:24:19 +01:00
thread_mbox ( "Cannot open " PERL_DLL "! \n\n "
"You must have a Visual C++ build of Perl "
2011-11-23 03:04:25 +01:00
PERL_REQUIRED_VERSION " installed in order to \n "
2013-03-24 18:49:45 -03:00
"run Perl scripts. A reboot may be required. \n\n "
2026-03-30 18:25:26 -06:00
"http://zoitechat.org/downloads.html \n\n "
2012-11-12 02:24:19 +01:00
"Make sure Perl's bin directory is in your PATH." );
2011-02-24 04:14:30 +01:00
}
}
/* failure */
return FALSE ;
}
/* success */
FreeLibrary ( lib );
}
#endif
if ( my_perl == NULL ) {
perl_init ();
}
2026-01-05 23:12:38 -07:00
return execute_perl ( sv_2mortal ( newSVpv ( "ZoiteChat::Embed::load" , 0 )),
2011-02-24 04:14:30 +01:00
filename );
}
static void
perl_end ( void )
{
if ( my_perl != NULL ) {
2026-01-05 23:12:38 -07:00
execute_perl ( sv_2mortal ( newSVpv ( "ZoiteChat::Embed::unload_all" , 0 )), "" );
2011-02-24 04:14:30 +01:00
PL_perl_destruct_level = 1 ;
perl_destruct ( my_perl );
perl_free ( my_perl );
PERL_SYS_TERM ();
my_perl = NULL ;
}
}
static int
perl_command_unloadall ( char * word [], char * word_eol [], void * userdata )
{
if ( my_perl != NULL ) {
2026-01-05 23:12:38 -07:00
execute_perl ( sv_2mortal ( newSVpv ( "ZoiteChat::Embed::unload_all" , 0 )), "" );
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_ZOITECHAT ;
2011-02-24 04:14:30 +01:00
}
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_ZOITECHAT ;
2011-02-24 04:14:30 +01:00
}
static int
perl_command_reloadall ( char * word [], char * word_eol [], void * userdata )
{
if ( my_perl != NULL ) {
2026-01-05 23:12:38 -07:00
execute_perl ( sv_2mortal ( newSVpv ( "ZoiteChat::Embed::reload_all" , 0 )), "" );
2011-02-24 04:14:30 +01:00
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_ZOITECHAT ;
2011-02-24 04:14:30 +01:00
} else {
perl_auto_load ( NULL );
}
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_ZOITECHAT ;
2011-02-24 04:14:30 +01:00
}
static int
perl_command_load ( char * word [], char * word_eol [], void * userdata )
{
char * file = get_filename ( word , word_eol );
if ( file != NULL )
{
perl_load_file ( file );
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_ZOITECHAT ;
2011-02-24 04:14:30 +01:00
}
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
}
static int
perl_command_unload ( char * word [], char * word_eol [], void * userdata )
{
char * file = get_filename ( word , word_eol );
if ( my_perl != NULL && file != NULL ) {
2026-01-05 23:12:38 -07:00
execute_perl ( sv_2mortal ( newSVpv ( "ZoiteChat::Embed::unload" , 0 )), file );
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_ZOITECHAT ;
2011-02-24 04:14:30 +01:00
}
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
}
static int
2013-08-04 04:36:10 -04:00
perl_command_reload ( char * word [], char * word_eol [], void * eat )
2011-02-24 04:14:30 +01:00
{
char * file = get_filename ( word , word_eol );
if ( my_perl != NULL && file != NULL ) {
2026-01-05 23:12:38 -07:00
execute_perl ( sv_2mortal ( newSVpv ( "ZoiteChat::Embed::reload" , 0 )), file );
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_ZOITECHAT ;
2011-02-24 04:14:30 +01:00
}
2013-08-04 04:36:10 -04:00
if ( eat )
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_ZOITECHAT ;
2013-08-04 04:36:10 -04:00
else
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_NONE ;
2011-02-24 04:14:30 +01:00
}
2013-10-02 17:47:56 +03:00
static int
perl_command_eval ( char * word [], char * word_eol [], void * userdata )
{
if ( my_perl != NULL )
2026-01-05 23:12:38 -07:00
execute_perl ( sv_2mortal ( newSVpv ( "ZoiteChat::Embed::evaluate" , 0 )), word_eol [ 2 ]);
2013-10-02 17:47:56 +03:00
2026-01-25 16:13:47 -07:00
return ZOITECHAT_EAT_ZOITECHAT ;
2013-10-02 17:47:56 +03:00
}
2011-02-24 04:14:30 +01:00
void
2026-01-05 23:12:38 -07:00
zoitechat_plugin_get_info ( char ** name , char ** desc , char ** version ,
2011-02-24 04:14:30 +01:00
void ** reserved )
{
* name = "Perl" ;
* desc = "Perl scripting interface" ;
* version = PACKAGE_VERSION ;
if ( reserved )
* reserved = NULL ;
}
/* Reinit safeguard */
static int initialized = 0 ;
int
2026-01-05 23:12:38 -07:00
zoitechat_plugin_init ( zoitechat_plugin * plugin_handle , char ** plugin_name ,
2011-02-24 04:14:30 +01:00
char ** plugin_desc , char ** plugin_version , char * arg )
{
if ( initialized != 0 ) {
2026-01-05 23:12:38 -07:00
zoitechat_print ( plugin_handle , "Perl interface already loaded \n " );
2011-02-24 04:14:30 +01:00
return 0 ;
}
ph = plugin_handle ;
initialized = 1 ;
* plugin_name = "Perl" ;
* plugin_desc = "Perl scripting interface" ;
* plugin_version = PACKAGE_VERSION ;
2026-01-25 16:13:47 -07:00
zoitechat_hook_command ( ph , "load" , ZOITECHAT_PRI_NORM , perl_command_load , 0 , 0 );
zoitechat_hook_command ( ph , "unload" , ZOITECHAT_PRI_NORM , perl_command_unload , 0 ,
2011-02-24 04:14:30 +01:00
0 );
2026-01-25 16:13:47 -07:00
zoitechat_hook_command ( ph , "reload" , ZOITECHAT_PRI_NORM , perl_command_reload , 0 ,
2011-02-24 04:14:30 +01:00
0 );
2026-01-25 16:13:47 -07:00
zoitechat_hook_command ( ph , "pl_reload" , ZOITECHAT_PRI_NORM , perl_command_reload ,
2013-10-02 17:47:56 +03:00
"Reloads a Perl script. Syntax: /pl_reload <filename.pl>" , ( int * ) 1 );
2026-01-25 16:13:47 -07:00
zoitechat_hook_command ( ph , "unloadall" , ZOITECHAT_PRI_NORM ,
2013-10-02 17:47:56 +03:00
perl_command_unloadall , "Unloads all loaded Perl scripts." , 0 );
2026-01-25 16:13:47 -07:00
zoitechat_hook_command ( ph , "reloadall" , ZOITECHAT_PRI_NORM ,
2013-10-02 17:47:56 +03:00
perl_command_reloadall , "Realoads all loaded Perl scripts." , 0 );
2026-01-25 16:13:47 -07:00
zoitechat_hook_command ( ph , "pl" , ZOITECHAT_PRI_NORM ,
2013-10-02 17:47:56 +03:00
perl_command_eval , "Evaluates Perl code. Syntax: /pl <perl code>" , 0 );
2011-02-24 04:14:30 +01:00
/*perl_init (); */
2026-01-05 23:12:38 -07:00
zoitechat_hook_timer ( ph , 0 , perl_auto_load , NULL );
2011-02-24 04:14:30 +01:00
2026-01-05 23:12:38 -07:00
zoitechat_print ( ph , "Perl interface loaded \n " );
2011-02-24 04:14:30 +01:00
return 1 ;
}
int
2026-01-05 23:12:38 -07:00
zoitechat_plugin_deinit ( zoitechat_plugin * plugin_handle )
2011-02-24 04:14:30 +01:00
{
perl_end ();
initialized = 0 ;
2026-01-05 23:12:38 -07:00
zoitechat_print ( plugin_handle , "Perl interface unloaded \n " );
2011-02-24 04:14:30 +01:00
return 1 ;
}