]> git.sesse.net Git - vlc/blob - modules/control/http/macro.c
Replace argument = realloc( argument, size ); with realloc_or_free() in modules/...
[vlc] / modules / control / http / macro.c
1 /*****************************************************************************
2  * macro.c : Custom <vlc> macro handling
3  *****************************************************************************
4  * Copyright (C) 2001-2005 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 <assert.h>
30
31 #include "http.h"
32 #include "macros.h"
33 #include <vlc_url.h>
34 #include <vlc_memory.h>
35
36 static int MacroParse( macro_t *m, char *psz_src )
37 {
38     char *dup = strdup( (char *)psz_src );
39     char *src = dup;
40     char *p;
41     int     i_skip;
42
43 #define EXTRACT( name, l ) \
44         src += l;    \
45         p = strchr( src, '"' );             \
46         if( p )                             \
47         {                                   \
48             *p++ = '\0';                    \
49         }                                   \
50         m->name = strdup( src );            \
51         if( !p )                            \
52         {                                   \
53             break;                          \
54         }                                   \
55         src = p;
56
57     /* init m */
58     m->id = NULL;
59     m->param1 = NULL;
60     m->param2 = NULL;
61
62     /* parse */
63     src += 4;
64
65     while( *src )
66     {
67         while( *src == ' ')
68         {
69             src++;
70         }
71         if( !strncmp( src, "id=\"", 4 ) )
72         {
73             EXTRACT( id, 4 );
74         }
75         else if( !strncmp( src, "param1=\"", 8 ) )
76         {
77             EXTRACT( param1, 8 );
78         }
79         else if( !strncmp( src, "param2=\"", 8 ) )
80         {
81             EXTRACT( param2, 8 );
82         }
83         else
84         {
85             break;
86         }
87     }
88     if( strstr( src, "/>" ) )
89     {
90         src = strstr( src, "/>" ) + 2;
91     }
92     else
93     {
94         src += strlen( src );
95     }
96
97     if( m->id == NULL )
98     {
99         m->id = strdup( "" );
100     }
101     if( m->param1 == NULL )
102     {
103         m->param1 = strdup( "" );
104     }
105     if( m->param2 == NULL )
106     {
107         m->param2 = strdup( "" );
108     }
109     i_skip = src - dup;
110
111     free( dup );
112     return i_skip;
113 #undef EXTRACT
114 }
115
116 static void MacroClean( macro_t *m )
117 {
118     free( m->id );
119     free( m->param1 );
120     free( m->param2 );
121 }
122
123 static int StrToMacroType( const char *name )
124 {
125     int i;
126
127     if( !name || *name == '\0')
128     {
129         return MVLC_UNKNOWN;
130     }
131     for( i = 0; StrToMacroTypeTab[i].psz_name != NULL; i++ )
132     {
133         if( !strcmp( name, StrToMacroTypeTab[i].psz_name ) )
134         {
135             return StrToMacroTypeTab[i].i_type;
136         }
137     }
138     return MVLC_UNKNOWN;
139 }
140
141 static void MacroDo( httpd_file_sys_t *p_args,
142                      macro_t *m,
143                      char *p_request, int i_request,
144                      char **pp_data,  int *pi_data,
145                      char **pp_dst )
146 {
147     intf_thread_t  *p_intf = p_args->p_intf;
148     intf_sys_t     *p_sys = p_args->p_intf->p_sys;
149     char control[512];
150
151 #define ALLOC( l ) \
152     {               \
153         int __i__ = *pp_dst - *pp_data; \
154         *pi_data += (l);                  \
155         *pp_data = realloc_or_free( *pp_data, *pi_data );   \
156         assert( *pp_data ); \
157         *pp_dst = (*pp_data) + __i__;   \
158     }
159 #define PRINT( str ) \
160     ALLOC( strlen( str ) + 1 ); \
161     *pp_dst += sprintf( *pp_dst, "%s", str );
162
163 #define PRINTS( str, s ) \
164     ALLOC( strlen( str ) + strlen( s ) + 1 ); \
165     { \
166         char * psz_cur = *pp_dst; \
167         *pp_dst += sprintf( *pp_dst, str, s ); \
168         while( psz_cur && *psz_cur ) \
169         {  \
170             /* Prevent script injection */ \
171             if( *psz_cur == '<' ) *psz_cur = '*'; \
172             if( *psz_cur == '>' ) *psz_cur = '*'; \
173             psz_cur++ ; \
174         } \
175     }
176
177     switch( StrToMacroType( m->id ) )
178     {
179         case MVLC_CONTROL:
180             if( i_request <= 0 )
181             {
182                 break;
183             }
184             ExtractURIValue( p_request, "control", control, 512 );
185             if( *m->param1 && !strstr( m->param1, control ) )
186             {
187                 msg_Warn( p_intf, "unauthorized control=%s", control );
188                 break;
189             }
190             switch( StrToMacroType( control ) )
191             {
192                 case MVLC_PLAY:
193                 {
194                     int i_item;
195                     char item[512];
196
197                     ExtractURIValue( p_request, "item", item, 512 );
198                     i_item = atoi( item );
199                     /* id = 0 : simply ask playlist to play */
200                     if( i_item == 0 )
201                     {
202                         playlist_Play( p_sys->p_playlist );
203                         msg_Dbg( p_intf, "requested playlist play" );
204                         break;
205                     }
206                     //TODO: really locked here ?
207                     playlist_Control( p_sys->p_playlist, PLAYLIST_VIEWPLAY,
208                                       true, NULL,
209                                       playlist_ItemGetById( p_sys->p_playlist,
210                                       i_item ) );
211                     msg_Dbg( p_intf, "requested playlist item: %i", i_item );
212                     break;
213                 }
214                 case MVLC_STOP:
215                     playlist_Control( p_sys->p_playlist, PLAYLIST_STOP,
216                                       true );
217                     msg_Dbg( p_intf, "requested playlist stop" );
218                     break;
219                 case MVLC_PAUSE:
220                     playlist_Control( p_sys->p_playlist, PLAYLIST_PAUSE,
221                                       true );
222                     msg_Dbg( p_intf, "requested playlist pause" );
223                     break;
224                 case MVLC_NEXT:
225                     playlist_Control( p_sys->p_playlist, PLAYLIST_SKIP,
226                                       true, 1 );
227                     msg_Dbg( p_intf, "requested playlist next" );
228                     break;
229                 case MVLC_PREVIOUS:
230                     playlist_Control( p_sys->p_playlist, PLAYLIST_SKIP,
231                                       true, -1 );
232                     msg_Dbg( p_intf, "requested playlist previous" );
233                     break;
234                 case MVLC_FULLSCREEN:
235                     if( p_sys->p_input )
236                     {
237                         vout_thread_t *p_vout;
238
239                         p_vout = input_GetVout( p_sys->p_input );
240                         if( p_vout )
241                         {
242                             var_ToggleBool( p_vout, "fullscreen" );
243                             vlc_object_release( p_vout );
244                             msg_Dbg( p_intf, "requested fullscreen toggle" );
245                         }
246                     }
247                     break;
248                 case MVLC_SEEK:
249                 {
250                     char value[30];
251                     ExtractURIValue( p_request, "seek_value", value, 30 );
252                     decode_URI( value );
253                     HandleSeek( p_intf, value );
254                     break;
255                 }
256                 case MVLC_VOLUME:
257                 {
258                     char vol[8];
259                     audio_volume_t i_volume;
260                     int i_value;
261
262                     ExtractURIValue( p_request, "value", vol, 8 );
263                     aout_VolumeGet( p_sys->p_playlist, &i_volume );
264                     decode_URI( vol );
265
266                     if( vol[0] == '+' )
267                     {
268                         i_value = atoi( vol + 1 );
269                         if( (i_volume + i_value) > AOUT_VOLUME_MAX )
270                         {
271                             aout_VolumeSet( p_sys->p_playlist, AOUT_VOLUME_MAX );
272                             msg_Dbg( p_intf, "requested volume set: max" );
273                         }
274                         else
275                         {
276                             aout_VolumeSet( p_sys->p_playlist, (i_volume + i_value) );
277                             msg_Dbg( p_intf, "requested volume set: +%i", (i_volume + i_value) );
278                         }
279                     }
280                     else if( vol[0] == '-' )
281                     {
282                         i_value = atoi( vol + 1 );
283                         if( (i_volume - i_value) < AOUT_VOLUME_MIN )
284                         {
285                             aout_VolumeSet( p_sys->p_playlist, AOUT_VOLUME_MIN );
286                             msg_Dbg( p_intf, "requested volume set: min" );
287                         }
288                         else
289                         {
290                             aout_VolumeSet( p_sys->p_playlist, (i_volume - i_value) );
291                             msg_Dbg( p_intf, "requested volume set: -%i", (i_volume - i_value) );
292                         }
293                     }
294                     else if( strstr(vol, "%") != NULL )
295                     {
296                         i_value = atoi( vol );
297                         if( (i_value <= 400) && (i_value>=0) ){
298                             aout_VolumeSet( p_sys->p_playlist, (i_value * (AOUT_VOLUME_MAX - AOUT_VOLUME_MIN))/400+AOUT_VOLUME_MIN);
299                             msg_Dbg( p_intf, "requested volume set: %i%%", atoi( vol ));
300                         }
301                     }
302                     else
303                     {
304                         i_value = atoi( vol );
305                         if( ( i_value <= AOUT_VOLUME_MAX ) && ( i_value >= AOUT_VOLUME_MIN ) )
306                         {
307                             aout_VolumeSet( p_sys->p_playlist, atoi( vol ) );
308                             msg_Dbg( p_intf, "requested volume set: %i", atoi( vol ) );
309                         }
310                     }
311                     break;
312                 }
313
314                 /* playlist management */
315                 case MVLC_ADD:
316                 {
317                     char mrl[1024], psz_name[1024], tmp[1024];
318                     char *p, *str;
319                     input_item_t *p_input;
320
321                     ExtractURIValue( p_request, "mrl", tmp, 1024 );
322                     decode_URI( tmp );
323                     ExtractURIValue( p_request, "name", psz_name, 1024 );
324                     decode_URI( psz_name );
325                     if( !*psz_name )
326                     {
327                         memcpy( psz_name, tmp, 1024 );
328                     }
329                     /* addslashes for backward compatibility with the old
330                      * http intf */
331                     p = mrl; str = tmp;
332                     while( *str != '\0' )
333                     {
334                         if( *str == '"' || *str == '\'' || *str == '\\' )
335                         {
336                             *p++ = '\\';
337                         }
338                         *p++ = *str;
339                         str++;
340                     }
341                     *p = '\0';
342
343                     p_input = MRLParse( p_intf, mrl, psz_name );
344
345                     char *psz_uri = p_input ? input_item_GetURI( p_input ) : NULL;
346                     if( psz_uri && *psz_uri &&
347                         playlist_AddInput( p_sys->p_playlist, p_input,
348                                            PLAYLIST_APPEND, PLAYLIST_END,
349                                            true, false) == VLC_SUCCESS )
350                         msg_Dbg( p_intf, "requested mrl add: %s", mrl );
351                     else
352                         msg_Warn( p_intf, "adding mrl failed: %s", mrl );
353                     free( psz_uri );
354                     if( p_input )
355                         vlc_gc_decref( p_input );
356                     break;
357                 }
358                 case MVLC_DEL:
359                 {
360                     int *p_items = NULL;
361                     size_t i_nb_items = 0;
362                     char item[512];
363                     const char *p_parser = p_request;
364
365                     /* Get the list of items to delete */
366                     while( (p_parser =
367                             ExtractURIValue( p_parser, "item", item, 512 )) )
368                     {
369                         if( !*item ) continue;
370
371                         int i_item = atoi( item );
372                         p_items = realloc_or_free( p_items,
373                                         (i_nb_items + 1) * sizeof(*p_items) );
374                         assert( p_items );
375                         p_items[i_nb_items] = i_item;
376                         i_nb_items++;
377                     }
378
379                     for( size_t i = 0; i < i_nb_items; i++ )
380                     {
381                         playlist_item_t *p_item;
382
383                         msg_Dbg( p_intf, "requested playlist delete: %d",
384                                  p_items[i] );
385                         p_item = playlist_ItemGetById( p_sys->p_playlist,
386                                                        p_items[i] );
387                         if( p_item )
388                             playlist_DeleteFromInput( p_sys->p_playlist,
389                                                       p_item->p_input,
390                                                       false );
391                     }
392
393                     free( p_items );
394                     break;
395                 }
396                 case MVLC_KEEP:
397                 {
398                     int *p_items = NULL;
399                     size_t i_nb_items = 0, i;
400                     char item[512];
401                     const char *p_parser = p_request;
402
403                     /* Get the list of items to keep */
404                     while( (p_parser =
405                        ExtractURIValue( p_parser, "item", item, 512 )) )
406                     {
407                         if( !*item ) continue;
408
409                         int i_item = atoi( item );
410                         p_items = realloc_or_free( p_items,
411                                         (i_nb_items + 1) * sizeof(*p_items) );
412                         assert( p_items );
413                         p_items[i_nb_items] = i_item;
414                         i_nb_items++;
415                     }
416
417                     size_t size = p_sys->p_playlist->items.i_size;
418                     for( i = 0; i < size; i++ )
419                     {
420                         size_t j;
421
422                         /* Check if the item is in the keep list */
423                         for( j = 0 ; j < i_nb_items ; j++ )
424                         {
425                             if( p_items[j] ==
426                                 ARRAY_VAL(p_sys->p_playlist->items,i)->i_id)
427                                 break;
428                         }
429                         if( j == i_nb_items )
430                         {
431                             msg_Dbg( p_intf, "requested playlist delete: %d",
432                                    p_sys->p_playlist->items.p_elems[i]->i_id );
433                             playlist_DeleteFromInput( p_sys->p_playlist,
434                                 p_sys->p_playlist->items.p_elems[i]->p_input,
435                                                       false );
436                         }
437                     }
438
439                     free( p_items );
440                     break;
441                 }
442                 case MVLC_EMPTY:
443                 {
444                     playlist_Clear( p_sys->p_playlist, false );
445                     msg_Dbg( p_intf, "requested playlist empty" );
446                     break;
447                 }
448                 case MVLC_SORT:
449                 {
450                     char type[12];
451                     char order[2];
452                     char item[512];
453                     int i_order;
454                     int i_item;
455
456                     ExtractURIValue( p_request, "type", type, 12 );
457                     ExtractURIValue( p_request, "order", order, 2 );
458                     ExtractURIValue( p_request, "item", item, 512 );
459                     i_item = atoi( item );
460
461                     if( order[0] == '0' ) i_order = ORDER_NORMAL;
462                     else i_order = ORDER_REVERSE;
463
464                     if( !strcmp( type , "title" ) )
465                     {
466                         playlist_RecursiveNodeSort( p_sys->p_playlist,
467                                                     /* Ugly hack,but not worse than before ... */
468                                                     p_sys->p_playlist->p_root_onelevel,
469                                                     SORT_TITLE_NODES_FIRST,
470                                                     ( i_order == 0 ) ? ORDER_NORMAL : ORDER_REVERSE );
471                         msg_Dbg( p_intf, "requested playlist sort by title (%d)" , i_order );
472                     }
473                     else if( !strcmp( type , "author" ) )
474                     {
475                         playlist_RecursiveNodeSort( p_sys->p_playlist, /*playlist_ItemGetById( p_sys->p_playlist, i_item ),*/
476                                                     p_sys->p_playlist->p_root_onelevel,
477                                                     SORT_ARTIST,
478                                                     ( i_order == 0 ) ? ORDER_NORMAL : ORDER_REVERSE );
479                         msg_Dbg( p_intf, "requested playlist sort by author (%d)" , i_order );
480                     }
481                     else if( !strcmp( type , "shuffle" ) )
482                     {
483                         playlist_RecursiveNodeSort( p_sys->p_playlist, /*playlist_ItemGetById( p_sys->p_playlist, i_item ),*/
484                                                     p_sys->p_playlist->p_root_onelevel,
485                                                     SORT_RANDOM,
486                                                     ( i_order == 0 ) ? ORDER_NORMAL : ORDER_REVERSE );
487                         msg_Dbg( p_intf, "requested playlist shuffle");
488                     }
489
490                     break;
491                 }
492                 case MVLC_MOVE:
493                 {
494                     char psz_pos[6];
495                     char psz_newpos[6];
496                     int i_pos;
497                     int i_newpos;
498                     ExtractURIValue( p_request, "psz_pos", psz_pos, 6 );
499                     ExtractURIValue( p_request, "psz_newpos", psz_newpos, 6 );
500                     i_pos = atoi( psz_pos );
501                     i_newpos = atoi( psz_newpos );
502                     /* FIXME FIXME TODO TODO XXX XXX
503                     ( duplicate from rpn.c )
504                     if ( i_pos < i_newpos )
505                     {
506                         playlist_Move( p_sys->p_playlist, i_pos, i_newpos + 1 );
507                     }
508                     else
509                     {
510                         playlist_Move( p_sys->p_playlist, i_pos, i_newpos );
511                     }
512                     msg_Dbg( p_intf, "requested move playlist item %d to %d", i_pos, i_newpos);
513                     FIXME FIXME TODO TODO XXX XXX */
514                     break;
515                 }
516
517                 /* admin function */
518                 case MVLC_CLOSE:
519                 {
520                     char id[512];
521                     ExtractURIValue( p_request, "id", id, 512 );
522                     msg_Dbg( p_intf, "requested close id=%s", id );
523 #if 0
524                     if( p_sys->p_httpd->pf_control( p_sys->p_httpd, HTTPD_SET_CLOSE, id, NULL ) )
525                     {
526                         msg_Warn( p_intf, "close failed for id=%s", id );
527                     }
528 #endif
529                     break;
530                 }
531                 case MVLC_SHUTDOWN:
532                 {
533                     msg_Dbg( p_intf, "requested shutdown" );
534                     libvlc_Quit( p_intf->p_libvlc );
535                     break;
536                 }
537 #ifdef ENABLE_VLM
538                 /* vlm */
539                 case MVLC_VLM_NEW:
540                 case MVLC_VLM_SETUP:
541                 {
542                     static const char vlm_properties[][9] =
543                     {
544                         /* no args */
545                         "enabled", "disabled", "loop", "unloop",
546                         /* args required */
547                         "input", "output", "option", "date", "period",
548                         "repeat", "append", "",
549                     };
550                     vlm_message_t *vlm_answer;
551                     char name[512];
552                     char *psz = malloc( strlen( p_request ) + 1000 );
553                     char *p = psz;
554                     char *vlm_error;
555                     int i;
556
557                     assert( psz );
558
559                     if( p_intf->p_sys->p_vlm == NULL )
560                         p_intf->p_sys->p_vlm = vlm_New( p_intf );
561
562                     if( p_intf->p_sys->p_vlm == NULL )
563                     {
564                         free( psz );
565                         break;
566                     }
567
568                     ExtractURIValue( p_request, "name", name, 512 );
569                     if( StrToMacroType( control ) == MVLC_VLM_NEW )
570                     {
571                         char type[20];
572                         ExtractURIValue( p_request, "type", type, 20 );
573                         p += sprintf( psz, "new %s %s", name, type );
574                     }
575                     else
576                     {
577                         p += sprintf( psz, "setup %s", name );
578                     }
579                     /* Parse the request */
580                     for( i = 0; vlm_properties[i][0]; i++ )
581                     {
582                         char val[512];
583                         ExtractURIValue( p_request,
584                                                vlm_properties[i], val, 512 );
585                         decode_URI( val );
586                         if( strlen( val ) > 0 && i >= 4 )
587                         {
588                             p += sprintf( p, " %s %s", vlm_properties[i], val );
589                         }
590                         else if( TestURIParam( p_request, vlm_properties[i] ) && i < 4 )
591                         {
592                             p += sprintf( p, " %s", vlm_properties[i] );
593                         }
594                     }
595                     vlm_ExecuteCommand( p_intf->p_sys->p_vlm, psz, &vlm_answer );
596                     if( vlm_answer->psz_value == NULL ) /* there is no error */
597                     {
598                         vlm_error = strdup( "" );
599                     }
600                     else
601                     {
602                         if( asprintf( &vlm_error , "%s : %s" ,
603                                       vlm_answer->psz_name,
604                                       vlm_answer->psz_value ) == -1 )
605                             vlm_error = NULL;
606                     }
607
608                     mvar_AppendNewVar( p_args->vars, "vlm_error", vlm_error );
609
610                     vlm_MessageDelete( vlm_answer );
611                     free( vlm_error );
612                     free( psz );
613                     break;
614                 }
615
616                 case MVLC_VLM_DEL:
617                 {
618                     vlm_message_t *vlm_answer;
619                     char name[512];
620                     char psz[512+10];
621                     if( p_intf->p_sys->p_vlm == NULL )
622                         p_intf->p_sys->p_vlm = vlm_New( p_intf );
623
624                     if( p_intf->p_sys->p_vlm == NULL ) break;
625
626                     ExtractURIValue( p_request, "name", name, 512 );
627                     sprintf( psz, "del %s", name );
628
629                     vlm_ExecuteCommand( p_intf->p_sys->p_vlm, psz, &vlm_answer );
630                     /* FIXME do a vlm_answer -> var stack conversion */
631                     vlm_MessageDelete( vlm_answer );
632                     break;
633                 }
634
635                 case MVLC_VLM_PLAY:
636                 case MVLC_VLM_PAUSE:
637                 case MVLC_VLM_STOP:
638                 case MVLC_VLM_SEEK:
639                 {
640                     vlm_message_t *vlm_answer;
641                     char name[512];
642                     char psz[512+10];
643                     if( p_intf->p_sys->p_vlm == NULL )
644                         p_intf->p_sys->p_vlm = vlm_New( p_intf );
645
646                     if( p_intf->p_sys->p_vlm == NULL ) break;
647
648                     ExtractURIValue( p_request, "name", name, 512 );
649                     if( StrToMacroType( control ) == MVLC_VLM_PLAY )
650                         sprintf( psz, "control %s play", name );
651                     else if( StrToMacroType( control ) == MVLC_VLM_PAUSE )
652                         sprintf( psz, "control %s pause", name );
653                     else if( StrToMacroType( control ) == MVLC_VLM_STOP )
654                         sprintf( psz, "control %s stop", name );
655                     else if( StrToMacroType( control ) == MVLC_VLM_SEEK )
656                     {
657                         char percent[20];
658                         ExtractURIValue( p_request, "percent", percent, 512 );
659                         sprintf( psz, "control %s seek %s", name, percent );
660                     }
661
662                     vlm_ExecuteCommand( p_intf->p_sys->p_vlm, psz, &vlm_answer );
663                     /* FIXME do a vlm_answer -> var stack conversion */
664                     vlm_MessageDelete( vlm_answer );
665                     break;
666                 }
667                 case MVLC_VLM_LOAD:
668                 case MVLC_VLM_SAVE:
669                 {
670                     vlm_message_t *vlm_answer;
671                     char file[512];
672                     char psz[512];
673
674                     if( p_intf->p_sys->p_vlm == NULL )
675                         p_intf->p_sys->p_vlm = vlm_New( p_intf );
676
677                     if( p_intf->p_sys->p_vlm == NULL ) break;
678
679                     ExtractURIValue( p_request, "file", file, 512 );
680                     decode_URI( file );
681
682                     if( StrToMacroType( control ) == MVLC_VLM_LOAD )
683                         sprintf( psz, "load %s", file );
684                     else
685                         sprintf( psz, "save %s", file );
686
687                     vlm_ExecuteCommand( p_intf->p_sys->p_vlm, psz, &vlm_answer );
688                     /* FIXME do a vlm_answer -> var stack conversion */
689                     vlm_MessageDelete( vlm_answer );
690                     break;
691                 }
692 #endif /* ENABLE_VLM */
693                 default:
694                     if( *control )
695                     {
696                         PRINTS( "<!-- control param(%s) unsupported -->", control );
697                     }
698                     break;
699             }
700             break;
701
702         case MVLC_SET:
703         {
704             char    value[512];
705             int     i;
706             float   f;
707
708             if( i_request <= 0 ||
709                 *m->param1  == '\0' ||
710                 strstr( p_request, m->param1 ) == NULL )
711             {
712                 break;
713             }
714             ExtractURIValue( p_request, m->param1,  value, 512 );
715             decode_URI( value );
716
717             switch( StrToMacroType( m->param2 ) )
718             {
719                 case MVLC_INT:
720                     i = atoi( value );
721                     config_PutInt( p_intf, m->param1, i );
722                     break;
723                 case MVLC_FLOAT:
724                     f = atof( value );
725                     config_PutFloat( p_intf, m->param1, f );
726                     break;
727                 case MVLC_STRING:
728                     config_PutPsz( p_intf, m->param1, value );
729                     break;
730                 default:
731                     PRINTS( "<!-- invalid type(%s) in set -->", m->param2 )
732             }
733             break;
734         }
735         case MVLC_GET:
736         {
737             char    value[512];
738             int     i;
739             float   f;
740             char    *psz;
741             lldiv_t div;
742
743             if( *m->param1  == '\0' )
744             {
745                 break;
746             }
747
748             switch( StrToMacroType( m->param2 ) )
749             {
750                 case MVLC_INT:
751                     i = config_GetInt( p_intf, m->param1 );
752                     sprintf( value, "%d", i );
753                     break;
754                 case MVLC_FLOAT:
755                     f = config_GetFloat( p_intf, m->param1 );
756                     div = lldiv( f * 1000000 , 1000000 );
757                     sprintf( value, "%lld.%06u", div.quot,
758                             (unsigned int)div.rem );
759                     break;
760                 case MVLC_STRING:
761                     psz = config_GetPsz( p_intf, m->param1 );
762                     if( psz != NULL )
763                     {
764                         strlcpy( value, psz,sizeof( value ) );
765                         free( psz );
766                     }
767                     else
768                         *value = '\0';
769                     msg_Dbg( p_intf, "%d: value = \"%s\"", __LINE__, value );
770                     break;
771                 default:
772                     snprintf( value, sizeof( value ),
773                               "invalid type(%s) in set", m->param2 );
774                     break;
775             }
776             PRINTS( "%s", value );
777             break;
778         }
779         case MVLC_VALUE:
780         {
781             char *s;
782             const char *v;
783
784             if( m->param1 )
785             {
786                 EvaluateRPN( p_intf, p_args->vars, &p_args->stack, m->param1 );
787                 s = SSPop( &p_args->stack );
788                 v = mvar_GetValue( p_args->vars, s );
789             }
790             else
791             {
792                 v = s = SSPop( &p_args->stack );
793             }
794
795             PRINTS( "%s", v );
796             free( s );
797             break;
798         }
799         case MVLC_RPN:
800             EvaluateRPN( p_intf, p_args->vars, &p_args->stack, m->param1 );
801             break;
802
803         /* Useful to learn stack management */
804         case MVLC_STACK:
805         {
806             int i;
807             msg_Dbg( p_intf, "stack" );
808             for (i=0;i<(&p_args->stack)->i_stack;i++)
809                 msg_Dbg( p_intf, "%d -> %s", i, (&p_args->stack)->stack[i] );
810             break;
811         }
812
813         case MVLC_UNKNOWN:
814         default:
815             PRINTS( "<!-- invalid macro id=`%s' -->", m->id );
816             msg_Dbg( p_intf, "invalid macro id=`%s'", m->id );
817             break;
818     }
819 #undef PRINTS
820 #undef PRINT
821 #undef ALLOC
822 }
823
824 static
825 char *MacroSearch( char *src, char *end, int i_mvlc, bool b_after )
826 {
827     int     i_id;
828     int     i_level = 0;
829
830     while( src < end )
831     {
832         if( src + 4 < end  && !strncmp( (char *)src, "<vlc", 4 ) )
833         {
834             int i_skip;
835             macro_t m;
836
837             i_skip = MacroParse( &m, src );
838
839             i_id = StrToMacroType( m.id );
840
841             switch( i_id )
842             {
843                 case MVLC_IF:
844                 case MVLC_FOREACH:
845                     i_level++;
846                     break;
847                 case MVLC_END:
848                     i_level--;
849                     break;
850                 default:
851                     break;
852             }
853
854             MacroClean( &m );
855
856             if( ( i_mvlc == MVLC_END && i_level == -1 ) ||
857                 ( i_mvlc != MVLC_END && i_level == 0 && i_mvlc == i_id ) )
858             {
859                 return src + ( b_after ? i_skip : 0 );
860             }
861             else if( i_level < 0 )
862             {
863                 return NULL;
864             }
865
866             src += i_skip;
867         }
868         else
869         {
870             src++;
871         }
872     }
873
874     return NULL;
875 }
876
877 void Execute( httpd_file_sys_t *p_args,
878                      char *p_request, int i_request,
879                      char **pp_data, int *pi_data,
880                      char **pp_dst,
881                      char *_src, char *_end )
882 {
883     intf_thread_t  *p_intf = p_args->p_intf;
884
885     char *src, *dup, *end;
886     char *dst = *pp_dst;
887
888     src = dup = malloc( _end - _src + 1 );
889     end = src +( _end - _src );
890
891     assert( src );
892
893     memcpy( src, _src, _end - _src );
894     *end = '\0';
895
896     /* we parse searching <vlc */
897     while( src < end )
898     {
899         char *p;
900         int i_copy;
901
902         p = (char *)strstr( (char *)src, "<vlc" );
903         if( p < end && p == src )
904         {
905             macro_t m;
906
907             src += MacroParse( &m, src );
908
909             //msg_Dbg( p_intf, "macro_id=%s", m.id );
910
911             switch( StrToMacroType( m.id ) )
912             {
913                 case MVLC_INCLUDE:
914                 {
915                     FILE *f;
916                     int  i_buffer;
917                     char *p_buffer;
918                     char psz_file[MAX_DIR_SIZE];
919                     char *p;
920                     char sep;
921
922 #if defined( WIN32 )
923                     sep = '\\';
924 #else
925                     sep = '/';
926 #endif
927
928                     if( m.param1[0] != sep )
929                     {
930                         strcpy( psz_file, p_args->file );
931                         p = strrchr( psz_file, sep );
932                         if( p != NULL )
933                             strcpy( p + 1, m.param1 );
934                         else
935                             strcpy( psz_file, m.param1 );
936                     }
937                     else
938                     {
939                         strcpy( psz_file, m.param1 );
940                     }
941
942                     /* We hereby assume that psz_file is in the
943                      * local character encoding */
944                     if( ( f = fopen( psz_file, "r" ) ) == NULL )
945                     {
946                         msg_Warn( p_args->p_intf,
947                                   "unable to include file %s (%m)",
948                                   psz_file );
949                         break;
950                     }
951
952                     /* first we load in a temporary buffer */
953                     FileLoad( f, &p_buffer, &i_buffer );
954
955                     /* we parse executing all  <vlc /> macros */
956                     Execute( p_args, p_request, i_request, pp_data, pi_data,
957                              &dst, &p_buffer[0], &p_buffer[i_buffer] );
958                     free( p_buffer );
959                     fclose(f);
960                     break;
961                 }
962                 case MVLC_IF:
963                 {
964                     bool i_test;
965                     char    *endif;
966
967                     EvaluateRPN( p_intf, p_args->vars, &p_args->stack, m.param1 );
968                     if( SSPopN( &p_args->stack, p_args->vars ) )
969                     {
970                         i_test = 1;
971                     }
972                     else
973                     {
974                         i_test = 0;
975                     }
976                     endif = MacroSearch( src, end, MVLC_END, true );
977
978                     if( i_test == 0 )
979                     {
980                         char *start = MacroSearch( src, endif, MVLC_ELSE, true );
981
982                         if( start )
983                         {
984                             char *stop  = MacroSearch( start, endif, MVLC_END, false );
985                             if( stop )
986                             {
987                                 Execute( p_args, p_request, i_request,
988                                          pp_data, pi_data, &dst, start, stop );
989                             }
990                         }
991                     }
992                     else if( i_test == 1 )
993                     {
994                         char *stop;
995                         if( ( stop = MacroSearch( src, endif, MVLC_ELSE, false ) ) == NULL )
996                         {
997                             stop = MacroSearch( src, endif, MVLC_END, false );
998                         }
999                         if( stop )
1000                         {
1001                             Execute( p_args, p_request, i_request,
1002                                      pp_data, pi_data, &dst, src, stop );
1003                         }
1004                     }
1005
1006                     src = endif;
1007                     break;
1008                 }
1009                 case MVLC_FOREACH:
1010                 {
1011                     char *endfor = MacroSearch( src, end, MVLC_END, true );
1012                     char *start = src;
1013                     char *stop = MacroSearch( src, end, MVLC_END, false );
1014
1015                     if( stop )
1016                     {
1017                         mvar_t *index;
1018                         int    i_idx;
1019                         mvar_t *v;
1020                         if( !strcmp( m.param2, "integer" ) )
1021                         {
1022                             char *arg = SSPop( &p_args->stack );
1023                             index = mvar_IntegerSetNew( m.param1, arg );
1024                             free( arg );
1025                         }
1026                         else if( !strcmp( m.param2, "directory" ) )
1027                         {
1028                             char *arg = SSPop( &p_args->stack );
1029                             index = mvar_FileSetNew( p_intf, m.param1, arg );
1030                             free( arg );
1031                         }
1032                         else if( !strcmp( m.param2, "object" ) )
1033                         {
1034                             char *arg = SSPop( &p_args->stack );
1035                             index = mvar_ObjectSetNew( p_intf, m.param1, arg );
1036                             free( arg );
1037                         }
1038                         else if( !strcmp( m.param2, "playlist" ) )
1039                         {
1040                             index = mvar_PlaylistSetNew( p_intf, m.param1,
1041                                                     p_intf->p_sys->p_playlist );
1042                         }
1043                         else if( !strcmp( m.param2, "information" ) )
1044                         {
1045                             index = mvar_InfoSetNew( m.param1,
1046                                                      p_intf->p_sys->p_input );
1047                         }
1048                         else if( !strcmp( m.param2, "program" )
1049                                   || !strcmp( m.param2, "title" )
1050                                   || !strcmp( m.param2, "chapter" )
1051                                   || !strcmp( m.param2, "audio-es" )
1052                                   || !strcmp( m.param2, "video-es" )
1053                                   || !strcmp( m.param2, "spu-es" ) )
1054                         {
1055                             index = mvar_InputVarSetNew( p_intf, m.param1,
1056                                                          p_intf->p_sys->p_input,
1057                                                          m.param2 );
1058                         }
1059 #ifdef ENABLE_VLM
1060                         else if( !strcmp( m.param2, "vlm" ) )
1061                         {
1062                             if( p_intf->p_sys->p_vlm == NULL )
1063                                 p_intf->p_sys->p_vlm = vlm_New( p_intf );
1064                             index = mvar_VlmSetNew( m.param1, p_intf->p_sys->p_vlm );
1065                         }
1066 #endif
1067 #if 0
1068                         else if( !strcmp( m.param2, "hosts" ) )
1069                         {
1070                             index = mvar_HttpdInfoSetNew( m.param1, p_intf->p_sys->p_httpd, HTTPD_GET_HOSTS );
1071                         }
1072                         else if( !strcmp( m.param2, "urls" ) )
1073                         {
1074                             index = mvar_HttpdInfoSetNew( m.param1, p_intf->p_sys->p_httpd, HTTPD_GET_URLS );
1075                         }
1076                         else if( !strcmp( m.param2, "connections" ) )
1077                         {
1078                             index = mvar_HttpdInfoSetNew(m.param1, p_intf->p_sys->p_httpd, HTTPD_GET_CONNECTIONS);
1079                         }
1080 #endif
1081                         else if( ( v = mvar_GetVar( p_args->vars, m.param2 ) ) )
1082                         {
1083                             index = mvar_Duplicate( v );
1084                         }
1085                         else
1086                         {
1087                             msg_Dbg( p_intf, "invalid index constructor (%s)", m.param2 );
1088                             src = endfor;
1089                             break;
1090                         }
1091
1092                         for( i_idx = 0; i_idx < index->i_field; i_idx++ )
1093                         {
1094                             mvar_t *f = mvar_Duplicate( index->field[i_idx] );
1095
1096                             //msg_Dbg( p_intf, "foreach field[%d] name=%s value=%s", i_idx, f->name, f->value );
1097
1098                             free( f->name );
1099                             f->name = strdup( m.param1 );
1100
1101
1102                             mvar_PushVar( p_args->vars, f );
1103                             Execute( p_args, p_request, i_request,
1104                                      pp_data, pi_data, &dst, start, stop );
1105                             mvar_RemoveVar( p_args->vars, f );
1106
1107                             mvar_Delete( f );
1108                         }
1109                         mvar_Delete( index );
1110
1111                         src = endfor;
1112                     }
1113                     break;
1114                 }
1115                 default:
1116                     MacroDo( p_args, &m, p_request, i_request,
1117                              pp_data, pi_data, &dst );
1118                     break;
1119             }
1120
1121             MacroClean( &m );
1122             continue;
1123         }
1124
1125         i_copy =   ( (p == NULL || p > end ) ? end : p  ) - src;
1126         if( i_copy > 0 )
1127         {
1128             int i_index = dst - *pp_data;
1129
1130             *pi_data += i_copy;
1131             *pp_data = realloc_or_free( *pp_data, *pi_data );
1132             assert( *pp_data );
1133             dst = (*pp_data) + i_index;
1134
1135             memcpy( dst, src, i_copy );
1136             dst += i_copy;
1137             src += i_copy;
1138         }
1139     }
1140
1141     *pp_dst = dst;
1142     free( dup );
1143 }