1 /*****************************************************************************
2 * intf.c: Generic lua interface functions
3 *****************************************************************************
4 * Copyright (C) 2007-2008 the VideoLAN team
6 * Authors: Antoine Cellerier <dionoea at videolan tod org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
30 #include <sys/types.h>
34 #include <vlc_common.h>
35 #include <vlc_interface.h>
41 /*****************************************************************************
43 *****************************************************************************/
44 static void *Run( void * );
46 static const char * const ppsz_intf_options
[] = { "intf", "config", NULL
};
48 /*****************************************************************************
50 *****************************************************************************/
56 vlclua_dtable_t dtable
;
58 /*****************************************************************************
60 *****************************************************************************/
62 static char *MakeConfig( intf_thread_t
*p_intf
, const char *name
)
64 char *psz_config
= NULL
;
66 if( !strcmp( name
, "http" ) )
68 char *psz_http_src
= var_InheritString( p_intf
, "http-src" );
69 bool b_http_index
= var_InheritBool( p_intf
, "http-index" );
72 char *psz_esc
= config_StringEscape( psz_http_src
);
74 if( asprintf( &psz_config
, "http={dir='%s',no_index=%s}", psz_esc
,
75 b_http_index
? "true" : "false" ) == -1 )
82 if( asprintf( &psz_config
, "http={no_index=%s}",
83 b_http_index
? "true" : "false" ) == -1 )
87 else if( !strcmp( name
, "telnet" ) )
89 char *psz_host
= var_InheritString( p_intf
, "telnet-host" );
90 if( !strcmp( psz_host
, "*console" ) )
95 vlc_UrlParse( &url
, psz_host
);
96 unsigned i_port
= var_InheritInteger( p_intf
, "telnet-port" );
97 if ( url
.i_port
!= 0 )
99 if ( i_port
== TELNETPORT_DEFAULT
)
101 else if ( url
.i_port
!= i_port
)
102 msg_Warn( p_intf
, "ignoring port %d (using %d)",
103 url
.i_port
, i_port
);
106 char *psz_esc_host
= config_StringEscape( url
.psz_host
);
108 vlc_UrlClean( &url
);
110 if( asprintf( &psz_host
, "telnet://%s:%d",
111 psz_esc_host
? psz_esc_host
: "", i_port
) == -1 )
113 free( psz_esc_host
);
116 char *psz_passwd
= var_InheritString( p_intf
, "telnet-password" );
118 char *psz_esc_passwd
= config_StringEscape( psz_passwd
);
120 if( asprintf( &psz_config
, "telnet={host='%s',password='%s'}",
121 psz_host
, psz_esc_passwd
) == -1 )
124 free( psz_esc_passwd
);
132 static char *StripPasswords( const char *psz_config
)
135 const char *p
= psz_config
;
136 while ((p
= strstr(p
, "password=")) != NULL
)
142 return strdup(psz_config
);
144 char *psz_log
= malloc(strlen(psz_config
) + n
* strlen("******") + 1);
149 for (p
= psz_config
; ; )
151 const char *pwd
= strstr(p
, "password=");
154 /* Copy the last, ending bit */
158 pwd
+= strlen("password=");
160 char delim
[3] = ",}";
161 if (*pwd
== '\'' || *pwd
== '"')
167 strncat(psz_log
, p
, pwd
- p
);
168 strcat(psz_log
, "******");
170 /* Advance to the delimiter at the end of the password */
174 p
= strpbrk(p
+ 1, delim
);
176 /* Oops, unbalanced quotes or brackets */
179 while (*(p
- 1) == '\\');
184 static const luaL_Reg p_reg
[] = { { NULL
, NULL
} };
186 static int Start_LuaIntf( vlc_object_t
*p_this
, const char *name
)
188 if( lua_Disabled( p_this
) )
191 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
192 struct vlc_logger
*logger
= p_intf
->obj
.logger
;
194 char *namebuf
= NULL
;
196 config_ChainParse( p_intf
, "lua-", ppsz_intf_options
, p_intf
->p_cfg
);
200 namebuf
= var_InheritString( p_this
, "lua-intf" );
201 if( unlikely(namebuf
== NULL
) )
206 intf_sys_t
*p_sys
= malloc( sizeof(*p_sys
) );
207 if( unlikely(p_sys
== NULL
) )
212 p_intf
->p_sys
= p_sys
;
214 p_intf
->obj
.logger
= vlc_LogHeaderCreate( logger
, name
);
215 if( p_intf
->obj
.logger
== NULL
)
217 p_intf
->obj
.logger
= logger
;
223 p_sys
->psz_filename
= vlclua_find_file( "intf", name
);
224 if( !p_sys
->psz_filename
)
226 msg_Err( p_intf
, "Couldn't find lua interface script \"%s\".",
230 msg_Dbg( p_intf
, "Found lua interface script: %s", p_sys
->psz_filename
);
235 msg_Err( p_intf
, "Could not create new Lua State" );
239 vlclua_set_this( L
, p_intf
);
240 vlc_playlist_t
*playlist
= vlc_intf_GetMainPlaylist(p_intf
);
241 vlclua_set_playlist_internal(L
, playlist
);
245 /* register our functions */
246 luaL_register_namespace( L
, "vlc", p_reg
);
248 /* register submodules */
254 if( vlclua_fd_init( L
, &p_sys
->dtable
) )
261 luaopen_playlist( L
);
263 luaopen_strings( L
);
264 luaopen_variables( L
);
268 luaopen_gettext( L
);
270 luaopen_equalizer( L
);
275 #if defined(_WIN32) && !VLC_WINSTORE_APP
282 /* Setup the module search path */
283 if( vlclua_add_modules_path( L
, p_sys
->psz_filename
) )
285 msg_Warn( p_intf
, "Error while setting the module search path for %s",
286 p_sys
->psz_filename
);
292 * Get the lua-config string.
293 * If the string is empty, try with the old http-* or telnet-* options
294 * and build the right configuration line
296 bool b_config_set
= false;
297 char *psz_config
= var_InheritString( p_intf
, "lua-config" );
299 psz_config
= MakeConfig( p_intf
, name
);
304 if( asprintf( &psz_buffer
, "config={%s}", psz_config
) != -1 )
306 char *psz_log
= StripPasswords( psz_buffer
);
307 if( psz_log
!= NULL
)
309 msg_Dbg( p_intf
, "Setting config variable: %s", psz_log
);
313 if( luaL_dostring( L
, psz_buffer
) == 1 )
314 msg_Err( p_intf
, "Error while parsing \"lua-config\"." );
316 lua_getglobal( L
, "config" );
317 if( lua_istable( L
, -1 ) )
319 if( !strcmp( name
, "cli" ) )
321 lua_getfield( L
, -1, "rc" );
322 if( lua_istable( L
, -1 ) )
324 /* msg_Warn( p_intf, "The `rc' lua interface script "
325 "was renamed `cli', please update "
326 "your configuration!" ); */
327 lua_setfield( L
, -2, "cli" );
332 lua_getfield( L
, -1, name
);
333 if( lua_istable( L
, -1 ) )
335 lua_setglobal( L
, "config" );
346 lua_setglobal( L
, "config" );
349 /* Wrapper for legacy telnet config */
350 if ( !strcmp( name
, "telnet" ) )
352 /* msg_Warn( p_intf, "The `telnet' lua interface script was replaced "
353 "by `cli', please update your configuration!" ); */
355 char *wrapped_file
= vlclua_find_file( "intf", "cli" );
358 msg_Err( p_intf
, "Couldn't find lua interface script \"cli\", "
359 "needed by telnet wrapper" );
360 lua_close( p_sys
->L
);
363 lua_pushstring( L
, wrapped_file
);
364 lua_setglobal( L
, "wrapped_file" );
365 free( wrapped_file
);
370 if( vlc_clone( &p_sys
->thread
, Run
, p_intf
, VLC_THREAD_PRIORITY_LOW
) )
372 vlclua_fd_cleanup( &p_sys
->dtable
);
373 lua_close( p_sys
->L
);
379 free( p_sys
->psz_filename
);
381 vlc_LogDestroy( p_intf
->obj
.logger
);
382 p_intf
->obj
.logger
= logger
;
387 void Close_LuaIntf( vlc_object_t
*p_this
)
389 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
390 intf_sys_t
*p_sys
= p_intf
->p_sys
;
392 vlclua_fd_interrupt( &p_sys
->dtable
);
393 vlc_join( p_sys
->thread
, NULL
);
395 lua_close( p_sys
->L
);
396 vlclua_fd_cleanup( &p_sys
->dtable
);
397 free( p_sys
->psz_filename
);
399 vlc_LogDestroy( p_intf
->obj
.logger
);
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" );