]> git.sesse.net Git - vlc/blob - modules/control/rc.c
* Add atrack, vtrack and strack commands. Those can be use to display/change audio...
[vlc] / modules / control / rc.c
1 /*****************************************************************************
2  * rc.c : remote control stdin/stdout module for vlc
3  *****************************************************************************
4  * Copyright (C) 2004 - 2005 the VideoLAN team
5  * $Id$
6  *
7  * Author: Peter Surda <shurdeek@panorama.sth.ac.at>
8  *         Jean-Paul Saman <jpsaman #_at_# m2x _replaceWith#dot_ nl>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <string.h>
30
31 #include <errno.h>                                                 /* ENOMEM */
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <signal.h>
35
36 #include <vlc/vlc.h>
37 #include <vlc/intf.h>
38 #include <vlc/aout.h>
39 #include <vlc/vout.h>
40 #include <vlc_video.h>
41 #include <vlc_osd.h>
42 #include <vlc_update.h>
43
44 #ifdef HAVE_UNISTD_H
45 #    include <unistd.h>
46 #endif
47
48 #ifdef HAVE_SYS_TIME_H
49 #    include <sys/time.h>
50 #endif
51 #include <sys/types.h>
52
53 #include "vlc_error.h"
54 #include "network.h"
55 #include "vlc_url.h"
56
57 #if defined(AF_UNIX) && !defined(AF_LOCAL)
58 #    define AF_LOCAL AF_UNIX
59 #endif
60
61 #if defined(AF_LOCAL) && ! defined(WIN32)
62 #    include <sys/un.h>
63 #endif
64
65 #define MAX_LINE_LENGTH 256
66 #define STATUS_CHANGE "status change: "
67
68 /*****************************************************************************
69  * Local prototypes
70  *****************************************************************************/
71 static int  Activate     ( vlc_object_t * );
72 static void Deactivate   ( vlc_object_t * );
73 static void Run          ( intf_thread_t * );
74
75 static void Help         ( intf_thread_t *, vlc_bool_t );
76 static void RegisterCallbacks( intf_thread_t * );
77
78 static vlc_bool_t ReadCommand( intf_thread_t *, char *, int * );
79
80 static input_item_t *parse_MRL( intf_thread_t *, char * );
81
82 static int  Input        ( vlc_object_t *, char const *,
83                            vlc_value_t, vlc_value_t, void * );
84 static int  Playlist     ( vlc_object_t *, char const *,
85                            vlc_value_t, vlc_value_t, void * );
86 static int  Other        ( vlc_object_t *, char const *,
87                            vlc_value_t, vlc_value_t, void * );
88 static int  Quit         ( vlc_object_t *, char const *,
89                            vlc_value_t, vlc_value_t, void * );
90 static int  Intf         ( vlc_object_t *, char const *,
91                            vlc_value_t, vlc_value_t, void * );
92 static int  Volume       ( vlc_object_t *, char const *,
93                            vlc_value_t, vlc_value_t, void * );
94 static int  VolumeMove   ( vlc_object_t *, char const *,
95                            vlc_value_t, vlc_value_t, void * );
96 static int  AudioConfig  ( vlc_object_t *, char const *,
97                            vlc_value_t, vlc_value_t, void * );
98 static int  Menu         ( vlc_object_t *, char const *,
99                            vlc_value_t, vlc_value_t, void * );
100 static void checkUpdates( intf_thread_t *p_intf, char *psz_arg );
101
102 /* Status Callbacks */
103 static int TimeOffsetChanged( vlc_object_t *, char const *,
104                               vlc_value_t, vlc_value_t , void * );
105 static int VolumeChanged    ( vlc_object_t *, char const *,
106                               vlc_value_t, vlc_value_t, void * );
107 static int StateChanged     ( vlc_object_t *, char const *,
108                               vlc_value_t, vlc_value_t, void * );
109 static int RateChanged      ( vlc_object_t *, char const *,
110                               vlc_value_t, vlc_value_t, void * );
111
112 struct intf_sys_t
113 {
114     int *pi_socket_listen;
115     int i_socket;
116     char *psz_unix_path;
117
118     /* status changes */
119     vlc_mutex_t       status_lock;
120     playlist_status_t i_last_state;
121
122 #ifdef WIN32
123     HANDLE hConsoleIn;
124     vlc_bool_t b_quiet;
125 #endif
126 };
127
128 #ifdef HAVE_VARIADIC_MACROS
129 #   define msg_rc( psz_format, args... ) \
130       __msg_rc( p_intf, psz_format, ## args )
131 #endif
132
133 void __msg_rc( intf_thread_t *p_intf, const char *psz_fmt, ... )
134 {
135     va_list args;
136     va_start( args, psz_fmt );
137
138     if( p_intf->p_sys->i_socket == -1 )
139     {
140         vprintf( psz_fmt, args );
141         printf( "\r\n" );
142     }
143     else
144     {
145         net_vaPrintf( p_intf, p_intf->p_sys->i_socket, NULL, psz_fmt, args );
146         net_Write( p_intf, p_intf->p_sys->i_socket, NULL, (uint8_t*)"\r\n", 2 );
147     }
148     va_end( args );
149 }
150
151 /*****************************************************************************
152  * Module descriptor
153  *****************************************************************************/
154 #define POS_TEXT N_("Show stream position")
155 #define POS_LONGTEXT N_("Show the current position in seconds within the " \
156                         "stream from time to time." )
157
158 #define TTY_TEXT N_("Fake TTY")
159 #define TTY_LONGTEXT N_("Force the rc module to use stdin as if it was a TTY.")
160
161 #define UNIX_TEXT N_("UNIX socket command input")
162 #define UNIX_LONGTEXT N_("Accept commands over a Unix socket rather than " \
163                          "stdin." )
164
165 #define HOST_TEXT N_("TCP command input")
166 #define HOST_LONGTEXT N_("Accept commands over a socket rather than stdin. " \
167             "You can set the address and port the interface will bind to." )
168
169 #ifdef WIN32
170 #define QUIET_TEXT N_("Do not open a DOS command box interface")
171 #define QUIET_LONGTEXT N_( \
172     "By default the rc interface plugin will start a DOS command box. " \
173     "Enabling the quiet mode will not bring this command box but can also " \
174     "be pretty annoying when you want to stop VLC and no video window is " \
175     "open." )
176 #endif
177
178 vlc_module_begin();
179     set_shortname( _("RC"));
180     set_category( CAT_INTERFACE );
181     set_subcategory( SUBCAT_INTERFACE_MAIN );
182     set_description( _("Remote control interface") );
183     add_bool( "rc-show-pos", 0, NULL, POS_TEXT, POS_LONGTEXT, VLC_TRUE );
184 #ifdef HAVE_ISATTY
185     add_bool( "rc-fake-tty", 0, NULL, TTY_TEXT, TTY_LONGTEXT, VLC_TRUE );
186 #endif
187     add_string( "rc-unix", 0, NULL, UNIX_TEXT, UNIX_LONGTEXT, VLC_TRUE );
188     add_string( "rc-host", 0, NULL, HOST_TEXT, HOST_LONGTEXT, VLC_TRUE );
189
190 #ifdef WIN32
191     add_bool( "rc-quiet", 0, NULL, QUIET_TEXT, QUIET_LONGTEXT, VLC_FALSE );
192 #endif
193
194     set_capability( "interface", 20 );
195     set_callbacks( Activate, Deactivate );
196 vlc_module_end();
197
198 /*****************************************************************************
199  * Activate: initialize and create stuff
200  *****************************************************************************/
201 static int Activate( vlc_object_t *p_this )
202 {
203     intf_thread_t *p_intf = (intf_thread_t*)p_this;
204     char *psz_host, *psz_unix_path;
205     int  *pi_socket = NULL;
206
207 #if defined(HAVE_ISATTY) && !defined(WIN32)
208     /* Check that stdin is a TTY */
209     if( !config_GetInt( p_intf, "rc-fake-tty" ) && !isatty( 0 ) )
210     {
211         msg_Warn( p_intf, "fd 0 is not a TTY" );
212         return VLC_EGENERIC;
213     }
214 #endif
215
216     psz_unix_path = config_GetPsz( p_intf, "rc-unix" );
217     if( psz_unix_path )
218     {
219         int i_socket;
220
221 #if !defined(AF_LOCAL) || defined(WIN32)
222         msg_Warn( p_intf, "your OS doesn't support filesystem sockets" );
223         free( psz_unix_path );
224         return VLC_EGENERIC;
225 #else
226         struct sockaddr_un addr;
227         int i_ret;
228
229         memset( &addr, 0, sizeof(struct sockaddr_un) );
230
231         msg_Dbg( p_intf, "trying UNIX socket" );
232
233         if( (i_socket = socket( AF_LOCAL, SOCK_STREAM, 0 ) ) < 0 )
234         {
235             msg_Warn( p_intf, "can't open socket: %s", strerror(errno) );
236             free( psz_unix_path );
237             return VLC_EGENERIC;
238         }
239
240         addr.sun_family = AF_LOCAL;
241         strncpy( addr.sun_path, psz_unix_path, sizeof( addr.sun_path ) );
242         addr.sun_path[sizeof( addr.sun_path ) - 1] = '\0';
243
244         if( (i_ret = bind( i_socket, (struct sockaddr*)&addr,
245                            sizeof(struct sockaddr_un) ) ) < 0 )
246         {
247             msg_Warn( p_intf, "couldn't bind socket to address: %s",
248                       strerror(errno) );
249             free( psz_unix_path );
250             net_Close( i_socket );
251             return VLC_EGENERIC;
252         }
253
254         if( ( i_ret = listen( i_socket, 1 ) ) < 0 )
255         {
256             msg_Warn( p_intf, "can't listen on socket: %s", strerror(errno));
257             free( psz_unix_path );
258             net_Close( i_socket );
259             return VLC_EGENERIC;
260         }
261
262         /* FIXME: we need a core function to merge listening sockets sets */
263         pi_socket = calloc( 2, sizeof( int ) );
264         if( pi_socket == NULL )
265         {
266             free( psz_unix_path );
267             net_Close( i_socket );
268             return VLC_ENOMEM;
269         }
270         pi_socket[0] = i_socket;
271         pi_socket[1] = -1;
272 #endif
273     }
274
275     if( ( pi_socket == NULL ) &&
276         ( psz_host = config_GetPsz( p_intf, "rc-host" ) ) != NULL )
277     {
278         vlc_url_t url;
279
280         vlc_UrlParse( &url, psz_host, 0 );
281
282         msg_Dbg( p_intf, "base: %s, port: %d", url.psz_host, url.i_port );
283
284         pi_socket = net_ListenTCP(p_this, url.psz_host, url.i_port);
285         if( pi_socket == NULL )
286         {
287             msg_Warn( p_intf, "can't listen to %s port %i",
288                       url.psz_host, url.i_port );
289             vlc_UrlClean( &url );
290             free( psz_host );
291             return VLC_EGENERIC;
292         }
293
294         vlc_UrlClean( &url );
295         free( psz_host );
296     }
297
298     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
299     if( !p_intf->p_sys )
300     {
301         msg_Err( p_intf, "no memory" );
302         return VLC_ENOMEM;
303     }
304
305     p_intf->p_sys->pi_socket_listen = pi_socket;
306     p_intf->p_sys->i_socket = -1;
307     p_intf->p_sys->psz_unix_path = psz_unix_path;
308     vlc_mutex_init( p_intf, &p_intf->p_sys->status_lock );
309     p_intf->p_sys->i_last_state = PLAYLIST_STOPPED;
310
311     /* Non-buffered stdout */
312     setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
313
314     p_intf->pf_run = Run;
315
316 #ifdef WIN32
317     p_intf->p_sys->b_quiet = config_GetInt( p_intf, "rc-quiet" );
318     if( !p_intf->p_sys->b_quiet ) { CONSOLE_INTRO_MSG; }
319 #else
320     CONSOLE_INTRO_MSG;
321 #endif
322
323     msg_rc( _("Remote control interface initialized. Type `help' for help.") );
324     return VLC_SUCCESS;
325 }
326
327 /*****************************************************************************
328  * Deactivate: uninitialize and cleanup
329  *****************************************************************************/
330 static void Deactivate( vlc_object_t *p_this )
331 {
332     intf_thread_t *p_intf = (intf_thread_t*)p_this;
333
334     net_ListenClose( p_intf->p_sys->pi_socket_listen );
335     if( p_intf->p_sys->i_socket != -1 )
336         net_Close( p_intf->p_sys->i_socket );
337     if( p_intf->p_sys->psz_unix_path != NULL )
338     {
339 #if defined(AF_LOCAL) && !defined(WIN32)
340         unlink( p_intf->p_sys->psz_unix_path );
341 #endif
342         free( p_intf->p_sys->psz_unix_path );
343     }
344     vlc_mutex_destroy( &p_intf->p_sys->status_lock );
345     free( p_intf->p_sys );
346 }
347
348 /*****************************************************************************
349  * RegisterCallbacks: Register callbacks to dynamic variables
350  *****************************************************************************/
351 static void RegisterCallbacks( intf_thread_t *p_intf )
352 {
353     /* Register commands that will be cleaned up upon object destruction */
354     var_Create( p_intf, "quit", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
355     var_AddCallback( p_intf, "quit", Quit, NULL );
356     var_Create( p_intf, "intf", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
357     var_AddCallback( p_intf, "intf", Intf, NULL );
358
359     var_Create( p_intf, "add", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
360     var_AddCallback( p_intf, "add", Playlist, NULL );
361     var_Create( p_intf, "enqueue", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
362     var_AddCallback( p_intf, "enqueue", Playlist, NULL );
363     var_Create( p_intf, "playlist", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
364     var_AddCallback( p_intf, "playlist", Playlist, NULL );
365     var_Create( p_intf, "sort", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
366     var_AddCallback( p_intf, "sort", Playlist, NULL );
367     var_Create( p_intf, "play", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
368     var_AddCallback( p_intf, "play", Playlist, NULL );
369     var_Create( p_intf, "stop", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
370     var_AddCallback( p_intf, "stop", Playlist, NULL );
371     var_Create( p_intf, "clear", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
372     var_AddCallback( p_intf, "clear", Playlist, NULL );
373     var_Create( p_intf, "prev", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
374     var_AddCallback( p_intf, "prev", Playlist, NULL );
375     var_Create( p_intf, "next", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
376     var_AddCallback( p_intf, "next", Playlist, NULL );
377     var_Create( p_intf, "goto", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
378     var_AddCallback( p_intf, "goto", Playlist, NULL );
379     var_Create( p_intf, "status", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
380     var_AddCallback( p_intf, "status", Playlist, NULL );
381
382     /* marquee on the fly items */
383     var_Create( p_intf, "marq-marquee", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
384     var_AddCallback( p_intf, "marq-marquee", Other, NULL );
385     var_Create( p_intf, "marq-x", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
386     var_AddCallback( p_intf, "marq-x", Other, NULL );
387     var_Create( p_intf, "marq-y", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
388     var_AddCallback( p_intf, "marq-y", Other, NULL );
389     var_Create( p_intf, "marq-position", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
390     var_AddCallback( p_intf, "marq-position", Other, NULL );
391     var_Create( p_intf, "marq-color", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
392     var_AddCallback( p_intf, "marq-color", Other, NULL );
393     var_Create( p_intf, "marq-opacity", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
394     var_AddCallback( p_intf, "marq-opacity", Other, NULL );
395     var_Create( p_intf, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
396     var_AddCallback( p_intf, "marq-timeout", Other, NULL );
397     var_Create( p_intf, "marq-size", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
398     var_AddCallback( p_intf, "marq-size", Other, NULL );
399
400     var_Create( p_intf, "mosaic-alpha", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
401     var_AddCallback( p_intf, "mosaic-alpha", Other, NULL );
402     var_Create( p_intf, "mosaic-height", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
403     var_AddCallback( p_intf, "mosaic-height", Other, NULL );
404     var_Create( p_intf, "mosaic-width", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
405     var_AddCallback( p_intf, "mosaic-width", Other, NULL );
406     var_Create( p_intf, "mosaic-xoffset", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
407     var_AddCallback( p_intf, "mosaic-xoffset", Other, NULL );
408     var_Create( p_intf, "mosaic-yoffset", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
409     var_AddCallback( p_intf, "mosaic-yoffset", Other, NULL );
410     var_Create( p_intf, "mosaic-align", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
411     var_AddCallback( p_intf, "mosaic-align", Other, NULL );
412     var_Create( p_intf, "mosaic-vborder", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
413     var_AddCallback( p_intf, "mosaic-vborder", Other, NULL );
414     var_Create( p_intf, "mosaic-hborder", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
415     var_AddCallback( p_intf, "mosaic-hborder", Other, NULL );
416     var_Create( p_intf, "mosaic-position",
417                      VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
418     var_AddCallback( p_intf, "mosaic-position", Other, NULL );
419     var_Create( p_intf, "mosaic-rows", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
420     var_AddCallback( p_intf, "mosaic-rows", Other, NULL );
421     var_Create( p_intf, "mosaic-cols", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
422     var_AddCallback( p_intf, "mosaic-cols", Other, NULL );
423     var_Create( p_intf, "mosaic-order", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
424     var_AddCallback( p_intf, "mosaic-order", Other, NULL );
425     var_Create( p_intf, "mosaic-keep-aspect-ratio",
426                      VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
427     var_AddCallback( p_intf, "mosaic-keep-aspect-ratio", Other, NULL );
428
429     /* time on the fly items */
430     var_Create( p_intf, "time-format", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
431     var_AddCallback( p_intf, "time-format", Other, NULL );
432     var_Create( p_intf, "time-x", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
433     var_AddCallback( p_intf, "time-x", Other, NULL );
434     var_Create( p_intf, "time-y", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
435     var_AddCallback( p_intf, "time-y", Other, NULL );
436     var_Create( p_intf, "time-position", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
437     var_AddCallback( p_intf, "time-position", Other, NULL );
438     var_Create( p_intf, "time-color", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
439     var_AddCallback( p_intf, "time-color", Other, NULL );
440     var_Create( p_intf, "time-opacity", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
441     var_AddCallback( p_intf, "time-opacity", Other, NULL );
442     var_Create( p_intf, "time-size", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
443     var_AddCallback( p_intf, "time-size", Other, NULL );
444
445     /* logo on the fly items */
446     var_Create( p_intf, "logo-file", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
447     var_AddCallback( p_intf, "logo-file", Other, NULL );
448     var_Create( p_intf, "logo-x", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
449     var_AddCallback( p_intf, "logo-x", Other, NULL );
450     var_Create( p_intf, "logo-y", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
451     var_AddCallback( p_intf, "logo-y", Other, NULL );
452     var_Create( p_intf, "logo-position", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
453     var_AddCallback( p_intf, "logo-position", Other, NULL );
454     var_Create( p_intf, "logo-transparency", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
455     var_AddCallback( p_intf, "logo-transparency", Other, NULL );
456
457     /* OSD menu commands */
458     var_Create( p_intf, "menu", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
459     var_AddCallback( p_intf, "menu", Menu, NULL );
460
461     /* DVD commands */
462     var_Create( p_intf, "pause", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
463     var_AddCallback( p_intf, "pause", Input, NULL );
464     var_Create( p_intf, "seek", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
465     var_AddCallback( p_intf, "seek", Input, NULL );
466     var_Create( p_intf, "title", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
467     var_AddCallback( p_intf, "title", Input, NULL );
468     var_Create( p_intf, "title_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
469     var_AddCallback( p_intf, "title_n", Input, NULL );
470     var_Create( p_intf, "title_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
471     var_AddCallback( p_intf, "title_p", Input, NULL );
472     var_Create( p_intf, "chapter", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
473     var_AddCallback( p_intf, "chapter", Input, NULL );
474     var_Create( p_intf, "chapter_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
475     var_AddCallback( p_intf, "chapter_n", Input, NULL );
476     var_Create( p_intf, "chapter_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
477     var_AddCallback( p_intf, "chapter_p", Input, NULL );
478
479     var_Create( p_intf, "fastforward", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
480     var_AddCallback( p_intf, "fastforward", Input, NULL );
481     var_Create( p_intf, "rewind", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
482     var_AddCallback( p_intf, "rewind", Input, NULL );
483     var_Create( p_intf, "faster", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
484     var_AddCallback( p_intf, "faster", Input, NULL );
485     var_Create( p_intf, "slower", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
486     var_AddCallback( p_intf, "slower", Input, NULL );
487     var_Create( p_intf, "normal", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
488     var_AddCallback( p_intf, "normal", Input, NULL );
489
490     var_Create( p_intf, "atrack", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
491     var_AddCallback( p_intf, "atrack", Input, NULL );
492     var_Create( p_intf, "vtrack", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
493     var_AddCallback( p_intf, "vtrack", Input, NULL );
494     var_Create( p_intf, "strack", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
495     var_AddCallback( p_intf, "strack", Input, NULL );
496
497     /* audio commands */
498     var_Create( p_intf, "volume", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
499     var_AddCallback( p_intf, "volume", Volume, NULL );
500     var_Create( p_intf, "volup", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
501     var_AddCallback( p_intf, "volup", VolumeMove, NULL );
502     var_Create( p_intf, "voldown", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
503     var_AddCallback( p_intf, "voldown", VolumeMove, NULL );
504     var_Create( p_intf, "adev", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
505     var_AddCallback( p_intf, "adev", AudioConfig, NULL );
506     var_Create( p_intf, "achan", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
507     var_AddCallback( p_intf, "achan", AudioConfig, NULL );
508 }
509
510 /*****************************************************************************
511  * Run: rc thread
512  *****************************************************************************
513  * This part of the interface is in a separate thread so that we can call
514  * exec() from within it without annoying the rest of the program.
515  *****************************************************************************/
516 static void Run( intf_thread_t *p_intf )
517 {
518     input_thread_t * p_input;
519     playlist_t *     p_playlist;
520
521     char       p_buffer[ MAX_LINE_LENGTH + 1 ];
522     vlc_bool_t b_showpos = config_GetInt( p_intf, "rc-show-pos" );
523     vlc_bool_t b_longhelp = VLC_FALSE;
524
525     int        i_size = 0;
526     int        i_oldpos = 0;
527     int        i_newpos;
528
529     p_buffer[0] = 0;
530     p_input = NULL;
531     p_playlist = NULL;
532
533     /* Register commands that will be cleaned up upon object destruction */
534     RegisterCallbacks( p_intf );
535
536     /* status callbacks */
537     /* Listen to audio volume updates */
538     var_AddCallback( p_intf->p_vlc, "volume-change", VolumeChanged, p_intf );
539
540 #ifdef WIN32
541     /* Get the file descriptor of the console input */
542     p_intf->p_sys->hConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
543     if( p_intf->p_sys->hConsoleIn == INVALID_HANDLE_VALUE )
544     {
545         msg_Err( p_intf, "couldn't find user input handle" );
546         p_intf->b_die = VLC_TRUE;
547     }
548 #endif
549
550     while( !p_intf->b_die )
551     {
552         char *psz_cmd, *psz_arg;
553         vlc_bool_t b_complete;
554
555         if( p_intf->p_sys->pi_socket_listen != NULL &&
556             p_intf->p_sys->i_socket == -1 )
557         {
558             p_intf->p_sys->i_socket =
559                 net_Accept( p_intf, p_intf->p_sys->pi_socket_listen, 0 );
560         }
561
562         b_complete = ReadCommand( p_intf, p_buffer, &i_size );
563
564         /* Manage the input part */
565         if( p_input == NULL )
566         {
567             if( p_playlist )
568             {
569                 p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT,
570                                                        FIND_CHILD );
571             }
572             else
573             {
574                 p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
575                                                    FIND_ANYWHERE );
576                 if( p_input )
577                 {
578                     p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
579                                                            FIND_PARENT );
580                 }
581             }
582             /* New input has been registered */
583             if( p_input )
584             {
585                 if( !p_input->b_dead || !p_input->b_die )
586                 {
587                     msg_rc( STATUS_CHANGE "( new input: %s )", p_input->input.p_item->psz_uri );
588                     msg_rc( STATUS_CHANGE "( audio volume: %d )", config_GetInt( p_intf, "volume" ));
589                 }
590                 var_AddCallback( p_input, "state", StateChanged, p_intf );
591                 var_AddCallback( p_input, "rate-faster", RateChanged, p_intf );
592                 var_AddCallback( p_input, "rate-slower", RateChanged, p_intf );
593                 var_AddCallback( p_input, "rate", RateChanged, p_intf );
594                 var_AddCallback( p_input, "time-offset", TimeOffsetChanged, p_intf );
595             }
596         }
597         else if( p_input->b_dead )
598         {
599             var_DelCallback( p_input, "state", StateChanged, p_intf );
600             var_DelCallback( p_input, "rate-faster", RateChanged, p_intf );
601             var_DelCallback( p_input, "rate-slower", RateChanged, p_intf );
602             var_DelCallback( p_input, "rate", RateChanged, p_intf );
603             var_DelCallback( p_input, "time-offset", TimeOffsetChanged, p_intf );
604             vlc_object_release( p_input );
605             p_input = NULL;
606
607             if( p_playlist )
608             {
609                 vlc_mutex_lock( &p_playlist->object_lock );
610                 p_intf->p_sys->i_last_state = (int) PLAYLIST_STOPPED;
611                 msg_rc( STATUS_CHANGE "( stop state: 0 )" );
612                 vlc_mutex_unlock( &p_playlist->object_lock );
613             }
614         }
615
616         if( (p_input != NULL) && !p_input->b_dead && !p_input->b_die &&
617             (p_playlist != NULL) )
618         {
619             vlc_mutex_lock( &p_playlist->object_lock );
620             if( (p_intf->p_sys->i_last_state != p_playlist->status.i_status) &&
621                 (p_playlist->status.i_status == PLAYLIST_STOPPED) )
622             {
623                 p_intf->p_sys->i_last_state = PLAYLIST_STOPPED;
624                 msg_rc( STATUS_CHANGE "( stop state: 0 )" );
625             }
626             else if( (p_intf->p_sys->i_last_state != p_playlist->status.i_status) &&
627                 (p_playlist->status.i_status == PLAYLIST_RUNNING) )
628             {
629                 p_intf->p_sys->i_last_state = p_playlist->status.i_status;
630                 msg_rc( STATUS_CHANGE "( play state: 1 )" );
631             }
632             else if( (p_intf->p_sys->i_last_state != p_playlist->status.i_status) &&
633                 (p_playlist->status.i_status == PLAYLIST_PAUSED) )
634             {
635                 p_intf->p_sys->i_last_state = p_playlist->status.i_status;
636                 msg_rc( STATUS_CHANGE "( pause state: 2 )" );
637             }
638             vlc_mutex_unlock( &p_playlist->object_lock );
639         }
640
641         if( p_input && b_showpos )
642         {
643             i_newpos = 100 * var_GetFloat( p_input, "position" );
644             if( i_oldpos != i_newpos )
645             {
646                 i_oldpos = i_newpos;
647                 msg_rc( "pos: %d%%", i_newpos );
648             }
649         }
650
651         /* Is there something to do? */
652         if( !b_complete ) continue;
653
654
655         /* Skip heading spaces */
656         psz_cmd = p_buffer;
657         while( *psz_cmd == ' ' )
658         {
659             psz_cmd++;
660         }
661
662         /* Split psz_cmd at the first space and make sure that
663          * psz_arg is valid */
664         psz_arg = strchr( psz_cmd, ' ' );
665         if( psz_arg )
666         {
667             *psz_arg++ = 0;
668             while( *psz_arg == ' ' )
669             {
670                 psz_arg++;
671             }
672         }
673         else
674         {
675             psz_arg = "";
676         }
677
678         /* If the user typed a registered local command, try it */
679         if( var_Type( p_intf, psz_cmd ) & VLC_VAR_ISCOMMAND )
680         {
681             vlc_value_t val;
682             int i_ret;
683
684             val.psz_string = psz_arg;
685             i_ret = var_Set( p_intf, psz_cmd, val );
686             msg_rc( "%s: returned %i (%s)",
687                     psz_cmd, i_ret, vlc_error( i_ret ) );
688         }
689         /* Or maybe it's a global command */
690         else if( var_Type( p_intf->p_libvlc, psz_cmd ) & VLC_VAR_ISCOMMAND )
691         {
692             vlc_value_t val;
693             int i_ret;
694
695             val.psz_string = psz_arg;
696             /* FIXME: it's a global command, but we should pass the
697              * local object as an argument, not p_intf->p_libvlc. */
698             i_ret = var_Set( p_intf->p_libvlc, psz_cmd, val );
699             if( i_ret != 0 )
700             {
701                 msg_rc( "%s: returned %i (%s)",
702                          psz_cmd, i_ret, vlc_error( i_ret ) );
703             }
704         }
705         else if( !strcmp( psz_cmd, "logout" ) )
706         {
707             /* Close connection */
708             if( p_intf->p_sys->i_socket != -1 )
709             {
710                 net_Close( p_intf->p_sys->i_socket );
711             }
712             p_intf->p_sys->i_socket = -1;
713         }
714         else if( !strcmp( psz_cmd, "info" ) )
715         {
716             if( p_input )
717             {
718                 int i, j;
719                 vlc_mutex_lock( &p_input->input.p_item->lock );
720                 for ( i = 0; i < p_input->input.p_item->i_categories; i++ )
721                 {
722                     info_category_t *p_category =
723                         p_input->input.p_item->pp_categories[i];
724
725                     msg_rc( "+----[ %s ]", p_category->psz_name );
726                     msg_rc( "| " );
727                     for ( j = 0; j < p_category->i_infos; j++ )
728                     {
729                         info_t *p_info = p_category->pp_infos[j];
730                         msg_rc( "| %s: %s", p_info->psz_name,
731                                 p_info->psz_value );
732                     }
733                     msg_rc( "| " );
734                 }
735                 msg_rc( "+----[ end of stream info ]" );
736                 vlc_mutex_unlock( &p_input->input.p_item->lock );
737             }
738             else
739             {
740                 msg_rc( "no input" );
741             }
742         }
743         else if( !strcmp( psz_cmd, "is_playing" ) )
744         {
745             if( ! p_input )
746             {
747                 msg_rc( "0" );
748             }
749             else
750             {
751                 msg_rc( "1" );
752             }
753         }
754         else if( !strcmp( psz_cmd, "get_time" ) )
755         {
756             if( ! p_input )
757             {
758                 msg_rc("0");
759             }
760             else
761             {
762                 vlc_value_t time;
763                 var_Get( p_input, "time", &time );
764                 msg_rc( "%i", time.i_time / 1000000);
765             }
766         }
767         else if( !strcmp( psz_cmd, "get_length" ) )
768         {
769             if( ! p_input )
770             {
771                 msg_rc("0");
772             }
773             else
774             {
775                 vlc_value_t time;
776                 var_Get( p_input, "length", &time );
777                 msg_rc( "%i", time.i_time / 1000000);
778             }
779         }
780         else if( !strcmp( psz_cmd, "get_title" ) )
781         {
782             if( ! p_input )
783             {
784                 msg_rc("");
785             }
786             else
787             {
788                 msg_rc( "%s", p_input->input.p_item->psz_name );
789             }
790         }
791         else if( !strcmp( psz_cmd, "longhelp" ) || !strncmp( psz_cmd, "h", 1 )
792                  || !strncmp( psz_cmd, "H", 1 ) || !strncmp( psz_cmd, "?", 1 ) )
793         {
794             if( !strcmp( psz_cmd, "longhelp" ) || !strncmp( psz_cmd, "H", 1 ) )
795                  b_longhelp = VLC_TRUE;
796             else b_longhelp = VLC_FALSE;
797
798             Help( p_intf, b_longhelp );
799         }
800         else if( !strcmp( psz_cmd, "check-updates" ) )
801         {
802             checkUpdates( p_intf, psz_arg );
803         }
804         else switch( psz_cmd[0] )
805         {
806         case 'f':
807         case 'F':
808             if( p_input )
809             {
810                 vout_thread_t *p_vout;
811                 p_vout = vlc_object_find( p_input,
812                                           VLC_OBJECT_VOUT, FIND_CHILD );
813
814                 if( p_vout )
815                 {
816                     vlc_value_t val;
817                     vlc_bool_t b_update = VLC_FALSE;
818                     var_Get( p_vout, "fullscreen", &val );
819                     val.b_bool = !val.b_bool;
820                     if( !strncmp(psz_arg, "on", 2) && (val.b_bool == VLC_TRUE) )
821                     {
822                         b_update = VLC_TRUE;
823                         val.b_bool = VLC_TRUE;
824                     }
825                     else if( !strncmp(psz_arg, "off", 3)  && (val.b_bool == VLC_FALSE) )
826                     {
827                         b_update = VLC_TRUE;
828                         val.b_bool = VLC_FALSE;
829                     }
830                     else if( strncmp(psz_arg, "off", 3) && strncmp(psz_arg, "on", 2) )
831                         b_update = VLC_TRUE;
832                     if( b_update ) var_Set( p_vout, "fullscreen", val );
833                     vlc_object_release( p_vout );
834                 }
835             }
836             break;
837
838         case 's':
839         case 'S':
840             ;
841             break;
842
843         case '\0':
844             /* Ignore empty lines */
845             break;
846
847         default:
848             msg_rc(_("Unknown command `%s'. Type `help' for help."), psz_cmd);
849             break;
850         }
851
852         /* Command processed */
853         i_size = 0; p_buffer[0] = 0;
854     }
855
856     msg_rc( STATUS_CHANGE "( stop state: 0 )" );
857     msg_rc( STATUS_CHANGE "( quit )" );
858
859     if( p_input )
860     {
861         var_DelCallback( p_input, "state", StateChanged, p_intf );
862         var_DelCallback( p_input, "rate-faster", RateChanged, p_intf );
863         var_DelCallback( p_input, "rate-slower", RateChanged, p_intf );
864         var_DelCallback( p_input, "rate", RateChanged, p_intf );
865         var_DelCallback( p_input, "time-offset", TimeOffsetChanged, p_intf );
866         vlc_object_release( p_input );
867         p_input = NULL;
868     }
869
870     if( p_playlist )
871     {
872         vlc_object_release( p_playlist );
873         p_playlist = NULL;
874     }
875
876     var_DelCallback( p_intf->p_vlc, "volume-change", VolumeChanged, p_intf );
877 }
878
879 static void Help( intf_thread_t *p_intf, vlc_bool_t b_longhelp)
880 {
881     msg_rc(_("+----[ Remote control commands ]"));
882     msg_rc(  "| ");
883     msg_rc(_("| add XYZ  . . . . . . . . . . add XYZ to playlist"));
884     msg_rc(_("| enqueue XYZ  . . . . . . . queue XYZ to playlist"));
885     msg_rc(_("| playlist . . .  show items currently in playlist"));
886     msg_rc(_("| play . . . . . . . . . . . . . . . . play stream"));
887     msg_rc(_("| stop . . . . . . . . . . . . . . . . stop stream"));
888     msg_rc(_("| next . . . . . . . . . . . .  next playlist item"));
889     msg_rc(_("| prev . . . . . . . . . .  previous playlist item"));
890     msg_rc(_("| goto . . . . . . . . . . . .  goto item at index"));
891     msg_rc(_("| clear . . . . . . . . . . .   clear the playlist"));
892     msg_rc(_("| status . . . . . . . . . current playlist status"));
893     msg_rc(_("| title [X]  . . . . set/get title in current item"));
894     msg_rc(_("| title_n  . . . . . .  next title in current item"));
895     msg_rc(_("| title_p  . . . .  previous title in current item"));
896     msg_rc(_("| chapter [X]  . . set/get chapter in current item"));
897     msg_rc(_("| chapter_n  . . . .  next chapter in current item"));
898     msg_rc(_("| chapter_p  . .  previous chapter in current item"));
899     msg_rc(  "| ");
900     msg_rc(_("| seek X . seek in seconds, for instance `seek 12'"));
901     msg_rc(_("| pause  . . . . . . . . . . . . . .  toggle pause"));
902     msg_rc(_("| fastforward  . . . . . .  .  set to maximum rate"));
903     msg_rc(_("| rewind  . . . . . . . . . .  set to minimum rate"));
904     msg_rc(_("| faster . . . . . . . .  faster playing of stream"));
905     msg_rc(_("| slower . . . . . . . .  slower playing of stream"));
906     msg_rc(_("| normal . . . . . . . .  normal playing of stream"));
907     msg_rc(_("| f [on|off] . . . . . . . . . . toggle fullscreen"));
908     msg_rc(_("| info . . .  information about the current stream"));
909     msg_rc(_("| get_time . . seconds elapsed since stream's beginning"));
910     msg_rc(_("| is_playing . .  1 if a stream plays, 0 otherwise"));
911     msg_rc(_("| get_title . . .  the title of the current stream"));
912     msg_rc(_("| get_length . .  the length of the current stream"));
913     msg_rc(  "| ");
914     msg_rc(_("| volume [X] . . . . . . . .  set/get audio volume"));
915     msg_rc(_("| volup [X]  . . . . .  raise audio volume X steps"));
916     msg_rc(_("| voldown [X]  . . . .  lower audio volume X steps"));
917     msg_rc(_("| adev [X] . . . . . . . . .  set/get audio device"));
918     msg_rc(_("| achan [X]. . . . . . . .  set/get audio channels"));
919     msg_rc(_("| atrack [X] . . . . . . . . . set/get audio track"));
920     msg_rc(_("| vtrack [X] . . . . . . . . . set/get video track"));
921     msg_rc(_("| strack [X] . . . . . . . set/get subtitles track"));
922     msg_rc(_("| menu [on|off|up|down|left|right|select] use menu"));
923     msg_rc(  "| ");
924
925     if (b_longhelp)
926     {
927         msg_rc(_("| marq-marquee STRING  . . overlay STRING in video"));
928         msg_rc(_("| marq-x X . . . . . . . . . . . .offset from left"));
929         msg_rc(_("| marq-y Y . . . . . . . . . . . . offset from top"));
930         msg_rc(_("| marq-position #. . .  .relative position control"));
931         msg_rc(_("| marq-color # . . . . . . . . . . font color, RGB"));
932         msg_rc(_("| marq-opacity # . . . . . . . . . . . . . opacity"));
933         msg_rc(_("| marq-timeout T. . . . . . . . . . timeout, in ms"));
934         msg_rc(_("| marq-size # . . . . . . . . font size, in pixels"));
935         msg_rc(  "| ");
936         msg_rc(_("| time-format STRING . . . overlay STRING in video"));
937         msg_rc(_("| time-x X . . . . . . . . . . . .offset from left"));
938         msg_rc(_("| time-y Y . . . . . . . . . . . . offset from top"));
939         msg_rc(_("| time-position #. . . . . . . . relative position"));
940         msg_rc(_("| time-color # . . . . . . . . . . font color, RGB"));
941         msg_rc(_("| time-opacity # . . . . . . . . . . . . . opacity"));
942         msg_rc(_("| time-size # . . . . . . . . font size, in pixels"));
943         msg_rc(  "| ");
944         msg_rc(_("| logo-file STRING . . .the overlay file path/name"));
945         msg_rc(_("| logo-x X . . . . . . . . . . . .offset from left"));
946         msg_rc(_("| logo-y Y . . . . . . . . . . . . offset from top"));
947         msg_rc(_("| logo-position #. . . . . . . . relative position"));
948         msg_rc(_("| logo-transparency #. . . . . . . . .transparency"));
949         msg_rc(  "| ");
950         msg_rc(_("| mosaic-alpha # . . . . . . . . . . . . . . alpha"));
951         msg_rc(_("| mosaic-height #. . . . . . . . . . . . . .height"));
952         msg_rc(_("| mosaic-width # . . . . . . . . . . . . . . width"));
953         msg_rc(_("| mosaic-xoffset # . . . .top left corner position"));
954         msg_rc(_("| mosaic-yoffset # . . . .top left corner position"));
955         msg_rc(_("| mosaic-align 0..2,4..6,8..10. . .mosaic alignment"));
956         msg_rc(_("| mosaic-vborder # . . . . . . . . vertical border"));
957         msg_rc(_("| mosaic-hborder # . . . . . . . horizontal border"));
958         msg_rc(_("| mosaic-position {0=auto,1=fixed} . . . .position"));
959         msg_rc(_("| mosaic-rows #. . . . . . . . . . .number of rows"));
960         msg_rc(_("| mosaic-cols #. . . . . . . . . . .number of cols"));
961         msg_rc(_("| mosaic-order id(,id)* . . . . order of pictures "));
962         msg_rc(_("| mosaic-keep-aspect-ratio {0,1} . . .aspect ratio"));
963         msg_rc(  "| ");
964         msg_rc(_("| check-updates [newer] [equal] [older]\n"
965                  "|               [undef] [info] [source] [binary] [plugin]"));
966         msg_rc(  "| ");
967     }
968     msg_rc(_("| help . . . . . . . . . . . . . this help message"));
969     msg_rc(_("| longhelp . . . . . . . . . a longer help message"));
970     msg_rc(_("| logout . . . . .  exit (if in socket connection)"));
971     msg_rc(_("| quit . . . . . . . . . . . . . . . . .  quit vlc"));
972     msg_rc(  "| ");
973     msg_rc(_("+----[ end of help ]"));
974 }
975
976 /********************************************************************
977  * Status callback routines
978  ********************************************************************/
979 static int TimeOffsetChanged( vlc_object_t *p_this, char const *psz_cmd,
980     vlc_value_t oldval, vlc_value_t newval, void *p_data )
981 {
982     intf_thread_t *p_intf = (intf_thread_t*)p_data;
983     input_thread_t *p_input = NULL;
984
985     vlc_mutex_lock( &p_intf->p_sys->status_lock );
986     p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
987     if( p_input )
988     {
989         msg_rc( STATUS_CHANGE "( time-offset: %d )", var_GetInteger( p_input, "time-offset" ) );
990         vlc_object_release( p_input );
991     }
992     vlc_mutex_unlock( &p_intf->p_sys->status_lock );
993     return VLC_SUCCESS;
994 }
995
996 static int VolumeChanged( vlc_object_t *p_this, char const *psz_cmd,
997     vlc_value_t oldval, vlc_value_t newval, void *p_data )
998 {
999     intf_thread_t *p_intf = (intf_thread_t*)p_data;
1000
1001     vlc_mutex_lock( &p_intf->p_sys->status_lock );
1002     msg_rc( STATUS_CHANGE "( audio volume: %d )", config_GetInt( p_this, "volume") );
1003     vlc_mutex_unlock( &p_intf->p_sys->status_lock );
1004     return VLC_SUCCESS;
1005 }
1006
1007 static int StateChanged( vlc_object_t *p_this, char const *psz_cmd,
1008     vlc_value_t oldval, vlc_value_t newval, void *p_data )
1009 {
1010     intf_thread_t *p_intf = (intf_thread_t*)p_data;
1011     playlist_t    *p_playlist = NULL;
1012     input_thread_t *p_input = NULL;
1013
1014     vlc_mutex_lock( &p_intf->p_sys->status_lock );
1015     p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1016     if( p_input )
1017     {
1018         p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_PARENT );
1019         if( p_playlist )
1020         {
1021             char cmd[5] = "";
1022             switch( p_playlist->status.i_status )
1023             {
1024             case PLAYLIST_STOPPED:
1025                 strncpy( &cmd[0], "stop", 4);
1026                 cmd[4] = '\0';
1027                 break;
1028             case PLAYLIST_RUNNING:
1029                 strncpy( &cmd[0], "play", 4);
1030                 cmd[4] = '\0';
1031                 break;
1032             case PLAYLIST_PAUSED:
1033                 strncpy( &cmd[0], "pause", 5);
1034                 cmd[5] = '\0';
1035                 break;
1036             } /* var_GetInteger( p_input, "state" )  */
1037             msg_rc( STATUS_CHANGE "( %s state: %d )", &cmd[0], newval.i_int );
1038             vlc_object_release( p_playlist );
1039         }
1040         vlc_object_release( p_input );
1041     }
1042     vlc_mutex_unlock( &p_intf->p_sys->status_lock );
1043     return VLC_SUCCESS;
1044 }
1045
1046 static int RateChanged( vlc_object_t *p_this, char const *psz_cmd,
1047     vlc_value_t oldval, vlc_value_t newval, void *p_data )
1048 {
1049     intf_thread_t *p_intf = (intf_thread_t*)p_data;
1050     input_thread_t *p_input = NULL;
1051
1052     vlc_mutex_lock( &p_intf->p_sys->status_lock );
1053     p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1054     if( p_input )
1055     {
1056         msg_rc( STATUS_CHANGE "( new rate: %d )", var_GetInteger( p_input, "rate" ) );
1057         vlc_object_release( p_input );
1058     }
1059     vlc_mutex_unlock( &p_intf->p_sys->status_lock );
1060     return VLC_SUCCESS;
1061 }
1062
1063 /********************************************************************
1064  * Command routines
1065  ********************************************************************/
1066 static int Input( vlc_object_t *p_this, char const *psz_cmd,
1067                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
1068 {
1069     intf_thread_t *p_intf = (intf_thread_t*)p_this;
1070     input_thread_t *p_input;
1071     vlc_value_t     val;
1072
1073     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1074     if( !p_input ) return VLC_ENOOBJ;
1075
1076     var_Get( p_input, "state", &val );
1077     if( ( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) ) &&
1078         ( strcmp( psz_cmd, "pause" ) != 0 ) )
1079     {
1080         msg_rc( _("Press menu select or pause to continue.") );
1081         vlc_object_release( p_input );
1082         return VLC_EGENERIC;
1083     }
1084
1085     /* Parse commands that only require an input */
1086     if( !strcmp( psz_cmd, "pause" ) )
1087     {
1088         val.i_int = config_GetInt( p_intf, "key-play-pause" );
1089         var_Set( p_intf->p_vlc, "key-pressed", val );
1090         vlc_object_release( p_input );
1091         return VLC_SUCCESS;
1092     }
1093     else if( !strcmp( psz_cmd, "seek" ) )
1094     {
1095         if( strlen( newval.psz_string ) > 0 &&
1096             newval.psz_string[strlen( newval.psz_string ) - 1] == '%' )
1097         {
1098             val.f_float = (float)atoi( newval.psz_string ) / 100.0;
1099             var_Set( p_input, "position", val );
1100         }
1101         else
1102         {
1103             val.i_time = ((int64_t)atoi( newval.psz_string )) * 1000000;
1104             var_Set( p_input, "time", val );
1105         }
1106         vlc_object_release( p_input );
1107         return VLC_SUCCESS;
1108     }
1109     else if ( !strcmp( psz_cmd, "fastforward" ) )
1110     {
1111         val.i_int = config_GetInt( p_intf, "key-jump+extrashort" );
1112         var_Set( p_intf->p_vlc, "key-pressed", val );
1113         vlc_object_release( p_input );
1114         return VLC_SUCCESS;
1115     }
1116     else if ( !strcmp( psz_cmd, "rewind" ) )
1117     {
1118         val.i_int = config_GetInt( p_intf, "key-jump-extrashort" );
1119         var_Set( p_intf->p_vlc, "key-pressed", val );
1120         vlc_object_release( p_input );
1121         return VLC_SUCCESS;
1122     }
1123     else if ( !strcmp( psz_cmd, "faster" ) )
1124     {
1125         val.b_bool = VLC_TRUE;
1126         var_Set( p_input, "rate-faster", val );
1127         vlc_object_release( p_input );
1128         return VLC_SUCCESS;
1129     }
1130     else if ( !strcmp( psz_cmd, "slower" ) )
1131     {
1132         val.b_bool = VLC_TRUE;
1133         var_Set( p_input, "rate-slower", val );
1134         vlc_object_release( p_input );
1135         return VLC_SUCCESS;
1136     }
1137     else if ( !strcmp( psz_cmd, "normal" ) )
1138     {
1139         val.i_int = INPUT_RATE_DEFAULT;
1140         var_Set( p_input, "rate", val );
1141         vlc_object_release( p_input );
1142         return VLC_SUCCESS;
1143     }
1144     else if( !strcmp( psz_cmd, "chapter" ) ||
1145              !strcmp( psz_cmd, "chapter_n" ) ||
1146              !strcmp( psz_cmd, "chapter_p" ) )
1147     {
1148         if( !strcmp( psz_cmd, "chapter" ) )
1149         {
1150             if ( *newval.psz_string )
1151             {
1152                 /* Set. */
1153                 val.i_int = atoi( newval.psz_string );
1154                 var_Set( p_input, "chapter", val );
1155             }
1156             else
1157             {
1158                 vlc_value_t val_list;
1159
1160                 /* Get. */
1161                 var_Get( p_input, "chapter", &val );
1162                 var_Change( p_input, "chapter", VLC_VAR_GETCHOICES,
1163                             &val_list, NULL );
1164                 msg_rc( "Currently playing chapter %d/%d.",
1165                         val.i_int, val_list.p_list->i_count );
1166                 var_Change( p_this, "chapter", VLC_VAR_FREELIST,
1167                             &val_list, NULL );
1168             }
1169         }
1170         else if( !strcmp( psz_cmd, "chapter_n" ) )
1171         {
1172             val.b_bool = VLC_TRUE;
1173             var_Set( p_input, "next-chapter", val );
1174         }
1175         else if( !strcmp( psz_cmd, "chapter_p" ) )
1176         {
1177             val.b_bool = VLC_TRUE;
1178             var_Set( p_input, "prev-chapter", val );
1179         }
1180         vlc_object_release( p_input );
1181         return VLC_SUCCESS;
1182     }
1183     else if( !strcmp( psz_cmd, "title" ) ||
1184              !strcmp( psz_cmd, "title_n" ) ||
1185              !strcmp( psz_cmd, "title_p" ) )
1186     {
1187         if( !strcmp( psz_cmd, "title" ) )
1188         {
1189             if ( *newval.psz_string )
1190             {
1191                 /* Set. */
1192                 val.i_int = atoi( newval.psz_string );
1193                 var_Set( p_input, "title", val );
1194             }
1195             else
1196             {
1197                 vlc_value_t val_list;
1198
1199                 /* Get. */
1200                 var_Get( p_input, "title", &val );
1201                 var_Change( p_input, "title", VLC_VAR_GETCHOICES,
1202                             &val_list, NULL );
1203                 msg_rc( "Currently playing title %d/%d.",
1204                         val.i_int, val_list.p_list->i_count );
1205                 var_Change( p_this, "title", VLC_VAR_FREELIST,
1206                             &val_list, NULL );
1207             }
1208         }
1209         else if( !strcmp( psz_cmd, "title_n" ) )
1210         {
1211             val.b_bool = VLC_TRUE;
1212             var_Set( p_input, "next-title", val );
1213         }
1214         else if( !strcmp( psz_cmd, "title_p" ) )
1215         {
1216             val.b_bool = VLC_TRUE;
1217             var_Set( p_input, "prev-title", val );
1218         }
1219
1220         vlc_object_release( p_input );
1221         return VLC_SUCCESS;
1222     }
1223     else if(    !strcmp( psz_cmd, "atrack" )
1224              || !strcmp( psz_cmd, "vtrack" )
1225              || !strcmp( psz_cmd, "strack" ) )
1226     {
1227         char *psz_variable;
1228         vlc_value_t val_name;
1229         int i_error;
1230
1231         if( !strcmp( psz_cmd, "atrack" ) )
1232         {
1233             psz_variable = "audio-es";
1234         }
1235         else if( !strcmp( psz_cmd, "vtrack" ) )
1236         {
1237             psz_variable = "video-es";
1238         }
1239         else
1240         {
1241             psz_variable = "spu-es";
1242         }
1243
1244         /* Get the descriptive name of the variable */
1245         var_Change( p_input, psz_variable, VLC_VAR_GETTEXT,
1246                      &val_name, NULL );
1247         if( !val_name.psz_string ) val_name.psz_string = strdup(psz_variable);
1248
1249         if( newval.psz_string && *newval.psz_string )
1250         {
1251             /* set */
1252             vlc_value_t val;
1253             val.i_int = atoi( newval.psz_string );
1254
1255             i_error = var_Set( p_input, psz_variable, val );
1256         }
1257         else
1258         {
1259             /* get */
1260             vlc_value_t val, text;
1261             int i, i_value;
1262
1263             if ( var_Get( p_input, psz_variable, &val ) < 0 )
1264             {
1265                 vlc_object_release( p_input );
1266                 return VLC_EGENERIC;
1267             }
1268             i_value = val.i_int;
1269
1270             if ( var_Change( p_input, psz_variable,
1271                              VLC_VAR_GETLIST, &val, &text ) < 0 )
1272             {
1273                 vlc_object_release( p_input );
1274                 return VLC_EGENERIC;
1275             }
1276
1277             msg_rc( "+----[ %s ]", val_name.psz_string );
1278             for ( i = 0; i < val.p_list->i_count; i++ )
1279             {
1280                 if ( i_value == val.p_list->p_values[i].i_int )
1281                     msg_rc( "| %i - %s *", val.p_list->p_values[i].i_int,
1282                             text.p_list->p_values[i].psz_string );
1283                 else
1284                     msg_rc( "| %i - %s", val.p_list->p_values[i].i_int,
1285                             text.p_list->p_values[i].psz_string );
1286             }
1287             var_Change( p_input, psz_variable, VLC_VAR_FREELIST,
1288                         &val, &text );
1289             msg_rc( "+----[ end of %s ]", val_name.psz_string );
1290
1291             if( val_name.psz_string ) free( val_name.psz_string );
1292
1293             i_error = VLC_SUCCESS;
1294         }
1295         vlc_object_release( p_input );
1296         return i_error;
1297     }
1298
1299     /* Never reached. */
1300     vlc_object_release( p_input );
1301     return VLC_EGENERIC;
1302 }
1303
1304 static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
1305                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
1306 {
1307     intf_thread_t *p_intf = (intf_thread_t*)p_this;
1308     playlist_t *p_playlist;
1309
1310     p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
1311                                            FIND_ANYWHERE );
1312     if( !p_playlist )
1313     {
1314         msg_Err( p_this, "no playlist" );
1315         return VLC_ENOOBJ;
1316     }
1317
1318     if( p_playlist->p_input )
1319     {
1320         vlc_value_t val;
1321         var_Get( p_playlist->p_input, "state", &val );
1322         if( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) )
1323         {
1324             msg_rc( _("Type 'menu select' or 'pause' to continue.") );
1325             vlc_object_release( p_playlist );
1326             return VLC_EGENERIC;
1327         }
1328     }
1329
1330     /* Parse commands that require a playlist */
1331     if( !strcmp( psz_cmd, "prev" ) )
1332     {
1333         playlist_Prev( p_playlist );
1334     }
1335     else if( !strcmp( psz_cmd, "next" ) )
1336     {
1337         playlist_Next( p_playlist );
1338     }
1339     else if( !strcmp( psz_cmd, "play" ) )
1340     {
1341         msg_Warn( p_playlist, "play" );
1342         playlist_Play( p_playlist );
1343     }
1344     else if (!strcmp( psz_cmd, "goto" ) )
1345     {
1346         msg_Err( p_playlist, "goto is deprecated" );
1347     }
1348     else if( !strcmp( psz_cmd, "stop" ) )
1349     {
1350         playlist_Stop( p_playlist );
1351     }
1352     else if( !strcmp( psz_cmd, "clear" ) )
1353     {
1354         playlist_Stop( p_playlist );
1355         vlc_mutex_lock( &p_playlist->object_lock );
1356         playlist_Clear( p_playlist );
1357         vlc_mutex_unlock( &p_playlist->object_lock );
1358     }
1359     else if( !strcmp( psz_cmd, "add" ) &&
1360              newval.psz_string && *newval.psz_string )
1361     {
1362         input_item_t *p_item = parse_MRL( p_intf, newval.psz_string );
1363
1364         if( p_item )
1365         {
1366             msg_rc( "Trying to add %s to playlist.", newval.psz_string );
1367             playlist_PlaylistAddInput( p_playlist, p_item,
1368                               PLAYLIST_GO|PLAYLIST_APPEND, PLAYLIST_END );
1369         }
1370     }
1371     else if( !strcmp( psz_cmd, "enqueue" ) &&
1372              newval.psz_string && *newval.psz_string )
1373     {
1374         input_item_t *p_item = parse_MRL( p_intf, newval.psz_string );
1375
1376         if( p_item )
1377         {
1378             msg_rc( "trying to enqueue %s to playlist", newval.psz_string );
1379             playlist_PlaylistAddInput( p_playlist, p_item,
1380                               PLAYLIST_APPEND, PLAYLIST_END );
1381         }
1382     }
1383     else if( !strcmp( psz_cmd, "playlist" ) )
1384     {
1385         msg_Dbg( p_playlist, "Dumping category" );
1386         playlist_NodeDump( p_playlist, p_playlist->p_root_category, 0 );
1387         msg_Dbg( p_playlist, "Dumping Onelevel" );
1388         playlist_NodeDump( p_playlist, p_playlist->p_root_onelevel, 0 );
1389     }
1390     else if( !strcmp( psz_cmd, "sort" ))
1391     {
1392         playlist_RecursiveNodeSort( p_playlist, p_playlist->p_root_onelevel, 
1393                                     SORT_ARTIST, ORDER_NORMAL );
1394     }
1395     else if( !strcmp( psz_cmd, "status" ) )
1396     {
1397         if( p_playlist->p_input )
1398         {
1399             /* Replay the current state of the system. */
1400             msg_rc( STATUS_CHANGE "( new input: %s )", p_playlist->p_input->input.p_item->psz_uri );
1401             msg_rc( STATUS_CHANGE "( audio volume: %d )", config_GetInt( p_intf, "volume" ));
1402
1403             vlc_mutex_lock( &p_playlist->object_lock );
1404             switch( p_playlist->status.i_status )
1405             {
1406                 case PLAYLIST_STOPPED:
1407                     msg_rc( STATUS_CHANGE "( stop state: 0 )" );
1408                     break;
1409                 case PLAYLIST_RUNNING:
1410                     msg_rc( STATUS_CHANGE "( play state: 1 )" );
1411                     break;
1412                 case PLAYLIST_PAUSED:
1413                     msg_rc( STATUS_CHANGE "( pause state: 2 )" );
1414                     break;
1415                 default:
1416                     msg_rc( STATUS_CHANGE "( state unknown )" );
1417                     break;
1418             }
1419             vlc_mutex_unlock( &p_playlist->object_lock );
1420         }
1421     }
1422
1423     /*
1424      * sanity check
1425      */
1426     else
1427     {
1428         msg_rc( "unknown command!" );
1429     }
1430
1431     vlc_object_release( p_playlist );
1432     return VLC_SUCCESS;
1433 }
1434
1435 static int Other( vlc_object_t *p_this, char const *psz_cmd,
1436                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
1437 {
1438     intf_thread_t *p_intf = (intf_thread_t*)p_this;
1439     vlc_object_t  *p_playlist;
1440     vlc_value_t    val;
1441     vlc_object_t  *p_input;
1442
1443     p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
1444     if( !p_playlist )
1445     {
1446         return VLC_ENOOBJ;
1447     }
1448
1449     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1450     if( !p_input )
1451     {
1452         vlc_object_release( p_playlist );
1453         return VLC_ENOOBJ;
1454     }
1455
1456     if( p_input )
1457     {
1458         var_Get( p_input, "state", &val );
1459         if( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) )
1460         {
1461             msg_rc( _("Type 'pause' to continue.") );
1462             vlc_object_release( p_playlist );
1463             vlc_object_release( p_input );
1464             return VLC_EGENERIC;
1465         }
1466     }
1467
1468     /* Parse miscellaneous commands */
1469     if( !strcmp( psz_cmd, "marq-marquee" ) )
1470     {
1471         if( strlen( newval.psz_string ) > 0 )
1472         {
1473             val.psz_string = newval.psz_string;
1474             var_Set( p_input->p_libvlc, "marq-marquee", val );
1475         }
1476         else
1477         {
1478                 val.psz_string = "";
1479                 var_Set( p_input->p_libvlc, "marq-marquee", val);
1480         }
1481     }
1482     else if( !strcmp( psz_cmd, "marq-x" ) )
1483     {
1484         if( strlen( newval.psz_string ) > 0)
1485         {
1486             val.i_int = atoi( newval.psz_string );
1487             var_Set( p_input->p_libvlc, "marq-x", val );
1488         }
1489     }
1490     else if( !strcmp( psz_cmd, "marq-y" ) )
1491     {
1492         if( strlen( newval.psz_string ) > 0)
1493         {
1494             val.i_int = atoi( newval.psz_string );
1495             var_Set( p_input->p_libvlc, "marq-y", val );
1496         }
1497     }
1498     else if( !strcmp( psz_cmd, "marq-position" ) )
1499     {
1500         if( strlen( newval.psz_string ) > 0)
1501         {
1502             val.i_int = atoi( newval.psz_string );
1503             var_Set( p_input->p_libvlc, "marq-position", val );
1504         }
1505     }
1506     else if( !strcmp( psz_cmd, "marq-color" ) )
1507     {
1508         if( strlen( newval.psz_string ) > 0)
1509         {
1510             val.i_int = strtol( newval.psz_string, NULL, 0 );
1511             var_Set( p_input->p_libvlc, "marq-color", val );
1512         }
1513     }
1514     else if( !strcmp( psz_cmd, "marq-opacity" ) )
1515     {
1516         if( strlen( newval.psz_string ) > 0)
1517         {
1518             val.i_int = strtol( newval.psz_string, NULL, 0 );
1519             var_Set( p_input->p_libvlc, "marq-opacity", val );
1520         }
1521     }
1522     else if( !strcmp( psz_cmd, "marq-size" ) )
1523     {
1524         if( strlen( newval.psz_string ) > 0)
1525         {
1526             val.i_int = atoi( newval.psz_string );
1527             var_Set( p_input->p_libvlc, "marq-size", val );
1528         }
1529     }
1530     else if( !strcmp( psz_cmd, "marq-timeout" ) )
1531     {
1532         if( strlen( newval.psz_string ) > 0)
1533         {
1534             val.i_int = atoi( newval.psz_string );
1535             var_Set( p_input, "marq-timeout", val );
1536         }
1537     }
1538     else if( !strcmp( psz_cmd, "mosaic-alpha" ) )
1539     {
1540         if( strlen( newval.psz_string ) > 0)
1541         {
1542             val.i_int = atoi( newval.psz_string );
1543             var_Set( p_input->p_libvlc, "mosaic-alpha", val );
1544         }
1545     }
1546     else if( !strcmp( psz_cmd, "mosaic-height" ) )
1547     {
1548         if( strlen( newval.psz_string ) > 0)
1549         {
1550             val.i_int = atoi( newval.psz_string );
1551             var_Set( p_input->p_libvlc, "mosaic-height", val );
1552         }
1553     }
1554     else if( !strcmp( psz_cmd, "mosaic-width" ) )
1555     {
1556         if( strlen( newval.psz_string ) > 0)
1557         {
1558             val.i_int = atoi( newval.psz_string );
1559             var_Set( p_input->p_libvlc, "mosaic-width", val );
1560         }
1561     }
1562     else if( !strcmp( psz_cmd, "mosaic-xoffset" ) )
1563     {
1564         if( strlen( newval.psz_string ) > 0)
1565         {
1566             val.i_int = atoi( newval.psz_string );
1567             var_Set( p_input->p_libvlc, "mosaic-xoffset", val );
1568         }
1569     }
1570     else if( !strcmp( psz_cmd, "mosaic-yoffset" ) )
1571     {
1572         if( strlen( newval.psz_string ) > 0)
1573         {
1574             val.i_int = atoi( newval.psz_string );
1575             var_Set( p_input->p_libvlc, "mosaic-yoffset", val );
1576         }
1577     }
1578     else if( !strcmp( psz_cmd, "mosaic-align" ) )
1579     {
1580         if( strlen( newval.psz_string ) > 0 )
1581         {
1582             val.i_int = atoi( newval.psz_string );
1583             var_Set( p_input->p_libvlc, "mosaic-align", val );
1584         }
1585     }
1586     else if( !strcmp( psz_cmd, "mosaic-vborder" ) )
1587     {
1588         if( strlen( newval.psz_string ) > 0)
1589         {
1590             val.i_int = atoi( newval.psz_string );
1591             var_Set( p_input->p_libvlc, "mosaic-vborder", val );
1592         }
1593     }
1594     else if( !strcmp( psz_cmd, "mosaic-hborder" ) )
1595     {
1596         if( strlen( newval.psz_string ) > 0)
1597         {
1598             val.i_int = atoi( newval.psz_string );
1599             var_Set( p_input->p_libvlc, "mosaic-hborder", val );
1600         }
1601     }
1602     else if( !strcmp( psz_cmd, "mosaic-position" ) )
1603     {
1604         if( strlen( newval.psz_string ) > 0)
1605         {
1606             val.i_int = atoi( newval.psz_string );
1607             var_Set( p_input->p_libvlc, "mosaic-position", val );
1608         }
1609     }
1610     else if( !strcmp( psz_cmd, "mosaic-rows" ) )
1611     {
1612         if( strlen( newval.psz_string ) > 0)
1613         {
1614             val.i_int = atoi( newval.psz_string );
1615             var_Set( p_input->p_libvlc, "mosaic-rows", val );
1616         }
1617     }
1618     else if( !strcmp( psz_cmd, "mosaic-cols" ) )
1619     {
1620         if( strlen( newval.psz_string ) > 0)
1621         {
1622             val.i_int = atoi( newval.psz_string );
1623             var_Set( p_input->p_libvlc, "mosaic-cols", val );
1624         }
1625     }
1626     else if( !strcmp( psz_cmd, "mosaic-order" ) )
1627     {
1628         if( strlen( newval.psz_string ) > 0)
1629         {
1630             val.psz_string = newval.psz_string;
1631             var_Set( p_input->p_libvlc, "mosaic-order", val );
1632         }
1633     }
1634     else if( !strcmp( psz_cmd, "mosaic-keep-aspect-ratio" ) )
1635     {
1636         if( strlen( newval.psz_string ) > 0)
1637         {
1638             val.i_int = atoi( newval.psz_string );
1639             var_Set( p_input->p_libvlc, "mosaic-keep-aspect-ratio", val );
1640         }
1641     }
1642     else if( !strcmp( psz_cmd, "time-format" ) )
1643     {
1644         if( strlen( newval.psz_string ) > 0 )
1645         {
1646             val.psz_string = newval.psz_string;
1647             var_Set( p_input->p_libvlc, "time-format", val );
1648         }
1649         else
1650         {
1651             val.psz_string = "";
1652             var_Set( p_input->p_libvlc, "time-format", val);
1653         }
1654     }
1655     else if( !strcmp( psz_cmd, "time-x" ) )
1656     {
1657         if( strlen( newval.psz_string ) > 0)
1658         {
1659             val.i_int = atoi( newval.psz_string );
1660             var_Set( p_input->p_libvlc, "time-x", val );
1661         }
1662     }
1663     else if( !strcmp( psz_cmd, "time-y" ) )
1664     {
1665         if( strlen( newval.psz_string ) > 0)
1666         {
1667             val.i_int = atoi( newval.psz_string );
1668             var_Set( p_input->p_libvlc, "time-y", val );
1669         }
1670     }
1671     else if( !strcmp( psz_cmd, "time-position" ) )
1672     {
1673         if( strlen( newval.psz_string ) > 0)
1674         {
1675             val.i_int = atoi( newval.psz_string );
1676             var_Set( p_input->p_libvlc, "time-position", val );
1677         }
1678     }
1679     else if( !strcmp( psz_cmd, "time-color" ) )
1680     {
1681         if( strlen( newval.psz_string ) > 0)
1682         {
1683             val.i_int = strtol( newval.psz_string, NULL, 0 );
1684             var_Set( p_input->p_libvlc, "time-color", val );
1685         }
1686     }
1687     else if( !strcmp( psz_cmd, "time-opacity" ) )
1688     {
1689         if( strlen( newval.psz_string ) > 0)
1690         {
1691             val.i_int = strtol( newval.psz_string, NULL, 0 );
1692             var_Set( p_input->p_libvlc, "time-opacity", val );
1693         }
1694     }
1695     else if( !strcmp( psz_cmd, "time-size" ) )
1696     {
1697         if( strlen( newval.psz_string ) > 0)
1698         {
1699             val.i_int = atoi( newval.psz_string );
1700             var_Set( p_input->p_libvlc, "time-size", val );
1701         }
1702     }
1703     else if( !strcmp( psz_cmd, "logo-file" ) )
1704     {
1705         if( strlen( newval.psz_string ) > 0 )
1706         {
1707             val.psz_string = newval.psz_string;
1708             var_Set( p_input->p_libvlc, "logo-file", val );
1709         }
1710     }
1711     else if( !strcmp( psz_cmd, "logo-x" ) )
1712     {
1713         if( strlen( newval.psz_string ) > 0)
1714         {
1715             val.i_int = atoi( newval.psz_string );
1716             var_Set( p_input->p_libvlc, "logo-x", val );
1717         }
1718     }
1719     else if( !strcmp( psz_cmd, "logo-y" ) )
1720     {
1721         if( strlen( newval.psz_string ) > 0)
1722         {
1723             val.i_int = atoi( newval.psz_string );
1724             var_Set( p_input->p_libvlc, "logo-y", val );
1725         }
1726     }
1727     else if( !strcmp( psz_cmd, "logo-position" ) )
1728     {
1729         if( strlen( newval.psz_string ) > 0)
1730         {
1731             val.i_int = atoi( newval.psz_string );
1732             var_Set( p_input->p_libvlc, "logo-position", val );
1733         }
1734     }
1735     else if( !strcmp( psz_cmd, "logo-transparency" ) )
1736     {
1737         if( strlen( newval.psz_string ) > 0)
1738         {
1739             val.i_int = strtol( newval.psz_string, NULL, 0 );
1740             var_Set( p_input->p_libvlc, "logo-transparency", val );
1741         }
1742     }
1743
1744     /*
1745      * sanity check
1746      */
1747     else
1748     {
1749         msg_rc( "Unknown command!" );
1750     }
1751
1752     vlc_object_release( p_playlist );
1753     vlc_object_release( p_input );
1754     return VLC_SUCCESS;
1755 }
1756
1757 static int Quit( vlc_object_t *p_this, char const *psz_cmd,
1758                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
1759 {
1760     playlist_t *p_playlist;
1761
1762     p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
1763     if( p_playlist )
1764     {
1765         playlist_Stop( p_playlist );
1766         vlc_object_release( p_playlist );
1767     }
1768     p_this->p_vlc->b_die = VLC_TRUE;
1769     return VLC_SUCCESS;
1770 }
1771
1772 static int Intf( vlc_object_t *p_this, char const *psz_cmd,
1773                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
1774 {
1775     intf_thread_t *p_newintf = NULL;
1776
1777     p_newintf = intf_Create( p_this->p_vlc, newval.psz_string, 0, NULL );
1778     if( p_newintf )
1779     {
1780         p_newintf->b_block = VLC_FALSE;
1781         if( intf_RunThread( p_newintf ) )
1782         {
1783             vlc_object_detach( p_newintf );
1784             intf_Destroy( p_newintf );
1785         }
1786     }
1787
1788     return VLC_SUCCESS;
1789 }
1790
1791 static int Volume( vlc_object_t *p_this, char const *psz_cmd,
1792                    vlc_value_t oldval, vlc_value_t newval, void *p_data )
1793 {
1794     intf_thread_t *p_intf = (intf_thread_t*)p_this;
1795     input_thread_t *p_input = NULL;
1796     int i_error = VLC_EGENERIC;
1797
1798     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1799     if( !p_input )
1800         return VLC_ENOOBJ;
1801
1802     if( p_input )
1803     {
1804         vlc_value_t val;
1805
1806         var_Get( p_input, "state", &val );
1807         if( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) )
1808         {
1809             msg_rc( _("Type 'menu select' or 'pause' to continue.") );
1810             vlc_object_release( p_input );
1811             return VLC_EGENERIC;
1812         }
1813         vlc_object_release( p_input );
1814     }
1815
1816     if ( *newval.psz_string )
1817     {
1818         /* Set. */
1819         audio_volume_t i_volume = atoi( newval.psz_string );
1820         if ( (i_volume > (audio_volume_t)AOUT_VOLUME_MAX) )
1821         {
1822             msg_rc( "Volume must be in the range %d-%d.", AOUT_VOLUME_MIN,
1823                     AOUT_VOLUME_MAX );
1824             i_error = VLC_EBADVAR;
1825         }
1826         else
1827         {
1828             if( i_volume == AOUT_VOLUME_MIN )
1829             {
1830                 vlc_value_t keyval;
1831
1832                 keyval.i_int = config_GetInt( p_intf, "key-vol-mute" );
1833                 var_Set( p_intf->p_vlc, "key-pressed", keyval );
1834             }
1835             i_error = aout_VolumeSet( p_this, i_volume );
1836             osd_Volume( p_this );
1837             msg_rc( STATUS_CHANGE "( audio volume: %d )", i_volume );
1838         }
1839     }
1840     else
1841     {
1842         /* Get. */
1843         audio_volume_t i_volume;
1844         if ( aout_VolumeGet( p_this, &i_volume ) < 0 )
1845         {
1846             i_error = VLC_EGENERIC;
1847         }
1848         else
1849         {
1850             msg_rc( STATUS_CHANGE "( audio volume: %d )", i_volume );
1851             i_error = VLC_SUCCESS;
1852         }
1853     }
1854
1855     return i_error;
1856 }
1857
1858 static int VolumeMove( vlc_object_t *p_this, char const *psz_cmd,
1859                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
1860 {
1861     intf_thread_t *p_intf = (intf_thread_t*)p_this;
1862     audio_volume_t i_volume;
1863     input_thread_t *p_input = NULL;
1864     int i_nb_steps = atoi(newval.psz_string);
1865     int i_error = VLC_SUCCESS;
1866     int i_volume_step = 0;
1867
1868     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1869     if( !p_input )
1870         return VLC_ENOOBJ;
1871
1872     if( p_input )
1873     {
1874         vlc_value_t val;
1875
1876         var_Get( p_input, "state", &val );
1877         if( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) )
1878         {
1879             msg_rc( _("Type 'menu select' or 'pause' to continue.") );
1880             vlc_object_release( p_input );
1881             return VLC_EGENERIC;
1882         }
1883         vlc_object_release( p_input );
1884     }
1885
1886     i_volume_step = config_GetInt( p_intf->p_vlc, "volume-step" );
1887     if ( i_nb_steps <= 0 || i_nb_steps > (AOUT_VOLUME_MAX/i_volume_step) )
1888     {
1889         i_nb_steps = 1;
1890     }
1891
1892     if ( !strcmp(psz_cmd, "volup") )
1893     {
1894         if ( aout_VolumeUp( p_this, i_nb_steps, &i_volume ) < 0 )
1895             i_error = VLC_EGENERIC;
1896     }
1897     else
1898     {
1899         if ( aout_VolumeDown( p_this, i_nb_steps, &i_volume ) < 0 )
1900             i_error = VLC_EGENERIC;
1901     }
1902     osd_Volume( p_this );
1903
1904     if ( !i_error ) msg_rc( STATUS_CHANGE "( audio volume: %d )", i_volume );
1905     return i_error;
1906 }
1907
1908 static int AudioConfig( vlc_object_t *p_this, char const *psz_cmd,
1909                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
1910 {
1911     intf_thread_t *p_intf = (intf_thread_t*)p_this;
1912     input_thread_t *p_input = NULL;
1913     aout_instance_t * p_aout;
1914     const char * psz_variable;
1915     vlc_value_t val_name;
1916     int i_error;
1917
1918     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
1919     if( !p_input )
1920         return VLC_ENOOBJ;
1921
1922     if( p_input )
1923     {
1924         vlc_value_t val;
1925
1926         var_Get( p_input, "state", &val );
1927         if( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) )        {
1928             msg_rc( _("Type 'menu select' or 'pause' to continue.") );
1929             vlc_object_release( p_input );
1930             return VLC_EGENERIC;
1931         }
1932         vlc_object_release( p_input );
1933     }
1934
1935     p_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT, FIND_ANYWHERE );
1936     if ( p_aout == NULL ) return VLC_ENOOBJ;
1937
1938     if ( !strcmp( psz_cmd, "adev" ) )
1939     {
1940         psz_variable = "audio-device";
1941     }
1942     else
1943     {
1944         psz_variable = "audio-channels";
1945     }
1946
1947     /* Get the descriptive name of the variable */
1948     var_Change( (vlc_object_t *)p_aout, psz_variable, VLC_VAR_GETTEXT,
1949                  &val_name, NULL );
1950     if( !val_name.psz_string ) val_name.psz_string = strdup(psz_variable);
1951
1952     if ( !*newval.psz_string )
1953     {
1954         /* Retrieve all registered ***. */
1955         vlc_value_t val, text;
1956         int i, i_value;
1957
1958         if ( var_Get( (vlc_object_t *)p_aout, psz_variable, &val ) < 0 )
1959         {
1960             vlc_object_release( (vlc_object_t *)p_aout );
1961             return VLC_EGENERIC;
1962         }
1963         i_value = val.i_int;
1964
1965         if ( var_Change( (vlc_object_t *)p_aout, psz_variable,
1966                          VLC_VAR_GETLIST, &val, &text ) < 0 )
1967         {
1968             vlc_object_release( (vlc_object_t *)p_aout );
1969             return VLC_EGENERIC;
1970         }
1971
1972         msg_rc( "+----[ %s ]", val_name.psz_string );
1973         for ( i = 0; i < val.p_list->i_count; i++ )
1974         {
1975             if ( i_value == val.p_list->p_values[i].i_int )
1976                 msg_rc( "| %i - %s *", val.p_list->p_values[i].i_int,
1977                         text.p_list->p_values[i].psz_string );
1978             else
1979                 msg_rc( "| %i - %s", val.p_list->p_values[i].i_int,
1980                         text.p_list->p_values[i].psz_string );
1981         }
1982         var_Change( (vlc_object_t *)p_aout, psz_variable, VLC_VAR_FREELIST,
1983                     &val, &text );
1984         msg_rc( "+----[ end of %s ]", val_name.psz_string );
1985
1986         if( val_name.psz_string ) free( val_name.psz_string );
1987         i_error = VLC_SUCCESS;
1988     }
1989     else
1990     {
1991         vlc_value_t val;
1992         val.i_int = atoi( newval.psz_string );
1993
1994         i_error = var_Set( (vlc_object_t *)p_aout, psz_variable, val );
1995     }
1996     vlc_object_release( (vlc_object_t *)p_aout );
1997
1998     return i_error;
1999 }
2000
2001 /* OSD menu commands */
2002 static int Menu( vlc_object_t *p_this, char const *psz_cmd,
2003     vlc_value_t oldval, vlc_value_t newval, void *p_data )
2004 {
2005     intf_thread_t *p_intf = (intf_thread_t*)p_this;
2006     playlist_t    *p_playlist = NULL;
2007     vlc_value_t val;
2008     int i_error = VLC_EGENERIC;
2009
2010     if ( !*newval.psz_string )
2011     {
2012         msg_rc( _("Please provide one of the following parameters:") );
2013         msg_rc( "[on|off|up|down|left|right|select]" );
2014         return i_error;
2015     }
2016
2017     p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
2018     if( !p_playlist )
2019         return VLC_ENOOBJ;
2020
2021     if( p_playlist->p_input )
2022     {
2023         var_Get( p_playlist->p_input, "state", &val );
2024         if( ( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) ) &&
2025             ( strcmp( newval.psz_string, "select" ) != 0 ) )
2026         {
2027             msg_rc( _("Type 'menu select' or 'pause' to continue.") );
2028             vlc_object_release( p_playlist );
2029             return VLC_EGENERIC;
2030         }
2031     }
2032     vlc_object_release( p_playlist );
2033
2034     val.psz_string = strdup( newval.psz_string );
2035     if( !strcmp( val.psz_string, "on" ) || !strcmp( val.psz_string, "show" ))
2036         osd_MenuShow( p_this );
2037     else if( !strcmp( val.psz_string, "off" ) || !strcmp( val.psz_string, "hide" ) )
2038         osd_MenuHide( p_this );
2039     else if( !strcmp( val.psz_string, "up" ) )
2040         osd_MenuUp( p_this );
2041     else if( !strcmp( val.psz_string, "down" ) )
2042         osd_MenuDown( p_this );
2043     else if( !strcmp( val.psz_string, "left" ) )
2044         osd_MenuPrev( p_this );
2045     else if( !strcmp( val.psz_string, "right" ) )
2046         osd_MenuNext( p_this );
2047     else if( !strcmp( val.psz_string, "select" ) )
2048         osd_MenuActivate( p_this );
2049     else
2050     {
2051         msg_rc( _("Please provide one of the following parameters:") );
2052         msg_rc( "[on|off|up|down|left|right|select]" );
2053         if( val.psz_string ) free( val.psz_string );
2054             return i_error;
2055     }
2056
2057     i_error = VLC_SUCCESS;
2058     if( val.psz_string ) free( val.psz_string );
2059     return i_error;
2060 }
2061
2062 #ifdef WIN32
2063 vlc_bool_t ReadWin32( intf_thread_t *p_intf, char *p_buffer, int *pi_size )
2064 {
2065     INPUT_RECORD input_record;
2066     DWORD i_dw;
2067
2068     /* On Win32, select() only works on socket descriptors */
2069     while( WaitForSingleObject( p_intf->p_sys->hConsoleIn,
2070                                 INTF_IDLE_SLEEP/1000 ) == WAIT_OBJECT_0 )
2071     {
2072         while( !p_intf->b_die && *pi_size < MAX_LINE_LENGTH &&
2073                ReadConsoleInput( p_intf->p_sys->hConsoleIn, &input_record,
2074                                  1, &i_dw ) )
2075         {
2076             if( input_record.EventType != KEY_EVENT ||
2077                 !input_record.Event.KeyEvent.bKeyDown ||
2078                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT ||
2079                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL||
2080                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_MENU ||
2081                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_CAPITAL )
2082             {
2083                 /* nothing interesting */
2084                 continue;
2085             }
2086
2087             p_buffer[ *pi_size ] = input_record.Event.KeyEvent.uChar.AsciiChar;
2088
2089             /* Echo out the command */
2090             putc( p_buffer[ *pi_size ], stdout );
2091
2092             /* Handle special keys */
2093             if( p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
2094             {
2095                 putc( '\n', stdout );
2096                 break;
2097             }
2098             switch( p_buffer[ *pi_size ] )
2099             {
2100             case '\b':
2101                 if( *pi_size )
2102                 {
2103                     *pi_size -= 2;
2104                     putc( ' ', stdout );
2105                     putc( '\b', stdout );
2106                 }
2107                 break;
2108             case '\r':
2109                 (*pi_size) --;
2110                 break;
2111             }
2112
2113             (*pi_size)++;
2114         }
2115
2116         if( *pi_size == MAX_LINE_LENGTH ||
2117             p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
2118         {
2119             p_buffer[ *pi_size ] = 0;
2120             return VLC_TRUE;
2121         }
2122     }
2123
2124     return VLC_FALSE;
2125 }
2126 #endif
2127
2128 vlc_bool_t ReadCommand( intf_thread_t *p_intf, char *p_buffer, int *pi_size )
2129 {
2130     int i_read = 0;
2131
2132 #ifdef WIN32
2133     if( p_intf->p_sys->i_socket == -1 && !p_intf->p_sys->b_quiet )
2134         return ReadWin32( p_intf, p_buffer, pi_size );
2135     else if( p_intf->p_sys->i_socket == -1 )
2136     {
2137         msleep( INTF_IDLE_SLEEP );
2138         return VLC_FALSE;
2139     }
2140 #endif
2141
2142     while( !p_intf->b_die && *pi_size < MAX_LINE_LENGTH &&
2143            (i_read = net_ReadNonBlock( p_intf, p_intf->p_sys->i_socket == -1 ?
2144                        0 /*STDIN_FILENO*/ : p_intf->p_sys->i_socket, NULL,
2145                   (uint8_t *)p_buffer + *pi_size, 1, INTF_IDLE_SLEEP ) ) > 0 )
2146     {
2147         if( p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
2148             break;
2149
2150         (*pi_size)++;
2151     }
2152
2153     /* Connection closed */
2154     if( i_read == -1 )
2155     {
2156         p_intf->p_sys->i_socket = -1;
2157         p_buffer[ *pi_size ] = 0;
2158         return VLC_TRUE;
2159     }
2160
2161     if( *pi_size == MAX_LINE_LENGTH ||
2162         p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
2163     {
2164         p_buffer[ *pi_size ] = 0;
2165         return VLC_TRUE;
2166     }
2167
2168     return VLC_FALSE;
2169 }
2170
2171 /*****************************************************************************
2172  * parse_MRL: build a input item from a full mrl
2173  *****************************************************************************
2174  * MRL format: "simplified-mrl [:option-name[=option-value]]"
2175  * We don't check for '"' or '\'', we just assume that a ':' that follows a
2176  * space is a new option. Should be good enough for our purpose.
2177  *****************************************************************************/
2178 static input_item_t *parse_MRL( intf_thread_t *p_intf, char *psz_mrl )
2179 {
2180 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
2181 #define SKIPTRAILINGSPACE( p, d ) \
2182     { char *e=d; while( e > p && (*(e-1)==' ' || *(e-1)=='\t') ){e--;*e=0;} }
2183
2184     input_item_t *p_item = NULL;
2185     char *psz_item = NULL, *psz_item_mrl = NULL, *psz_orig;
2186     char **ppsz_options = NULL;
2187     int i, i_options = 0;
2188
2189     if( !psz_mrl ) return 0;
2190
2191     psz_mrl = psz_orig = strdup( psz_mrl );
2192     while( *psz_mrl )
2193     {
2194         SKIPSPACE( psz_mrl );
2195         psz_item = psz_mrl;
2196
2197         for( ; *psz_mrl; psz_mrl++ )
2198         {
2199             if( (*psz_mrl == ' ' || *psz_mrl == '\t') && psz_mrl[1] == ':' )
2200             {
2201                 /* We have a complete item */
2202                 break;
2203             }
2204             if( (*psz_mrl == ' ' || *psz_mrl == '\t') &&
2205                 (psz_mrl[1] == '"' || psz_mrl[1] == '\'') && psz_mrl[2] == ':')
2206             {
2207                 /* We have a complete item */
2208                 break;
2209             }
2210         }
2211
2212         if( *psz_mrl ) { *psz_mrl = 0; psz_mrl++; }
2213         SKIPTRAILINGSPACE( psz_item, psz_item + strlen( psz_item ) );
2214
2215         /* Remove '"' and '\'' if necessary */
2216         if( *psz_item == '"' && psz_item[strlen(psz_item)-1] == '"' )
2217         { psz_item++; psz_item[strlen(psz_item)-1] = 0; }
2218         if( *psz_item == '\'' && psz_item[strlen(psz_item)-1] == '\'' )
2219         { psz_item++; psz_item[strlen(psz_item)-1] = 0; }
2220
2221         if( !psz_item_mrl ) psz_item_mrl = psz_item;
2222         else if( *psz_item )
2223         {
2224             i_options++;
2225             ppsz_options = realloc( ppsz_options, i_options * sizeof(char *) );
2226             ppsz_options[i_options - 1] = &psz_item[1];
2227         }
2228
2229         if( *psz_mrl ) SKIPSPACE( psz_mrl );
2230     }
2231
2232     /* Now create a playlist item */
2233     if( psz_item_mrl )
2234     {
2235         p_item = input_ItemNew( p_intf, psz_item_mrl, psz_item_mrl );
2236         for( i = 0; i < i_options; i++ )
2237         {
2238             vlc_input_item_AddOption( p_item, ppsz_options[i] );
2239         }
2240     }
2241
2242     if( i_options ) free( ppsz_options );
2243     free( psz_orig );
2244
2245     return p_item;
2246 }
2247
2248 /*****************************************************************************
2249  * checkUpdates : check for updates
2250  ****************************************************************************/
2251 static void checkUpdates( intf_thread_t *p_intf, char *psz_arg )
2252 {
2253     update_iterator_t *p_uit;
2254     update_t *p_u = update_New( p_intf );
2255     if( p_u == NULL ) return;
2256     p_uit = update_iterator_New( p_u );
2257     if( p_uit )
2258     {
2259         int s = 0, t = 0;
2260
2261         if( strstr( psz_arg, "newer" ) )
2262             s |= UPDATE_RELEASE_STATUS_NEWER;
2263         if( strstr( psz_arg, "equal" ) )
2264             s |= UPDATE_RELEASE_STATUS_EQUAL;
2265         if( strstr( psz_arg, "older" ) )
2266             s |= UPDATE_RELEASE_STATUS_OLDER;
2267         if( s ) p_uit->i_rs = s;
2268         else p_uit->i_rs = UPDATE_RELEASE_STATUS_NEWER;
2269
2270         if( strstr( psz_arg, "undef" ) )
2271             t |= UPDATE_FILE_TYPE_UNDEF;
2272         if( strstr( psz_arg, "info" ) )
2273             t |= UPDATE_FILE_TYPE_INFO;
2274         if( strstr( psz_arg, "source" ) )
2275             t |= UPDATE_FILE_TYPE_SOURCE;
2276         if( strstr( psz_arg, "binary" ) )
2277             t |= UPDATE_FILE_TYPE_BINARY;
2278         if( strstr( psz_arg, "plugin" ) )
2279             t |= UPDATE_FILE_TYPE_PLUGIN;
2280         if( t ) p_uit->i_t = t;
2281
2282         update_Check( p_u, VLC_FALSE );
2283         update_iterator_Action( p_uit, UPDATE_MIRROR );
2284         msg_rc( "\nUsing mirror: %s (%s) [%s]",
2285                 p_uit->mirror.psz_name,
2286                 p_uit->mirror.psz_location,
2287                 p_uit->mirror.psz_type );
2288         while( (s = update_iterator_Action( p_uit, UPDATE_FILE )) != UPDATE_FAIL )
2289         {
2290             char *psz_tmp;
2291             if( s & UPDATE_RELEASE )
2292             {
2293                 switch( p_uit->release.i_status )
2294                 {
2295                     case UPDATE_RELEASE_STATUS_OLDER:
2296                         psz_tmp = strdup( "older" );
2297                         break;
2298                     case UPDATE_RELEASE_STATUS_EQUAL:
2299                         psz_tmp = strdup( "equal" );
2300                         break;
2301                     case UPDATE_RELEASE_STATUS_NEWER:
2302                         psz_tmp = strdup( "newer" );
2303                         break;
2304                     default:
2305                         psz_tmp = strdup( "?!?" );
2306                         break;
2307                 }
2308                 msg_rc( "\n+----[ VLC %s %s (%s) ] ",
2309                         p_uit->release.psz_version,
2310                         p_uit->release.psz_svn_revision,
2311                         psz_tmp );
2312                 free( psz_tmp );
2313             }
2314             switch( p_uit->file.i_type )
2315             {
2316                 case UPDATE_FILE_TYPE_UNDEF:
2317                     psz_tmp = strdup( "undef" );
2318                     break;
2319                 case UPDATE_FILE_TYPE_INFO:
2320                     psz_tmp = strdup( "info" );
2321                     break;
2322                 case UPDATE_FILE_TYPE_SOURCE:
2323                     psz_tmp = strdup( "source" );
2324                     break;
2325                 case UPDATE_FILE_TYPE_BINARY:
2326                     psz_tmp = strdup( "binary" );
2327                     break;
2328                 case UPDATE_FILE_TYPE_PLUGIN:
2329                     psz_tmp = strdup( "plugin" );
2330                     break;
2331                 default:
2332                     psz_tmp = strdup( "?!?" );
2333                     break;
2334             }
2335             msg_rc( "| %s (%s)", p_uit->file.psz_description, psz_tmp );
2336             free( psz_tmp );
2337             if( p_uit->file.l_size )
2338             {
2339                 if( p_uit->file.l_size > 1024 * 1024 * 1024 )
2340                     asprintf( &psz_tmp, "(%ld GB)",
2341                               p_uit->file.l_size / (1024*1024*1024) );
2342                 if( p_uit->file.l_size > 1024 * 1024 )
2343                     asprintf( &psz_tmp, "(%ld MB)",
2344                               p_uit->file.l_size / (1024*1024) );
2345                 else if( p_uit->file.l_size > 1024 )
2346                     asprintf( &psz_tmp, "(%ld kB)",
2347                               p_uit->file.l_size / 1024 );
2348                 else
2349                     asprintf( &psz_tmp, "(%ld B)", p_uit->file.l_size );
2350             }
2351             else
2352             {
2353                 psz_tmp = strdup( "" );
2354             }
2355             msg_rc( "| %s %s", p_uit->file.psz_url, psz_tmp );
2356             msg_rc( "+----" );
2357             free( psz_tmp );
2358         }
2359         msg_rc( "" );
2360         update_iterator_Delete( p_uit );
2361     }
2362     update_Delete( p_u );
2363 }