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