* mosaic alignment (works like --marq-position) and callback
[vlc.git] / modules / control / rc.c
1 /*****************************************************************************
2  * rc.c : remote control stdin/stdout module for vlc
3  *****************************************************************************
4  * Copyright (C) 2004 - 2005 VideoLAN
5  * $Id$
6  *
7  * Author: Peter Surda <shurdeek@panorama.sth.ac.at>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>
29
30 #include <errno.h>                                                 /* ENOMEM */
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <signal.h>
34
35 #include <vlc/vlc.h>
36 #include <vlc/intf.h>
37 #include <vlc/aout.h>
38 #include <vlc/vout.h>
39
40 #ifdef HAVE_UNISTD_H
41 #    include <unistd.h>
42 #endif
43
44 #ifdef HAVE_SYS_TIME_H
45 #    include <sys/time.h>
46 #endif
47 #include <sys/types.h>
48
49 #include "vlc_error.h"
50 #include "network.h"
51
52 #if defined(PF_UNIX) && !defined(PF_LOCAL)
53 #    define PF_LOCAL PF_UNIX
54 #endif
55 #if defined(AF_UNIX) && !defined(AF_LOCAL)
56 #    define AF_LOCAL AF_UNIX
57 #endif
58
59 #ifdef PF_LOCAL
60 #    include <sys/un.h>
61 #endif
62
63 #define MAX_LINE_LENGTH 256
64
65 /*****************************************************************************
66  * Local prototypes
67  *****************************************************************************/
68 static int  Activate     ( vlc_object_t * );
69 static void Deactivate   ( vlc_object_t * );
70 static void Run          ( intf_thread_t * );
71
72 static vlc_bool_t ReadCommand( intf_thread_t *, char *, int * );
73
74 static playlist_item_t *parse_MRL( intf_thread_t *, char * );
75
76 static int  Input        ( vlc_object_t *, char const *,
77                            vlc_value_t, vlc_value_t, void * );
78 static int  Playlist     ( vlc_object_t *, char const *,
79                            vlc_value_t, vlc_value_t, void * );
80 static int  Other        ( vlc_object_t *, char const *,
81                            vlc_value_t, vlc_value_t, void * );
82 static int  Quit         ( vlc_object_t *, char const *,
83                            vlc_value_t, vlc_value_t, void * );
84 static int  Intf         ( vlc_object_t *, char const *,
85                            vlc_value_t, vlc_value_t, void * );
86 static int  Volume       ( vlc_object_t *, char const *,
87                            vlc_value_t, vlc_value_t, void * );
88 static int  VolumeMove   ( vlc_object_t *, char const *,
89                            vlc_value_t, vlc_value_t, void * );
90 static int  AudioConfig  ( vlc_object_t *, char const *,
91                            vlc_value_t, vlc_value_t, void * );
92
93 struct intf_sys_t
94 {
95     int i_socket_listen;
96     int i_socket;
97     char *psz_unix_path;
98
99 #ifdef WIN32
100     HANDLE hConsoleIn;
101     vlc_bool_t b_quiet;
102 #endif
103 };
104
105 #ifdef HAVE_VARIADIC_MACROS
106 #   define msg_rc( psz_format, args... ) \
107       __msg_rc( p_intf, psz_format, ## args )
108 #endif
109
110 void __msg_rc( intf_thread_t *p_intf, const char *psz_fmt, ... )
111 {
112     va_list args;
113     va_start( args, psz_fmt );
114     if( p_intf->p_sys->i_socket == -1 ) vprintf( psz_fmt, args );
115     else
116     { net_vaPrintf( p_intf, p_intf->p_sys->i_socket, NULL, psz_fmt, args );
117       net_Printf( VLC_OBJECT(p_intf), p_intf->p_sys->i_socket, NULL, "\r" ); }
118     va_end( args );
119 }
120
121 /*****************************************************************************
122  * Module descriptor
123  *****************************************************************************/
124 #define POS_TEXT N_("Show stream position")
125 #define POS_LONGTEXT N_("Show the current position in seconds within the " \
126                         "stream from time to time." )
127
128 #define TTY_TEXT N_("Fake TTY")
129 #define TTY_LONGTEXT N_("Force the rc module to use stdin as if it was a TTY.")
130
131 #define UNIX_TEXT N_("UNIX socket command input")
132 #define UNIX_LONGTEXT N_("Accept commands over a Unix socket rather than " \
133                          "stdin." )
134
135 #define HOST_TEXT N_("TCP command input")
136 #define HOST_LONGTEXT N_("Accept commands over a socket rather than stdin. " \
137             "You can set the address and port the interface will bind to." )
138
139 #ifdef WIN32
140 #define QUIET_TEXT N_("Do not open a DOS command box interface")
141 #define QUIET_LONGTEXT N_( \
142     "By default the rc interface plugin will start a DOS command box. " \
143     "Enabling the quiet mode will not bring this command box but can also " \
144     "be pretty annoying when you want to stop VLC and no video window is " \
145     "open." )
146 #endif
147
148 vlc_module_begin();
149     set_shortname( _("RC"));
150     set_category( CAT_INTERFACE );
151     set_subcategory( SUBCAT_INTERFACE_GENERAL );
152     set_description( _("Remote control interface") );
153     add_bool( "rc-show-pos", 0, NULL, POS_TEXT, POS_LONGTEXT, VLC_TRUE );
154 #ifdef HAVE_ISATTY
155     add_bool( "rc-fake-tty", 0, NULL, TTY_TEXT, TTY_LONGTEXT, VLC_TRUE );
156 #endif
157     add_string( "rc-unix", 0, NULL, UNIX_TEXT, UNIX_LONGTEXT, VLC_TRUE );
158     add_string( "rc-host", 0, NULL, HOST_TEXT, HOST_LONGTEXT, VLC_TRUE );
159
160 #ifdef WIN32
161     add_bool( "rc-quiet", 0, NULL, QUIET_TEXT, QUIET_LONGTEXT, VLC_FALSE );
162 #endif
163
164     set_capability( "interface", 20 );
165     set_callbacks( Activate, Deactivate );
166 vlc_module_end();
167
168 /*****************************************************************************
169  * Activate: initialize and create stuff
170  *****************************************************************************/
171 static int Activate( vlc_object_t *p_this )
172 {
173     intf_thread_t *p_intf = (intf_thread_t*)p_this;
174     playlist_t *p_playlist;
175     char *psz_host, *psz_unix_path;
176     int i_socket = -1;
177
178 #if defined(HAVE_ISATTY) && !defined(WIN32)
179     /* Check that stdin is a TTY */
180     if( !config_GetInt( p_intf, "rc-fake-tty" ) && !isatty( 0 ) )
181     {
182         msg_Warn( p_intf, "fd 0 is not a TTY" );
183         return VLC_EGENERIC;
184     }
185 #endif
186
187     psz_unix_path = config_GetPsz( p_intf, "rc-unix" );
188     if( psz_unix_path )
189     {
190 #ifndef PF_LOCAL
191         msg_Warn( p_intf, "your OS doesn't support filesystem sockets" );
192         free( psz_unix_path );
193         return VLC_EGENERIC;
194 #else
195         struct sockaddr_un addr;
196         int i_ret;
197
198         memset( &addr, 0, sizeof(struct sockaddr_un) );
199
200         msg_Dbg( p_intf, "trying UNIX socket" );
201
202         if( (i_socket = socket( PF_LOCAL, SOCK_STREAM, 0 ) ) < 0 )
203         {
204             msg_Warn( p_intf, "can't open socket: %s", strerror(errno) );
205             free( psz_unix_path );
206             return VLC_EGENERIC;
207         }
208
209         addr.sun_family = AF_LOCAL;
210         strncpy( addr.sun_path, psz_unix_path, sizeof( addr.sun_path ) );
211         addr.sun_path[sizeof( addr.sun_path ) - 1] = '\0';
212
213         if( (i_ret = bind( i_socket, (struct sockaddr*)&addr,
214                            sizeof(struct sockaddr_un) ) ) < 0 )
215         {
216             msg_Warn( p_intf, "couldn't bind socket to address: %s",
217                       strerror(errno) );
218             free( psz_unix_path );
219             net_Close( i_socket );
220             return VLC_EGENERIC;
221         }
222
223         if( ( i_ret = listen( i_socket, 1 ) ) < 0 )
224         {
225             msg_Warn( p_intf, "can't listen on socket: %s", strerror(errno));
226             free( psz_unix_path );
227             net_Close( i_socket );
228             return VLC_EGENERIC;
229         }
230 #endif
231     }
232
233     if( ( i_socket == -1) &&
234         ( psz_host = config_GetPsz( p_intf, "rc-host" ) ) != NULL )
235     {
236         vlc_url_t url;
237
238         vlc_UrlParse( &url, psz_host, 0 );
239
240         msg_Dbg( p_intf, "base %s port %d", url.psz_host, url.i_port );
241
242         if( (i_socket = net_ListenTCP(p_this, url.psz_host, url.i_port)) == -1)
243         {
244             msg_Warn( p_intf, "can't listen to %s port %i",
245                       url.psz_host, url.i_port );
246             vlc_UrlClean( &url );
247             free( psz_host );
248             return VLC_EGENERIC;
249         }
250
251         vlc_UrlClean( &url );
252         free( psz_host );
253     }
254
255     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
256     if( !p_intf->p_sys )
257     {
258         msg_Err( p_intf, "no memory" );
259         return VLC_ENOMEM;
260     }
261
262     p_intf->p_sys->i_socket_listen = i_socket;
263     p_intf->p_sys->i_socket = -1;
264     p_intf->p_sys->psz_unix_path = psz_unix_path;
265
266     /* Non-buffered stdout */
267     setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
268
269     p_intf->pf_run = Run;
270
271 #ifdef WIN32
272     p_intf->p_sys->b_quiet = config_GetInt( p_intf, "rc-quiet" );
273     if( !p_intf->p_sys->b_quiet ) { CONSOLE_INTRO_MSG; }
274 #else
275     CONSOLE_INTRO_MSG;
276 #endif
277
278     /* Force "no-view" mode */
279     p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
280                                                  FIND_ANYWHERE );
281     if( p_playlist )
282     {
283         vlc_mutex_lock( &p_playlist->object_lock );
284         p_playlist->status.i_view = -1;
285         vlc_mutex_unlock( &p_playlist->object_lock );
286         vlc_object_release( p_playlist );
287     }
288
289     msg_rc( _("Remote control interface initialized, `h' for help\n") );
290     return VLC_SUCCESS;
291 }
292
293 /*****************************************************************************
294  * Deactivate: uninitialize and cleanup
295  *****************************************************************************/
296 static void Deactivate( vlc_object_t *p_this )
297 {
298     intf_thread_t *p_intf = (intf_thread_t*)p_this;
299
300     if( p_intf->p_sys->i_socket_listen != -1 )
301         net_Close( p_intf->p_sys->i_socket_listen );
302     if( p_intf->p_sys->i_socket != -1 )
303         net_Close( p_intf->p_sys->i_socket );
304     if( p_intf->p_sys->psz_unix_path != NULL )
305     {
306 #ifdef PF_LOCAL
307         unlink( p_intf->p_sys->psz_unix_path );
308 #endif
309         free( p_intf->p_sys->psz_unix_path );
310     }
311     free( p_intf->p_sys );
312 }
313
314 /*****************************************************************************
315  * Run: rc thread
316  *****************************************************************************
317  * This part of the interface is in a separate thread so that we can call
318  * exec() from within it without annoying the rest of the program.
319  *****************************************************************************/
320 static void Run( intf_thread_t *p_intf )
321 {
322     input_thread_t * p_input;
323     playlist_t *     p_playlist;
324
325     char       p_buffer[ MAX_LINE_LENGTH + 1 ];
326     vlc_bool_t b_showpos = config_GetInt( p_intf, "rc-show-pos" );
327     vlc_bool_t b_longhelp = VLC_FALSE;
328
329     int        i_size = 0;
330     int        i_oldpos = 0;
331     int        i_newpos;
332
333     p_buffer[0] = 0;
334     p_input = NULL;
335     p_playlist = NULL;
336  
337     /* Register commands that will be cleaned up upon object destruction */
338     var_Create( p_intf, "quit", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
339     var_AddCallback( p_intf, "quit", Quit, NULL );
340     var_Create( p_intf, "intf", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
341     var_AddCallback( p_intf, "intf", Intf, NULL );
342
343     var_Create( p_intf, "add", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
344     var_AddCallback( p_intf, "add", Playlist, NULL );
345     var_Create( p_intf, "playlist", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
346     var_AddCallback( p_intf, "playlist", Playlist, NULL );
347     var_Create( p_intf, "play", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
348     var_AddCallback( p_intf, "play", Playlist, NULL );
349     var_Create( p_intf, "stop", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
350     var_AddCallback( p_intf, "stop", Playlist, NULL );
351     var_Create( p_intf, "prev", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
352     var_AddCallback( p_intf, "prev", Playlist, NULL );
353     var_Create( p_intf, "next", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
354     var_AddCallback( p_intf, "next", Playlist, NULL );
355     var_Create( p_intf, "goto", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
356     var_AddCallback( p_intf, "goto", Playlist, NULL );
357  
358     /* marquee on the fly items */
359     var_Create( p_intf, "marq-marquee", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
360     var_AddCallback( p_intf, "marq-marquee", Other, NULL );
361     var_Create( p_intf, "marq-x", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
362     var_AddCallback( p_intf, "marq-x", Other, NULL );
363     var_Create( p_intf, "marq-y", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
364     var_AddCallback( p_intf, "marq-y", Other, NULL );
365     var_Create( p_intf, "marq-position", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
366     var_AddCallback( p_intf, "marq-position", Other, NULL );
367     var_Create( p_intf, "marq-color", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
368     var_AddCallback( p_intf, "marq-color", Other, NULL );
369     var_Create( p_intf, "marq-opacity", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
370     var_AddCallback( p_intf, "marq-opacity", Other, NULL );
371     var_Create( p_intf, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
372     var_AddCallback( p_intf, "marq-timeout", Other, NULL );
373     var_Create( p_intf, "marq-size", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
374     var_AddCallback( p_intf, "marq-size", Other, NULL );
375
376     var_Create( p_intf, "mosaic-alpha", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
377     var_AddCallback( p_intf, "mosaic-alpha", Other, NULL );
378     var_Create( p_intf, "mosaic-height", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
379     var_AddCallback( p_intf, "mosaic-height", Other, NULL );
380     var_Create( p_intf, "mosaic-width", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
381     var_AddCallback( p_intf, "mosaic-width", Other, NULL );
382     var_Create( p_intf, "mosaic-xoffset", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
383     var_AddCallback( p_intf, "mosaic-xoffset", Other, NULL );
384     var_Create( p_intf, "mosaic-yoffset", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
385     var_AddCallback( p_intf, "mosaic-yoffset", Other, NULL );
386     var_Create( p_intf, "mosaic-align", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
387     var_AddCallback( p_intf, "mosaic-align", Other, NULL );
388     var_Create( p_intf, "mosaic-vborder", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
389     var_AddCallback( p_intf, "mosaic-vborder", Other, NULL );
390     var_Create( p_intf, "mosaic-hborder", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
391     var_AddCallback( p_intf, "mosaic-hborder", Other, NULL );
392     var_Create( p_intf, "mosaic-position",
393                      VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
394     var_AddCallback( p_intf, "mosaic-position", Other, NULL );
395     var_Create( p_intf, "mosaic-rows", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
396     var_AddCallback( p_intf, "mosaic-rows", Other, NULL );
397     var_Create( p_intf, "mosaic-cols", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
398     var_AddCallback( p_intf, "mosaic-cols", Other, NULL );
399     var_Create( p_intf, "mosaic-keep-aspect-ratio",
400                      VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
401     var_AddCallback( p_intf, "mosaic-keep-aspect-ratio", Other, NULL );
402
403     /* time on the fly items */
404     var_Create( p_intf, "time-format", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
405     var_AddCallback( p_intf, "time-format", Other, NULL );
406     var_Create( p_intf, "time-x", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
407     var_AddCallback( p_intf, "time-x", Other, NULL );
408     var_Create( p_intf, "time-y", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
409     var_AddCallback( p_intf, "time-y", Other, NULL );
410     var_Create( p_intf, "time-position", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
411     var_AddCallback( p_intf, "time-position", Other, NULL );
412     var_Create( p_intf, "time-color", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
413     var_AddCallback( p_intf, "time-color", Other, NULL );
414     var_Create( p_intf, "time-opacity", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
415     var_AddCallback( p_intf, "time-opacity", Other, NULL );
416     var_Create( p_intf, "time-size", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
417     var_AddCallback( p_intf, "time-size", Other, NULL );
418     
419     /* logo on the fly items */
420     var_Create( p_intf, "logo-file", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
421     var_AddCallback( p_intf, "logo-file", Other, NULL );
422     var_Create( p_intf, "logo-x", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
423     var_AddCallback( p_intf, "logo-x", Other, NULL );
424     var_Create( p_intf, "logo-y", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
425     var_AddCallback( p_intf, "logo-y", Other, NULL );
426     var_Create( p_intf, "logo-position", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
427     var_AddCallback( p_intf, "logo-position", Other, NULL );
428     var_Create( p_intf, "logo-transparency", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
429     var_AddCallback( p_intf, "logo-transparency", Other, NULL );
430     
431     
432     var_Create( p_intf, "pause", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
433     var_AddCallback( p_intf, "pause", Input, NULL );
434     var_Create( p_intf, "seek", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
435     var_AddCallback( p_intf, "seek", Input, NULL );
436     var_Create( p_intf, "title", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
437     var_AddCallback( p_intf, "title", Input, NULL );
438     var_Create( p_intf, "title_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
439     var_AddCallback( p_intf, "title_n", Input, NULL );
440     var_Create( p_intf, "title_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
441     var_AddCallback( p_intf, "title_p", Input, NULL );
442     var_Create( p_intf, "chapter", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
443     var_AddCallback( p_intf, "chapter", Input, NULL );
444     var_Create( p_intf, "chapter_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
445     var_AddCallback( p_intf, "chapter_n", Input, NULL );
446     var_Create( p_intf, "chapter_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
447     var_AddCallback( p_intf, "chapter_p", Input, NULL );
448
449     var_Create( p_intf, "fastforward", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
450     var_AddCallback( p_intf, "fastforward", Input, NULL );
451     var_Create( p_intf, "rewind", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
452     var_AddCallback( p_intf, "rewind", Input, NULL );
453
454     var_Create( p_intf, "volume", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
455     var_AddCallback( p_intf, "volume", Volume, NULL );
456     var_Create( p_intf, "volup", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
457     var_AddCallback( p_intf, "volup", VolumeMove, NULL );
458     var_Create( p_intf, "voldown", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
459     var_AddCallback( p_intf, "voldown", VolumeMove, NULL );
460     var_Create( p_intf, "adev", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
461     var_AddCallback( p_intf, "adev", AudioConfig, NULL );
462     var_Create( p_intf, "achan", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
463     var_AddCallback( p_intf, "achan", AudioConfig, NULL );
464
465 #ifdef WIN32
466     /* Get the file descriptor of the console input */
467     p_intf->p_sys->hConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
468     if( p_intf->p_sys->hConsoleIn == INVALID_HANDLE_VALUE )
469     {
470         msg_Err( p_intf, "Couldn't open STD_INPUT_HANDLE" );
471         p_intf->b_die = VLC_TRUE;
472     }
473 #endif
474
475     while( !p_intf->b_die )
476     {
477         char *psz_cmd, *psz_arg;
478         vlc_bool_t b_complete;
479
480         if( p_intf->p_sys->i_socket_listen != - 1 &&
481             p_intf->p_sys->i_socket == -1 )
482         {
483             p_intf->p_sys->i_socket =
484                 net_Accept( p_intf, p_intf->p_sys->i_socket_listen, 0 );
485         }
486
487         b_complete = ReadCommand( p_intf, p_buffer, &i_size );
488
489         /* Manage the input part */
490         if( p_input == NULL )
491         {
492             if( p_playlist )
493             {
494                 p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT,
495                                                        FIND_CHILD );
496             }
497             else
498             {
499                 p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
500                                                    FIND_ANYWHERE );
501                 if( p_input )
502                 {
503                     p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
504                                                            FIND_PARENT );
505                 }
506             }
507         }
508         else if( p_input->b_dead )
509         {
510             vlc_object_release( p_input );
511             p_input = NULL;
512         }
513
514         if( p_input && b_showpos )
515         {
516             i_newpos = 100 * var_GetFloat( p_input, "position" );
517             if( i_oldpos != i_newpos )
518             {
519                 i_oldpos = i_newpos;
520                 msg_rc( "pos: %d%%\n", i_newpos );
521             }
522         }
523
524         /* Is there something to do? */
525         if( !b_complete ) continue;
526
527
528         /* Skip heading spaces */
529         psz_cmd = p_buffer;
530         while( *psz_cmd == ' ' )
531         {
532             psz_cmd++;
533         }
534
535         /* Split psz_cmd at the first space and make sure that
536          * psz_arg is valid */
537         psz_arg = strchr( psz_cmd, ' ' );
538         if( psz_arg )
539         {
540             *psz_arg++ = 0;
541             while( *psz_arg == ' ' )
542             {
543                 psz_arg++;
544             }
545         }
546         else
547         {
548             psz_arg = "";
549         }
550
551         /* If the user typed a registered local command, try it */
552         if( var_Type( p_intf, psz_cmd ) & VLC_VAR_ISCOMMAND )
553         {
554             vlc_value_t val;
555             int i_ret;
556
557             val.psz_string = psz_arg;
558             i_ret = var_Set( p_intf, psz_cmd, val );
559             msg_rc( "%s: returned %i (%s)\n",
560                     psz_cmd, i_ret, vlc_error( i_ret ) );
561         }
562         /* Or maybe it's a global command */
563         else if( var_Type( p_intf->p_libvlc, psz_cmd ) & VLC_VAR_ISCOMMAND )
564         {
565             vlc_value_t val;
566             int i_ret;
567
568             val.psz_string = psz_arg;
569             /* FIXME: it's a global command, but we should pass the
570              * local object as an argument, not p_intf->p_libvlc. */
571             i_ret = var_Set( p_intf->p_libvlc, psz_cmd, val );
572             if( i_ret != 0 )
573             {
574                 msg_rc( "%s: returned %i (%s)\n",
575                          psz_cmd, i_ret, vlc_error( i_ret ) );
576             }
577         }
578         else if( !strcmp( psz_cmd, "logout" ) )
579         {
580             /* Close connection */
581             if( p_intf->p_sys->i_socket != -1 )
582             {
583                 net_Close( p_intf->p_sys->i_socket );
584             }
585             p_intf->p_sys->i_socket = -1;
586         }
587         else if( !strcmp( psz_cmd, "info" ) )
588         {
589             if( p_input )
590             {
591                 int i, j;
592                 vlc_mutex_lock( &p_input->input.p_item->lock );
593                 for ( i = 0; i < p_input->input.p_item->i_categories; i++ )
594                 {
595                     info_category_t *p_category =
596                         p_input->input.p_item->pp_categories[i];
597
598                     msg_rc( "+----[ %s ]\n", p_category->psz_name );
599                     msg_rc( "| \n" );
600                     for ( j = 0; j < p_category->i_infos; j++ )
601                     {
602                         info_t *p_info = p_category->pp_infos[j];
603                         msg_rc( "| %s: %s\n", p_info->psz_name,
604                                 p_info->psz_value );
605                     }
606                     msg_rc( "| \n" );
607                 }
608                 msg_rc( "+----[ end of stream info ]\n" );
609                 vlc_mutex_unlock( &p_input->input.p_item->lock );
610             }
611             else
612             {
613                 msg_rc( "no input\n" );
614             }
615         }
616         else if( !strcmp( psz_cmd, "is_playing" ) )
617         {
618             if( ! p_input )
619             {
620                 msg_rc( "0\n" );
621             }
622             else
623             {
624                 msg_rc( "1\n" );
625             }
626         }
627         else if( !strcmp( psz_cmd, "get_time" ) )
628         {
629             if( ! p_input )
630             {
631                 msg_rc("0\n");
632             }
633             else
634             {
635                 vlc_value_t time;
636                 var_Get( p_input, "time", &time );
637                 msg_rc( "%i\n", time.i_time / 1000000);
638             }
639         }
640         else if( !strcmp( psz_cmd, "get_length" ) )
641         {
642             if( ! p_input )
643             {
644                 msg_rc("0\n");
645             }
646             else
647             {
648                 vlc_value_t time;
649                 var_Get( p_input, "length", &time );
650                 msg_rc( "%i\n", time.i_time / 1000000);
651             }
652         }
653         else if( !strcmp( psz_cmd, "get_title" ) )
654         {
655             if( ! p_input )
656             {
657                 msg_rc("\n");
658             }
659             else
660             {
661                 msg_rc( "%s\n", p_input->input.p_item->psz_name );
662             }
663         }
664         else if( !strcmp( psz_cmd, "longhelp" ) || !strncmp( psz_cmd, "h", 1 )
665                  || !strncmp( psz_cmd, "H", 1 ) || !strncmp( psz_cmd, "?", 1 ) )
666         {
667             if( !strcmp( psz_cmd, "longhelp" ) || !strncmp( psz_cmd, "H", 1 ) )
668                  b_longhelp = VLC_TRUE;
669             else b_longhelp = VLC_FALSE;
670             
671             msg_rc(_("+----[ Remote control commands ]\n"));
672             msg_rc(  "| \n");
673             msg_rc(_("| add XYZ  . . . . . . . . . . add XYZ to playlist\n"));
674             msg_rc(_("| playlist . . .  show items currently in playlist\n"));
675             msg_rc(_("| play . . . . . . . . . . . . . . . . play stream\n"));
676             msg_rc(_("| stop . . . . . . . . . . . . . . . . stop stream\n"));
677             msg_rc(_("| next . . . . . . . . . . . .  next playlist item\n"));
678             msg_rc(_("| prev . . . . . . . . . .  previous playlist item\n"));
679             msg_rc(_("| goto . . . . . . . . . . . .  goto item at index\n"));
680             msg_rc(_("| title [X]  . . . . set/get title in current item\n"));
681             msg_rc(_("| title_n  . . . . . .  next title in current item\n"));
682             msg_rc(_("| title_p  . . . .  previous title in current item\n"));
683             msg_rc(_("| chapter [X]  . . set/get chapter in current item\n"));
684             msg_rc(_("| chapter_n  . . . .  next chapter in current item\n"));
685             msg_rc(_("| chapter_p  . .  previous chapter in current item\n"));
686             msg_rc(  "| \n");
687             msg_rc(_("| seek X . seek in seconds, for instance `seek 12'\n"));
688             msg_rc(_("| pause  . . . . . . . . . . . . . .  toggle pause\n"));
689             msg_rc(_("| fastforward  . . . . . .  .  set to maximum rate\n"));
690             msg_rc(_("| rewind  . . . . . . . . . .  set to minimum rate\n"));
691             msg_rc(_("| f  . . . . . . . . . . . . . . toggle fullscreen\n"));
692             msg_rc(_("| info . . .  information about the current stream\n"));
693             msg_rc(  "| \n");
694             msg_rc(_("| volume [X] . . . . . . . .  set/get audio volume\n"));
695             msg_rc(_("| volup [X]  . . . . .  raise audio volume X steps\n"));
696             msg_rc(_("| voldown [X]  . . . .  lower audio volume X steps\n"));
697             msg_rc(_("| adev [X] . . . . . . . . .  set/get audio device\n"));
698             msg_rc(_("| achan [X]. . . . . . . .  set/get audio channels\n"));
699             msg_rc(  "| \n");
700             
701             if (b_longhelp)
702             {
703                 msg_rc(_("| marq-marquee STRING  . . overlay STRING in video\n"));
704                 msg_rc(_("| marq-x X . . . . . . . . . . . .offset from left\n"));
705                 msg_rc(_("| marq-y Y . . . . . . . . . . . . offset from top\n"));
706                 msg_rc(_("| marq-position #. . .  .relative position control\n"));
707                 msg_rc(_("| marq-color # . . . . . . . . . . font color, RGB\n"));
708                 msg_rc(_("| marq-opacity # . . . . . . . . . . . . . opacity\n"));
709                 msg_rc(_("| marq-timeout T. . . . . . . . . . timeout, in ms\n"));
710                 msg_rc(_("| marq-size # . . . . . . . . font size, in pixels\n"));
711                 msg_rc(  "| \n");
712                 msg_rc(_("| time-format STRING . . . overlay STRING in video\n"));
713                 msg_rc(_("| time-x X . . . . . . . . . . . .offset from left\n"));
714                 msg_rc(_("| time-y Y . . . . . . . . . . . . offset from top\n"));
715                 msg_rc(_("| time-position #. . . . . . . . relative position\n"));
716                 msg_rc(_("| time-color # . . . . . . . . . . font color, RGB\n"));
717                 msg_rc(_("| time-opacity # . . . . . . . . . . . . . opacity\n"));
718                 msg_rc(_("| time-size # . . . . . . . . font size, in pixels\n"));
719                 msg_rc(  "| \n");
720                 msg_rc(_("| logo-file STRING . . . the overlay file path/name\n"));
721                 msg_rc(_("| logo-x X . . . . . . . . . . . .offset from left\n"));
722                 msg_rc(_("| logo-y Y . . . . . . . . . . . . offset from top\n"));
723                 msg_rc(_("| logo-position #. . . . . . . . relative position\n"));
724                 msg_rc(_("| logo-transparency #. . . . . . . . .transparency\n"));
725                 msg_rc(  "| \n");
726                 msg_rc(_("| mosaic-alpha # . . . . . . . . . . . . . . alpha\n"));
727                 msg_rc(_("| mosaic-height #. . . . . . . . . . . . . .height\n"));
728                 msg_rc(_("| mosaic-width # . . . . . . . . . . . . . . width\n"));
729                 msg_rc(_("| mosaic-xoffset # . . . .top left corner position\n"));
730                 msg_rc(_("| mosaic-yoffset # . . . .top left corner position\n"));
731                 msg_rc(_("| mosaic-align 0..2,4..6,8..10. . .mosaic alignment\n"));
732                 msg_rc(_("| mosaic-vborder # . . . . . . . . vertical border\n"));
733                 msg_rc(_("| mosaic-hborder # . . . . . . . horizontal border\n"));
734                 msg_rc(_("| mosaic-position {0=auto,1=fixed} . . . .position\n"));
735                 msg_rc(_("| mosaic-rows #. . . . . . . . . . .number of rows\n"));
736                 msg_rc(_("| mosaic-cols #. . . . . . . . . . .number of cols\n"));
737                 msg_rc(_("| mosaic-keep-aspect-ratio {0,1} . . .aspect ratio\n"));
738                 msg_rc(  "| \n");
739             }    
740             msg_rc(_("| help . . . . . . . . . . . . . this help message\n"));
741             msg_rc(_("| longhelp . . . . . . . . . a longer help message\n"));
742             msg_rc(_("| logout . . . . .  exit (if in socket connection)\n"));
743             msg_rc(_("| quit . . . . . . . . . . . . . . . . .  quit vlc\n"));
744             msg_rc(  "| \n");
745             msg_rc(_("+----[ end of help ]\n"));
746         }
747         else switch( psz_cmd[0] )
748         {
749         case 'f':
750         case 'F':
751             if( p_input )
752             {
753                 vout_thread_t *p_vout;
754                 p_vout = vlc_object_find( p_input,
755                                           VLC_OBJECT_VOUT, FIND_CHILD );
756
757                 if( p_vout )
758                 {
759                     p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
760                     vlc_object_release( p_vout );
761                 }
762             }
763             break;
764
765         case 's':
766         case 'S':
767             ;
768             break;
769
770         case '\0':
771             /* Ignore empty lines */
772             break;
773
774         default:
775             msg_rc(_("unknown command `%s', type `help' for help\n"), psz_cmd);
776             break;
777         }
778
779         /* Command processed */
780         i_size = 0; p_buffer[0] = 0;
781     }
782
783     if( p_input )
784     {
785         vlc_object_release( p_input );
786         p_input = NULL;
787     }
788
789     if( p_playlist )
790     {
791         vlc_object_release( p_playlist );
792         p_playlist = NULL;
793     }
794 }
795
796 static int Input( vlc_object_t *p_this, char const *psz_cmd,
797                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
798 {
799     intf_thread_t *p_intf = (intf_thread_t*)p_this;
800     input_thread_t *p_input;
801     vlc_value_t     val;
802
803     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
804     if( !p_input ) return VLC_ENOOBJ;
805
806     /* Parse commands that only require an input */
807     if( !strcmp( psz_cmd, "pause" ) )
808     {
809         val.i_int = PAUSE_S;
810
811         var_Set( p_input, "state", val );
812         vlc_object_release( p_input );
813         return VLC_SUCCESS;
814     }
815     else if( !strcmp( psz_cmd, "seek" ) )
816     {
817         if( strlen( newval.psz_string ) > 0 &&
818             newval.psz_string[strlen( newval.psz_string ) - 1] == '%' )
819         {
820             val.f_float = (float)atoi( newval.psz_string ) / 100.0;
821             var_Set( p_input, "position", val );
822         }
823         else
824         {
825             val.i_time = ((int64_t)atoi( newval.psz_string )) * 1000000;
826             var_Set( p_input, "time", val );
827         }
828         vlc_object_release( p_input );
829         return VLC_SUCCESS;
830     }
831     else if ( !strcmp( psz_cmd, "fastforward" ) )
832     {
833         val.i_int = INPUT_RATE_MAX;
834
835         var_Set( p_input, "rate", val );
836         vlc_object_release( p_input );
837         return VLC_SUCCESS;
838     }
839     else if ( !strcmp( psz_cmd, "rewind" ) )
840     {
841         val.i_int = INPUT_RATE_MIN;
842
843         var_Set( p_input, "rate", val );
844         vlc_object_release( p_input );
845         return VLC_SUCCESS;
846     }
847     else if( !strcmp( psz_cmd, "chapter" ) ||
848              !strcmp( psz_cmd, "chapter_n" ) ||
849              !strcmp( psz_cmd, "chapter_p" ) )
850     {
851         if( !strcmp( psz_cmd, "chapter" ) )
852         {
853             if ( *newval.psz_string )
854             {
855                 /* Set. */
856                 val.i_int = atoi( newval.psz_string );
857                 var_Set( p_input, "chapter", val );
858             }
859             else
860             {
861                 vlc_value_t val_list;
862
863                 /* Get. */
864                 var_Get( p_input, "chapter", &val );
865                 var_Change( p_input, "chapter", VLC_VAR_GETCHOICES,
866                             &val_list, NULL );
867                 msg_rc( "Currently playing chapter %d/%d\n",
868                         val.i_int, val_list.p_list->i_count );
869                 var_Change( p_this, "chapter", VLC_VAR_FREELIST,
870                             &val_list, NULL );
871             }
872         }
873         else if( !strcmp( psz_cmd, "chapter_n" ) )
874         {
875             val.b_bool = VLC_TRUE;
876             var_Set( p_input, "next-chapter", val );
877         }
878         else if( !strcmp( psz_cmd, "chapter_p" ) )
879         {
880             val.b_bool = VLC_TRUE;
881             var_Set( p_input, "prev-chapter", val );
882         }
883
884         vlc_object_release( p_input );
885         return VLC_SUCCESS;
886     }
887     else if( !strcmp( psz_cmd, "title" ) ||
888              !strcmp( psz_cmd, "title_n" ) ||
889              !strcmp( psz_cmd, "title_p" ) )
890     {
891         if( !strcmp( psz_cmd, "title" ) )
892         {
893             if ( *newval.psz_string )
894             {
895                 /* Set. */
896                 val.i_int = atoi( newval.psz_string );
897                 var_Set( p_input, "title", val );
898             }
899             else
900             {
901                 vlc_value_t val_list;
902
903                 /* Get. */
904                 var_Get( p_input, "title", &val );
905                 var_Change( p_input, "title", VLC_VAR_GETCHOICES,
906                             &val_list, NULL );
907                 msg_rc( "Currently playing title %d/%d\n",
908                         val.i_int, val_list.p_list->i_count );
909                 var_Change( p_this, "title", VLC_VAR_FREELIST,
910                             &val_list, NULL );
911             }
912         }
913         else if( !strcmp( psz_cmd, "title_n" ) )
914         {
915             val.b_bool = VLC_TRUE;
916             var_Set( p_input, "next-title", val );
917         }
918         else if( !strcmp( psz_cmd, "title_p" ) )
919         {
920             val.b_bool = VLC_TRUE;
921             var_Set( p_input, "prev-title", val );
922         }
923
924         vlc_object_release( p_input );
925         return VLC_SUCCESS;
926     }
927
928     /* Never reached. */
929     return VLC_EGENERIC;
930 }
931
932 static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
933                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
934 {
935     vlc_value_t val;
936     intf_thread_t *p_intf = (intf_thread_t*)p_this;
937     playlist_t *p_playlist;
938
939     p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
940                                            FIND_ANYWHERE );
941     if( !p_playlist )
942     {
943         return VLC_ENOOBJ;
944     }
945
946     /* Parse commands that require a playlist */
947     if( !strcmp( psz_cmd, "prev" ) )
948     {
949         playlist_Prev( p_playlist );
950     }
951     else if( !strcmp( psz_cmd, "next" ) )
952     {
953         playlist_Next( p_playlist );
954     }
955     else if( !strcmp( psz_cmd, "play" ) )
956     {
957         playlist_Play( p_playlist );
958     }
959     else if (!strcmp( psz_cmd, "goto" ) )
960     {
961         if( strlen( newval.psz_string ) > 0) 
962         {
963             val.i_int = atoi( newval.psz_string );
964             playlist_Goto( p_playlist, val.i_int); 
965         }
966     }
967     else if( !strcmp( psz_cmd, "stop" ) )
968     {
969         playlist_Stop( p_playlist );
970     }
971     else if( !strcmp( psz_cmd, "add" ) &&
972              newval.psz_string && *newval.psz_string )
973     {
974         playlist_item_t *p_item = parse_MRL( p_intf, newval.psz_string );
975
976         if( p_item )
977         {
978             msg_rc( "trying to add %s to playlist\n", newval.psz_string );
979             playlist_AddItem( p_playlist, p_item,
980                               PLAYLIST_GO|PLAYLIST_APPEND, PLAYLIST_END );
981         }
982     }
983     else if( !strcmp( psz_cmd, "playlist" ) )
984     {
985         int i;
986         for ( i = 0; i < p_playlist->i_size; i++ )
987         {
988             msg_rc( "|%s%s   %s|%s|\n", i == p_playlist->i_index ? "*" : " ",
989                     p_playlist->pp_items[i]->input.psz_name,
990                     p_playlist->pp_items[i]->input.psz_uri,
991                     p_playlist->pp_items[i]->i_parents > 0 ?
992                     p_playlist->pp_items[i]->pp_parents[0]->p_parent->input.psz_name : "" );
993         }
994         if ( i == 0 )
995         {
996             msg_rc( "| no entries\n" );
997         }
998     }
999  
1000     /*
1001      * sanity check
1002      */
1003     else
1004     {
1005         msg_rc( "unknown command!\n" );
1006     }
1007
1008     vlc_object_release( p_playlist );
1009     return VLC_SUCCESS;
1010 }
1011
1012 static int Other( vlc_object_t *p_this, char const *psz_cmd,
1013                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
1014 {
1015     intf_thread_t *p_intf = (intf_thread_t*)p_this;
1016     vlc_object_t *p_pl;
1017     vlc_value_t     val;
1018     vlc_object_t *p_inp;
1019
1020     p_pl = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
1021                                            FIND_ANYWHERE );
1022     if( !p_pl )
1023     {
1024         return VLC_ENOOBJ;
1025     }
1026     
1027     p_inp = vlc_object_find( p_this, VLC_OBJECT_INPUT,
1028                                            FIND_ANYWHERE );
1029     if( !p_inp )
1030     {
1031         return VLC_ENOOBJ;
1032     }
1033
1034     /* Parse miscellaneous commands */
1035     if( !strcmp( psz_cmd, "marq-marquee" ) )
1036     {
1037         if( strlen( newval.psz_string ) > 0 )
1038         {
1039             val.psz_string = newval.psz_string;
1040             var_Set( p_inp->p_libvlc, "marq-marquee", val );
1041         }
1042         else 
1043         {
1044                 val.psz_string = "";
1045                 var_Set( p_inp->p_libvlc, "marq-marquee", val);
1046         }
1047     }
1048     else if( !strcmp( psz_cmd, "marq-x" ) )
1049     {
1050         if( strlen( newval.psz_string ) > 0) 
1051         {
1052             val.i_int = atoi( newval.psz_string );
1053             var_Set( p_inp->p_libvlc, "marq-x", val );
1054         }
1055     }
1056     else if( !strcmp( psz_cmd, "marq-y" ) )
1057     {
1058         if( strlen( newval.psz_string ) > 0) 
1059         {
1060             val.i_int = atoi( newval.psz_string );
1061             var_Set( p_inp->p_libvlc, "marq-y", val );
1062         }
1063     }
1064     else if( !strcmp( psz_cmd, "marq-position" ) )
1065     {
1066         if( strlen( newval.psz_string ) > 0) 
1067         {
1068             val.i_int = atoi( newval.psz_string );
1069             var_Set( p_inp->p_libvlc, "marq-position", val );
1070         }
1071     }
1072     else if( !strcmp( psz_cmd, "marq-color" ) )
1073     {
1074         if( strlen( newval.psz_string ) > 0) 
1075         {
1076             val.i_int = strtol( newval.psz_string, NULL, 0 );
1077             var_Set( p_inp->p_libvlc, "marq-color", val );
1078         }
1079     }
1080     else if( !strcmp( psz_cmd, "marq-opacity" ) )
1081     {
1082         if( strlen( newval.psz_string ) > 0) 
1083         {
1084             val.i_int = strtol( newval.psz_string, NULL, 0 );
1085             var_Set( p_inp->p_libvlc, "marq-opacity", val );
1086         }
1087     }
1088     else if( !strcmp( psz_cmd, "marq-size" ) )
1089     {
1090         if( strlen( newval.psz_string ) > 0) 
1091         {
1092             val.i_int = atoi( newval.psz_string );
1093             var_Set( p_inp->p_libvlc, "marq-size", val );
1094         }
1095     }
1096     else if( !strcmp( psz_cmd, "marq-timeout" ) )
1097     {
1098         if( strlen( newval.psz_string ) > 0) 
1099         {
1100             val.i_int = atoi( newval.psz_string );
1101             var_Set( p_inp, "marq-timeout", val );
1102         }
1103     }
1104     else if( !strcmp( psz_cmd, "mosaic-alpha" ) )
1105     {
1106         if( strlen( newval.psz_string ) > 0)
1107         {
1108             val.i_int = atoi( newval.psz_string );
1109             var_Set( p_inp->p_libvlc, "mosaic-alpha", val );
1110         }
1111     }
1112     else if( !strcmp( psz_cmd, "mosaic-height" ) )
1113     {
1114         if( strlen( newval.psz_string ) > 0)
1115         {
1116             val.i_int = atoi( newval.psz_string );
1117             var_Set( p_inp->p_libvlc, "mosaic-height", val );
1118         }
1119     }
1120     else if( !strcmp( psz_cmd, "mosaic-width" ) )
1121     {
1122         if( strlen( newval.psz_string ) > 0)
1123         {
1124             val.i_int = atoi( newval.psz_string );
1125             var_Set( p_inp->p_libvlc, "mosaic-width", val );
1126         }
1127     }
1128     else if( !strcmp( psz_cmd, "mosaic-xoffset" ) )
1129     {
1130         if( strlen( newval.psz_string ) > 0)
1131         {
1132             val.i_int = atoi( newval.psz_string );
1133             var_Set( p_inp->p_libvlc, "mosaic-xoffset", val );
1134         }
1135     }
1136     else if( !strcmp( psz_cmd, "mosaic-yoffset" ) )
1137     {
1138         if( strlen( newval.psz_string ) > 0)
1139         {
1140             val.i_int = atoi( newval.psz_string );
1141             var_Set( p_inp->p_libvlc, "mosaic-yoffset", val );
1142         }
1143     }
1144     else if( !strcmp( psz_cmd, "mosaic-align" ) )
1145     {
1146         if( strlen( newval.psz_string ) > 0 )
1147         {
1148             val.i_int = atoi( newval.psz_string );
1149             var_Set( p_inp->p_libvlc, "mosaic-align", val );
1150         }
1151     }
1152     else if( !strcmp( psz_cmd, "mosaic-vborder" ) )
1153     {
1154         if( strlen( newval.psz_string ) > 0)
1155         {
1156             val.i_int = atoi( newval.psz_string );
1157             var_Set( p_inp->p_libvlc, "mosaic-vborder", val );
1158         }
1159     }
1160     else if( !strcmp( psz_cmd, "mosaic-hborder" ) )
1161     {
1162         if( strlen( newval.psz_string ) > 0)
1163         {
1164             val.i_int = atoi( newval.psz_string );
1165             var_Set( p_inp->p_libvlc, "mosaic-hborder", val );
1166         }
1167     }
1168     else if( !strcmp( psz_cmd, "mosaic-position" ) )
1169     {
1170         if( strlen( newval.psz_string ) > 0)
1171         {
1172             val.i_int = atoi( newval.psz_string );
1173             var_Set( p_inp->p_libvlc, "mosaic-position", val );
1174         }
1175     }
1176     else if( !strcmp( psz_cmd, "mosaic-rows" ) )
1177     {
1178         if( strlen( newval.psz_string ) > 0)
1179         {
1180             val.i_int = atoi( newval.psz_string );
1181             var_Set( p_inp->p_libvlc, "mosaic-rows", val );
1182         }
1183     }
1184     else if( !strcmp( psz_cmd, "mosaic-cols" ) )
1185     {
1186         if( strlen( newval.psz_string ) > 0)
1187         {
1188             val.i_int = atoi( newval.psz_string );
1189             var_Set( p_inp->p_libvlc, "mosaic-cols", val );
1190         }
1191     }
1192     else if( !strcmp( psz_cmd, "mosaic-keep-aspect-ratio" ) )
1193     {
1194         if( strlen( newval.psz_string ) > 0)
1195         {
1196             val.i_int = atoi( newval.psz_string );
1197             var_Set( p_inp->p_libvlc, "mosaic-keep-aspect-ratio", val );
1198         }
1199     }
1200     else if( !strcmp( psz_cmd, "time-format" ) )
1201     {
1202         if( strlen( newval.psz_string ) > 0 )
1203         {
1204             val.psz_string = newval.psz_string;
1205             var_Set( p_inp->p_libvlc, "time-format", val );
1206         }
1207         else 
1208         {
1209                 val.psz_string = "";
1210                 var_Set( p_inp->p_libvlc, "time-format", val);
1211         }
1212     }
1213     else if( !strcmp( psz_cmd, "time-x" ) )
1214     {
1215         if( strlen( newval.psz_string ) > 0) 
1216         {
1217             val.i_int = atoi( newval.psz_string );
1218             var_Set( p_inp->p_libvlc, "time-x", val );
1219         }
1220     }
1221     else if( !strcmp( psz_cmd, "time-y" ) )
1222     {
1223         if( strlen( newval.psz_string ) > 0) 
1224         {
1225             val.i_int = atoi( newval.psz_string );
1226             var_Set( p_inp->p_libvlc, "time-y", val );
1227         }
1228     }
1229     else if( !strcmp( psz_cmd, "time-position" ) )
1230     {
1231         if( strlen( newval.psz_string ) > 0) 
1232         {
1233             val.i_int = atoi( newval.psz_string );
1234             var_Set( p_inp->p_libvlc, "time-position", val );
1235         }
1236     }
1237     else if( !strcmp( psz_cmd, "time-color" ) )
1238     {
1239         if( strlen( newval.psz_string ) > 0) 
1240         {
1241             val.i_int = strtol( newval.psz_string, NULL, 0 );
1242             var_Set( p_inp->p_libvlc, "time-color", val );
1243         }
1244     }
1245     else if( !strcmp( psz_cmd, "time-opacity" ) )
1246     {
1247         if( strlen( newval.psz_string ) > 0) 
1248         {
1249             val.i_int = strtol( newval.psz_string, NULL, 0 );
1250             var_Set( p_inp->p_libvlc, "time-opacity", val );
1251         }
1252     }
1253     else if( !strcmp( psz_cmd, "time-size" ) )
1254     {
1255         if( strlen( newval.psz_string ) > 0) 
1256         {
1257             val.i_int = atoi( newval.psz_string );
1258             var_Set( p_inp->p_libvlc, "time-size", val );
1259         }
1260     }
1261     else if( !strcmp( psz_cmd, "logo-file" ) )
1262     {
1263         if( strlen( newval.psz_string ) > 0 )
1264         {
1265             val.psz_string = newval.psz_string;
1266             var_Set( p_inp->p_libvlc, "logo-file", val );
1267         }
1268     }
1269     else if( !strcmp( psz_cmd, "logo-x" ) )
1270     {
1271         if( strlen( newval.psz_string ) > 0) 
1272         {
1273             val.i_int = atoi( newval.psz_string );
1274             var_Set( p_inp->p_libvlc, "logo-x", val );
1275         }
1276     }
1277     else if( !strcmp( psz_cmd, "logo-y" ) )
1278     {
1279         if( strlen( newval.psz_string ) > 0) 
1280         {
1281             val.i_int = atoi( newval.psz_string );
1282             var_Set( p_inp->p_libvlc, "logo-y", val );
1283         }
1284     }
1285     else if( !strcmp( psz_cmd, "logo-position" ) )
1286     {
1287         if( strlen( newval.psz_string ) > 0) 
1288         {
1289             val.i_int = atoi( newval.psz_string );
1290             var_Set( p_inp->p_libvlc, "logo-position", val );
1291         }
1292     }
1293     else if( !strcmp( psz_cmd, "logo-transparency" ) )
1294     {
1295         if( strlen( newval.psz_string ) > 0) 
1296         {
1297             val.i_int = strtol( newval.psz_string, NULL, 0 );
1298             var_Set( p_inp->p_libvlc, "logo-transparency", val );
1299         }
1300     }
1301
1302     /*
1303      * sanity check
1304      */
1305     else
1306     {
1307         msg_rc( "unknown command!\n" );
1308     }
1309
1310     vlc_object_release( p_pl );
1311     vlc_object_release( p_inp );
1312     return VLC_SUCCESS;
1313 }
1314
1315 static int Quit( vlc_object_t *p_this, char const *psz_cmd,
1316                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
1317 {
1318     p_this->p_vlc->b_die = VLC_TRUE;
1319     return VLC_SUCCESS;
1320 }
1321
1322 static int Intf( vlc_object_t *p_this, char const *psz_cmd,
1323                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
1324 {
1325     intf_thread_t *p_newintf;
1326
1327     p_newintf = intf_Create( p_this->p_vlc, newval.psz_string );
1328
1329     if( p_newintf )
1330     {
1331         p_newintf->b_block = VLC_FALSE;
1332         if( intf_RunThread( p_newintf ) )
1333         {
1334             vlc_object_detach( p_newintf );
1335             intf_Destroy( p_newintf );
1336         }
1337     }
1338
1339     return VLC_SUCCESS;
1340 }
1341
1342 static int Volume( vlc_object_t *p_this, char const *psz_cmd,
1343                    vlc_value_t oldval, vlc_value_t newval, void *p_data )
1344 {
1345     intf_thread_t *p_intf = (intf_thread_t*)p_this;
1346     int i_error;
1347
1348     if ( *newval.psz_string )
1349     {
1350         /* Set. */
1351         audio_volume_t i_volume = atoi( newval.psz_string );
1352         if ( i_volume > AOUT_VOLUME_MAX )
1353         {
1354             msg_rc( "Volume must be in the range %d-%d\n", AOUT_VOLUME_MIN,
1355                     AOUT_VOLUME_MAX );
1356             i_error = VLC_EBADVAR;
1357         }
1358         else i_error = aout_VolumeSet( p_this, i_volume );
1359     }
1360     else
1361     {
1362         /* Get. */
1363         audio_volume_t i_volume;
1364         if ( aout_VolumeGet( p_this, &i_volume ) < 0 )
1365         {
1366             i_error = VLC_EGENERIC;
1367         }
1368         else
1369         {
1370             msg_rc( "Volume is %d\n", i_volume );
1371             i_error = VLC_SUCCESS;
1372         }
1373     }
1374
1375     return i_error;
1376 }
1377
1378 static int VolumeMove( vlc_object_t *p_this, char const *psz_cmd,
1379                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
1380 {
1381     intf_thread_t *p_intf = (intf_thread_t*)p_this;
1382     audio_volume_t i_volume;
1383     int i_nb_steps = atoi(newval.psz_string);
1384     int i_error = VLC_SUCCESS;
1385
1386     if ( i_nb_steps <= 0 || i_nb_steps > (AOUT_VOLUME_MAX/AOUT_VOLUME_STEP) )
1387     {
1388         i_nb_steps = 1;
1389     }
1390
1391     if ( !strcmp(psz_cmd, "volup") )
1392     {
1393         if ( aout_VolumeUp( p_this, i_nb_steps, &i_volume ) < 0 )
1394             i_error = VLC_EGENERIC;
1395     }
1396     else
1397     {
1398         if ( aout_VolumeDown( p_this, i_nb_steps, &i_volume ) < 0 )
1399             i_error = VLC_EGENERIC;
1400     }
1401
1402     if ( !i_error ) msg_rc( "Volume is %d\n", i_volume );
1403     return i_error;
1404 }
1405
1406 static int AudioConfig( vlc_object_t *p_this, char const *psz_cmd,
1407                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
1408 {
1409     intf_thread_t *p_intf = (intf_thread_t*)p_this;
1410     aout_instance_t * p_aout;
1411     const char * psz_variable;
1412     vlc_value_t val_name;
1413     int i_error;
1414
1415     p_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT, FIND_ANYWHERE );
1416     if ( p_aout == NULL ) return VLC_ENOOBJ;
1417
1418     if ( !strcmp( psz_cmd, "adev" ) )
1419     {
1420         psz_variable = "audio-device";
1421     }
1422     else
1423     {
1424         psz_variable = "audio-channels";
1425     }
1426
1427     /* Get the descriptive name of the variable */
1428     var_Change( (vlc_object_t *)p_aout, psz_variable, VLC_VAR_GETTEXT,
1429                  &val_name, NULL );
1430     if( !val_name.psz_string ) val_name.psz_string = strdup(psz_variable);
1431
1432     if ( !*newval.psz_string )
1433     {
1434         /* Retrieve all registered ***. */
1435         vlc_value_t val, text;
1436         int i, i_value;
1437
1438         if ( var_Get( (vlc_object_t *)p_aout, psz_variable, &val ) < 0 )
1439         {
1440             vlc_object_release( (vlc_object_t *)p_aout );
1441             return VLC_EGENERIC;
1442         }
1443         i_value = val.i_int;
1444
1445         if ( var_Change( (vlc_object_t *)p_aout, psz_variable,
1446                          VLC_VAR_GETLIST, &val, &text ) < 0 )
1447         {
1448             vlc_object_release( (vlc_object_t *)p_aout );
1449             return VLC_EGENERIC;
1450         }
1451
1452         msg_rc( "+----[ %s ]\n", val_name.psz_string );
1453         for ( i = 0; i < val.p_list->i_count; i++ )
1454         {
1455             if ( i_value == val.p_list->p_values[i].i_int )
1456                 msg_rc( "| %i - %s *\n", val.p_list->p_values[i].i_int,
1457                         text.p_list->p_values[i].psz_string );
1458             else
1459                 msg_rc( "| %i - %s\n", val.p_list->p_values[i].i_int,
1460                         text.p_list->p_values[i].psz_string );
1461         }
1462         var_Change( (vlc_object_t *)p_aout, psz_variable, VLC_VAR_FREELIST,
1463                     &val, &text );
1464         msg_rc( "+----[ end of %s ]\n", val_name.psz_string );
1465
1466         if( val_name.psz_string ) free( val_name.psz_string );
1467         i_error = VLC_SUCCESS;
1468     }
1469     else
1470     {
1471         vlc_value_t val;
1472         val.i_int = atoi( newval.psz_string );
1473
1474         i_error = var_Set( (vlc_object_t *)p_aout, psz_variable, val );
1475     }
1476     vlc_object_release( (vlc_object_t *)p_aout );
1477
1478     return i_error;
1479 }
1480
1481 #ifdef WIN32
1482 vlc_bool_t ReadWin32( intf_thread_t *p_intf, char *p_buffer, int *pi_size )
1483 {
1484     INPUT_RECORD input_record;
1485     DWORD i_dw;
1486
1487     /* On Win32, select() only works on socket descriptors */
1488     while( WaitForSingleObject( p_intf->p_sys->hConsoleIn,
1489                                 INTF_IDLE_SLEEP/1000 ) == WAIT_OBJECT_0 )
1490     {
1491         while( !p_intf->b_die && *pi_size < MAX_LINE_LENGTH &&
1492                ReadConsoleInput( p_intf->p_sys->hConsoleIn, &input_record,
1493                                  1, &i_dw ) )
1494         {
1495             if( input_record.EventType != KEY_EVENT ||
1496                 !input_record.Event.KeyEvent.bKeyDown ||
1497                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT ||
1498                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL||
1499                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_MENU ||
1500                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_CAPITAL )
1501             {
1502                 /* nothing interesting */
1503                 continue;
1504             }
1505
1506             p_buffer[ *pi_size ] = input_record.Event.KeyEvent.uChar.AsciiChar;
1507
1508             /* Echo out the command */
1509             putc( p_buffer[ *pi_size ], stdout );
1510
1511             /* Handle special keys */
1512             if( p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
1513             {
1514                 putc( '\n', stdout );
1515                 break;
1516             }
1517             switch( p_buffer[ *pi_size ] )
1518             {
1519             case '\b':
1520                 if( *pi_size )
1521                 {
1522                     *pi_size -= 2;
1523                     putc( ' ', stdout );
1524                     putc( '\b', stdout );
1525                 }
1526                 break;
1527             case '\r':
1528                 (*pi_size) --;
1529                 break;
1530             }
1531
1532             (*pi_size)++;
1533         }
1534
1535         if( *pi_size == MAX_LINE_LENGTH ||
1536             p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
1537         {
1538             p_buffer[ *pi_size ] = 0;
1539             return VLC_TRUE;
1540         }
1541     }
1542
1543     return VLC_FALSE;
1544 }
1545 #endif
1546
1547 vlc_bool_t ReadCommand( intf_thread_t *p_intf, char *p_buffer, int *pi_size )
1548 {
1549     int i_read = 0;
1550
1551 #ifdef WIN32
1552     if( p_intf->p_sys->i_socket == -1 && !p_intf->p_sys->b_quiet )
1553         return ReadWin32( p_intf, p_buffer, pi_size );
1554     else if( p_intf->p_sys->i_socket == -1 )
1555     {
1556         msleep( INTF_IDLE_SLEEP );
1557         return VLC_FALSE;
1558     }
1559 #endif
1560
1561     while( !p_intf->b_die && *pi_size < MAX_LINE_LENGTH &&
1562            (i_read = net_ReadNonBlock( p_intf, p_intf->p_sys->i_socket == -1 ?
1563                        0 /*STDIN_FILENO*/ : p_intf->p_sys->i_socket, NULL,
1564                        p_buffer + *pi_size, 1, INTF_IDLE_SLEEP ) ) > 0 )
1565     {
1566         if( p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
1567             break;
1568
1569         (*pi_size)++;
1570     }
1571
1572     /* Connection closed */
1573     if( i_read == -1 )
1574     {
1575         p_intf->p_sys->i_socket = -1;
1576         p_buffer[ *pi_size ] = 0;
1577         return VLC_TRUE;
1578     }
1579
1580     if( *pi_size == MAX_LINE_LENGTH ||
1581         p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
1582     {
1583         p_buffer[ *pi_size ] = 0;
1584         return VLC_TRUE;
1585     }
1586
1587     return VLC_FALSE;
1588 }
1589
1590 /*****************************************************************************
1591  * parse_MRL: build a playlist item from a full mrl
1592  *****************************************************************************
1593  * MRL format: "simplified-mrl [:option-name[=option-value]]"
1594  * We don't check for '"' or '\'', we just assume that a ':' that follows a
1595  * space is a new option. Should be good enough for our purpose.
1596  *****************************************************************************/
1597 static playlist_item_t *parse_MRL( intf_thread_t *p_intf, char *psz_mrl )
1598 {
1599 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
1600 #define SKIPTRAILINGSPACE( p, d ) \
1601     { char *e=d; while( e > p && (*(e-1)==' ' || *(e-1)=='\t') ){e--;*e=0;} }
1602
1603     playlist_item_t *p_item = NULL;
1604     char *psz_item = NULL, *psz_item_mrl = NULL, *psz_orig;
1605     char **ppsz_options = NULL;
1606     int i, i_options = 0;
1607
1608     if( !psz_mrl ) return 0;
1609
1610     psz_mrl = psz_orig = strdup( psz_mrl );
1611     while( *psz_mrl )
1612     {
1613         SKIPSPACE( psz_mrl );
1614         psz_item = psz_mrl;
1615
1616         for( ; *psz_mrl; psz_mrl++ )
1617         {
1618             if( (*psz_mrl == ' ' || *psz_mrl == '\t') && psz_mrl[1] == ':' )
1619             {
1620                 /* We have a complete item */
1621                 break;
1622             }
1623             if( (*psz_mrl == ' ' || *psz_mrl == '\t') &&
1624                 (psz_mrl[1] == '"' || psz_mrl[1] == '\'') && psz_mrl[2] == ':')
1625             {
1626                 /* We have a complete item */
1627                 break;
1628             }
1629         }
1630
1631         if( *psz_mrl ) { *psz_mrl = 0; psz_mrl++; }
1632         SKIPTRAILINGSPACE( psz_item, psz_item + strlen( psz_item ) );
1633
1634         /* Remove '"' and '\'' if necessary */
1635         if( *psz_item == '"' && psz_item[strlen(psz_item)-1] == '"' )
1636         { psz_item++; psz_item[strlen(psz_item)-1] = 0; }
1637         if( *psz_item == '\'' && psz_item[strlen(psz_item)-1] == '\'' )
1638         { psz_item++; psz_item[strlen(psz_item)-1] = 0; }
1639
1640         if( !psz_item_mrl ) psz_item_mrl = psz_item;
1641         else if( *psz_item )
1642         {
1643             i_options++;
1644             ppsz_options = realloc( ppsz_options, i_options * sizeof(char *) );
1645             ppsz_options[i_options - 1] = &psz_item[1];
1646         }
1647
1648         if( *psz_mrl ) SKIPSPACE( psz_mrl );
1649     }
1650
1651     /* Now create a playlist item */
1652     if( psz_item_mrl )
1653     {
1654         p_item = playlist_ItemNew( p_intf, psz_item_mrl, psz_item_mrl );
1655         for( i = 0; i < i_options; i++ )
1656         {
1657             playlist_ItemAddOption( p_item, ppsz_options[i] );
1658         }
1659     }
1660
1661     if( i_options ) free( ppsz_options );
1662     free( psz_orig );
1663
1664     return p_item;
1665 }