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