Commit de31813f authored by Antoine Cellerier's avatar Antoine Cellerier

Add a new type of VLC Lua module: Interfaces.

Two things led me to add this new type of Lua modules:
 * Most interfaces duplicate code from one another (rc and telnet both deal
   with sockets, rc and hotkeys duplicate VLC interfacing code)
 * It's easier to code in Lua than in C (for high level stuff)
(* Users can code their own module easily, all they need is a text editor.)

Most of the changes in modules/misc/ are Lua wrappers for different C APIs
in VLC. I'd say that 90% of those wrappers won't change, the other 10% might
 need small changes (mostly to simplify the C code).

The VLC Lua "interface" module will look for lua scripts in the
*share*/luaintf/ directory. Files in *share*/luaintf/modules/ are lua modules
which can be used by multiple VLC Lua modules (using require "modulename").

This commit includes 4 Lua interface modules:
 * dummy.lua: the default module. Prints error messages and quits.
 * rc.lua: equivalent to the legacy rc.c module. Also includes a bunch of
   new features (+ multiple socket connections at a time work!). See file for
   more details.
 * telnet.lua: equivalent to the legacy telnet.c module. See file for more
   details.
 * hotkeys.lua: a rewrite of the hotkey handling module. This module is still
   experimental. I'll need to change VLC core hotkeys stuff to make it work
   like I want (ie: 1 hotkey triggers 1 action instead of the current 1 action
   can have 1 hotkey). This version executes 3 dummy actions when keys 'q',
   'w' or 'x' are pressed.

What's left to do:
 * Port the http interface plugin to this framework (at least for the
   macros/rpn part ... using <?vlc some lua code ?> à la PHP would be way
   easier than what we currently have).
 * Finish work on the hotkeys module.
 * Code a real telnet/rc module with autocompletion and all the cool features
   usually found in a telnet/terminal interface.
 * Trash the legacy C modules.

Stuff to test (which I can't test myself):
 * Win32 and Mac OS X specific changes to Makefile.am
 * Console interface under Win32. I expect it not to work.

Other stuff included in this changeset are:
 * Code cleanup (I'm sure that it's still possible to simplify some of the old lua bindings code).
 * That's pretty much it in fact :/
parent 154d9e74
......@@ -433,6 +433,14 @@ VLC-release.app: vlc
for i in $(srcdir)/share/luameta/*.* ; do \
$(INSTALL) -m 644 $${i} $(top_builddir)/VLC-release.app/Contents/MacOS/share/luameta/`basename $${i}` ; \
done ; \
$(INSTALL) -d $(top_builddir)/VLC-release.app/Contents/MacOS/share/luaintf
for i in $(srcdir)/share/luaintf/*.* ; do \
$(INSTALL) -m 644 $${i} $(top_builddir)/VLC-release.app/Contents/MacOS/share/luaintf/`basename $${i}` ; \
done ; \
$(INSTALL) -d $(top_builddir)/VLC-release.app/Contents/MacOS/share/luaintf/modules
for i in $(srcdir)/share/luaintf/modules/*.* ; do \
$(INSTALL) -m 644 $${i} $(top_builddir)/VLC-release.app/Contents/MacOS/share/luaintf/modules/`basename $${i}` ; \
done ; \
$(INSTALL) -d $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/dialogs
$(INSTALL) -d $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/js
$(INSTALL) -d $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/old
......@@ -733,6 +741,14 @@ package-win32-base-debug: package-win-common
for i in $(srcdir)/share/luameta/*.* ; do \
$(INSTALL) -m 644 $${i} $(top_builddir)/vlc-${VERSION}/share/luameta/`basename $${i}` ; \
done ;
$(INSTALL) -d $(top_builddir)/vlc-${VERSION}/share/luaintf
for i in $(srcdir)/share/luaintf/*.* ; do \
$(INSTALL) -m 644 $${i} $(top_builddir)/vlc-${VERSION}/share/luaintf/`basename $${i}` ; \
done ;
$(INSTALL) -d $(top_builddir)/vlc-${VERSION}/share/luaintf/modules
for i in $(srcdir)/share/luaintf/modules/*.* ; do \
$(INSTALL) -m 644 $${i} $(top_builddir)/vlc-${VERSION}/share/luaintf/modules/`basename $${i}` ; \
done ;
mkdir -p "$(top_builddir)/vlc-${VERSION}/osdmenu"
cp $(srcdir)/share/osdmenu/*.* "$(top_builddir)/vlc-${VERSION}/osdmenu"
......
SOURCES_lua = luaplaylist.c luameta.c vlclua.c vlclua.h
SOURCES_lua = playlist.c meta.c intf.c vlc.c vlc.h callbacks.c objects.c variables.c configuration.c net.c vlm.c
This diff is collapsed.
/*****************************************************************************
* configuration.c: Generic lua<->vlc config inteface
*****************************************************************************
* Copyright (C) 2007 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan tod org>
*
* 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <vlc/vlc.h>
#include <lua.h> /* Low level lua C API */
#include <lauxlib.h> /* Higher level C API */
#include <lualib.h> /* Lua libs */
#include "vlc.h"
/*****************************************************************************
* Config handling
*****************************************************************************/
int vlclua_config_get( lua_State *L )
{
vlc_object_t * p_this = vlclua_get_this( L );
const char *psz_name;
psz_name = luaL_checkstring( L, 1 );
switch( config_GetType( p_this, psz_name ) )
{
case VLC_VAR_MODULE:
case VLC_VAR_STRING:
case VLC_VAR_FILE:
case VLC_VAR_DIRECTORY:
lua_pushstring( L, config_GetPsz( p_this, psz_name ) );
break;
case VLC_VAR_INTEGER:
lua_pushinteger( L, config_GetInt( p_this, psz_name ) );
break;
case VLC_VAR_BOOL:
lua_pushboolean( L, config_GetInt( p_this, psz_name ) );
break;
case VLC_VAR_FLOAT:
lua_pushnumber( L, config_GetFloat( p_this, psz_name ) );
break;
default:
return vlclua_error( L );
}
return 1;
}
int vlclua_config_set( lua_State *L )
{
vlc_object_t *p_this = vlclua_get_this( L );
const char *psz_name;
psz_name = luaL_checkstring( L, 1 );
switch( config_GetType( p_this, psz_name ) )
{
case VLC_VAR_MODULE:
case VLC_VAR_STRING:
case VLC_VAR_FILE:
case VLC_VAR_DIRECTORY:
config_PutPsz( p_this, psz_name, luaL_checkstring( L, 2 ) );
break;
case VLC_VAR_INTEGER:
config_PutInt( p_this, psz_name, luaL_checkint( L, 2 ) );
break;
case VLC_VAR_BOOL:
config_PutInt( p_this, psz_name, luaL_checkboolean( L, 2 ) );
break;
case VLC_VAR_FLOAT:
config_PutFloat( p_this, psz_name,
luaL_checknumber( L, 2 ) );
break;
default:
return vlclua_error( L );
}
return 0;
}
This diff is collapsed.
/*****************************************************************************
* net.c: Network related functions
*****************************************************************************
* Copyright (C) 2007 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan tod org>
*
* 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <vlc/vlc.h>
#include <vlc_network.h>
#include <vlc_url.h>
#include <lua.h> /* Low level lua C API */
#include <lauxlib.h> /* Higher level C API */
#include <lualib.h> /* Lua libs */
#include "vlc.h"
/*****************************************************************************
*
*****************************************************************************/
int vlclua_url_parse( lua_State *L )
{
const char *psz_url = luaL_checkstring( L, 1 );
const char *psz_option = luaL_optstring( L, 2, NULL );
vlc_url_t url;
vlc_UrlParse( &url, psz_url, psz_option?*psz_option:0 );
lua_newtable( L );
lua_pushstring( L, url.psz_protocol );
lua_setfield( L, -2, "protocol" );
lua_pushstring( L, url.psz_username );
lua_setfield( L, -2, "username" );
lua_pushstring( L, url.psz_password );
lua_setfield( L, -2, "password" );
lua_pushstring( L, url.psz_host );
lua_setfield( L, -2, "host" );
lua_pushinteger( L, url.i_port );
lua_setfield( L, -2, "port" );
lua_pushstring( L, url.psz_path );
lua_setfield( L, -2, "path" );
lua_pushstring( L, url.psz_option );
lua_setfield( L, -2, "option" );
vlc_UrlClean( &url );
return 1;
}
int vlclua_net_listen_tcp( lua_State *L )
{
vlc_object_t *p_this = vlclua_get_this( L );
const char *psz_host = luaL_checkstring( L, 1 );
int i_port = luaL_checkint( L, 2 );
int *pi_fd = net_ListenTCP( p_this, psz_host, i_port );
if( pi_fd == NULL )
return luaL_error( L, "Cannot listen on %s:%d", psz_host, i_port );
lua_pushlightuserdata( L, pi_fd );
return 1;
}
int vlclua_net_listen_close( lua_State *L )
{
int *pi_fd = (int*)luaL_checklightuserdata( L, 1 );
net_ListenClose( pi_fd );
return 0;
}
int vlclua_net_accept( lua_State *L )
{
vlc_object_t *p_this = vlclua_get_this( L );
int *pi_fd = (int*)luaL_checklightuserdata( L, 1 );
mtime_t i_wait = luaL_optint( L, 2, -1 ); /* default to block */
int i_fd = net_Accept( p_this, pi_fd, i_wait );
lua_pushinteger( L, i_fd );
return 1;
}
int vlclua_net_close( lua_State *L )
{
int i_fd = luaL_checkint( L, 1 );
net_Close( i_fd );
return 0;
}
int vlclua_net_send( lua_State *L )
{
int i_fd = luaL_checkint( L, 1 );
size_t i_len;
const char *psz_buffer = luaL_checklstring( L, 2, &i_len );
i_len = luaL_optint( L, 3, i_len );
i_len = send( i_fd, psz_buffer, i_len, 0 );
lua_pushinteger( L, i_len );
return 1;
}
int vlclua_net_recv( lua_State *L )
{
int i_fd = luaL_checkint( L, 1 );
size_t i_len = luaL_optint( L, 2, 1 );
char psz_buffer[i_len];
i_len = recv( i_fd, psz_buffer, i_len, 0 );
lua_pushlstring( L, psz_buffer, i_len );
return 1;
}
int vlclua_net_select( lua_State *L )
{
int i_ret;
int i_nfds = luaL_checkint( L, 1 );
fd_set *fds_read = (fd_set*)luaL_checkuserdata( L, 2, sizeof( fd_set ) );
fd_set *fds_write = (fd_set*)luaL_checkuserdata( L, 3, sizeof( fd_set ) );
double f_timeout = luaL_checknumber( L, 4 );
struct timeval timeout;
timeout.tv_sec = (int)f_timeout;
timeout.tv_usec = (int)(1e6*(f_timeout-(double)((int)f_timeout)));
i_ret = select( i_nfds, fds_read, fds_write, 0, &timeout );
lua_pushinteger( L, i_ret );
lua_pushinteger( L, (double)timeout.tv_sec+((double)timeout.tv_usec)/1e-6 );
return 2;
}
int vlclua_fd_set_new( lua_State *L )
{
fd_set *fds = (fd_set*)lua_newuserdata( L, sizeof( fd_set ) );
FD_ZERO( fds );
return 1;
}
int vlclua_fd_clr( lua_State *L )
{
fd_set *fds = (fd_set*)luaL_checkuserdata( L, 1, sizeof( fd_set ) );
int i_fd = luaL_checkint( L, 2 );
FD_CLR( i_fd, fds );
return 0;
}
int vlclua_fd_isset( lua_State *L )
{
fd_set *fds = (fd_set*)luaL_checkuserdata( L, 1, sizeof( fd_set ) );
int i_fd = luaL_checkint( L, 2 );
lua_pushboolean( L, FD_ISSET( i_fd, fds ) );
return 1;
}
int vlclua_fd_set( lua_State *L )
{
fd_set *fds = (fd_set*)luaL_checkuserdata( L, 1, sizeof( fd_set ) );
int i_fd = luaL_checkint( L, 2 );
FD_SET( i_fd, fds );
return 0;
}
int vlclua_fd_zero( lua_State *L )
{
fd_set *fds = (fd_set*)luaL_checkuserdata( L, 1, sizeof( fd_set ) );
FD_ZERO( fds );
return 0;
}
/*
int vlclua_fd_open( lua_State *L )
{
}
*/
int vlclua_fd_write( lua_State *L )
{
int i_fd = luaL_checkint( L, 1 );
size_t i_len;
ssize_t i_ret;
const char *psz_buffer = luaL_checklstring( L, 2, &i_len );
i_len = luaL_optint( L, 3, i_len );
i_ret = write( i_fd, psz_buffer, i_len );
lua_pushinteger( L, i_ret );
return 1;
}
int vlclua_fd_read( lua_State *L )
{
int i_fd = luaL_checkint( L, 1 );
size_t i_len = luaL_optint( L, 2, 1 );
char psz_buffer[i_len];
i_len = read( i_fd, psz_buffer, i_len );
lua_pushlstring( L, psz_buffer, i_len );
return 1;
}
/*****************************************************************************
* objects.c: Generic lua<->vlc object wrapper
*****************************************************************************
* Copyright (C) 2007 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan tod org>
*
* 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <vlc/vlc.h>
#include <lua.h> /* Low level lua C API */
#include <lauxlib.h> /* Higher level C API */
#include <lualib.h> /* Lua libs */
#include "vlc.h"
typedef struct
{
vlc_object_t *p_obj;
} vlclua_object_t;
/*****************************************************************************
* Generic vlc_object_t wrapper creation
*****************************************************************************/
int __vlclua_push_vlc_object( lua_State *L, vlc_object_t *p_obj,
lua_CFunction pf_gc )
{
vlclua_object_t *p_ud = (vlclua_object_t *)
lua_newuserdata( L, sizeof( vlclua_object_t ) );
p_ud->p_obj = p_obj;
lua_newtable( L );
/* Hide the metatable */
lua_pushstring( L, "__metatable" );
lua_pushstring( L, "none of your business" );
lua_settable( L, -3 );
if( pf_gc )
{
/* Set the garbage collector if needed */
lua_pushstring( L, "__gc" );
lua_pushcfunction( L, pf_gc );
lua_settable( L, -3 );
}
lua_setmetatable( L, -2 );
return 1;
}
int vlclua_gc_release( lua_State *L )
{
vlclua_object_t *p_ud = (vlclua_object_t *)lua_touserdata( L, -1 );
lua_pop( L, 1 );
vlc_object_release( p_ud->p_obj );
return 0;
}
vlc_object_t *vlclua_checkobject( lua_State *L, int narg, int i_type )
{
vlclua_object_t *p_obj = (vlclua_object_t *)luaL_checkuserdata( L, narg, sizeof( vlclua_object_t ) );
/* TODO: add some metatable based method to check that this isn't
* any userdata, but really some vlc object */
if( i_type )
{
if( p_obj->p_obj->i_object_type == i_type )
return p_obj->p_obj;
else
{
luaL_error( L, "VLC object type doesn't match requirements." );
return NULL; /* luaL_error alread longjmp-ed out of here.
* This is to make gcc happy */
}
}
else
{
return p_obj->p_obj;
}
}
static int vlc_object_type_from_string( const char *psz_name )
{
static const struct
{
int i_type;
const char *psz_name;
} pp_objects[] =
{ { VLC_OBJECT_GLOBAL, "global" },
{ VLC_OBJECT_LIBVLC, "libvlc" },
{ VLC_OBJECT_MODULE, "module" },
{ VLC_OBJECT_INTF, "intf" },
{ VLC_OBJECT_PLAYLIST, "playlist" },
{ VLC_OBJECT_ITEM, "item" },
{ VLC_OBJECT_INPUT, "input" },
{ VLC_OBJECT_DECODER, "decoder" },
{ VLC_OBJECT_VOUT, "vout" },
{ VLC_OBJECT_AOUT, "aout" },
{ VLC_OBJECT_SOUT, "sout" },
{ VLC_OBJECT_HTTPD, "httpd" },
{ VLC_OBJECT_PACKETIZER, "packetizer" },
{ VLC_OBJECT_ENCODER, "encoder" },
{ VLC_OBJECT_DIALOGS, "dialogs" },
{ VLC_OBJECT_VLM, "vlm" },
{ VLC_OBJECT_ANNOUNCE, "announce" },
{ VLC_OBJECT_DEMUX, "demux" },
{ VLC_OBJECT_ACCESS, "access" },
{ VLC_OBJECT_STREAM, "stream" },
{ VLC_OBJECT_OPENGL, "opengl" },
{ VLC_OBJECT_FILTER, "filter" },
{ VLC_OBJECT_VOD, "vod" },
{ VLC_OBJECT_SPU, "spu" },
{ VLC_OBJECT_SD, "sd" },
{ VLC_OBJECT_XML, "xml" },
{ VLC_OBJECT_OSDMENU, "osdmenu" },
{ VLC_OBJECT_HTTPD_HOST, "httpd_host" },
{ VLC_OBJECT_META_ENGINE, "meta_engine" },
{ VLC_OBJECT_GENERIC, "generic" },
{ 0, "" } };
int i;
for( i = 0; pp_objects[i].i_type; i++ )
{
if( !strcmp( psz_name, pp_objects[i].psz_name ) )
return pp_objects[i].i_type;
}
return 0;
}
static int vlc_object_search_mode_from_string( const char *psz_name )
{
static const struct
{
int i_mode;
const char *psz_name;
} pp_modes[] =
{ { FIND_PARENT, "parent" },
{ FIND_CHILD, "child" },
{ FIND_ANYWHERE, "anywhere" },
{ 0, "" } };
int i;
for( i = 0; pp_modes[i].i_mode; i++ )
{
if( !strcmp( psz_name, pp_modes[i].psz_name ) )
return pp_modes[i].i_mode;
}
return 0;
}
int vlclua_object_find( lua_State *L )
{
const char *psz_type = luaL_checkstring( L, 2 );
const char *psz_mode = luaL_checkstring( L, 3 );
vlc_object_t *p_this;
int i_type = vlc_object_type_from_string( psz_type );
int i_mode = vlc_object_search_mode_from_string( psz_mode );
vlc_object_t *p_result;
if( !i_type )
return luaL_error( L, "\"%s\" is not a valid object type.", psz_type );
if( !i_mode )
return luaL_error( L, "\"%s\" is not a valid search mode.", psz_mode );
if( lua_type( L, 1 ) == LUA_TNIL )
p_this = vlclua_get_this( L );
else
p_this = vlclua_checkobject( L, 1, 0 );
p_result = vlc_object_find( p_this, i_type, i_mode );
if( !p_result )
lua_pushnil( L );
else
vlclua_push_vlc_object( L, p_result, vlclua_gc_release );
return 1;
}
int vlclua_object_find_name( lua_State *L )
{
const char *psz_name = luaL_checkstring( L, 2 );
const char *psz_mode = luaL_checkstring( L, 3 );
vlc_object_t *p_this;
int i_mode = vlc_object_search_mode_from_string( psz_mode );
vlc_object_t *p_result;
if( !i_mode )
return luaL_error( L, "\"%s\" is not a valid search mode.",
psz_mode );
if( lua_type( L, 1 ) == LUA_TNIL )
p_this = vlclua_get_this( L );
else
p_this = vlclua_checkobject( L, 1, 0 );
p_result = vlc_object_find_name( p_this, psz_name, i_mode );
if( !p_result )
lua_pushnil( L );
else
vlclua_push_vlc_object( L, p_result, vlclua_gc_release );
return 1;
}
/*****************************************************************************
* variables.c: Generic lua<->vlc variables inteface
*****************************************************************************
* Copyright (C) 2007 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan tod org>
*
* 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <vlc/vlc.h>
#include <lua.h> /* Low level lua C API */
#include <lauxlib.h> /* Higher level C API */
#include <lualib.h> /* Lua libs */
#include "vlc.h"
/*****************************************************************************
* Variables handling
*****************************************************************************/
int vlclua_pushvalue( lua_State *L, int i_type, vlc_value_t val )
{
switch( i_type &= 0xf0 )
{
case VLC_VAR_VOID:
vlclua_error( L );
break;
case VLC_VAR_BOOL:
lua_pushboolean( L, val.b_bool );
break;
case VLC_VAR_INTEGER:
lua_pushinteger( L, val.i_int );
break;
case VLC_VAR_STRING:
lua_pushstring( L, val.psz_string );
break;
case VLC_VAR_FLOAT:
lua_pushnumber( L, val.f_float );
break;
case VLC_VAR_TIME:
/* FIXME? (we're losing some precision, but does it really matter?) */
lua_pushnumber( L, ((double)val.i_time)/1000000. );
break;
case VLC_VAR_ADDRESS:
vlclua_error( L );
break;
case VLC_VAR_MUTEX:
vlclua_error( L );
break;
case VLC_VAR_LIST:
{
int i_count = val.p_list->i_count;
int i;
lua_createtable( L, i_count, 0 );
for( i = 0; i < i_count; i++ )
{
lua_pushinteger( L, i+1 );
if( !vlclua_pushvalue( L, val.p_list->pi_types[i],
val.p_list->p_values[i] ) )
lua_pushnil( L );
lua_settable( L, -3 );
}
}
break;
default:
vlclua_error( L );
}
return 1;
}
static int vlclua_tovalue( lua_State *L, int i_type, vlc_value_t *val )
{
switch( i_type & 0xf0 )
{
case VLC_VAR_VOID:
break;
case VLC_VAR_BOOL:
val->b_bool = luaL_checkboolean( L, -1 );
break;
case VLC_VAR_INTEGER:
val->i_int = luaL_checkint( L, -1 );
break;
case VLC_VAR_STRING:
val->psz_string = (char*)luaL_checkstring( L, -1 ); /* XXX: Beware, this only stays valid as long as (L,-1) stays in the stack */
break;
case VLC_VAR_FLOAT:
val->f_float = luaL_checknumber( L, -1 );
break;
case VLC_VAR_TIME:
{
double f = luaL_checknumber( L, -1 );
val->i_time = (vlc_int64_t)(f*1000000.);
}
break;
case VLC_VAR_ADDRESS:
vlclua_error( L );
break;
case VLC_VAR_MUTEX:
vlclua_error( L );
break;
case VLC_VAR_LIST:
vlclua_error( L );
break;
default:
vlclua_error( L );
}
return 1;
}
int vlclua_var_get( lua_State *L )
{
int i_type;
vlc_value_t val;
vlc_object_t *p_obj = vlclua_checkobject( L, 1, 0 );
const char *psz_var = luaL_checkstring( L, 2 );
i_type = var_Type( p_obj, psz_var );
var_Get( p_obj, psz_var, &val );
lua_pop( L, 2 );
return vlclua_pushvalue( L, i_type, val );
}
int vlclua_var_set( lua_State *L )
{
int i_type;
vlc_value_t val;
vlc_object_t *p_obj = vlclua_checkobject( L, 1, 0 );
const char *psz_var = luaL_checkstring( L, 2 );
int i_ret;
i_type = var_Type( p_obj, psz_var );
vlclua_tovalue( L, i_type, &val );
i_ret = var_Set( p_obj, psz_var, val );
lua_pop( L, 3 );
return vlclua_push_ret( L, i_ret );
}
int vlclua_var_get_list( lua_State *L )
{
vlc_value_t val;
vlc_value_t text;
vlc_object_t *p_obj = vlclua_checkobject( L, 1, 0 );
const char *psz_var = luaL_checkstring( L, 2 );
int i_ret = var_Change( p_obj, psz_var, VLC_VAR_GETLIST, &val, &text );
if( i_ret < 0 ) return vlclua_push_ret( L, i_ret );
vlclua_pushvalue( L, VLC_VAR_LIST, val );
vlclua_pushvalue( L, VLC_VAR_LIST, text );
var_Change( p_obj, psz_var, VLC_VAR_FREELIST, &val, &text );
return 2;
}
int vlclua_module_command( lua_State *L )
{
vlc_object_t * p_this = vlclua_get_this( L );
const char *psz_name;
const char *psz_cmd;
const char *psz_arg;
char *psz_msg;
psz_name = luaL_checkstring( L, 1 );
psz_cmd = luaL_checkstring( L, 2 );
psz_arg = luaL_checkstring( L, 3 );
lua_pop( L, 3 );
var_Command( p_this, psz_name, psz_cmd, psz_arg, &psz_msg );
if( psz_msg )
{
lua_pushstring( L, psz_msg );
free( psz_msg );
}
else
{
lua_pushstring( L, "" );
}
return 1;
}
int vlclua_libvlc_command( lua_State *L )
{
vlc_object_t * p_this = vlclua_get_this( L );
const char *psz_cmd;
vlc_value_t val_arg;
psz_cmd = luaL_checkstring( L, 1 );
val_arg.psz_string = strdup( luaL_optstring( L, 2, "" ) );
lua_pop( L, 2 );
if( !var_Type( p_this->p_libvlc, psz_cmd ) & VLC_VAR_ISCOMMAND )
{
free( val_arg.psz_string );
return luaL_error( L, "libvlc's \"%s\" is not a command",
psz_cmd );
}
return vlclua_push_ret( L,
var_Set( p_this->p_libvlc, psz_cmd, val_arg ) );
}
......@@ -57,6 +57,9 @@ int E_(FindMeta)( vlc_object_t * );
int E_(Import_LuaPlaylist)( vlc_object_t * );
void E_(Close_LuaPlaylist)( vlc_object_t * );
int E_(Open_LuaIntf)( vlc_object_t * );
void E_(Close_LuaIntf)( vlc_object_t * );
/*****************************************************************************
* Lua debug
......@@ -74,21 +77,102 @@ static inline void lua_Dbg( vlc_object_t * p_this, const char * ppz_fmt, ... )
va_end( ap );
}
/*****************************************************************************
* Functions that should be in lua ... but aren't for some obscure reason
*****************************************************************************/
static inline int luaL_checkboolean( lua_State *L, int narg )
{
luaL_checktype( L, narg, LUA_TBOOLEAN ); /* can raise an error */
return lua_toboolean( L, narg );
}
static inline const void *luaL_checklightuserdata( lua_State *L, int narg )
{
luaL_checktype( L, narg, LUA_TLIGHTUSERDATA ); /* can raise an error */
return lua_topointer( L, narg );
}
static inline const void *luaL_checkuserdata( lua_State *L, int narg, size_t size )
{
luaL_checktype( L, narg, LUA_TUSERDATA ); /* can raise an error */
if( size && size != lua_objlen( L, narg ) ) /* this isn't worth much ... but it might still prevent a few errors */
luaL_error( L, "user data size doesn't match" );
return lua_topointer( L, narg );
}
/*****************************************************************************
* Lua vlc_object_t wrapper
*****************************************************************************/
int __vlclua_push_vlc_object( lua_State *L, vlc_object_t *p_obj,
lua_CFunction pf_gc );
#define vlclua_push_vlc_object( a, b, c ) \
__vlclua_push_vlc_object( a, VLC_OBJECT( b ), c )
vlc_object_t *vlclua_checkobject( lua_State *L, int narg, int i_type );
int vlclua_gc_release( lua_State *L );
int vlclua_object_find( lua_State *L );
int vlclua_object_find_name( lua_State *L );
int vlclua_add_callback( lua_State * );
int vlclua_del_callback( lua_State * );
int vlclua_url_parse( lua_State * );
int vlclua_net_listen_tcp( lua_State * );
int vlclua_net_listen_close( lua_State * );
int vlclua_net_accept( lua_State * );
int vlclua_net_close( lua_State * );
int vlclua_net_send( lua_State * );
int vlclua_net_recv( lua_State * );
int vlclua_net_select( lua_State * );
int vlclua_fd_set_new( lua_State * );
int vlclua_fd_clr( lua_State * );
int vlclua_fd_isset( lua_State * );
int vlclua_fd_set( lua_State * );
int vlclua_fd_zero( lua_State * );
int vlclua_fd_read( lua_State * );
int vlclua_fd_write( lua_State * );
int vlclua_vlm_new( lua_State * );
int vlclua_vlm_delete( lua_State * );
int vlclua_vlm_execute_command( lua_State * );
/*****************************************************************************
* Lua function bridge
*****************************************************************************/
vlc_object_t * vlclua_get_this( lua_State *p_state );
int vlclua_stream_new( lua_State *p_state );
int vlclua_stream_read( lua_State *p_state );
int vlclua_stream_readline( lua_State *p_state );
int vlclua_stream_delete( lua_State *p_state );
int vlclua_decode_uri( lua_State *p_state );
int vlclua_resolve_xml_special_chars( lua_State *p_state );
int vlclua_msg_dbg( lua_State *p_state );
int vlclua_msg_warn( lua_State *p_state );
int vlclua_msg_err( lua_State *p_state );
int vlclua_msg_info( lua_State *p_state );
vlc_object_t * vlclua_get_this( lua_State * );
#define vlclua_error( L ) luaL_error( L, "VLC lua error in file %s line %d (function %s)", __FILE__, __LINE__, __func__ )
int vlclua_push_ret( lua_State *, int i_error );
int vlclua_version( lua_State * );
int vlclua_quit( lua_State * );
int vlclua_pushvalue( lua_State *L, int i_type, vlc_value_t val ); /* internal use only */
int vlclua_var_get( lua_State * );
int vlclua_var_get_list( lua_State * );
int vlclua_var_set( lua_State * );
int vlclua_module_command( lua_State * );
int vlclua_libvlc_command( lua_State * );
int vlclua_config_get( lua_State * );
int vlclua_config_set( lua_State * );
int vlclua_volume_set( lua_State * );
int vlclua_volume_get( lua_State * );
int vlclua_volume_up( lua_State * );
int vlclua_volume_down( lua_State * );
int vlclua_stream_new( lua_State * );
int vlclua_stream_read( lua_State * );
int vlclua_stream_readline( lua_State * );
int vlclua_stream_delete( lua_State * );
int vlclua_decode_uri( lua_State * );
int vlclua_resolve_xml_special_chars( lua_State * );
int vlclua_msg_dbg( lua_State * );
int vlclua_msg_warn( lua_State * );
int vlclua_msg_err( lua_State * );
int vlclua_msg_info( lua_State * );
/*****************************************************************************
* Will execute func on all scripts in luadirname, and stop if func returns
......@@ -96,19 +180,23 @@ int vlclua_msg_info( lua_State *p_state );
*****************************************************************************/
int vlclua_scripts_batch_execute( vlc_object_t *p_this, const char * luadirname,
int (*func)(vlc_object_t *, const char *, lua_State *, void *),
lua_State * p_state, void * user_data);
lua_State * L, void * user_data );
int vlclua_dir_list( vlc_object_t *p_this, const char *luadirname, char **ppsz_dir_list );
/*****************************************************************************
* Meta data setters utility.
* Playlist and meta data internal utilities.
*****************************************************************************/
void vlclua_read_meta_data( vlc_object_t *p_this,
lua_State *p_state, int o, int t, input_item_t *p_input );
void __vlclua_read_options( vlc_object_t *, lua_State *, int *, char *** );
#define vlclua_read_options(a,b,c,d) __vlclua_read_options(VLC_OBJECT(a),b,c,d)
void __vlclua_read_meta_data( vlc_object_t *, lua_State *, input_item_t * );
#define vlclua_read_meta_data(a,b,c) __vlclua_read_meta_data(VLC_OBJECT(a),b,c)
void __vlclua_read_custom_meta_data( vlc_object_t *, lua_State *,
input_item_t *);
#define vlclua_read_custom_meta_data(a,b,c) __vlclua_read_custom_meta_data(VLC_OBJECT(a),b,c)
int __vlclua_playlist_add_internal( vlc_object_t *, lua_State *, playlist_t *,
input_item_t *, vlc_bool_t );
#define vlclua_playlist_add_internal(a,b,c,d,e) __vlclua_playlist_add_internal(VLC_OBJECT(a),b,c,d,e)
void vlclua_read_custom_meta_data( vlc_object_t *p_this,
lua_State *p_state, int o, int t, input_item_t *p_input );
#endif /* VLC_LUA_H */
/*****************************************************************************
* objects.c: Generic lua VLM wrapper
*****************************************************************************
* Copyright (C) 2007 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan tod org>
*
* 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <vlc/vlc.h>
#include <vlc_vlm.h>
#include <lua.h> /* Low level lua C API */
#include <lauxlib.h> /* Higher level C API */
#include <lualib.h> /* Lua libs */
#include "vlc.h"
/*****************************************************************************
*
*****************************************************************************/
int vlclua_vlm_new( lua_State *L )
{
vlc_object_t *p_this = vlclua_get_this( L );
vlm_t *p_vlm = vlm_New( p_this );
if( !p_vlm )
return luaL_error( L, "Cannot start VLM." );
__vlclua_push_vlc_object( L, (vlc_object_t*)p_vlm, NULL );
return 1;
}
int vlclua_vlm_delete( lua_State *L )
{
vlm_t *p_vlm = (vlm_t*)vlclua_checkobject( L, 1, VLC_OBJECT_VLM );
vlm_Delete( p_vlm );
return 0;
}
void push_message( lua_State *L, vlm_message_t *message );
void push_message( lua_State *L, vlm_message_t *message )
{
lua_createtable( L, 0, 2 );
lua_pushstring( L, message->psz_name );
lua_setfield( L, -2, "name" );
if( message->i_child > 0 )
{
int i;
lua_createtable( L, message->i_child, 0 );
for( i = 0; i < message->i_child; i++ )
{
lua_pushinteger( L, i+1 );
push_message( L, message->child[i] );
lua_settable( L, -3 );
}
lua_setfield( L, -2, "children" );
}
else
{
lua_pushstring( L, message->psz_value );
lua_setfield( L, -2, "value" );
}
}
int vlclua_vlm_execute_command( lua_State *L )
{
vlm_t *p_vlm = (vlm_t*)vlclua_checkobject( L, 1, VLC_OBJECT_VLM );
const char *psz_command = luaL_checkstring( L, 2 );
vlm_message_t *message;
vlm_ExecuteCommand( p_vlm, psz_command, &message );
lua_settop( L, 0 );
push_message( L, message );
vlm_MessageDelete( message );
return 1;
}
......@@ -256,4 +256,10 @@ DIST_lua= \
luaplaylist/youtube.lua \
luaplaylist/youtube_homepage.lua \
luaplaylist/metacafe.lua \
luaplaylist/googlevideo.lua
luaplaylist/googlevideo.lua \
luaintf/rc.lua \
luaintf/hotkeys.lua \
luaintf/modules/common.lua \
luaintf/modules/host.lua \
luaintf/telnet.lua \
luaintf/dummy.lua
--[[ This code is public domain (since it really isn't very interesting) ]]--
msg = [[
This is the `dummy' VLC Lua interface module.
Please specify a VLC Lua interface to load with the --lua-intf option.
VLC Lua interface modules include: `rc', `telnet' and `hotkeys'.
For example: vlc -I lua --lua-intf rc]]
--You can also use the alternate syntax: vlc -I "lua{intf=rc}"]]
for line in string.gmatch(msg,"([^\n]+)\n*") do
vlc.msg.err(line)
end
--[==========================================================================[
hotkeys.lua: hotkey handling for VLC
--[==========================================================================[
Copyright (C) 2007 the VideoLAN team
$Id: $
Authors: Antoine Cellerier <dionoea at videolan dot org>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
--]==========================================================================]
--[==========================================================================[
This is meant to replace modules/control/hotkeys.c
(which will require some changes in the VLC core hotkeys stuff)
--]==========================================================================]
require("common")
--common.table_print(vlc,"vlc.\t")
bindings = {
["Ctrl-q"] = "quit",
["Space"] = "play-pause",
[113] --[[q]] = "quit",
[119] --[[w]] = "demo",
[120] --[[x]] = "demo2",
}
function quit()
print("Bye-bye!")
vlc.quit()
end
function demo()
vlc.osd.icon("speaker")
end
function demo2()
if not channel1 then
channel1 = vlc.osd.channel_register()
channel2 = vlc.osd.channel_register()
end
vlc.osd.message("Hey!",channel1)
vlc.osd.slider( 10, "horizontal", channel2 )
end
function action(func,delta)
return { func = func, delta = delta or 0, last = 0, times = 0 }
end
actions = {
["quit"] = action(quit),
["play-pause"] = action(play_pause),
["demo"] = action(demo),
["demo2"] = action(demo2),
}
action = nil
queue = {}
function action_trigger( action )
print("action_trigger:",tostring(action))
local a = actions[action]
if a then
local date = vlc.mdate()
if a.delta and date > a.last + a.delta then
a.times = 0
else
a.times = a.times + 1
end
a.last = date
table.insert(queue,action)
vlc.signal()
else
vlc.msg_err("Key `"..key.."' points to unknown action `"..bindings[key].."'.")
end
end
function key_press( var, old, new, data )
local key = new
print("key_press:",tostring(key))
if bindings[key] then
action_trigger(bindings[key])
else
vlc.msg_err("Key `"..key.."' isn't bound to any action.")
end
end
vlc.var.add_callback( vlc.object.libvlc(), "key-pressed", key_press )
--vlc.var.add_callback( vlc.object.libvlc(), "action-triggered", action_trigger )
while not die do
if #queue ~= 0 then
local action = actions[queue[1]]
local ok, msg = pcall( action.func )
if not ok then
vlc.msg.err("Error while executing action `"..queue[1].."': "..msg)
end
table.remove(queue,1)
else
die = vlc.lock_and_wait()
end
end
-- Clean up
vlc.var.del_callback( vlc.object.libvlc(), "key-pressed", key_press )
--vlc.var.del_callback( vlc.object.libvlc(), "action-triggered", action_trigger )
--[[ This code is public domain (since it really isn't very interesting) ]]--
module("common",package.seeall)
-- Iterate over a table in the keys' alphabetical order
function pairs_sorted(t)
local s = {}
for k,_ in pairs(t) do table.insert(s,k) end
table.sort(s)
local i = 0
return function () i = i + 1; return s[i], t[s[i]] end
end
-- Return a function such as skip(foo)(a,b,c) = foo(b,c)
function skip(foo)
return function(discard,...) return foo(...) end
end
-- Return a function such as setarg(foo,a)(b,c) = foo(a,b,c)
function setarg(foo,a)
return function(...) return foo(a,...) end
end
-- Trigger a hotkey
function hotkey(arg)
vlc.var.set( vlc.object.libvlc(), "key-pressed", vlc.config.get( arg ) )
end
-- Take a video snapshot
function snapshot()
local vout = vlc.object.find(nil,"vout","anywhere")
if not vout then return end
vlc.var.set(vout,"video-snapshot",nil)
end
-- Naive (non recursive) table copy
function table_copy(t)
c = {}
for i,v in pairs(t) do c[i]=v end
return c
end
-- strip leading and trailing spaces
function strip(str)
return string.gsub(str, "^%s*(.-)%s*$", "%1")
end
-- print a table (recursively)
function table_print(t,prefix)
local prefix = prefix or ""
for a,b in pairs_sorted(t) do
print(prefix..tostring(a),b)
if type(b)==type({}) then
table_print(b,prefix.."\t")
end
end
end
-- print the list of callbacks registered in lua
-- usefull for debug purposes
function print_callbacks()
print "callbacks:"
table_print(vlc.callbacks)
end
-- convert a duration (in seconds) to a string
function durationtostring(duration)
return string.format("%02d:%02d:%02d",
math.floor(duration/3600),
math.floor(duration/60)%60,
math.floor(duration%60))
end
This diff is collapsed.
This diff is collapsed.
--[==========================================================================[
telnet.lua: VLM interface plugin
--[==========================================================================[
Copyright (C) 2007 the VideoLAN team
$Id: $
Authors: Antoine Cellerier <dionoea at videolan dot org>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
--]==========================================================================]
--[==========================================================================[
Copy (features wise) of the original VLC modules/control/telnet.c module.
Differences are:
* it's in Lua
* 'lock' command to lock the telnet promt
* possibility to listen on different hosts including stdin
for example:
listen on stdin: vlc -I lua --lua-intf telnet --lua-config "telnet={host='*console'}"
listen on stdin + 2 ports on localhost: vlc -I lua --lua-intf telnet --lua-config "telnet={hosts={'localhost:4212','localhost:5678','*console'}}"
--]==========================================================================]
require "host"
--[[ Some telnet command special characters ]]
WILL = "\251" -- Indicates the desire to begin performing, or confirmation that you are now performing, the indicated option.
WONT = "\252" -- Indicates the refusal to perform, or continue performing, the indicated option.
DO = "\253" -- Indicates the request that the other party perform, or confirmation that you are expecting the other party to perform, the indicated option.
DONT = "\254" -- Indicates the demand that the other party stop performing, or confirmation that you are no longer expecting the other party to perform, the indicated option.
IAC = "\255" -- Interpret as command
ECHO = "\001"
--[[ Client status change callbacks ]]
function on_password( client )
if client.type == host.client_type.net then
client:send( "Password: " ..IAC..WILL..ECHO )
else
-- no authentification needed on stdin
client:switch_status( host.status.read )
end
end
function on_read( client )
client:send( "> " )
end
function on_write( client )
end
--[[ Misc functions ]]
function telnet_commands( client )
-- remove telnet command replies from the client's data
client.buffer = string.gsub( client.buffer, IAC.."["..DO..DONT..WILL..WONT.."].", "" )
end
function vlm_message_to_string(client,message,prefix)
local prefix = prefix or ""
if message.value then
client:append(prefix .. message.name .. " : " .. message.value)
return
else
client:append(prefix .. message.name)
if message.children then
for i,c in ipairs(message.children) do
vlm_message_to_string(client,c,prefix.." ")
end
end
return
end
end
--[[ Configure the host ]]
h = host.host()
h.status_callbacks[host.status.password] = on_password
h.status_callbacks[host.status.read] = on_read
h.status_callbacks[host.status.write] = on_write
h:listen( config.hosts or config.host or "localhost:4212" )
password = config.password or "admin"
--[[ Launch vlm ]]
vlm = vlc.vlm.new()
--[[ Commands ]]
function shutdown(client)
h:broadcast("Shutting down.\r\n")
vlc.msg.err("shutdown requested")
vlc.quit()
return true
end
function logout(client)
client:del()
return true
end
function quit(client)
if client.type == host.client_type.net then
return logout(client)
else
return shutdown(client)
end
end
function lock(client)
client:send("\r\n")
client:switch_status( host.status.password )
client.buffer = ""
return false
end
function help(client)
client:append(" Telnet Specific Commands:")
for c,t in pairs(commands) do
client:append(" "..c.." : "..t.help)
end
return true
end
commands = {
["shutdown"] = { func = shutdown, help = "shutdown VLC" },
["quit"] = { func = quit, help = "logout from telnet/shutdown VLC from local shell" },
["logout"] = { func = logout, help = "logout" },
["lock"] = { func = lock, help = "lock the telnet prompt" },
["help"] = { func = help, help = "show this help", dovlm = true },
}
function client_command( client )
local cmd = client.buffer
client.buffer = ""
if not commands[cmd] or not commands[cmd].func or commands[cmd].dovlm then
-- if it's not an interface specific command, it has to be a VLM command
message = vlc.vlm.execute_command( vlm, cmd )
vlm_message_to_string( client, message )
if not commands[cmd] or not commands[cmd].func and not commands[cmd].dovlm then
return true
end
end
ok, msg = pcall( commands[cmd].func, client )
if not ok then
client:append( "Error in `"..cmd.."' "..msg )
return true
end
return msg
end
--[[ The main loop ]]
while not vlc.should_die() do
h:accept()
local w, r = h:select( 0.1 )
-- Handle writes
for _, client in pairs(w) do
local len = client:send()
client.buffer = string.sub(client.buffer,len+1)
if client.buffer == "" then client:switch_status( host.status.read ) end
end
-- Handle reads
for _, client in pairs(r) do
local str = client:recv(1000)
local done = false
if string.match(str,"\n$") then
client.buffer = string.gsub(client.buffer..str,"\r?\n$","")
done = true
elseif client.buffer == ""
and ((client.type == host.client_type.stdio and str == "")
or (client.type == host.client_type.net and str == "\004")) then
-- Caught a ^D
client.buffer = "quit"
done = true
else
client.buffer = client.buffer .. str
end
if client.type == host.client_type.net then
telnet_commands( client )
end
if done then
if client.status == host.status.password then
if client.buffer == password then
client:send( IAC..WONT..ECHO.."\r\nWelcome, Master\r\n" )
client.buffer = ""
client:switch_status( host.status.write )
else
client:send( "\r\nWrong password\r\nPassword: " )
client.buffer = ""
end
elseif client_command( client ) then
client:switch_status( host.status.write )
end
end
end
end
--[[ Clean up ]]
vlc.vlm.delete( vlm )
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment