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