librivox: create a node for each book of the podcast.
[vlc/asuraparaju-public.git] / modules / control / http / mvar.c
blob33ba6dcfae980d3d6100258c0a55cd740506edd4
1 /*****************************************************************************
2 * mvar.c : Variables handling for the HTTP Interface
3 *****************************************************************************
4 * Copyright (C) 2001-2007 the VideoLAN team
5 * $Id$
7 * Authors: Gildas Bazin <gbazin@netcourrier.com>
8 * Laurent Aimar <fenrir@via.ecp.fr>
9 * Christophe Massiot <massiot@via.ecp.fr>
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.
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.
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
29 #include "http.h"
30 #include <limits.h>
31 #include <errno.h>
32 #include <ctype.h>
33 #include <fcntl.h>
34 #ifdef HAVE_SYS_STAT_H
35 #include <sys/stat.h>
36 #endif
37 #include <vlc_fs.h>
38 #include <vlc_services_discovery.h>
40 /* Utility function for scandir */
41 static int Filter( const char *foo )
43 return strcmp( foo, "." );
46 static int InsensitiveAlphasort( const char **foo1,
47 const char **foo2 )
49 return strcasecmp( *foo1, *foo2 );
54 mvar_t *mvar_New( const char *name, const char *value )
56 mvar_t *v = malloc( sizeof( mvar_t ) );
58 if( !v ) return NULL;
59 v->name = strdup( name );
60 v->value = strdup( value ? value : "" );
62 v->i_field = 0;
63 v->field = xmalloc( sizeof( mvar_t * ) );
64 v->field[0] = NULL;
66 return v;
69 void mvar_Delete( mvar_t *v )
71 int i;
73 free( v->name );
74 free( v->value );
76 for( i = 0; i < v->i_field; i++ )
78 mvar_Delete( v->field[i] );
80 free( v->field );
81 free( v );
84 void mvar_AppendVar( mvar_t *v, mvar_t *f )
86 v->field = xrealloc( v->field, sizeof( mvar_t * ) * ( v->i_field + 2 ) );
87 v->field[v->i_field] = f;
88 v->i_field++;
91 mvar_t *mvar_Duplicate( const mvar_t *v )
93 int i;
94 mvar_t *n;
96 n = mvar_New( v->name, v->value );
97 for( i = 0; i < v->i_field; i++ )
99 mvar_AppendVar( n, mvar_Duplicate( v->field[i] ) );
102 return n;
105 void mvar_PushVar( mvar_t *v, mvar_t *f )
107 v->field = xrealloc( v->field, sizeof( mvar_t * ) * ( v->i_field + 2 ) );
108 if( v->i_field > 0 )
110 memmove( &v->field[1], &v->field[0], sizeof( mvar_t * ) * v->i_field );
112 v->field[0] = f;
113 v->i_field++;
116 void mvar_RemoveVar( mvar_t *v, mvar_t *f )
118 int i;
119 for( i = 0; i < v->i_field; i++ )
121 if( v->field[i] == f )
123 break;
126 if( i >= v->i_field )
128 return;
131 if( i + 1 < v->i_field )
133 memmove( &v->field[i], &v->field[i+1], sizeof( mvar_t * ) * ( v->i_field - i - 1 ) );
135 v->i_field--;
136 /* FIXME should do a realloc */
139 mvar_t *mvar_GetVar( mvar_t *s, const char *name )
141 /* format: name[index].field */
142 const char *field = strchr( name, '.' );
143 char base[1 + (field ? (size_t)(field - name) : strlen( name ))];
144 char *p;
145 int i_index, i;
147 strlcpy( base, name, sizeof (base) );
148 if( field != NULL )
149 field++;
151 if( ( p = strchr( base, '[' ) ) != NULL )
153 char *end;
154 unsigned long l = strtoul( p, &end, 0 );
156 if( ( l > INT_MAX ) || strcmp( "]", end ) )
157 return NULL;
159 *p++ = '\0';
160 i_index = (int)l;
162 else
164 i_index = 0;
167 for( i = 0; i < s->i_field; i++ )
169 if( !strcmp( s->field[i]->name, base ) )
171 if( i_index > 0 )
173 i_index--;
175 else
177 if( field )
179 return mvar_GetVar( s->field[i], field );
181 else
183 return s->field[i];
188 return NULL;
191 const char *mvar_GetValue( mvar_t *v, const char *field )
193 if( *field == '\0' )
195 return v->value;
197 else
199 mvar_t *f = mvar_GetVar( v, field );
200 if( f )
202 return f->value;
204 else
206 return field;
211 void mvar_PushNewVar( mvar_t *vars, const char *name,
212 const char *value )
214 mvar_t *f = mvar_New( name, value );
215 mvar_PushVar( vars, f );
218 void mvar_AppendNewVar( mvar_t *vars, const char *name,
219 const char *value )
221 mvar_t *f = mvar_New( name, value );
222 mvar_AppendVar( vars, f );
226 /* arg= start[:stop[:step]],.. */
227 mvar_t *mvar_IntegerSetNew( const char *name, const char *arg )
229 char *dup = strdup( arg );
230 char *str = dup;
231 mvar_t *s = mvar_New( name, "set" );
233 while( str )
235 char *p;
236 int i_start,i_stop,i_step;
237 int i_match;
239 p = strchr( str, ',' );
240 if( p )
242 *p++ = '\0';
245 i_step = 0;
246 i_match = sscanf( str, "%d:%d:%d", &i_start, &i_stop, &i_step );
248 if( i_match == 1 )
250 i_stop = i_start;
251 i_step = 1;
253 else if( i_match == 2 )
255 i_step = i_start < i_stop ? 1 : -1;
258 if( i_match >= 1 )
260 int i;
262 if( ( i_start <= i_stop && i_step > 0 ) ||
263 ( i_start >= i_stop && i_step < 0 ) )
265 for( i = i_start; ; i += i_step )
267 char value[79];
269 if( ( i_step > 0 && i > i_stop ) ||
270 ( i_step < 0 && i < i_stop ) )
272 break;
275 sprintf( value, "%d", i );
277 mvar_PushNewVar( s, name, value );
281 str = p;
284 free( dup );
285 return s;
288 /********************************************************************
289 * Special sets handling
290 ********************************************************************/
292 mvar_t *mvar_PlaylistSetNew( intf_thread_t *p_intf, char *name,
293 playlist_t *p_pl )
295 mvar_t *s = mvar_New( name, "set" );
296 playlist_Lock( p_pl );
297 PlaylistListNode( p_intf, p_pl, p_pl->p_root_category , name, s, 0 );
298 playlist_Unlock( p_pl );
299 return s;
302 mvar_t *mvar_InfoSetNew( char *name, input_thread_t *p_input )
304 mvar_t *s = mvar_New( name, "set" );
305 int i, j;
307 if( p_input == NULL || p_input->p == NULL /* workarround assert in input_GetItem */ )
309 return s;
312 vlc_mutex_lock( &input_GetItem(p_input)->lock );
313 for ( i = 0; i < input_GetItem(p_input)->i_categories; i++ )
315 info_category_t *p_category = input_GetItem(p_input)->pp_categories[i];
317 mvar_t *cat = mvar_New( name, "set" );
318 mvar_t *iset = mvar_New( "info", "set" );
320 mvar_AppendNewVar( cat, "name", p_category->psz_name );
321 mvar_AppendVar( cat, iset );
323 for ( j = 0; j < p_category->i_infos; j++ )
325 info_t *p_info = p_category->pp_infos[j];
326 mvar_t *info = mvar_New( "info", "" );
328 /* msg_Dbg( p_input, "adding info name=%s value=%s",
329 psz_name, psz_value ); */
330 mvar_AppendNewVar( info, "name", p_info->psz_name );
331 mvar_AppendNewVar( info, "value", p_info->psz_value );
332 mvar_AppendVar( iset, info );
334 mvar_AppendVar( s, cat );
336 vlc_mutex_unlock( &input_GetItem(p_input)->lock );
338 return s;
341 mvar_t *mvar_ServicesSetNew( intf_thread_t *p_intf, char *psz_name )
343 mvar_t *s = mvar_New( psz_name, "set" );
344 char **longnames;
345 char **names = vlc_sd_GetNames( p_intf, &longnames, NULL );
346 if( names == NULL )
347 goto out;
349 for( size_t i = 0; names[i]; i++ )
351 mvar_t *sd = mvar_New( "sd", names[i] );
352 mvar_AppendNewVar( sd, "name", longnames[i] );
353 mvar_AppendVar( s, sd );
354 free( names[i] );
355 free( longnames[i] );
358 free( longnames );
359 free( names );
360 out:
361 return s;
364 mvar_t *mvar_InputVarSetNew( intf_thread_t *p_intf, char *name,
365 input_thread_t *p_input,
366 const char *psz_variable )
368 intf_sys_t *p_sys = p_intf->p_sys;
369 mvar_t *s = mvar_New( name, "set" );
370 vlc_value_t val, val_list, text_list;
371 int i_type, i;
373 if( p_input == NULL )
375 return s;
378 /* Check the type of the object variable */
379 i_type = var_Type( p_sys->p_input, psz_variable );
381 /* Make sure we want to display the variable */
382 if( i_type & VLC_VAR_HASCHOICE )
384 var_Change( p_sys->p_input, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
385 if( val.i_int == 0 ) return s;
386 if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
387 return s;
389 else
391 return s;
394 switch( i_type & VLC_VAR_TYPE )
396 case VLC_VAR_VOID:
397 case VLC_VAR_BOOL:
398 case VLC_VAR_VARIABLE:
399 case VLC_VAR_STRING:
400 case VLC_VAR_INTEGER:
401 break;
402 default:
403 /* Variable doesn't exist or isn't handled */
404 return s;
407 if( var_Get( p_sys->p_input, psz_variable, &val ) < 0 )
409 return s;
412 if( var_Change( p_sys->p_input, psz_variable, VLC_VAR_GETLIST,
413 &val_list, &text_list ) < 0 )
415 if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
416 return s;
419 for( i = 0; i < val_list.p_list->i_count; i++ )
421 char psz_int[21];
422 mvar_t *itm;
424 switch( i_type & VLC_VAR_TYPE )
426 case VLC_VAR_STRING:
427 itm = mvar_New( name, "set" );
428 mvar_AppendNewVar( itm, "name", text_list.p_list->p_values[i].psz_string );
429 mvar_AppendNewVar( itm, "id", val_list.p_list->p_values[i].psz_string );
430 snprintf( psz_int, sizeof(psz_int), "%d",
431 ( !strcmp( val.psz_string,
432 val_list.p_list->p_values[i].psz_string )
433 && !( i_type & VLC_VAR_ISCOMMAND ) ) );
434 mvar_AppendNewVar( itm, "selected", psz_int );
435 mvar_AppendVar( s, itm );
436 break;
438 case VLC_VAR_INTEGER:
439 itm = mvar_New( name, "set" );
440 mvar_AppendNewVar( itm, "name", text_list.p_list->p_values[i].psz_string );
441 snprintf( psz_int, sizeof(psz_int), "%"PRId64,
442 val_list.p_list->p_values[i].i_int );
443 mvar_AppendNewVar( itm, "id", psz_int );
444 snprintf( psz_int, sizeof(psz_int), "%d",
445 ( val.i_int == val_list.p_list->p_values[i].i_int )
446 && !( i_type & VLC_VAR_ISCOMMAND ) );
447 mvar_AppendNewVar( itm, "selected", psz_int );
448 mvar_AppendVar( s, itm );
449 break;
451 default:
452 break;
455 /* clean up everything */
456 if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
457 var_FreeList( &val_list, &text_list );
458 return s;
461 #if 0
462 mvar_t *mvar_HttpdInfoSetNew( char *name, httpd_t *p_httpd, int i_type )
464 mvar_t *s = mvar_New( name, "set" );
465 httpd_info_t info;
466 int i;
468 if( !p_httpd->pf_control( p_httpd, i_type, &info, NULL ) )
470 for( i= 0; i < info.i_count; )
472 mvar_t *inf;
474 inf = mvar_New( name, "set" );
477 /* fprintf( stderr," mvar_HttpdInfoSetNew: append name=`%s' value=`%s'\n",
478 info.info[i].psz_name, info.info[i].psz_value ); */
479 mvar_AppendNewVar( inf,
480 info.info[i].psz_name,
481 info.info[i].psz_value );
482 i++;
483 } while( i < info.i_count && strcmp( info.info[i].psz_name, "id" ) );
484 mvar_AppendVar( s, inf );
488 /* free mem */
489 for( i = 0; i < info.i_count; i++ )
491 free( info.info[i].psz_name );
492 free( info.info[i].psz_value );
494 if( info.i_count > 0 )
496 free( info.info );
499 return s;
501 #endif
503 mvar_t *mvar_FileSetNew( intf_thread_t *p_intf, char *name,
504 char *psz_dir )
506 mvar_t *s = mvar_New( name, "set" );
507 char **ppsz_dir_content;
508 int i_dir_content, i;
509 psz_dir = RealPath( psz_dir );
511 /* parse psz_src dir */
512 if( ( i_dir_content = vlc_scandir( psz_dir, &ppsz_dir_content, Filter,
513 InsensitiveAlphasort ) ) == -1 )
515 if( errno != ENOENT && errno != ENOTDIR )
516 msg_Warn( p_intf, "error while scanning dir %s (%m)", psz_dir );
517 free( psz_dir );
518 return s;
521 for( i = 0; i < i_dir_content; i++ )
523 #ifdef HAVE_SYS_STAT_H
524 struct stat stat_info;
525 #endif
526 char *psz_name = ppsz_dir_content[i], *psz_ext, *psz_dummy;
527 char psz_tmp[strlen( psz_dir ) + 1 + strlen( psz_name ) + 1];
528 mvar_t *f;
530 #if defined( WIN32 )
531 if( psz_dir[0] == '\0' || (psz_dir[0] == '\\' && psz_dir[1] == '\0') )
533 strcpy( psz_tmp, psz_name );
535 else
536 #endif
538 sprintf( psz_tmp, "%s"DIR_SEP"%s", psz_dir, psz_name );
540 #ifdef HAVE_SYS_STAT_H
541 if( vlc_stat( psz_tmp, &stat_info ) == -1 )
543 free( psz_name );
544 continue;
546 #endif
548 f = mvar_New( name, "set" );
550 /* put lower-case file extension in 'ext' */
551 psz_ext = strrchr( psz_name, '.' );
552 psz_ext = strdup( psz_ext != NULL ? psz_ext + 1 : "" );
553 for( psz_dummy = psz_ext; *psz_dummy != '\0'; psz_dummy++ )
554 *psz_dummy = tolower( *psz_dummy );
556 mvar_AppendNewVar( f, "ext", psz_ext );
557 free( psz_ext );
559 #if defined( WIN32 )
560 if( psz_dir[0] == '\0' || (psz_dir[0] == '\\' && psz_dir[1] == '\0') )
562 char psz_tmp[3];
563 sprintf( psz_tmp, "%c:", psz_name[0] );
564 mvar_AppendNewVar( f, "name", psz_name );
565 mvar_AppendNewVar( f, "basename", psz_tmp );
566 mvar_AppendNewVar( f, "type", "directory" );
567 mvar_AppendNewVar( f, "size", "unknown" );
568 mvar_AppendNewVar( f, "date", "unknown" );
570 else
571 #endif
573 char psz_buf[20];
574 char psz_tmp[strlen( psz_dir ) + 1 + strlen( psz_name ) + 1];
576 sprintf( psz_tmp, "%s"DIR_SEP"%s", psz_dir, psz_name );
577 mvar_AppendNewVar( f, "name", psz_tmp );
578 mvar_AppendNewVar( f, "basename", psz_name );
580 #ifdef HAVE_SYS_STAT_H
581 if( S_ISDIR( stat_info.st_mode ) )
583 mvar_AppendNewVar( f, "type", "directory" );
585 else if( S_ISREG( stat_info.st_mode ) )
587 mvar_AppendNewVar( f, "type", "file" );
589 else
591 mvar_AppendNewVar( f, "type", "unknown" );
594 snprintf( psz_buf, sizeof( psz_buf ), "%"PRId64,
595 (int64_t)stat_info.st_size );
596 mvar_AppendNewVar( f, "size", psz_buf );
598 /* FIXME memory leak FIXME */
599 struct tm tm;
600 strftime( psz_buf, sizeof( psz_buf ), "%F %H:%M:%S",
601 localtime_r( &stat_info.st_mtime, &tm ) );
602 mvar_AppendNewVar( f, "date", psz_buf );
603 #else
604 mvar_AppendNewVar( f, "type", "unknown" );
605 mvar_AppendNewVar( f, "size", "unknown" );
606 mvar_AppendNewVar( f, "date", "unknown" );
607 #endif
610 mvar_AppendVar( s, f );
612 free( psz_name );
615 free( psz_dir );
616 free( ppsz_dir_content );
617 return s;
620 static void mvar_VlmSetNewLoop( char *name, vlm_t *vlm, mvar_t *s,
621 vlm_message_t *el, bool b_name )
623 /* Over name */
624 mvar_t *set;
625 int k;
627 /* Add a node with name and info */
628 set = mvar_New( name, "set" );
629 if( b_name == true )
631 mvar_AppendNewVar( set, "name", el->psz_name );
634 for( k = 0; k < el->i_child; k++ )
636 vlm_message_t *ch = el->child[k];
637 if( ch->i_child > 0 )
639 mvar_VlmSetNewLoop( ch->psz_name, vlm, set, ch, false );
641 else
643 if( ch->psz_value )
645 mvar_AppendNewVar( set, ch->psz_name, ch->psz_value );
647 else
649 mvar_AppendNewVar( set, el->psz_name, ch->psz_name );
654 mvar_AppendVar( s, set );
657 mvar_t *mvar_VlmSetNew( char *name, vlm_t *vlm )
659 mvar_t *s = mvar_New( name, "set" );
660 #ifdef ENABLE_VLM
661 vlm_message_t *msg;
662 int i;
664 if( vlm == NULL ) return s;
666 if( vlm_ExecuteCommand( vlm, "show", &msg ) )
667 return s;
669 for( i = 0; i < msg->i_child; i++ )
671 /* Over media, schedule */
672 vlm_message_t *ch = msg->child[i];
673 int j;
675 for( j = 0; j < ch->i_child; j++ )
677 /* Over name */
678 vlm_message_t *el = ch->child[j];
679 vlm_message_t *inf, *desc;
680 char psz[6 + strlen(el->psz_name)];
682 sprintf( psz, "show %s", el->psz_name );
683 if( vlm_ExecuteCommand( vlm, psz, &inf ) )
684 continue;
685 desc = inf->child[0];
687 mvar_VlmSetNewLoop( el->psz_name, vlm, s, desc, true );
689 vlm_MessageDelete( inf );
692 vlm_MessageDelete( msg );
693 #endif /* ENABLE_VLM */
694 return s;