]> git.sesse.net Git - vlc/blob - modules/control/http/mvar.c
Remove debug message
[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$
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
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 *E_(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 E_(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         E_(mvar_Delete)( v->field[i] );
67     }
68     free( v->field );
69     free( v );
70 }
71
72 void E_(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 *E_(mvar_Duplicate)( const mvar_t *v )
80 {
81     int i;
82     mvar_t *n;
83
84     n = E_(mvar_New)( v->name, v->value );
85     for( i = 0; i < v->i_field; i++ )
86     {
87         E_(mvar_AppendVar)( n, E_(mvar_Duplicate)( v->field[i] ) );
88     }
89
90     return n;
91 }
92
93 void E_(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 E_(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 *E_(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 E_(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 *E_(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 = E_(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 E_(mvar_PushNewVar)( mvar_t *vars, const char *name,
207                           const char *value )
208 {
209     mvar_t *f = E_(mvar_New)( name, value );
210     E_(mvar_PushVar)( vars, f );
211 }
212
213 void E_(mvar_AppendNewVar)( mvar_t *vars, const char *name,
214                             const char *value )
215 {
216     mvar_t *f = E_(mvar_New)( name, value );
217     E_(mvar_AppendVar)( vars, f );
218 }
219
220
221 /* arg= start[:stop[:step]],.. */
222 mvar_t *E_(mvar_IntegerSetNew)( const char *name, const char *arg )
223 {
224     char *dup = strdup( arg );
225     char *str = dup;
226     mvar_t *s = E_(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                     E_(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 *E_(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 = E_(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 *E_(mvar_InfoSetNew)( intf_thread_t *p_intf, char *name,
307                              input_thread_t *p_input )
308 {
309     mvar_t *s = E_(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  = E_(mvar_New)( name, "set" );
324         mvar_t *iset = E_(mvar_New)( "info", "set" );
325
326         psz = E_(FromUTF8)( p_intf, p_category->psz_name );
327         E_(mvar_AppendNewVar)( cat, "name", psz );
328         free( psz );
329         E_(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 = E_(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             E_(mvar_AppendNewVar)( info, "name",  psz_name );
341             E_(mvar_AppendNewVar)( info, "value", psz_value );
342             free( psz_name );
343             free( psz_value );
344             E_(mvar_AppendVar)( iset, info );
345         }
346         E_(mvar_AppendVar)( s, cat );
347     }
348     vlc_mutex_unlock( &p_input->input.p_item->lock );
349
350     return s;
351 }
352
353 mvar_t *E_(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 = E_(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 = E_(mvar_New)( name, "set" );
417             psz = E_(FromUTF8)( p_intf, text_list.p_list->p_values[i].psz_string );
418             E_(mvar_AppendNewVar)( itm, "name", psz );
419             psz = E_(FromUTF8)( p_intf, val_list.p_list->p_values[i].psz_string );
420             E_(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             E_(mvar_AppendNewVar)( itm, "selected", psz_int );
427             E_(mvar_AppendVar)( s, itm );
428             break;
429
430         case VLC_VAR_INTEGER:
431             itm = E_(mvar_New)( name, "set" );
432             psz = E_(FromUTF8)( p_intf, text_list.p_list->p_values[i].psz_string );
433             E_(mvar_AppendNewVar)( itm, "name", psz );
434             snprintf( psz_int, sizeof(psz_int), "%d",
435                       val_list.p_list->p_values[i].i_int );
436             E_(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             E_(mvar_AppendNewVar)( itm, "selected", psz_int );
441             E_(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 *E_(mvar_HttpdInfoSetNew)( char *name, httpd_t *p_httpd, int i_type )
457 {
458     mvar_t       *s = E_(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 = E_(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                 E_(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             E_(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 *E_(mvar_FileSetNew)( intf_thread_t *p_intf, char *name,
498                              char *psz_dir )
499 {
500     mvar_t *s = E_(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 #   if defined( WIN32 )
521           && psz_dir[0] != '\0' && (psz_dir[0] != '\\' || psz_dir[1] != '\0')
522 #   endif
523       )
524     {
525         free( psz_dir );
526         return s;
527     }
528 #endif
529
530     /* parse psz_src dir */
531     if( ( i_dir_content = scandir( psz_dir, &pp_dir_content, Filter,
532                                    InsensitiveAlphasort ) ) == -1 )
533     {
534         msg_Warn( p_intf, "scandir error on %s (%s)", psz_dir,
535                   strerror(errno) );
536         free( psz_dir );
537         return s;
538     }
539
540     for( i = 0; i < i_dir_content; i++ )
541     {
542         struct dirent *p_dir_content = pp_dir_content[i];
543         mvar_t *f;
544         char *psz_name, *psz_tmp, *psz_ext;
545
546         if( !strcmp( p_dir_content->d_name, "." ) )
547         {
548             continue;
549         }
550
551 #if defined( WIN32 )
552         if( psz_dir[0] == '\0' || (psz_dir[0] == '\\' && psz_dir[1] == '\0') )
553         {
554             snprintf( tmp, sizeof(tmp), "%s", p_dir_content->d_name );
555         }
556         else
557 #endif
558         {
559             snprintf( tmp, sizeof(tmp), "%s%c%s", psz_dir, sep,
560                       p_dir_content->d_name );
561
562 #ifdef HAVE_SYS_STAT_H
563             if( stat( tmp, &stat_info ) == -1 )
564             {
565                 continue;
566             }
567 #endif
568         }
569         f = E_(mvar_New)( name, "set" );
570
571         psz_tmp = vlc_fix_readdir_charset( p_intf, p_dir_content->d_name );
572         psz_name = E_(FromUTF8)( p_intf, psz_tmp );
573         free( psz_tmp );
574
575         /* put lower-case file extension in 'ext' */
576         psz_ext = strrchr( psz_name, '.' );
577         psz_tmp = psz_ext = strdup( psz_ext != NULL ? psz_ext + 1 : "" );
578         while ( *psz_tmp != '\0' )
579         {
580             *psz_tmp = tolower( *psz_tmp );
581             psz_tmp++;
582         }
583         E_(mvar_AppendNewVar)( f, "ext", psz_ext );
584         free( psz_ext );
585
586 #if defined( WIN32 )
587         if( psz_dir[0] == '\0' || (psz_dir[0] == '\\' && psz_dir[1] == '\0') )
588         {
589             snprintf( tmp, sizeof(tmp), "%c:", psz_name[0] );
590             E_(mvar_AppendNewVar)( f, "name", psz_name );
591             E_(mvar_AppendNewVar)( f, "basename", tmp );
592             E_(mvar_AppendNewVar)( f, "type", "directory" );
593             E_(mvar_AppendNewVar)( f, "size", "unknown" );
594             E_(mvar_AppendNewVar)( f, "date", "unknown" );
595         }
596         else
597 #endif
598         {
599             snprintf( tmp, sizeof(tmp), "%s%c%s", psz_dir, sep, psz_name );
600             E_(mvar_AppendNewVar)( f, "name", tmp );
601             E_(mvar_AppendNewVar)( f, "basename", psz_name );
602
603 #ifdef HAVE_SYS_STAT_H
604             if( S_ISDIR( stat_info.st_mode ) )
605             {
606                 E_(mvar_AppendNewVar)( f, "type", "directory" );
607             }
608             else if( S_ISREG( stat_info.st_mode ) )
609             {
610                 E_(mvar_AppendNewVar)( f, "type", "file" );
611             }
612             else
613             {
614                 E_(mvar_AppendNewVar)( f, "type", "unknown" );
615             }
616
617             sprintf( tmp, I64Fd, (int64_t)stat_info.st_size );
618             E_(mvar_AppendNewVar)( f, "size", tmp );
619
620             /* FIXME memory leak FIXME */
621 #   ifdef HAVE_CTIME_R
622             ctime_r( &stat_info.st_mtime, tmp );
623             E_(mvar_AppendNewVar)( f, "date", tmp );
624 #   else
625             E_(mvar_AppendNewVar)( f, "date", ctime( &stat_info.st_mtime ) );
626 #   endif
627
628 #else
629             E_(mvar_AppendNewVar)( f, "type", "unknown" );
630             E_(mvar_AppendNewVar)( f, "size", "unknown" );
631             E_(mvar_AppendNewVar)( f, "date", "unknown" );
632 #endif
633         }
634
635         E_(mvar_AppendVar)( s, f );
636
637         free( psz_name );
638     }
639
640     free( psz_dir );
641     for( i = 0; i < i_dir_content; i++ )
642         if( pp_dir_content[i] ) free( pp_dir_content[i] );
643     if( pp_dir_content) free( pp_dir_content );
644     return s;
645 }
646
647 void E_(mvar_VlmSetNewLoop)( char *name, vlm_t *vlm, mvar_t *s, vlm_message_t *el, vlc_bool_t b_name );
648 void E_(mvar_VlmSetNewLoop)( char *name, vlm_t *vlm, mvar_t *s, vlm_message_t *el, vlc_bool_t b_name )
649 {
650     /* Over name */
651     mvar_t        *set;
652     int k;
653
654     /* Add a node with name and info */
655     set = E_(mvar_New)( name, "set" );
656     if( b_name == VLC_TRUE )
657     {
658         E_(mvar_AppendNewVar)( set, "name", el->psz_name );
659     }
660
661     for( k = 0; k < el->i_child; k++ )
662     {
663         vlm_message_t *ch = el->child[k];
664         if( ch->i_child > 0 )
665         {
666             E_(mvar_VlmSetNewLoop)( ch->psz_name, vlm, set, ch, VLC_FALSE );
667         }
668         else
669         {
670             if( ch->psz_value )
671             {
672                 E_(mvar_AppendNewVar)( set, ch->psz_name, ch->psz_value );
673             }
674             else
675             {
676                 E_(mvar_AppendNewVar)( set, el->psz_name, ch->psz_name );
677             }
678         }
679     }
680
681     E_(mvar_AppendVar)( s, set );
682 }
683
684 mvar_t *E_(mvar_VlmSetNew)( char *name, vlm_t *vlm )
685 {
686     mvar_t        *s = E_(mvar_New)( name, "set" );
687     vlm_message_t *msg;
688     int    i;
689
690     if( vlm == NULL ) return s;
691
692     if( vlm_ExecuteCommand( vlm, "show", &msg ) )
693     {
694         return s;
695     }
696
697     for( i = 0; i < msg->i_child; i++ )
698     {
699         /* Over media, schedule */
700         vlm_message_t *ch = msg->child[i];
701         int j;
702
703         for( j = 0; j < ch->i_child; j++ )
704         {
705             /* Over name */
706             vlm_message_t *el = ch->child[j];
707             vlm_message_t *inf, *desc;
708             char          psz[500];
709
710             sprintf( psz, "show %s", el->psz_name );
711             if( vlm_ExecuteCommand( vlm, psz, &inf ) )
712                 continue;
713             desc = inf->child[0];
714
715             E_(mvar_VlmSetNewLoop)( el->psz_name, vlm, s, desc, VLC_TRUE );
716
717             vlm_MessageDelete( inf );
718         }
719     }
720     vlm_MessageDelete( msg );
721
722     return s;
723 }