1 /*****************************************************************************
2 * intf.c: Generic lua interface functions
3 *****************************************************************************
4 * Copyright (C) 2007-2008 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea at videolan tod org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <sys/types.h>
35 #include <vlc_common.h>
36 #include <vlc_interface.h>
42 /*****************************************************************************
44 *****************************************************************************/
45 static void *Run( void * );
47 static const char * const ppsz_intf_options
[] = { "intf", "config", NULL
};
49 /*****************************************************************************
51 *****************************************************************************/
57 vlclua_dtable_t dtable
;
59 /*****************************************************************************
61 *****************************************************************************/
63 static char *MakeConfig( intf_thread_t
*p_intf
, const char *name
)
65 char *psz_config
= NULL
;
67 if( !strcmp( name
, "http" ) )
69 char *psz_http_src
= var_InheritString( p_intf
, "http-src" );
70 bool b_http_index
= var_InheritBool( p_intf
, "http-index" );
73 char *psz_esc
= config_StringEscape( psz_http_src
);
75 if( asprintf( &psz_config
, "http={dir='%s',no_index=%s}", psz_esc
,
76 b_http_index
? "true" : "false" ) == -1 )
83 if( asprintf( &psz_config
, "http={no_index=%s}",
84 b_http_index
? "true" : "false" ) == -1 )
88 else if( !strcmp( name
, "telnet" ) )
90 char *psz_host
= var_InheritString( p_intf
, "telnet-host" );
91 if( !strcmp( psz_host
, "*console" ) )
96 vlc_UrlParse( &url
, psz_host
);
97 unsigned i_port
= var_InheritInteger( p_intf
, "telnet-port" );
98 if ( url
.i_port
!= 0 )
100 if ( i_port
== TELNETPORT_DEFAULT
)
102 else if ( url
.i_port
!= i_port
)
103 msg_Warn( p_intf
, "ignoring port %d (using %d)",
104 url
.i_port
, i_port
);
107 char *psz_esc_host
= config_StringEscape( url
.psz_host
);
109 vlc_UrlClean( &url
);
111 if( asprintf( &psz_host
, "telnet://%s:%d",
112 psz_esc_host
? psz_esc_host
: "", i_port
) == -1 )
114 free( psz_esc_host
);
117 char *psz_passwd
= var_InheritString( p_intf
, "telnet-password" );
119 char *psz_esc_passwd
= config_StringEscape( psz_passwd
);
121 if( asprintf( &psz_config
, "telnet={host='%s',password='%s'}",
122 psz_host
, psz_esc_passwd
) == -1 )
125 free( psz_esc_passwd
);
129 else if( !strcmp( name
, "cli" ) )
131 char *psz_rc_host
= var_InheritString( p_intf
, "rc-host" );
133 psz_rc_host
= var_InheritString( p_intf
, "cli-host" );
136 char *psz_esc_host
= config_StringEscape( psz_rc_host
);
138 if( asprintf( &psz_config
, "cli={host='%s'}", psz_esc_host
) == -1 )
140 free( psz_esc_host
);
148 static char *StripPasswords( const char *psz_config
)
151 const char *p
= psz_config
;
152 while ((p
= strstr(p
, "password=")) != NULL
)
158 return strdup(psz_config
);
160 char *psz_log
= malloc(strlen(psz_config
) + n
* strlen("******") + 1);
165 for (p
= psz_config
; ; )
167 const char *pwd
= strstr(p
, "password=");
170 /* Copy the last, ending bit */
174 pwd
+= strlen("password=");
176 char delim
[3] = ",}";
177 if (*pwd
== '\'' || *pwd
== '"')
183 strncat(psz_log
, p
, pwd
- p
);
184 strcat(psz_log
, "******");
186 /* Advance to the delimiter at the end of the password */
190 p
= strpbrk(p
+ 1, delim
);
192 /* Oops, unbalanced quotes or brackets */
195 while (*(p
- 1) == '\\');
200 static const luaL_Reg p_reg
[] = { { NULL
, NULL
} };
202 static int Start_LuaIntf( vlc_object_t
*p_this
, const char *name
)
204 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
207 config_ChainParse( p_intf
, "lua-", ppsz_intf_options
, p_intf
->p_cfg
);
211 char *n
= var_InheritString( p_this
, "lua-intf" );
212 if( unlikely(n
== NULL
) )
214 name
= p_intf
->obj
.header
= n
;
217 /* Cleaned up by vlc_object_release() */
218 p_intf
->obj
.header
= strdup( name
);
220 intf_sys_t
*p_sys
= malloc( sizeof(*p_sys
) );
221 if( unlikely(p_sys
== NULL
) )
223 free( p_intf
->obj
.header
);
224 p_intf
->obj
.header
= NULL
;
227 p_intf
->p_sys
= p_sys
;
229 p_sys
->psz_filename
= vlclua_find_file( "intf", name
);
230 if( !p_sys
->psz_filename
)
232 msg_Err( p_intf
, "Couldn't find lua interface script \"%s\".",
236 msg_Dbg( p_intf
, "Found lua interface script: %s", p_sys
->psz_filename
);
241 msg_Err( p_intf
, "Could not create new Lua State" );
245 vlclua_set_this( L
, p_intf
);
246 vlclua_set_playlist_internal( L
, pl_Get(p_intf
) );
250 /* register our functions */
251 luaL_register_namespace( L
, "vlc", p_reg
);
253 /* register submodules */
259 if( vlclua_fd_init( L
, &p_sys
->dtable
) )
266 luaopen_playlist( L
);
267 luaopen_sd_intf( L
);
269 luaopen_strings( L
);
270 luaopen_variables( L
);
274 luaopen_gettext( L
);
276 luaopen_equalizer( L
);
277 #if defined(_WIN32) && !VLC_WINSTORE_APP
284 /* Setup the module search path */
285 if( vlclua_add_modules_path( L
, p_sys
->psz_filename
) )
287 msg_Warn( p_intf
, "Error while setting the module search path for %s",
288 p_sys
->psz_filename
);
294 * Get the lua-config string.
295 * If the string is empty, try with the old http-* or telnet-* options
296 * and build the right configuration line
298 bool b_config_set
= false;
299 char *psz_config
= var_InheritString( p_intf
, "lua-config" );
301 psz_config
= MakeConfig( p_intf
, name
);
306 if( asprintf( &psz_buffer
, "config={%s}", psz_config
) != -1 )
308 char *psz_log
= StripPasswords( psz_buffer
);
309 if( psz_log
!= NULL
)
311 msg_Dbg( p_intf
, "Setting config variable: %s", psz_log
);
315 if( luaL_dostring( L
, psz_buffer
) == 1 )
316 msg_Err( p_intf
, "Error while parsing \"lua-config\"." );
318 lua_getglobal( L
, "config" );
319 if( lua_istable( L
, -1 ) )
321 if( !strcmp( name
, "cli" ) )
323 lua_getfield( L
, -1, "rc" );
324 if( lua_istable( L
, -1 ) )
326 /* msg_Warn( p_intf, "The `rc' lua interface script "
327 "was renamed `cli', please update "
328 "your configuration!" ); */
329 lua_setfield( L
, -2, "cli" );
334 lua_getfield( L
, -1, name
);
335 if( lua_istable( L
, -1 ) )
337 lua_setglobal( L
, "config" );
348 lua_setglobal( L
, "config" );
351 /* Wrapper for legacy telnet config */
352 if ( !strcmp( name
, "telnet" ) )
354 /* msg_Warn( p_intf, "The `telnet' lua interface script was replaced "
355 "by `cli', please update your configuration!" ); */
357 char *wrapped_file
= vlclua_find_file( "intf", "cli" );
360 msg_Err( p_intf
, "Couldn't find lua interface script \"cli\", "
361 "needed by telnet wrapper" );
362 lua_close( p_sys
->L
);
365 lua_pushstring( L
, wrapped_file
);
366 lua_setglobal( L
, "wrapped_file" );
367 free( wrapped_file
);
372 if( vlc_clone( &p_sys
->thread
, Run
, p_intf
, VLC_THREAD_PRIORITY_LOW
) )
374 vlclua_fd_cleanup( &p_sys
->dtable
);
375 lua_close( p_sys
->L
);
381 free( p_sys
->psz_filename
);
383 free( p_intf
->obj
.header
);
384 p_intf
->obj
.header
= NULL
;
388 void Close_LuaIntf( vlc_object_t
*p_this
)
390 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
391 intf_sys_t
*p_sys
= p_intf
->p_sys
;
393 vlclua_fd_interrupt( &p_sys
->dtable
);
394 vlc_join( p_sys
->thread
, NULL
);
396 lua_close( p_sys
->L
);
397 vlclua_fd_cleanup( &p_sys
->dtable
);
398 free( p_sys
->psz_filename
);
402 static void *Run( void *data
)
404 intf_thread_t
*p_intf
= data
;
405 intf_sys_t
*p_sys
= p_intf
->p_sys
;
406 lua_State
*L
= p_sys
->L
;
408 if( vlclua_dofile( VLC_OBJECT(p_intf
), L
, p_sys
->psz_filename
) )
410 msg_Err( p_intf
, "Error loading script %s: %s", p_sys
->psz_filename
,
411 lua_tostring( L
, lua_gettop( L
) ) );
417 int Open_LuaIntf( vlc_object_t
*p_this
)
419 return Start_LuaIntf( p_this
, NULL
);
422 int Open_LuaHTTP( vlc_object_t
*p_this
)
424 return Start_LuaIntf( p_this
, "http" );
427 int Open_LuaCLI( vlc_object_t
*p_this
)
429 return Start_LuaIntf( p_this
, "cli" );
432 int Open_LuaTelnet( vlc_object_t
*p_this
)
434 char *pw
= var_CreateGetNonEmptyString( p_this
, "telnet-password" );
437 msg_Err( p_this
, "password not configured" );
438 msg_Info( p_this
, "Please specify the password in the preferences." );
442 return Start_LuaIntf( p_this
, "telnet" );