50aa5e8a79f5911fd0bfc706f86c707c5195ceba
[vlc.git] / modules / control / http / rpn.c
1 /*****************************************************************************
2  * rpn.c : RPN evaluator for the HTTP Interface
3  *****************************************************************************
4  * Copyright (C) 2001-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *          Laurent Aimar <fenrir@via.ecp.fr>
9  *          Christophe Massiot <massiot@via.ecp.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include "http.h"
30 #include "vlc_url.h"
31 #include "vlc_meta.h"
32 #include "vlc_strings.h"
33
34 static vlc_object_t *GetVLCObject( intf_thread_t *p_intf,
35                                    const char *psz_object,
36                                    bool *pb_need_release )
37 {
38     intf_sys_t    *p_sys = p_intf->p_sys;
39     int i_object_type = 0;
40     vlc_object_t *p_object = NULL;
41     *pb_need_release = false;
42
43     if( !strcmp( psz_object, "VLC_OBJECT_LIBVLC" ) )
44         p_object = VLC_OBJECT(p_intf->p_libvlc);
45     else if( !strcmp( psz_object, "VLC_OBJECT_INTF" ) )
46         p_object = VLC_OBJECT(p_intf);
47     else if( !strcmp( psz_object, "VLC_OBJECT_PLAYLIST" ) )
48         p_object = VLC_OBJECT(p_sys->p_playlist);
49     else if( !strcmp( psz_object, "VLC_OBJECT_INPUT" ) )
50         p_object = VLC_OBJECT(p_sys->p_input);
51     else if( !strcmp( psz_object, "VLC_OBJECT_VOUT" ) )
52         i_object_type = VLC_OBJECT_VOUT;
53     else if( !strcmp( psz_object, "VLC_OBJECT_AOUT" ) )
54         i_object_type = VLC_OBJECT_AOUT;
55     else
56         msg_Warn( p_intf, "unknown object type (%s)", psz_object );
57
58     if( p_object == NULL && i_object_type )
59     {
60         *pb_need_release = true;
61         p_object = vlc_object_find( p_intf, i_object_type, FIND_ANYWHERE );
62     }
63
64     return p_object;
65 }
66
67 void SSInit( rpn_stack_t *st )
68 {
69     st->i_stack = 0;
70 }
71
72 void SSClean( rpn_stack_t *st )
73 {
74     while( st->i_stack > 0 )
75     {
76         free( st->stack[--st->i_stack] );
77     }
78 }
79
80 void SSPush( rpn_stack_t *st, const char *s )
81 {
82     if( st->i_stack < STACK_MAX )
83     {
84         st->stack[st->i_stack++] = strdup( s );
85     }
86 }
87
88 char *SSPop( rpn_stack_t *st )
89 {
90     if( st->i_stack <= 0 )
91     {
92         return strdup( "" );
93     }
94     else
95     {
96         return st->stack[--st->i_stack];
97     }
98 }
99
100 int SSPopN( rpn_stack_t *st, mvar_t  *vars )
101 {
102     char *name;
103
104     char *end;
105     int  i;
106
107     name = SSPop( st );
108     i = strtol( name, &end, 0 );
109     if( end == name )
110     {
111         const char *value = mvar_GetValue( vars, name );
112         i = atoi( value );
113     }
114     free( name );
115
116     return( i );
117 }
118
119 void SSPushN( rpn_stack_t *st, int i )
120 {
121     char v[12];
122
123     snprintf( v, sizeof (v), "%d", i );
124     SSPush( st, v );
125 }
126
127 void EvaluateRPN( intf_thread_t *p_intf, mvar_t  *vars,
128                       rpn_stack_t *st, char *exp )
129 {
130     intf_sys_t    *p_sys = p_intf->p_sys;
131
132     while( exp != NULL && *exp != '\0' )
133     {
134         char *p, *s;
135
136         /* skip space */
137         while( *exp == ' ' )
138         {
139             exp++;
140         }
141
142         if( *exp == '\'' )
143         {
144             /* extract string */
145             p = FirstWord( exp, exp );
146             SSPush( st, exp );
147             exp = p;
148             continue;
149         }
150
151         /* extract token */
152         p = FirstWord( exp, exp );
153         s = exp;
154         if( p == NULL )
155         {
156             exp += strlen( exp );
157         }
158         else
159         {
160             exp = p;
161         }
162
163         if( *s == '\0' )
164         {
165             break;
166         }
167
168         /* 1. Integer function */
169         if( !strcmp( s, "!" ) )
170         {
171             SSPushN( st, ~SSPopN( st, vars ) );
172         }
173         else if( !strcmp( s, "^" ) )
174         {
175             SSPushN( st, SSPopN( st, vars ) ^ SSPopN( st, vars ) );
176         }
177         else if( !strcmp( s, "&" ) )
178         {
179             SSPushN( st, SSPopN( st, vars ) & SSPopN( st, vars ) );
180         }
181         else if( !strcmp( s, "|" ) )
182         {
183             SSPushN( st, SSPopN( st, vars ) | SSPopN( st, vars ) );
184         }
185         else if( !strcmp( s, "+" ) )
186         {
187             SSPushN( st, SSPopN( st, vars ) + SSPopN( st, vars ) );
188         }
189         else if( !strcmp( s, "-" ) )
190         {
191             int j = SSPopN( st, vars );
192             int i = SSPopN( st, vars );
193             SSPushN( st, i - j );
194         }
195         else if( !strcmp( s, "*" ) )
196         {
197             SSPushN( st, SSPopN( st, vars ) * SSPopN( st, vars ) );
198         }
199         else if( !strcmp( s, "/" ) )
200         {
201             int i, j;
202
203             j = SSPopN( st, vars );
204             i = SSPopN( st, vars );
205
206             SSPushN( st, j != 0 ? i / j : 0 );
207         }
208         else if( !strcmp( s, "%" ) )
209         {
210             int i, j;
211
212             j = SSPopN( st, vars );
213             i = SSPopN( st, vars );
214
215             SSPushN( st, j != 0 ? i % j : 0 );
216         }
217         /* 2. integer tests */
218         else if( !strcmp( s, "=" ) )
219         {
220             SSPushN( st, SSPopN( st, vars ) == SSPopN( st, vars ) ? -1 : 0 );
221         }
222         else if( !strcmp( s, "!=" ) )
223         {
224             SSPushN( st, SSPopN( st, vars ) != SSPopN( st, vars ) ? -1 : 0 );
225         }
226         else if( !strcmp( s, "<" ) )
227         {
228             int j = SSPopN( st, vars );
229             int i = SSPopN( st, vars );
230
231             SSPushN( st, i < j ? -1 : 0 );
232         }
233         else if( !strcmp( s, ">" ) )
234         {
235             int j = SSPopN( st, vars );
236             int i = SSPopN( st, vars );
237
238             SSPushN( st, i > j ? -1 : 0 );
239         }
240         else if( !strcmp( s, "<=" ) )
241         {
242             int j = SSPopN( st, vars );
243             int i = SSPopN( st, vars );
244
245             SSPushN( st, i <= j ? -1 : 0 );
246         }
247         else if( !strcmp( s, ">=" ) )
248         {
249             int j = SSPopN( st, vars );
250             int i = SSPopN( st, vars );
251
252             SSPushN( st, i >= j ? -1 : 0 );
253         }
254         /* 3. string functions */
255         else if( !strcmp( s, "strcat" ) )
256         {
257             char *s2 = SSPop( st );
258             char *s1 = SSPop( st );
259             char *str = malloc( strlen( s1 ) + strlen( s2 ) + 1 );
260
261             strcpy( str, s1 );
262             strcat( str, s2 );
263
264             SSPush( st, str );
265             free( s1 );
266             free( s2 );
267             free( str );
268         }
269         else if( !strcmp( s, "strcmp" ) )
270         {
271             char *s2 = SSPop( st );
272             char *s1 = SSPop( st );
273
274             SSPushN( st, strcmp( s1, s2 ) );
275             free( s1 );
276             free( s2 );
277         }
278         else if( !strcmp( s, "strncmp" ) )
279         {
280             int n = SSPopN( st, vars );
281             char *s2 = SSPop( st );
282             char *s1 = SSPop( st );
283
284             SSPushN( st, strncmp( s1, s2 , n ) );
285             free( s1 );
286             free( s2 );
287         }
288         else if( !strcmp( s, "strsub" ) )
289         {
290             int n = SSPopN( st, vars );
291             int m = SSPopN( st, vars );
292             int i_len;
293             char *s = SSPop( st );
294             char *str;
295
296             if( n >= m )
297             {
298                 i_len = n - m + 1;
299             }
300             else
301             {
302                 i_len = 0;
303             }
304
305             str = malloc( i_len + 1 );
306
307             memcpy( str, s + m - 1, i_len );
308             str[ i_len ] = '\0';
309
310             SSPush( st, str );
311             free( s );
312             free( str );
313         }
314         else if( !strcmp( s, "strlen" ) )
315         {
316             char *str = SSPop( st );
317
318             SSPushN( st, strlen( str ) );
319             free( str );
320         }
321         else if( !strcmp( s, "str_replace" ) )
322         {
323             char *psz_to = SSPop( st );
324             char *psz_from = SSPop( st );
325             char *psz_in = SSPop( st );
326             char *psz_in_current = psz_in;
327             char *psz_out = malloc( strlen(psz_in) * strlen(psz_to) + 1 );
328             char *psz_out_current = psz_out;
329
330             while( (p = strstr( psz_in_current, psz_from )) != NULL )
331             {
332                 memcpy( psz_out_current, psz_in_current, p - psz_in_current );
333                 psz_out_current += p - psz_in_current;
334                 strcpy( psz_out_current, psz_to );
335                 psz_out_current += strlen(psz_to);
336                 psz_in_current = p + strlen(psz_from);
337             }
338             strcpy( psz_out_current, psz_in_current );
339             psz_out_current += strlen(psz_in_current);
340             *psz_out_current = '\0';
341
342             SSPush( st, psz_out );
343             free( psz_to );
344             free( psz_from );
345             free( psz_in );
346             free( psz_out );
347         }
348         else if( !strcmp( s, "url_extract" ) )
349         {
350             const char *url = mvar_GetValue( vars, "url_value" );
351             char *name = SSPop( st );
352             char *value = ExtractURIString( url, name );
353             if( value != NULL )
354             {
355                 decode_URI( value );
356                 SSPush( st, value );
357                 free( value );
358             }
359             else
360                 SSPush( st, "" );
361
362             free( name );
363         }
364         else if( !strcmp( s, "url_encode" ) )
365         {
366             char *url = SSPop( st );
367             char *value = vlc_UrlEncode( url );
368             free( url );
369             SSPush( st, value );
370             free( value );
371         }
372         else if( !strcmp( s, "xml_encode" ) )
373         {
374             char *url = SSPop( st );
375             char *value = convert_xml_special_chars( url );
376             free( url );
377             SSPush( st, value );
378             free( value );
379         }
380         else if( !strcmp( s, "addslashes" ) )
381         {
382             char *psz_src = SSPop( st );
383             char *psz_dest;
384             char *str = psz_src;
385
386             p = psz_dest = malloc( strlen( str ) * 2 + 1 );
387
388             while( *str != '\0' )
389             {
390                 if( *str == '"' || *str == '\'' || *str == '\\' )
391                 {
392                     *p++ = '\\';
393                 }
394                 *p++ = *str;
395                 str++;
396             }
397             *p = '\0';
398
399             SSPush( st, psz_dest );
400             free( psz_src );
401             free( psz_dest );
402         }
403         else if( !strcmp( s, "stripslashes" ) )
404         {
405             char *psz_src = SSPop( st );
406             char *psz_dest;
407             char *str = psz_src;
408
409             p = psz_dest = strdup( psz_src );
410
411             while( *str )
412             {
413                 if( *str == '\\' && *(str + 1) )
414                 {
415                     str++;
416                 }
417                 *p++ = *str++;
418             }
419             *p = '\0';
420
421             SSPush( st, psz_dest );
422             free( psz_src );
423             free( psz_dest );
424         }
425         else if( !strcmp( s, "htmlspecialchars" ) )
426         {
427             char *psz_src = SSPop( st );
428             char *psz_dest;
429
430             psz_dest = convert_xml_special_chars( psz_src );
431
432             SSPush( st, psz_dest );
433             free( psz_src );
434             free( psz_dest );
435         }
436         else if( !strcmp( s, "realpath" ) )
437         {
438             char *psz_src = SSPop( st );
439             char *psz_dir = RealPath( psz_src );
440
441             SSPush( st, psz_dir );
442             free( psz_src );
443             free( psz_dir );
444         }
445         /* 4. stack functions */
446         else if( !strcmp( s, "dup" ) )
447         {
448             char *str = SSPop( st );
449             SSPush( st, str );
450             SSPush( st, str );
451             free( str );
452         }
453         else if( !strcmp( s, "drop" ) )
454         {
455             char *str = SSPop( st );
456             free( str );
457         }
458         else if( !strcmp( s, "swap" ) )
459         {
460             char *s1 = SSPop( st );
461             char *s2 = SSPop( st );
462
463             SSPush( st, s1 );
464             SSPush( st, s2 );
465             free( s1 );
466             free( s2 );
467         }
468         else if( !strcmp( s, "flush" ) )
469         {
470             SSClean( st );
471             SSInit( st );
472         }
473         else if( !strcmp( s, "store" ) )
474         {
475             char *value = SSPop( st );
476             char *name  = SSPop( st );
477
478             mvar_PushNewVar( vars, name, value );
479             free( name );
480             free( value );
481         }
482         else if( !strcmp( s, "value" ) )
483         {
484             char *name  = SSPop( st );
485             const char *value = mvar_GetValue( vars, name );
486
487             SSPush( st, value );
488
489             free( name );
490         }
491         /* 5. player control */
492         else if( !strcmp( s, "vlc_play" ) )
493         {
494             int i_id = SSPopN( st, vars );
495             int i_ret;
496
497             playlist_Lock( p_sys->p_playlist );
498             i_ret = playlist_Control( p_sys->p_playlist, PLAYLIST_VIEWPLAY,
499                                       pl_Locked, NULL,
500                                       playlist_ItemGetById( p_sys->p_playlist,
501                                       i_id, pl_Locked ) );
502             playlist_Unlock( p_sys->p_playlist );
503             msg_Dbg( p_intf, "requested playlist item: %i", i_id );
504             SSPushN( st, i_ret );
505         }
506         else if( !strcmp( s, "vlc_stop" ) )
507         {
508             playlist_Control( p_sys->p_playlist, PLAYLIST_STOP, pl_Unlocked );
509             msg_Dbg( p_intf, "requested playlist stop" );
510         }
511         else if( !strcmp( s, "vlc_pause" ) )
512         {
513             playlist_Control( p_sys->p_playlist, PLAYLIST_PAUSE, pl_Unlocked );
514             msg_Dbg( p_intf, "requested playlist pause" );
515         }
516         else if( !strcmp( s, "vlc_next" ) )
517         {
518             playlist_Control( p_sys->p_playlist, PLAYLIST_SKIP, pl_Unlocked, 1 );
519             msg_Dbg( p_intf, "requested playlist next" );
520         }
521         else if( !strcmp( s, "vlc_previous" ) )
522         {
523             playlist_Control( p_sys->p_playlist, PLAYLIST_SKIP, pl_Unlocked, -1 );
524             msg_Dbg( p_intf, "requested playlist previous" );
525         }
526         else if( !strcmp( s, "vlc_seek" ) )
527         {
528             char *psz_value = SSPop( st );
529             HandleSeek( p_intf, psz_value );
530             msg_Dbg( p_intf, "requested playlist seek: %s", psz_value );
531             free( psz_value );
532         }
533         else if( !strcmp( s, "vlc_var_type" )
534                   || !strcmp( s, "vlc_config_type" ) )
535         {
536             vlc_object_t *p_object;
537             const char *psz_type = NULL;
538             int i_type = 0;
539
540             if( !strcmp( s, "vlc_var_type" ) )
541             {
542                 char *psz_object = SSPop( st );
543                 char *psz_variable = SSPop( st );
544                 bool b_need_release;
545
546                 p_object = GetVLCObject( p_intf, psz_object, &b_need_release );
547
548                 if( p_object != NULL )
549                     i_type = var_Type( p_object, psz_variable );
550                 free( psz_variable );
551                 free( psz_object );
552                 if( b_need_release && p_object != NULL )
553                     vlc_object_release( p_object );
554             }
555             else
556             {
557                 char *psz_variable = SSPop( st );
558                 p_object = VLC_OBJECT(p_intf);
559                 i_type = config_GetType( p_object, psz_variable );
560                 free( psz_variable );
561             }
562
563             if( p_object != NULL )
564             {
565                 switch( i_type & VLC_VAR_TYPE )
566                 {
567                 case VLC_VAR_BOOL:
568                     psz_type = "VLC_VAR_BOOL";
569                     break;
570                 case VLC_VAR_INTEGER:
571                     psz_type = "VLC_VAR_INTEGER";
572                     break;
573                 case VLC_VAR_HOTKEY:
574                     psz_type = "VLC_VAR_HOTKEY";
575                     break;
576                 case VLC_VAR_STRING:
577                     psz_type = "VLC_VAR_STRING";
578                     break;
579                 case VLC_VAR_MODULE:
580                     psz_type = "VLC_VAR_MODULE";
581                     break;
582                 case VLC_VAR_FILE:
583                     psz_type = "VLC_VAR_FILE";
584                     break;
585                 case VLC_VAR_DIRECTORY:
586                     psz_type = "VLC_VAR_DIRECTORY";
587                     break;
588                 case VLC_VAR_VARIABLE:
589                     psz_type = "VLC_VAR_VARIABLE";
590                     break;
591                 case VLC_VAR_FLOAT:
592                     psz_type = "VLC_VAR_FLOAT";
593                     break;
594                 default:
595                     psz_type = "UNDEFINED";
596                 }
597             }
598             else
599                 psz_type = "INVALID";
600
601             SSPush( st, psz_type );
602         }
603         else if( !strcmp( s, "vlc_var_set" ) )
604         {
605             char *psz_object = SSPop( st );
606             char *psz_variable = SSPop( st );
607             bool b_need_release;
608
609             vlc_object_t *p_object = GetVLCObject( p_intf, psz_object,
610                                                    &b_need_release );
611
612             if( p_object != NULL )
613             {
614                 bool b_error = false;
615                 char *psz_value = NULL;
616                 vlc_value_t val;
617                 int i_type;
618
619                 i_type = var_Type( p_object, psz_variable );
620
621                 switch( i_type & VLC_VAR_TYPE )
622                 {
623                 case VLC_VAR_BOOL:
624                     val.b_bool = SSPopN( st, vars );
625                     msg_Dbg( p_intf, "requested %s var change: %s->%d",
626                              psz_object, psz_variable, val.b_bool );
627                     break;
628                 case VLC_VAR_INTEGER:
629                 case VLC_VAR_HOTKEY:
630                     val.i_int = SSPopN( st, vars );
631                     msg_Dbg( p_intf, "requested %s var change: %s->%d",
632                              psz_object, psz_variable, val.i_int );
633                     break;
634                 case VLC_VAR_STRING:
635                 case VLC_VAR_MODULE:
636                 case VLC_VAR_FILE:
637                 case VLC_VAR_DIRECTORY:
638                 case VLC_VAR_VARIABLE:
639                     val.psz_string = psz_value = SSPop( st );
640                     msg_Dbg( p_intf, "requested %s var change: %s->%s",
641                              psz_object, psz_variable, psz_value );
642                     break;
643                 case VLC_VAR_FLOAT:
644                     psz_value = SSPop( st );
645                     val.f_float = atof( psz_value );
646                     msg_Dbg( p_intf, "requested %s var change: %s->%f",
647                              psz_object, psz_variable, val.f_float );
648                     break;
649                 default:
650                     SSPopN( st, vars );
651                     msg_Warn( p_intf, "invalid %s variable type %d (%s)",
652                               psz_object, i_type & VLC_VAR_TYPE, psz_variable );
653                     b_error = true;
654                 }
655
656                 if( !b_error )
657                     var_Set( p_object, psz_variable, val );
658                 if( psz_value != NULL )
659                     free( psz_value );
660             }
661             else
662                 msg_Warn( p_intf, "vlc_var_set called without an object" );
663             free( psz_variable );
664             free( psz_object );
665
666             if( b_need_release && p_object != NULL )
667                 vlc_object_release( p_object );
668         }
669         else if( !strcmp( s, "vlc_var_get" ) )
670         {
671             char *psz_object = SSPop( st );
672             char *psz_variable = SSPop( st );
673             bool b_need_release;
674
675             vlc_object_t *p_object = GetVLCObject( p_intf, psz_object,
676                                                    &b_need_release );
677
678             if( p_object != NULL )
679             {
680                 vlc_value_t val;
681                 int i_type;
682
683                 i_type = var_Type( p_object, psz_variable );
684                 var_Get( p_object, psz_variable, &val );
685
686                 switch( i_type & VLC_VAR_TYPE )
687                 {
688                 case VLC_VAR_BOOL:
689                     SSPushN( st, val.b_bool );
690                     break;
691                 case VLC_VAR_INTEGER:
692                 case VLC_VAR_HOTKEY:
693                     SSPushN( st, val.i_int );
694                     break;
695                 case VLC_VAR_STRING:
696                 case VLC_VAR_MODULE:
697                 case VLC_VAR_FILE:
698                 case VLC_VAR_DIRECTORY:
699                 case VLC_VAR_VARIABLE:
700                     SSPush( st, val.psz_string );
701                     free( val.psz_string );
702                     break;
703                 case VLC_VAR_FLOAT:
704                 {
705                     char psz_value[20];
706                     lldiv_t value = lldiv( val.f_float * 1000000, 1000000 );
707                     snprintf( psz_value, sizeof(psz_value), "%lld.%06u",
708                                     value.quot, (unsigned int)value.rem );
709                     SSPush( st, psz_value );
710                     break;
711                 }
712                 default:
713                     msg_Warn( p_intf, "invalid %s variable type %d (%s)",
714                               psz_object, i_type & VLC_VAR_TYPE, psz_variable );
715                     SSPush( st, "" );
716                 }
717             }
718             else
719             {
720                 msg_Warn( p_intf, "vlc_var_get called without an object" );
721                 SSPush( st, "" );
722             }
723             free( psz_variable );
724             free( psz_object );
725
726             if( b_need_release && p_object != NULL )
727                 vlc_object_release( p_object );
728         }
729         else if( !strcmp( s, "vlc_object_exists" ) )
730         {
731             char *psz_object = SSPop( st );
732             bool b_need_release;
733
734             vlc_object_t *p_object = GetVLCObject( p_intf, psz_object,
735                                                    &b_need_release );
736             if( b_need_release && p_object != NULL )
737                 vlc_object_release( p_object );
738
739             if( p_object != NULL )
740                 SSPush( st, "1" );
741             else
742                 SSPush( st, "0" );
743         }
744         else if( !strcmp( s, "vlc_config_set" ) )
745         {
746             char *psz_variable = SSPop( st );
747             int i_type = config_GetType( p_intf, psz_variable );
748
749             switch( i_type & VLC_VAR_TYPE )
750             {
751             case VLC_VAR_BOOL:
752             case VLC_VAR_INTEGER:
753                 config_PutInt( p_intf, psz_variable, SSPopN( st, vars ) );
754                 break;
755             case VLC_VAR_STRING:
756             case VLC_VAR_MODULE:
757             case VLC_VAR_FILE:
758             case VLC_VAR_DIRECTORY:
759             {
760                 char *psz_string = SSPop( st );
761                 config_PutPsz( p_intf, psz_variable, psz_string );
762                 free( psz_string );
763                 break;
764             }
765             case VLC_VAR_FLOAT:
766             {
767                 char *psz_string = SSPop( st );
768                 config_PutFloat( p_intf, psz_variable, atof(psz_string) );
769                 free( psz_string );
770                 break;
771             }
772             default:
773                 msg_Warn( p_intf, "vlc_config_set called on unknown var (%s)",
774                           psz_variable );
775             }
776             free( psz_variable );
777         }
778         else if( !strcmp( s, "vlc_config_get" ) )
779         {
780             char *psz_variable = SSPop( st );
781             int i_type = config_GetType( p_intf, psz_variable );
782
783             switch( i_type & VLC_VAR_TYPE )
784             {
785             case VLC_VAR_BOOL:
786             case VLC_VAR_INTEGER:
787                 SSPushN( st, config_GetInt( p_intf, psz_variable ) );
788                 break;
789             case VLC_VAR_STRING:
790             case VLC_VAR_MODULE:
791             case VLC_VAR_FILE:
792             case VLC_VAR_DIRECTORY:
793             {
794                 char *psz_string = config_GetPsz( p_intf, psz_variable );
795                 SSPush( st, psz_string );
796                 free( psz_string );
797                 break;
798             }
799             case VLC_VAR_FLOAT:
800             {
801                 char psz_string[20];
802                 lldiv_t value = lldiv( config_GetFloat( p_intf, psz_variable )
803                                        * 1000000, 1000000 );
804                 snprintf( psz_string, sizeof(psz_string), "%lld.%06u",
805                           value.quot, (unsigned int)value.rem );
806                 SSPush( st, psz_string );
807                 break;
808             }
809             default:
810                 msg_Warn( p_intf, "vlc_config_get called on unknown var (%s)",
811                           psz_variable );
812                 SSPush( st, "" );
813             }
814             free( psz_variable );
815         }
816         else if( !strcmp( s, "vlc_config_save" ) )
817         {
818             char *psz_module = SSPop( st );
819             int i_result;
820
821             if( !*psz_module )
822             {
823                 free( psz_module );
824                 psz_module = NULL;
825             }
826             i_result = config_SaveConfigFile( p_intf, psz_module );
827
828             if( psz_module != NULL )
829                 free( psz_module );
830             SSPushN( st, i_result );
831         }
832         else if( !strcmp( s, "vlc_config_reset" ) )
833         {
834             config_ResetAll( p_intf );
835         }
836         /* 6. playlist functions */
837         else if( !strcmp( s, "playlist_add" ) )
838         {
839             char *psz_name = SSPop( st );
840             char *mrl = SSPop( st );
841             input_item_t *p_input;
842             int i_ret;
843
844             p_input = MRLParse( p_intf, mrl, psz_name );
845
846             char *psz_uri = input_item_GetURI( p_input );
847             if( !p_input || !psz_uri || !*psz_uri )
848             {
849                 i_ret = VLC_EGENERIC;
850                 msg_Dbg( p_intf, "invalid requested mrl: %s", mrl );
851             }
852             else
853             {
854                 i_ret = playlist_AddInput( p_sys->p_playlist, p_input,
855                                    PLAYLIST_APPEND, PLAYLIST_END, true,
856                                    pl_Unlocked );
857                 if( i_ret == VLC_SUCCESS )
858                 {
859                     playlist_item_t *p_item;
860                     msg_Dbg( p_intf, "requested mrl add: %s", mrl );
861                     p_item = playlist_ItemGetByInput( p_sys->p_playlist,
862                                                       p_input,
863                                                       pl_Unlocked );
864                     if( p_item )
865                         i_ret = p_item->i_id;
866                 }
867                 else
868                     msg_Warn( p_intf, "adding mrl %s failed", mrl );
869                 vlc_gc_decref( p_input );
870             }
871             free( psz_uri );
872             SSPushN( st, i_ret );
873
874             free( mrl );
875             free( psz_name );
876         }
877         else if( !strcmp( s, "playlist_empty" ) )
878         {
879             playlist_Clear( p_sys->p_playlist, pl_Unlocked );
880             msg_Dbg( p_intf, "requested playlist empty" );
881         }
882         else if( !strcmp( s, "playlist_delete" ) )
883         {
884             int i_id = SSPopN( st, vars );
885             playlist_item_t *p_item = playlist_ItemGetById( p_sys->p_playlist,
886                                                             i_id, pl_Unlocked );
887             if( p_item )
888             {
889                 playlist_DeleteFromInput( p_sys->p_playlist,
890                                           p_item->p_input->i_id, pl_Unlocked );
891                 msg_Dbg( p_intf, "requested playlist delete: %d", i_id );
892             }
893             else
894             {
895                 msg_Dbg( p_intf, "couldn't find playlist item to delete (%d)",
896                          i_id );
897             }
898         }
899         else if( !strcmp( s, "playlist_move" ) )
900         {
901             /*int i_newpos =*/ SSPopN( st, vars );
902             /*int i_pos =*/ SSPopN( st, vars );
903             /* FIXME FIXME TODO TODO XXX XXX
904             do not release before fixing this
905             if ( i_pos < i_newpos )
906             {
907                 playlist_Move( p_sys->p_playlist, i_pos, i_newpos + 1 );
908             }
909             else
910             {
911                 playlist_Move( p_sys->p_playlist, i_pos, i_newpos );
912             }
913             msg_Dbg( p_intf, "requested to move playlist item %d to %d",
914                      i_pos, i_newpos);
915                FIXME FIXME TODO TODO XXX XXX */
916             msg_Err( p_intf, "moving using indexes is obsolete. We need to update this function" );
917         }
918         else if( !strcmp( s, "playlist_sort" ) )
919         {
920             int i_order = SSPopN( st, vars );
921             int i_sort = SSPopN( st, vars );
922             i_order = i_order % 2;
923             i_sort = i_sort % 9;
924             /* FIXME FIXME TODO TODO XXX XXX
925             do not release before fixing this
926             playlist_RecursiveNodeSort(  p_sys->p_playlist,
927                                          p_sys->p_playlist->p_general,
928                                          i_sort, i_order );
929             msg_Dbg( p_intf, "requested sort playlist by : %d in order : %d",
930                      i_sort, i_order );
931                FIXME FIXME TODO TODO XXX XXX */
932             msg_Err( p_intf, "this needs to be fixed to use the new playlist framework" );
933         }
934         else if( !strcmp( s, "services_discovery_add" ) )
935         {
936             char *psz_sd = SSPop( st );
937             playlist_ServicesDiscoveryAdd( p_sys->p_playlist, psz_sd );
938             free( psz_sd );
939         }
940         else if( !strcmp( s, "services_discovery_remove" ) )
941         {
942             char *psz_sd = SSPop( st );
943             playlist_ServicesDiscoveryRemove( p_sys->p_playlist, psz_sd );
944             free( psz_sd );
945         }
946         else if( !strcmp( s, "services_discovery_is_loaded" ) )
947         {
948             char *psz_sd = SSPop( st );
949             SSPushN( st,
950             playlist_IsServicesDiscoveryLoaded( p_sys->p_playlist, psz_sd ) );
951             free( psz_sd );
952         }
953         else if( !strcmp( s, "vlc_volume_set" ) )
954         {
955             char *psz_vol = SSPop( st );
956             int i_value;
957             audio_volume_t i_volume;
958             aout_VolumeGet( p_intf, &i_volume );
959             if( psz_vol[0] == '+' )
960             {
961                 i_value = atoi( psz_vol );
962                 if( (i_volume + i_value) > AOUT_VOLUME_MAX )
963                     aout_VolumeSet( p_intf, AOUT_VOLUME_MAX );
964                 else
965                     aout_VolumeSet( p_intf, i_volume + i_value );
966             }
967             else if( psz_vol[0] == '-' )
968             {
969                 i_value = atoi( psz_vol );
970                 if( (i_volume + i_value) < AOUT_VOLUME_MIN )
971                     aout_VolumeSet( p_intf, AOUT_VOLUME_MIN );
972                 else
973                     aout_VolumeSet( p_intf, i_volume + i_value );
974             }
975             else if( strstr( psz_vol, "%") != NULL )
976             {
977                 i_value = atoi( psz_vol );
978                 if( i_value < 0 ) i_value = 0;
979                 if( i_value > 400 ) i_value = 400;
980                 aout_VolumeSet( p_intf, (i_value * (AOUT_VOLUME_MAX - AOUT_VOLUME_MIN))/400+AOUT_VOLUME_MIN);
981             }
982             else
983             {
984                 i_value = atoi( psz_vol );
985                 if( i_value > AOUT_VOLUME_MAX ) i_value = AOUT_VOLUME_MAX;
986                 if( i_value < AOUT_VOLUME_MIN ) i_value = AOUT_VOLUME_MIN;
987                 aout_VolumeSet( p_intf, i_value );
988             }
989             aout_VolumeGet( p_intf, &i_volume );
990             free( psz_vol );
991         }
992         else if( !strcmp( s, "vlc_get_meta" ) )
993         {
994             char *psz_meta = SSPop( st );
995             char *psz_val = NULL;
996             if( p_sys->p_input && input_GetItem(p_sys->p_input) )
997             {
998 #define p_item input_GetItem( p_sys->p_input )
999                 if( !strcmp( psz_meta, "ARTIST" ) )
1000                 {
1001                     psz_val = input_item_GetArtist( p_item );
1002                 }
1003                 else if( !strcmp( psz_meta, "TITLE" ) )
1004                 {
1005                     psz_val = input_item_GetTitle( p_item );
1006                     if( !psz_val )
1007                         psz_val = input_item_GetName( p_item );
1008                 }
1009                 else if( !strcmp( psz_meta, "ALBUM" ) )
1010                 {
1011                     psz_val = input_item_GetAlbum( p_item );
1012                 }
1013                 else if( !strcmp( psz_meta, "GENRE" ) )
1014                 {
1015                     psz_val = input_item_GetGenre( p_item );
1016                 }
1017                 else if( !strcmp( psz_meta, "COPYRIGHT" ) )
1018                 {
1019                      psz_val = input_item_GetCopyright( p_item );
1020                 }
1021                 else if( !strcmp( psz_meta, "TRACK_NUMBER" ) )
1022                 {
1023                     psz_val = input_item_GetTrackNum( p_item );
1024                 }
1025                 else if( !strcmp( psz_meta, "DESCRIPTION" ) )
1026                 {
1027                     psz_val = input_item_GetDescription( p_item );
1028                 }
1029                 else if( !strcmp( psz_meta, "RATING" ) )
1030                 {
1031                     psz_val = input_item_GetRating( p_item );
1032                 }
1033                 else if( !strcmp( psz_meta, "DATE" ) )
1034                 {
1035                     psz_val = input_item_GetDate( p_item );
1036                 }
1037                 else if( !strcmp( psz_meta, "URL" ) )
1038                 {
1039                     psz_val = input_item_GetURL( p_item );
1040                 }
1041                 else if( !strcmp( psz_meta, "LANGUAGE" ) )
1042                 {
1043                     psz_val = input_item_GetLanguage( p_item );
1044                 }
1045                 else if( !strcmp( psz_meta, "NOW_PLAYING" ) )
1046                 {
1047                     psz_val = input_item_GetNowPlaying( p_item );
1048                 }
1049                 else if( !strcmp( psz_meta, "PUBLISHER" ) )
1050                 {
1051                     psz_val = input_item_GetPublisher( p_item );
1052                 }
1053                 else if( !strcmp( psz_meta, "ENCODED_BY" ) )
1054                 {
1055                     psz_val = input_item_GetEncodedBy( p_item );
1056                 }
1057                 else if( !strcmp( psz_meta, "ART_URL" ) )
1058                 {
1059                     psz_val = input_item_GetEncodedBy( p_item );
1060                 }
1061                 else if( !strcmp( psz_meta, "TRACK_ID" ) )
1062                 {
1063                     psz_val = input_item_GetTrackID( p_item );
1064                 }
1065 #undef p_item
1066             }
1067             if( psz_val == NULL ) psz_val = strdup( "" );
1068             SSPush( st, psz_val );
1069             free( psz_meta );
1070             free( psz_val );
1071         }
1072 #ifdef ENABLE_VLM
1073         else if( !strcmp( s, "vlm_command" ) || !strcmp( s, "vlm_cmd" ) )
1074         {
1075             char *psz_elt;
1076             char *psz_cmd = strdup( "" );
1077             char *psz_error;
1078             vlm_message_t *vlm_answer;
1079
1080             /* make sure that we have a vlm object */
1081             if( p_intf->p_sys->p_vlm == NULL )
1082                 p_intf->p_sys->p_vlm = vlm_New( p_intf );
1083
1084
1085             /* vlm command uses the ';' delimiter
1086              * (else we can't know when to stop) */
1087             while( strcmp( psz_elt = SSPop( st ), "" )
1088                    && strcmp( psz_elt, ";" ) )
1089             {
1090                 char* psz_buf;
1091                 if( asprintf( &psz_buf, "%s %s", psz_cmd, psz_elt ) == -1 )
1092                     psz_buf = NULL;
1093                 free( psz_cmd );
1094                 free( psz_elt );
1095                 psz_cmd = psz_buf;
1096             }
1097
1098             msg_Dbg( p_intf, "executing vlm command: %s", psz_cmd );
1099             vlm_ExecuteCommand( p_intf->p_sys->p_vlm, psz_cmd, &vlm_answer );
1100
1101             if( vlm_answer->psz_value == NULL )
1102             {
1103                 psz_error = strdup( "" );
1104             }
1105             else
1106             {
1107                 if( asprintf( &psz_error , "%s : %s" , vlm_answer->psz_name,
1108                               vlm_answer->psz_value ) == -1 )
1109                     psz_error = NULL;
1110             }
1111
1112             mvar_AppendNewVar( vars, "vlm_error", psz_error );
1113             /* this is kind of a duplicate but we need to have the message
1114              * without the command name for the "export" command */
1115             mvar_AppendNewVar( vars, "vlm_value", vlm_answer->psz_value );
1116             vlm_MessageDelete( vlm_answer );
1117
1118             free( psz_cmd );
1119             free( psz_error );
1120         }
1121 #endif /* ENABLE_VLM */
1122         else if( !strcmp( s, "snapshot" ) )
1123         {
1124             if( p_sys->p_input )
1125             {
1126                 vout_thread_t *p_vout;
1127                 p_vout = vlc_object_find( p_sys->p_input,
1128                                           VLC_OBJECT_VOUT, FIND_CHILD );
1129
1130                 if( p_vout )
1131                 {
1132                     vout_Control( p_vout, VOUT_SNAPSHOT );
1133                     vlc_object_release( p_vout );
1134                     msg_Dbg( p_intf, "requested snapshot" );
1135                 }
1136             }
1137             break;
1138
1139         }
1140         else
1141         {
1142             SSPush( st, s );
1143         }
1144     }
1145 }