<?php
/**************************************************
* NZBirc v1
* Copyright (c) 2006 Harry Bragg
* tiberious.org
* Module: config
**************************************************
*
* Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
*
* 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
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
class Net_SmartIRC_module_config extends Net_SmartIRC_module_base
{
// default module variable
var $name = 'config';
var $version = 'v0.1';
var $description = 'Configure the bot';
/**
* Config Module
*
* STARTCONFIG
* @var array publicCommand - Lists the commands that trigger this module, and return publicly
* @var array privateCommand - Lists the commands that trigger this module privatly (notice you)
* @var string configFile - Define the configuration file (Only change if you know what you are doing)
* @var string configVar - The configuration variable in $irc (Only change if you know what you are doing)
* ENDCONFIG
*/
var $_config = array(
'publicCommand' => array( '^config', '^!config' ),
'privateCommand' => array( '^@config' ),
'configFile' => 'config.inc.php',
'configVar' => 'config'
);
var $_def = array(
'regex' => array(
'configVars' => '/\\\*\*\s+\*\s(.+)\s+\*\s+\*\sSTARTCONFIG\s+(?s:(.+?))\s+\*\sENDCONFIG\s+\*\//',
'varVal' => '/\s*\* \@var(\s+)(\w+) (\w+)\s+(- (.+))?/'
),
'file' => array(
'header' => "<?php\n\n/**************************************************\n * NZBirc v1\n * Copyright (c) 2006 Harry Bragg\n * tiberious.org\n * irc config\n **************************************************/\n",
'footer' => "\nglobal \$config;\n\n?>",
'sectionHeader' => "\n/**\n * %s\n *\n",
'sectionVariable' => " * @var %s%s %s %s\n",
'sectionFooter' => " */\n",
'dataIRC' => "\$config->%s = %s;\n",
'dataModule' => "\$config->moduleConf['%s'] = %s;\n"
),
'export' => array(
'from' => array(
'/^(\s+)(\d+) => (.+),$/im',
'/=>(\s*)\n(\s+)array \(/',
'/^(\s{2,})/im'
),
'to' => array(
'$1$3,',
'=> array (',
'$1$1'
)
)
);
var $_template = array(
'error' => '**Error:** {errormsg}',
'avVar' => 'Available variables for __{pwd}__: {varList}',
'avMod' => 'Available modules: {varList}',
'varDetails' => '{type} **{name}** = {value} - {description}',
'varSet' => 'Variable __{pwd}__: set to: {newVar}',
'varAdd' => '{newVar} has been added to variable: __{pwd}__',
'varDel' => '{oldVar} has been deleted from variable: __{pwd}__',
'help' => '{command} - {description}',
'helpList' => array(
'Commands available for NZB: {helpCommands}',
'Type: {trigger} {subTrigger} command, for more information on each command'
)
);
var $_help = array(
'help' => array(
'command' => '{trigger} help [command]',
'description' => 'Display the available commands, if a __command__ is specified, then extra information is provided',
'longDescription' => 'Display the available commands, if a __command__ is specified, then extra information is provided'
),
'commands' => array(
'command' => '{trigger} commands',
'description' => 'List the available commands with their descriptions',
'longDescription' => 'List the available commands with their descriptions'
),
'set' => array(
'command' => '{trigger} module variable =/+/- value',
'description' => 'Set a config variable, __module__ can be **irc**, or the name of a module, __variable__ is a pathway to the variable, if the __variable__ is an array, use **+** and **-** to add or remove entries',
'longDescription' => array(
'Set a config variable, __module__ can be **irc**, or the name of a module, __variable__ is a pathway to the variable',
'if the __variable__ is an array, use **+** and **-** to add or remove entries'
)
),
'get' => array(
'command' => '{trigger} module variable',
'description' => 'Get a config variable, __module__ can be **irc**, or the name of a module',
'longDescription' => 'Get a config variable, __module__ can be **irc**, or the name of a module'
)
);
function _registerCommands()
{
global $irc;
$this->_setHandler( '^(\w+) (.+) (=|\+|-)\s?(.+)$', $this, 'botSet' );
$this->_setHandler( '^(\w+)([^=\+\-]+)?$', $this, 'botGet' );
$this->_setHandler( '^$', $this, 'botList' );
}
/*****************************************************
* Bot functions
*****************************************************/
function botList( &$irc, &$data, $notice )
{
// admin check
if ( !$irc->_modules['func']->isAdmin( $irc, $data->nick ) )
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Insufficient privaleges to run this command' ) );
$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
return;
}
$vars['varList'][] = 'irc';
foreach( $irc->_modules as $name => $module )
{
if ( isset( $module->_config ) )
{
$vars['varList'][] = $name;
}
}
$this->parseTemplate( $msg, 'avMod', $vars );
$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
}
function botSet( &$irc, &$data, $notice )
{
// admin check
if ( !$irc->_modules['func']->isAdmin( $irc, $data->nick ) )
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Insufficient privaleges to run this command' ) );
$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
return;
}
if ( $data->trig[1] == 'irc' )
{
$opts = $this->getOptions( 'irc', 'irc.php' );
$conf = (array)$irc->config;
}
else if ( $irc->isLoadedModule( $data->trig[1] ) )
{
$opts = $this->getOptions( $data->trig[1], $irc->config->modulePath.'/'.$data->trig[1].'.php' );
$conf = $irc->_modules[$data->trig[1]]->_config;
}
else
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Invalid Module: '.$data->trig[1] ) );
$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
return;
}
if ( strlen( $data->trig[2] ) > 0 ) {
$pSplit = explode( ' ', trim( $data->trig[2] ) );
}
else
{
$pSplit = array();
}
$pwd[] = $data->trig[1];
$irc->_modules['func']->array_append( $pwd, $pSplit );
$pwd = implode( '__ > __', $pwd );
if ( ( $val = $this->_gTravArray( $conf, $pSplit ) ) !== 'fakeFalse' )
{
$cInfo = $this->_gTravArray( $opts, $pSplit );
if ( isset( $cInfo['description'] ) )
{
if ( $cInfo['name'] != 'password' )
{
if ( is_array( $val ) )
{
if ( $data->trig[3] != '=' )
{
if ( $data->trig[3] == '+' )
{
$val[] = $data->trig[4];
$nConf = $this->_sTravArray( $conf, $pSplit, $val );
$this->_setConfig( $data->trig[1], $nConf );
$vars = array(
'pwd' => $pwd,
'newVar' => $data->trig[4]
);
$this->parseTemplate( $msg, 'varAdd', $vars );
}
else
{
if ( ( $key = array_search( trim( $data->trig[4] ), $val ) ) !== false )
{
unset( $val[$key] );
$nVal = $this->_resortArray( $val );
$nConf = $this->_sTravArray( $conf, $pSplit, $nVal );
$this->_setConfig( $data->trig[1], $nConf );
$vars = array(
'pwd' => $pwd,
'oldVar' => $data->trig[4]
);
$this->parseTemplate( $msg, 'varDel', $vars );
}
else
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Can not delete item: {oldVar}, does not exist in variable: __{pwd}__', 'oldVar' => $data->trig[4], 'pwd' => $pwd ) );
}
}
}
else
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Variable: __{pwd}__ is an array, use the **+** and **-** commands to add or remove items', 'pwd' => $pwd ) );
}
}
else
{
switch( $cInfo['type'] )
{
case 'bool':
{
$nVar = ( $data->trig[4] == 'true' )? true:false;
break;
}
case 'int':
{
if ( is_numeric( $data->trig[4] ) )
{
$nVar = $data->trig[4];
}
else
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Failed to set variable: __{pwd}__, value: {newVal} is not numeric', 'pwd' => $pwd, 'newVal' => $data->trig[4] ) );
$fail = true;
}
break;
}
default:
$nVar = $data->trig[4];
}
if ( !$fail )
{
$nConf = $this->_sTravArray( $conf, $pSplit, $nVar );
$this->_setConfig( $data->trig[1], $nConf );
$vars = array(
'pwd' => $pwd,
'newVar' => $data->trig[4]
);
$this->parseTemplate( $msg, 'varSet', $vars );
$irc->_respawn();
}
}
}
else
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Password Variables are out of bounds' ) );
$notice = true;
}
}
else
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Variable: __{path}__ is not writeable', 'path' => $pwd ) );
}
}
else
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Invalid path: __{path}__', 'path' => $pwd ) );
}
if ( isset( $msg ) )
{
$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
}
}
function botGet( &$irc, &$data, $notice )
{
// admin check
if ( !$irc->_modules['func']->isAdmin( $irc, $data->nick ) )
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Insufficient privaleges to run this command' ) );
$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
return;
}
if ( $data->trig[1] == 'help' )
{
$data->subMessage = trim( str_replace( $data->trig[1], '', $data->strippedMessage ) );
$data->trig = array( 'help' );
return $this->botHelp( $irc, $data, $notice );
}
else if ( $data->trig[1] == 'irc' )
{
$opts = $this->getOptions( 'irc', 'irc.php' );
$conf = (array)$irc->config;
}
else if ( $irc->isLoadedModule( $data->trig[1] ) )
{
$opts = $this->getOptions( $data->trig[1], $irc->config->modulePath.'/'.$data->trig[1].'.php' );
$conf = $irc->_modules[$data->trig[1]]->_config;
}
else
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Invalid Module: '.$data->trig[1] ) );
$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
return;
}
if ( strlen( $data->trig[2] ) > 0 ) {
$pSplit = explode( ' ', trim( $data->trig[2] ) );
}
else
{
$pSplit = array();
}
if ( ( $val = $this->_gTravArray( $conf, $pSplit ) ) !== 'fakeFalse' )
{
$cInfo = $this->_gTravArray( $opts, $pSplit );
if ( isset( $cInfo['description'] ) )
{
if ( $cInfo['name'] != 'password' )
{
$vars = $cInfo;
if ( is_array( $val ) )
{
$vars['value'] = 'array( {vals} )';
$vars['vals'] = $val;
}
else if ( $cInfo['type'] == 'bool' )
{
$vars['value'] = ( $val )? 'true':'false';
}
else
{
$vars['value'] = $val;
}
$this->parseTemplate( $msg, 'varDetails', $vars );
}
else
{
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Password Variables are out of bounds' ) );
$notice = true;
}
}
else
{
foreach( $val as $id => $item )
{
if ( $id != 'password' )
{
if ( isset( $cInfo[$id] ) )
{
if ( !isset( $cInfo[$id]['description'] ) )
$id = '**'.$id.'**';
$vars['varList'][] = $id;
}
else if ( count( $cInfo ) == 1 )
{
$keys = array_keys( $cInfo );
if ( substr( $keys[0], -1 ) == '_' )
{
if ( !isset( $cInfo[$keys[0]]['description'] ) )
$id = '**'.$id.'**';
$vars['varList'][] = $id;
}
}
}
}
// if i change the seperator part of the template system to allow 2 lists with different seperators in 1 template var this can be tidied up
$tmp[] = $data->trig[1];
$irc->_modules['func']->array_append( $tmp, $pSplit );
$vars['pwd'] = implode( '__ > __', $tmp );
// $irc->_modules['func']->array_append( $vars['pwd'], $pSplit );
$this->parseTemplate( $msg, 'avVar', $vars );
}
}
else
{
$tmp[] = $data->trig[1];
$irc->_modules['func']->array_append( $tmp, $pSplit );
$this->parseTemplate( $msg, 'error', array( 'errormsg' => 'Invalid path: __{path}__', 'path' => implode( '__ > __', $tmp ) ) );
}
if ( isset( $msg ) )
{
$irc->_modules['func']->reply( $irc, $data, $msg, $notice );
}
}
function botHelp( &$irc, &$data, $notice )
{
if ( strlen( $data->subMessage ) > 0 )
{
if ( isset( $this->_help[$data->subMessage] ) )
{
$this->parseHelp( $msg, $data->subMessage, array( 'trigger' => $data->trigger ) );
}
else
{
//$this->parseTemplate( $msg, 'error', array( 'errormsg' => sprintf( 'Unknown command: %s', $data->subMessage ) ) );
}
}
else
{
foreach ( $this->_help as $id => $helpItem )
{
$vars['helpCommands'][] = $id;
}
$vars['trigger'] = $data->trigger;
$vars['subTrigger'] = $data->trig[0];
$this->parseTemplate( $msg, 'helpList', $vars );
}
if ( isset( $msg ) )
{
$irc->_modules['func']->reply( $irc, $data, $msg, true );
}
}
/*****************************************************
* Reading config options from a file
*****************************************************/
function getOptions( $module, $file, $header = false )
{
global $irc;
if ( is_file( $file ) )
{
$text = file_get_contents( $file );
preg_match_all( $this->_def['regex']['configVars'], $text, $match );
$conf = array();
for( $i=0, $l=0; $i < count( $match[0] ); $i++ )
{
if ( $header )
{
$conf['configSplit'.$l++] = $match[1][$i];
}
preg_match_all( $this->_def['regex']['varVal'], $match[2][$i], $vars );
for( $j=0; $j < count( $vars[0] ); $j++ )
{
$apos = ( strlen( $vars[1][$j] ) - 1 ) / 4;
$pos[$apos] = $vars[3][$j];
$pos = array_splice( $pos, 0, $apos + 1 );
if ( ( !empty( $vars[5][$j] ) ) )
{
$tmp = array(
'type' => $vars[2][$j],
'name' => $vars[3][$j],
'description' => $vars[5][$j]
);
$conf = $this->_sTravArray( $conf, $pos, $tmp );
}
}
}
return $conf;
}
}
function _gTravArray( $array, $pos )
{
if ( count( $pos ) == 0 )
{
return $array;
}
else if ( !array_key_exists( $pos[0], $array ) )
{
if ( count( $array ) == 1 )
{
$keys = array_keys( $array );
if ( substr( $keys[0], -1 ) == '_' )
{
$array[$pos[0]] = $array[$keys[0]];
return $this->_gTravArray( $array[$pos[0]], array_splice( $pos, 1 ) );
}
}
return 'fakeFalse';
}
else
{
return $this->_gTravArray( $array[$pos[0]], array_splice( $pos, 1 ) );
}
}
function _sTravArray( $array, $pos, $set )
{
if ( count( $pos ) == 0 )
{
$array = $set;
}
else
{
$array[$pos[0]] = $this->_sTravArray( $array[$pos[0]], array_splice( $pos, 1 ), $set );
}
return $array;
}
function _resortArray( $array )
{
$nArr = array();
foreach( $array as $val )
{
$nArr[] = $val;
}
return $nArr;
}
function _setConfig( $module, $newConf )
{
global $irc;
if ( $module == 'irc' )
{
$irc->config = (object)$newConf;
}
else
{
//print_r( $newConf );
$irc->_modules[$module]->_config = $newConf;
}
// can not have a slash, because if basePath is not set it will write to root
$this->_writeConfig( $irc->config->userPath.$this->_config['configFile'] );
}
function _writeConfig( $file )
{
global $irc;
$text = $this->_def['file']['header'];
// get irc options
$text .= $this->_writeConfigModule( 'irc' );
$mList = $irc->config->moduleConf;
foreach( $irc->config->modules as $mod )
{
$text .= $this->_writeConfigModule( $mod );
if ( isset( $mList[$mod] ) )
{
unset( $mList[$mod] );
}
}
foreach( $mList as $mod => $bla )
{
$text .= $this->_writeConfigModule( $mod );
}
$text .= $this->_def['file']['footer'];
$fp = @fopen( $file, 'w' );
if (!$fp) {
$irc->modDebug( 'config', 'unable to open config file: '.$file, __FILE__, __LINE__ );
return 'unable to open file: '.$file;
}
fwrite( $fp, $text );
fclose( $fp );
return true;
}
function _writeConfigModule( $module )
{
global $irc;
if ( $module == 'irc' )
{
$opts = $this->getOptions( 'irc', $irc->config->basePath.'/'.'irc.php', true );
}
else
{
$opts = $this->getOptions( $module, $irc->config->modulePath.'/'.$module.'.php', true );
}
$i = 0;
foreach( $opts as $id => $item )
{
if ( substr( $id, 0, 11 ) == 'configSplit' )
{
// if not first, write everything down
if ( $i > 0 )
{
$text .= $this->_writeConfigSection( $module, $section[$i] );
}
$section[++$i] = array(
'header' => $item,
'vars' => array()
);
}
else
{
$section[$i]['vars'][$id] = $item;
}
}
$text .= $this->_writeConfigSection( $module, $section[$i] );
return $text;
}
function _writeConfigSection( $module, $section )
{
global $irc;
if ( !is_array( $section['vars'] ) )
{
return false;
}
$text = sprintf( $this->_def['file']['sectionHeader'], $section['header'] );
$text .= $this->_writeConfigInfo( $section['vars'], 0 );
$text .= $this->_def['file']['sectionFooter'];
if ( $module == 'irc' )
{
foreach( $section['vars'] as $name => $var )
{
$text .= sprintf( $this->_def['file']['dataIRC'], $name, $this->_writeVarFormat( $irc->config->$name ) );
}
}
else
{
if ( ( !isset( $irc->_modules[$module]->_config ) ) &&
( isset( $irc->config->moduleConf[$module] ) ) )
{
$text .= sprintf( $this->_def['file']['dataModule'], $module, $this->_writeVarFormat( $irc->config->moduleConf[$module] ) );
}
else
{
$text .= sprintf( $this->_def['file']['dataModule'], $module, $this->_writeVarFormat( $irc->_modules[$module]->_config ) );
}
}
return $text;
}
function _writeConfigInfo( $var, $spaces )
{
foreach( $var as $id => $item )
{
if ( !isset( $item['description'] ) )
{
// array
$text .= sprintf( $this->_def['file']['sectionVariable'], str_repeat( ' ', $spaces ), 'array', $id, '' );
$text .= $this->_writeConfigInfo( $item, $spaces + 4 );
}
else
{
$text .= sprintf( $this->_def['file']['sectionVariable'], str_repeat( ' ', $spaces ), $item['type'], $item['name'], '- '.$item['description'] );
}
}
return $text;
}
function _writeVarFormat( $var )
{
// format
$export = var_export( $var, true );
return preg_replace( $this->_def['export']['from'], $this->_def['export']['to'], $export );
}
}
?>