]> git.sesse.net Git - vlc/blob - modules/lua/intf.c
transform: special cases for packed YUV
[vlc] / modules / lua / intf.c
1 /*****************************************************************************
2  * intf.c: Generic lua interface functions
3  *****************************************************************************
4  * Copyright (C) 2007-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea at videolan tod org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33
34 #include <vlc_common.h>
35 #include <vlc_interface.h>
36
37 #include "vlc.h"
38 #include "libs.h"
39
40 /*****************************************************************************
41  * Prototypes
42  *****************************************************************************/
43 static void *Run( void * );
44
45 static const char * const ppsz_intf_options[] = { "intf", "config", NULL };
46
47 /*****************************************************************************
48  *
49  *****************************************************************************/
50 static inline void luaL_register_submodule( lua_State *L, const char *psz_name,
51                                             const luaL_Reg *l )
52 {
53     lua_newtable( L );
54     luaL_register( L, NULL, l );
55     lua_setfield( L, -2, psz_name );
56 }
57
58 static char *MakeConfig( intf_thread_t *p_intf, const char *name )
59 {
60     char *psz_config = NULL;
61
62     if( !strcmp( name, "http" ) )
63     {
64         char *psz_http_src = var_CreateGetNonEmptyString( p_intf, "http-src" );
65         bool b_http_index = var_CreateGetBool( p_intf, "http-index" );
66         if( psz_http_src )
67         {
68             char *psz_esc = config_StringEscape( psz_http_src );
69             asprintf( &psz_config, "http={dir='%s',no_index=%s}", psz_esc, b_http_index ? "true" : "false" );
70             free( psz_esc );
71             free( psz_http_src );
72         }
73         else
74             asprintf( &psz_config, "http={no_index=%s}", b_http_index ? "true" : "false" );
75     }
76     else if( !strcmp( name, "telnet" ) )
77     {
78         char *psz_telnet_host = var_CreateGetString( p_intf, "telnet-host" );
79         if( !strcmp( psz_telnet_host, "*console" ) )
80             ;
81         else
82         {
83             vlc_url_t url;
84             vlc_UrlParse( &url, psz_telnet_host, 0 );
85             int i_telnet_port = var_CreateGetInteger( p_intf, "telnet-port" );
86             if ( url.i_port != 0 )
87             {
88                 if ( i_telnet_port == TELNETPORT_DEFAULT )
89                     i_telnet_port = url.i_port;
90                 else if ( url.i_port != i_telnet_port )
91                     msg_Warn( p_intf, "ignoring port %d (using %d)", url.i_port, i_telnet_port );
92             }
93
94             char *psz_esc_host = config_StringEscape( url.psz_host );
95             free( psz_telnet_host );
96             vlc_UrlClean( &url );
97
98             asprintf( &psz_telnet_host, "telnet://%s:%d", psz_esc_host ? psz_esc_host : "", i_telnet_port );
99             free( psz_esc_host );
100         }
101
102         char *psz_telnet_passwd = var_CreateGetString( p_intf, "telnet-password" );
103
104         char *psz_esc_passwd = config_StringEscape( psz_telnet_passwd );
105
106         asprintf( &psz_config, "telnet={host='%s',password='%s'}", psz_telnet_host, psz_esc_passwd );
107
108         free( psz_esc_passwd );
109         free( psz_telnet_passwd );
110         free( psz_telnet_host );
111     }
112     else if( !strcmp( name, "cli" ) )
113     {
114         char *psz_rc_host = var_CreateGetNonEmptyString( p_intf, "rc-host" );
115         if( !psz_rc_host )
116             psz_rc_host = var_CreateGetNonEmptyString( p_intf, "cli-host" );
117         if( psz_rc_host )
118         {
119             char *psz_esc_host = config_StringEscape( psz_rc_host );
120             asprintf( &psz_config, "cli={host='%s'}", psz_esc_host );
121
122             free( psz_esc_host );
123             free( psz_rc_host );
124         }
125     }
126
127     return psz_config;
128 }
129
130 static char *StripPasswords( const char *psz_config )
131 {
132     unsigned n = 0;
133     const char *p = psz_config;
134     while ((p = strstr(p, "password=")) != NULL)
135     {
136         n++;
137         p++;
138     }
139     if (n == 0)
140         return strdup(psz_config);
141  
142     char *psz_log = malloc(strlen(psz_config) + n * strlen("******") + 1);
143     if (psz_log == NULL)
144         return NULL;
145     psz_log[0] = '\0';
146
147     for (p = psz_config; ; )
148     {
149         const char *pwd = strstr(p, "password=");
150         if (pwd == NULL)
151         {
152             /* Copy the last, ending bit */
153             strcat(psz_log, p);
154             break;
155         }
156         pwd += strlen("password=");
157
158         char delim[3] = ",}";
159         if (*pwd == '\'' || *pwd == '"')
160         {
161             delim[0] = *pwd++;
162             delim[1] = '\0';
163         }
164
165         strncat(psz_log, p, pwd - p);
166         strcat(psz_log, "******");
167
168         /* Advance to the delimiter at the end of the password */
169         p = pwd - 1;
170         do
171         {
172             p = strpbrk(p + 1, delim);
173             if (p == NULL)
174                 /* Oops, unbalanced quotes or brackets */
175                 return psz_log;
176         }
177         while (*(p - 1) == '\\');
178     }
179     return psz_log;
180 }
181
182 static const luaL_Reg p_reg[] = { { NULL, NULL } };
183
184 static int Start_LuaIntf( vlc_object_t *p_this, const char *name )
185 {
186     intf_thread_t *p_intf = (intf_thread_t*)p_this;
187     intf_sys_t *p_sys;
188     lua_State *L;
189
190     config_ChainParse( p_intf, "lua-", ppsz_intf_options, p_intf->p_cfg );
191
192     if( name == NULL )
193     {
194         char *n = var_InheritString( p_this, "lua-intf" );
195         if( unlikely(n == NULL) )
196             return VLC_EGENERIC;
197         name = p_intf->psz_header = n;
198     }
199     else
200         /* Cleaned up by vlc_object_release() */
201         p_intf->psz_header = strdup( name );
202
203     p_intf->p_sys = (intf_sys_t*)malloc( sizeof(intf_sys_t) );
204     if( !p_intf->p_sys )
205     {
206         free( p_intf->psz_header );
207         p_intf->psz_header = NULL;
208         return VLC_ENOMEM;
209     }
210     p_sys = p_intf->p_sys;
211     p_sys->psz_filename = vlclua_find_file( p_this, "intf", name );
212     if( !p_sys->psz_filename )
213     {
214         msg_Err( p_intf, "Couldn't find lua interface script \"%s\".",
215                  name );
216         goto error;
217     }
218     msg_Dbg( p_intf, "Found lua interface script: %s", p_sys->psz_filename );
219
220     L = luaL_newstate();
221     if( !L )
222     {
223         msg_Err( p_intf, "Could not create new Lua State" );
224         goto error;
225     }
226
227     vlclua_set_this( L, p_intf );
228     vlclua_set_intf( L, p_sys );
229
230     luaL_openlibs( L );
231
232     /* register our functions */
233     luaL_register( L, "vlc", p_reg );
234
235     /* register submodules */
236     luaopen_acl( L );
237     luaopen_config( L );
238     luaopen_volume( L );
239     luaopen_httpd( L );
240     luaopen_input( L );
241     luaopen_msg( L );
242     luaopen_misc( L );
243     luaopen_net( L );
244     luaopen_object( L );
245     luaopen_osd( L );
246     luaopen_playlist( L );
247     luaopen_sd( L );
248     luaopen_stream( L );
249     luaopen_strings( L );
250     luaopen_variables( L );
251     luaopen_video( L );
252     luaopen_vlm( L );
253     luaopen_volume( L );
254     luaopen_gettext( L );
255     luaopen_xml( L );
256     luaopen_equalizer( L );
257 #ifdef WIN32
258     luaopen_win( L );
259 #endif
260
261     /* clean up */
262     lua_pop( L, 1 );
263
264     /* Setup the module search path */
265     if( vlclua_add_modules_path( p_intf, L, p_sys->psz_filename ) )
266     {
267         msg_Warn( p_intf, "Error while setting the module search path for %s",
268                   p_sys->psz_filename );
269         lua_close( L );
270         goto error;
271     }
272
273     /*
274      * Get the lua-config string.
275      * If the string is empty, try with the old http-* or telnet-* options
276      * and build the right configuration line
277      */
278     bool b_config_set = false;
279     char *psz_config = var_InheritString( p_intf, "lua-config" );
280     if( !psz_config )
281         psz_config = MakeConfig( p_intf, name );
282
283     if( psz_config )
284     {
285         char *psz_buffer;
286         if( asprintf( &psz_buffer, "config={%s}", psz_config ) != -1 )
287         {
288             char *psz_log = StripPasswords( psz_buffer );
289             if( psz_log != NULL )
290             {
291                 msg_Dbg( p_intf, "Setting config variable: %s", psz_log );
292                 free( psz_log );
293             }
294
295             if( luaL_dostring( L, psz_buffer ) == 1 )
296                 msg_Err( p_intf, "Error while parsing \"lua-config\"." );
297             free( psz_buffer );
298             lua_getglobal( L, "config" );
299             if( lua_istable( L, -1 ) )
300             {
301                 if( !strcmp( name, "cli" ) )
302                 {
303                     lua_getfield( L, -1, "rc" );
304                     if( lua_istable( L, -1 ) )
305                     {
306                         /* msg_Warn( p_intf, "The `rc' lua interface script "
307                                           "was renamed `cli', please update "
308                                           "your configuration!" ); */
309                         lua_setfield( L, -2, "cli" );
310                     }
311                     else
312                         lua_pop( L, 1 );
313                 }
314                 lua_getfield( L, -1, name );
315                 if( lua_istable( L, -1 ) )
316                 {
317                     lua_setglobal( L, "config" );
318                     b_config_set = true;
319                 }
320             }
321         }
322         free( psz_config );
323     }
324
325     if( !b_config_set )
326     {
327         lua_newtable( L );
328         lua_setglobal( L, "config" );
329     }
330
331     /* Wrapper for legacy telnet config */
332     if ( !strcmp( name, "telnet" ) )
333     {
334         /* msg_Warn( p_intf, "The `telnet' lua interface script was replaced "
335                           "by `cli', please update your configuration!" ); */
336
337         char *wrapped_file = vlclua_find_file( p_this, "intf", "cli" );
338         if( !wrapped_file )
339         {
340             msg_Err( p_intf, "Couldn't find lua interface script \"cli\", "
341                              "needed by telnet wrapper" );
342             lua_close( p_sys->L );
343             goto error;
344         }
345         lua_pushstring( L, wrapped_file );
346         lua_setglobal( L, "wrapped_file" );
347         free( wrapped_file );
348     }
349
350     p_sys->L = L;
351
352     vlc_mutex_init( &p_sys->lock );
353     vlc_cond_init( &p_sys->wait );
354     p_sys->exiting = false;
355
356     if( vlc_clone( &p_sys->thread, Run, p_intf, VLC_THREAD_PRIORITY_LOW ) )
357     {
358         vlc_cond_destroy( &p_sys->wait );
359         vlc_mutex_destroy( &p_sys->lock );
360         lua_close( p_sys->L );
361         goto error;
362     }
363
364     return VLC_SUCCESS;
365 error:
366     free( p_sys->psz_filename );
367     free( p_sys );
368     free( p_intf->psz_header );
369     p_intf->psz_header = NULL;
370     return VLC_EGENERIC;
371 }
372
373 void Close_LuaIntf( vlc_object_t *p_this )
374 {
375     intf_thread_t *p_intf = (intf_thread_t*)p_this;
376     intf_sys_t *p_sys = p_intf->p_sys;
377
378     vlc_cancel( p_sys->thread );
379
380     vlc_mutex_lock( &p_sys->lock );
381     p_sys->exiting = true;
382     vlc_cond_signal( &p_sys->wait );
383     vlc_mutex_unlock( &p_sys->lock );
384     vlc_join( p_sys->thread, NULL );
385     vlc_cond_destroy( &p_sys->wait );
386     vlc_mutex_destroy( &p_sys->lock );
387
388     lua_close( p_sys->L );
389
390     free( p_sys->psz_filename );
391     free( p_sys );
392 }
393
394 static void *Run( void *data )
395 {
396     intf_thread_t *p_intf = data;
397     intf_sys_t *p_sys = p_intf->p_sys;
398     lua_State *L = p_sys->L;
399
400     if( luaL_dofile( L, p_sys->psz_filename ) )
401     {
402         msg_Err( p_intf, "Error loading script %s: %s", p_sys->psz_filename,
403                  lua_tostring( L, lua_gettop( L ) ) );
404         lua_pop( L, 1 );
405     }
406     return NULL;
407 }
408
409 int Open_LuaIntf( vlc_object_t *p_this )
410 {
411     return Start_LuaIntf( p_this, NULL );
412 }
413
414 int Open_LuaHTTP( vlc_object_t *p_this )
415 {
416     return Start_LuaIntf( p_this, "http" );
417 }
418
419 int Open_LuaCLI( vlc_object_t *p_this )
420 {
421     return Start_LuaIntf( p_this, "cli" );
422 }
423
424 int Open_LuaTelnet( vlc_object_t *p_this )
425 {
426     return Start_LuaIntf( p_this, "telnet" );
427 }