]> git.sesse.net Git - vlc/blob - modules/control/http/mvar.c
* modules/control/http/rpn.c: vlc_var_* now take an extra argument to
[vlc] / modules / control / http / mvar.c
1 /*****************************************************************************
2  * mvar.c : Variables handling for the HTTP Interface
3  *****************************************************************************
4  * Copyright (C) 2001-2005 the VideoLAN team
5  * $Id: http.c 12225 2005-08-18 10:01:30Z massiot $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 #include "http.h"
27
28 /* Utility function for scandir */
29 static int Filter( const struct dirent *foo )
30 {
31     return VLC_TRUE;
32 };
33
34 static int InsensitiveAlphasort( const struct dirent **foo1,
35                                  const struct dirent **foo2 )
36 {
37     return strcasecmp( (*foo1)->d_name, (*foo2)->d_name );
38 };
39
40
41
42 mvar_t *mvar_New( const char *name, const char *value )
43 {
44     mvar_t *v = malloc( sizeof( mvar_t ) );
45
46     if( !v ) return NULL;
47     v->name = strdup( name );
48     v->value = strdup( value ? value : "" );
49
50     v->i_field = 0;
51     v->field = malloc( sizeof( mvar_t * ) );
52     v->field[0] = NULL;
53
54     return v;
55 }
56
57 void mvar_Delete( mvar_t *v )
58 {
59     int i;
60
61     free( v->name );
62     free( v->value );
63
64     for( i = 0; i < v->i_field; i++ )
65     {
66         mvar_Delete( v->field[i] );
67     }
68     free( v->field );
69     free( v );
70 }
71
72 void mvar_AppendVar( mvar_t *v, mvar_t *f )
73 {
74     v->field = realloc( v->field, sizeof( mvar_t * ) * ( v->i_field + 2 ) );
75     v->field[v->i_field] = f;
76     v->i_field++;
77 }
78
79 mvar_t *mvar_Duplicate( const mvar_t *v )
80 {
81     int i;
82     mvar_t *n;
83
84     n = mvar_New( v->name, v->value );
85     for( i = 0; i < v->i_field; i++ )
86     {
87         mvar_AppendVar( n, mvar_Duplicate( v->field[i] ) );
88     }
89
90     return n;
91 }
92
93 void mvar_PushVar( mvar_t *v, mvar_t *f )
94 {
95     v->field = realloc( v->field, sizeof( mvar_t * ) * ( v->i_field + 2 ) );
96     if( v->i_field > 0 )
97     {
98         memmove( &v->field[1], &v->field[0], sizeof( mvar_t * ) * v->i_field );
99     }
100     v->field[0] = f;
101     v->i_field++;
102 }
103
104 void mvar_RemoveVar( mvar_t *v, mvar_t *f )
105 {
106     int i;
107     for( i = 0; i < v->i_field; i++ )
108     {
109         if( v->field[i] == f )
110         {
111             break;
112         }
113     }
114     if( i >= v->i_field )
115     {
116         return;
117     }
118
119     if( i + 1 < v->i_field )
120     {
121         memmove( &v->field[i], &v->field[i+1], sizeof( mvar_t * ) * ( v->i_field - i - 1 ) );
122     }
123     v->i_field--;
124     /* FIXME should do a realloc */
125 }
126
127 mvar_t *mvar_GetVar( mvar_t *s, const char *name )
128 {
129     int i;
130     char base[512], *field, *p;
131     int  i_index;
132
133     /* format: name[index].field */
134
135     field = strchr( name, '.' );
136     if( field )
137     {
138         int i = field - name;
139         strncpy( base, name, i );
140         base[i] = '\0';
141         field++;
142     }
143     else
144     {
145         strcpy( base, name );
146     }
147
148     if( ( p = strchr( base, '[' ) ) )
149     {
150         *p++ = '\0';
151         sscanf( p, "%d]", &i_index );
152         if( i_index < 0 )
153         {
154             return NULL;
155         }
156     }
157     else
158     {
159         i_index = 0;
160     }
161
162     for( i = 0; i < s->i_field; i++ )
163     {
164         if( !strcmp( s->field[i]->name, base ) )
165         {
166             if( i_index > 0 )
167             {
168                 i_index--;
169             }
170             else
171             {
172                 if( field )
173                 {
174                     return mvar_GetVar( s->field[i], field );
175                 }
176                 else
177                 {
178                     return s->field[i];
179                 }
180             }
181         }
182     }
183     return NULL;
184 }
185
186 char *mvar_GetValue( mvar_t *v, char *field )
187 {
188     if( *field == '\0' )
189     {
190         return v->value;
191     }
192     else
193     {
194         mvar_t *f = mvar_GetVar( v, field );
195         if( f )
196         {
197             return f->value;
198         }
199         else
200         {
201             return field;
202         }
203     }
204 }
205
206 void mvar_PushNewVar( mvar_t *vars, const char *name,
207                              const char *value )
208 {
209     mvar_t *f = mvar_New( name, value );
210     mvar_PushVar( vars, f );
211 }
212
213 void mvar_AppendNewVar( mvar_t *vars, const char *name,
214                                const char *value )
215 {
216     mvar_t *f = mvar_New( name, value );
217     mvar_AppendVar( vars, f );
218 }
219
220
221 /* arg= start[:stop[:step]],.. */
222 mvar_t *mvar_IntegerSetNew( const char *name, const char *arg )
223 {
224     char *dup = strdup( arg );
225     char *str = dup;
226     mvar_t *s = mvar_New( name, "set" );
227
228     while( str )
229     {
230         char *p;
231         int  i_start,i_stop,i_step;
232         int  i_match;
233
234         p = strchr( str, ',' );
235         if( p )
236         {
237             *p++ = '\0';
238         }
239
240         i_step = 0;
241         i_match = sscanf( str, "%d:%d:%d", &i_start, &i_stop, &i_step );
242
243         if( i_match == 1 )
244         {
245             i_stop = i_start;
246             i_step = 1;
247         }
248         else if( i_match == 2 )
249         {
250             i_step = i_start < i_stop ? 1 : -1;
251         }
252
253         if( i_match >= 1 )
254         {
255             int i;
256
257             if( ( i_start <= i_stop && i_step > 0 ) ||
258                 ( i_start >= i_stop && i_step < 0 ) )
259             {
260                 for( i = i_start; ; i += i_step )
261                 {
262                     char   value[79];
263
264                     if( ( i_step > 0 && i > i_stop ) ||
265                         ( i_step < 0 && i < i_stop ) )
266                     {
267                         break;
268                     }
269
270                     sprintf( value, "%d", i );
271
272                     mvar_PushNewVar( s, name, value );
273                 }
274             }
275         }
276         str = p;
277     }
278
279     free( dup );
280     return s;
281 }
282
283 /********************************************************************
284  * Special sets handling
285  ********************************************************************/
286
287 mvar_t *mvar_PlaylistSetNew( intf_thread_t *p_intf, char *name,
288                                     playlist_t *p_pl )
289 {
290     playlist_view_t *p_view;
291     mvar_t *s = mvar_New( name, "set" );
292
293
294     vlc_mutex_lock( &p_pl->object_lock );
295
296     p_view = playlist_ViewFind( p_pl, VIEW_CATEGORY ); /* FIXME */
297
298     if( p_view != NULL )
299         E_(PlaylistListNode)( p_intf, p_pl, p_view->p_root, name, s, 0 );
300
301     vlc_mutex_unlock( &p_pl->object_lock );
302
303     return s;
304 }
305
306 mvar_t *mvar_InfoSetNew( intf_thread_t *p_intf, char *name,
307                                 input_thread_t *p_input )
308 {
309     mvar_t *s = mvar_New( name, "set" );
310     int i, j;
311
312     if( p_input == NULL )
313     {
314         return s;
315     }
316
317     vlc_mutex_lock( &p_input->input.p_item->lock );
318     for ( i = 0; i < p_input->input.p_item->i_categories; i++ )
319     {
320         info_category_t *p_category = p_input->input.p_item->pp_categories[i];
321         char *psz;
322
323         mvar_t *cat  = mvar_New( name, "set" );
324         mvar_t *iset = mvar_New( "info", "set" );
325
326         psz = E_(FromUTF8)( p_intf, p_category->psz_name );
327         mvar_AppendNewVar( cat, "name", psz );
328         free( psz );
329         mvar_AppendVar( cat, iset );
330
331         for ( j = 0; j < p_category->i_infos; j++ )
332         {
333             info_t *p_info = p_category->pp_infos[j];
334             mvar_t *info = mvar_New( "info", "" );
335             char *psz_name = E_(FromUTF8)( p_intf, p_info->psz_name );
336             char *psz_value = E_(FromUTF8)( p_intf, p_info->psz_value );
337
338             msg_Dbg( p_input, "adding info name=%s value=%s",
339                      psz_name, psz_value );
340             mvar_AppendNewVar( info, "name",  psz_name );
341             mvar_AppendNewVar( info, "value", psz_value );
342             free( psz_name );
343             free( psz_value );
344             mvar_AppendVar( iset, info );
345         }
346         mvar_AppendVar( s, cat );
347     }
348     vlc_mutex_unlock( &p_input->input.p_item->lock );
349
350     return s;
351 }
352
353 mvar_t *mvar_InputVarSetNew( intf_thread_t *p_intf, char *name,
354                                     input_thread_t *p_input,
355                                     const char *psz_variable )
356 {
357     intf_sys_t     *p_sys = p_intf->p_sys;
358     mvar_t *s = mvar_New( name, "set" );
359     vlc_value_t val, val_list, text_list;
360     int i_type, i;
361
362     if( p_input == NULL )
363     {
364         return s;
365     }
366
367     /* Check the type of the object variable */
368     i_type = var_Type( p_sys->p_input, psz_variable );
369
370     /* Make sure we want to display the variable */
371     if( i_type & VLC_VAR_HASCHOICE )
372     {
373         var_Change( p_sys->p_input, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
374         if( val.i_int == 0 ) return s;
375         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
376             return s;
377     }
378     else
379     {
380         return s;
381     }
382
383     switch( i_type & VLC_VAR_TYPE )
384     {
385     case VLC_VAR_VOID:
386     case VLC_VAR_BOOL:
387     case VLC_VAR_VARIABLE:
388     case VLC_VAR_STRING:
389     case VLC_VAR_INTEGER:
390         break;
391     default:
392         /* Variable doesn't exist or isn't handled */
393         return s;
394     }
395
396     if( var_Get( p_sys->p_input, psz_variable, &val ) < 0 )
397     {
398         return s;
399     }
400
401     if( var_Change( p_sys->p_input, psz_variable, VLC_VAR_GETLIST,
402                     &val_list, &text_list ) < 0 )
403     {
404         if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
405         return s;
406     }
407
408     for( i = 0; i < val_list.p_list->i_count; i++ )
409     {
410         char *psz, psz_int[16];
411         mvar_t *itm;
412
413         switch( i_type & VLC_VAR_TYPE )
414         {
415         case VLC_VAR_STRING:
416             itm = mvar_New( name, "set" );
417             psz = E_(FromUTF8)( p_intf, text_list.p_list->p_values[i].psz_string );
418             mvar_AppendNewVar( itm, "name", psz );
419             psz = E_(FromUTF8)( p_intf, val_list.p_list->p_values[i].psz_string );
420             mvar_AppendNewVar( itm, "id", psz );
421             free( psz );
422             snprintf( psz_int, sizeof(psz_int), "%d",
423                       ( !strcmp( val.psz_string,
424                                    val_list.p_list->p_values[i].psz_string )
425                            && !( i_type & VLC_VAR_ISCOMMAND ) ) );
426             mvar_AppendNewVar( itm, "selected", psz_int );
427             mvar_AppendVar( s, itm );
428             break;
429
430         case VLC_VAR_INTEGER:
431             itm = mvar_New( name, "set" );
432             psz = E_(FromUTF8)( p_intf, text_list.p_list->p_values[i].psz_string );
433             mvar_AppendNewVar( itm, "name", psz );
434             snprintf( psz_int, sizeof(psz_int), "%d",
435                       val_list.p_list->p_values[i].i_int );
436             mvar_AppendNewVar( itm, "id", psz_int );
437             snprintf( psz_int, sizeof(psz_int), "%d",
438                       ( val.i_int == val_list.p_list->p_values[i].i_int )
439                          && !( i_type & VLC_VAR_ISCOMMAND ) );
440             mvar_AppendNewVar( itm, "selected", psz_int );
441             mvar_AppendVar( s, itm );
442             break;
443
444         default:
445             break;
446         }
447     }
448     /* clean up everything */
449     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
450     var_Change( p_sys->p_input, psz_variable, VLC_VAR_FREELIST, &val_list,
451                 &text_list );
452     return s;
453 }
454
455 #if 0
456 mvar_t *mvar_HttpdInfoSetNew( char *name, httpd_t *p_httpd, int i_type )
457 {
458     mvar_t       *s = mvar_New( name, "set" );
459     httpd_info_t info;
460     int          i;
461
462     if( !p_httpd->pf_control( p_httpd, i_type, &info, NULL ) )
463     {
464         for( i= 0; i < info.i_count; )
465         {
466             mvar_t *inf;
467
468             inf = mvar_New( name, "set" );
469             do
470             {
471                 /* fprintf( stderr," mvar_HttpdInfoSetNew: append name=`%s' value=`%s'\n",
472                             info.info[i].psz_name, info.info[i].psz_value ); */
473                 mvar_AppendNewVar( inf,
474                                    info.info[i].psz_name,
475                                    info.info[i].psz_value );
476                 i++;
477             } while( i < info.i_count && strcmp( info.info[i].psz_name, "id" ) );
478             mvar_AppendVar( s, inf );
479         }
480     }
481
482     /* free mem */
483     for( i = 0; i < info.i_count; i++ )
484     {
485         free( info.info[i].psz_name );
486         free( info.info[i].psz_value );
487     }
488     if( info.i_count > 0 )
489     {
490         free( info.info );
491     }
492
493     return s;
494 }
495 #endif
496
497 mvar_t *mvar_FileSetNew( intf_thread_t *p_intf, char *name,
498                          char *psz_dir )
499 {
500     mvar_t *s = mvar_New( name, "set" );
501     char          tmp[MAX_DIR_SIZE];
502 #ifdef HAVE_SYS_STAT_H
503     struct stat   stat_info;
504 #endif
505     struct dirent **pp_dir_content;
506     int           i_dir_content, i;
507     char          sep;
508
509     /* convert all / to native separator */
510 #if defined( WIN32 )
511     sep = '\\';
512 #else
513     sep = '/';
514 #endif
515
516     psz_dir = E_(RealPath)( p_intf, psz_dir );
517
518 #ifdef HAVE_SYS_STAT_H
519     if( stat( psz_dir, &stat_info ) == -1 || !S_ISDIR( stat_info.st_mode ) )
520     {
521         free( psz_dir );
522         return s;
523     }
524 #endif
525
526     /* parse psz_src dir */
527     if( ( i_dir_content = scandir( psz_dir, &pp_dir_content, Filter,
528                                    InsensitiveAlphasort ) ) == -1 )
529     {
530         msg_Warn( p_intf, "scandir error on %s (%s)", psz_dir,
531                   strerror(errno) );
532         free( psz_dir );
533         return s;
534     }
535
536     for( i = 0; i < i_dir_content; i++ )
537     {
538         struct dirent *p_dir_content = pp_dir_content[i];
539         mvar_t *f;
540         const char *psz_ext;
541         char *psz_name, *psz_tmp;
542
543         if( !strcmp( p_dir_content->d_name, "." ) )
544         {
545             continue;
546         }
547
548         snprintf( tmp, sizeof(tmp), "%s%c%s", psz_dir, sep,
549                   p_dir_content->d_name );
550
551 #ifdef HAVE_SYS_STAT_H
552         if( stat( tmp, &stat_info ) == -1 )
553         {
554             continue;
555         }
556 #endif
557         f = mvar_New( name, "set" );
558
559         psz_tmp = vlc_fix_readdir_charset( p_intf, p_dir_content->d_name );
560         psz_name = E_(FromUTF8)( p_intf, psz_tmp );
561         free( psz_tmp );
562         snprintf( tmp, sizeof(tmp), "%s%c%s", psz_dir, sep, psz_name );
563         mvar_AppendNewVar( f, "name", tmp );
564         mvar_AppendNewVar( f, "basename", psz_name );
565
566         /* put file extension in 'ext' */
567         psz_ext = strrchr( psz_name, '.' );
568         mvar_AppendNewVar( f, "ext", psz_ext != NULL ? psz_ext + 1 : "" );
569
570         free( psz_name );
571
572 #ifdef HAVE_SYS_STAT_H
573         if( S_ISDIR( stat_info.st_mode ) )
574         {
575             mvar_AppendNewVar( f, "type", "directory" );
576         }
577         else if( S_ISREG( stat_info.st_mode ) )
578         {
579             mvar_AppendNewVar( f, "type", "file" );
580         }
581         else
582         {
583             mvar_AppendNewVar( f, "type", "unknown" );
584         }
585
586         sprintf( tmp, I64Fd, (int64_t)stat_info.st_size );
587         mvar_AppendNewVar( f, "size", tmp );
588
589         /* FIXME memory leak FIXME */
590 #ifdef HAVE_CTIME_R
591         ctime_r( &stat_info.st_mtime, tmp );
592         mvar_AppendNewVar( f, "date", tmp );
593 #else
594         mvar_AppendNewVar( f, "date", ctime( &stat_info.st_mtime ) );
595 #endif
596
597 #else
598         mvar_AppendNewVar( f, "type", "unknown" );
599         mvar_AppendNewVar( f, "size", "unknown" );
600         mvar_AppendNewVar( f, "date", "unknown" );
601 #endif
602         mvar_AppendVar( s, f );
603     }
604
605     free( psz_dir );
606     return s;
607 }
608
609 mvar_t *mvar_VlmSetNew( char *name, vlm_t *vlm )
610 {
611     mvar_t        *s = mvar_New( name, "set" );
612     vlm_message_t *msg;
613     int    i;
614
615     if( vlm == NULL ) return s;
616
617     if( vlm_ExecuteCommand( vlm, "show", &msg ) )
618     {
619         return s;
620     }
621
622     for( i = 0; i < msg->i_child; i++ )
623     {
624         /* Over media, schedule */
625         vlm_message_t *ch = msg->child[i];
626         int j;
627
628         for( j = 0; j < ch->i_child; j++ )
629         {
630             /* Over name */
631             vlm_message_t *el = ch->child[j];
632             vlm_message_t *inf, *desc;
633             mvar_t        *set;
634             char          psz[500];
635             int k;
636
637             sprintf( psz, "show %s", el->psz_name );
638             if( vlm_ExecuteCommand( vlm, psz, &inf ) )
639                 continue;
640             desc = inf->child[0];
641
642             /* Add a node with name and info */
643             set = mvar_New( name, "set" );
644             mvar_AppendNewVar( set, "name", el->psz_name );
645
646             for( k = 0; k < desc->i_child; k++ )
647             {
648                 vlm_message_t *ch = desc->child[k];
649                 if( ch->i_child > 0 )
650                 {
651                     int c;
652                     mvar_t *n = mvar_New( ch->psz_name, "set" );
653
654                     for( c = 0; c < ch->i_child; c++ )
655                     {
656                         if( ch->child[c]->psz_value )
657                         {
658                             mvar_AppendNewVar( n, ch->child[c]->psz_name, ch->child[c]->psz_value );
659                         }
660                         else
661                         {
662                             mvar_t *in = mvar_New( ch->psz_name, ch->child[c]->psz_name );
663                             mvar_AppendVar( n, in );
664                         }
665                     }
666                     mvar_AppendVar( set, n );
667                 }
668                 else
669                 {
670                     mvar_AppendNewVar( set, ch->psz_name, ch->psz_value );
671                 }
672             }
673             vlm_MessageDelete( inf );
674
675             mvar_AppendVar( s, set );
676         }
677     }
678     vlm_MessageDelete( msg );
679
680     return s;
681 }