1 /*****************************************************************************
2 * mvar.c : Variables handling for the HTTP Interface
3 *****************************************************************************
4 * Copyright (C) 2001-2007 the VideoLAN team
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 *****************************************************************************/
34 #ifdef HAVE_SYS_STAT_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
,
49 return strcasecmp( *foo1
, *foo2
);
54 mvar_t
*mvar_New( const char *name
, const char *value
)
56 mvar_t
*v
= malloc( sizeof( mvar_t
) );
59 v
->name
= strdup( name
);
60 v
->value
= strdup( value
? value
: "" );
63 v
->field
= xmalloc( sizeof( mvar_t
* ) );
69 void mvar_Delete( mvar_t
*v
)
76 for( i
= 0; i
< v
->i_field
; i
++ )
78 mvar_Delete( v
->field
[i
] );
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
;
91 mvar_t
*mvar_Duplicate( const mvar_t
*v
)
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
] ) );
105 void mvar_PushVar( mvar_t
*v
, mvar_t
*f
)
107 v
->field
= xrealloc( v
->field
, sizeof( mvar_t
* ) * ( v
->i_field
+ 2 ) );
110 memmove( &v
->field
[1], &v
->field
[0], sizeof( mvar_t
* ) * v
->i_field
);
116 void mvar_RemoveVar( mvar_t
*v
, mvar_t
*f
)
119 for( i
= 0; i
< v
->i_field
; i
++ )
121 if( v
->field
[i
] == f
)
126 if( i
>= v
->i_field
)
131 if( i
+ 1 < v
->i_field
)
133 memmove( &v
->field
[i
], &v
->field
[i
+1], sizeof( mvar_t
* ) * ( v
->i_field
- i
- 1 ) );
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
))];
147 strlcpy( base
, name
, sizeof (base
) );
151 if( ( p
= strchr( base
, '[' ) ) != NULL
)
154 unsigned long l
= strtoul( p
, &end
, 0 );
156 if( ( l
> INT_MAX
) || strcmp( "]", end
) )
167 for( i
= 0; i
< s
->i_field
; i
++ )
169 if( !strcmp( s
->field
[i
]->name
, base
) )
179 return mvar_GetVar( s
->field
[i
], field
);
191 const char *mvar_GetValue( mvar_t
*v
, const char *field
)
199 mvar_t
*f
= mvar_GetVar( v
, field
);
211 void mvar_PushNewVar( mvar_t
*vars
, const char *name
,
214 mvar_t
*f
= mvar_New( name
, value
);
215 mvar_PushVar( vars
, f
);
218 void mvar_AppendNewVar( mvar_t
*vars
, const char *name
,
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
);
231 mvar_t
*s
= mvar_New( name
, "set" );
236 int i_start
,i_stop
,i_step
;
239 p
= strchr( str
, ',' );
246 i_match
= sscanf( str
, "%d:%d:%d", &i_start
, &i_stop
, &i_step
);
253 else if( i_match
== 2 )
255 i_step
= i_start
< i_stop
? 1 : -1;
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
)
269 if( ( i_step
> 0 && i
> i_stop
) ||
270 ( i_step
< 0 && i
< i_stop
) )
275 sprintf( value
, "%d", i
);
277 mvar_PushNewVar( s
, name
, value
);
288 /********************************************************************
289 * Special sets handling
290 ********************************************************************/
292 mvar_t
*mvar_PlaylistSetNew( intf_thread_t
*p_intf
, char *name
,
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
);
302 mvar_t
*mvar_InfoSetNew( char *name
, input_thread_t
*p_input
)
304 mvar_t
*s
= mvar_New( name
, "set" );
307 if( p_input
== NULL
|| p_input
->p
== NULL
/* workarround assert in input_GetItem */ )
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
);
341 mvar_t
*mvar_ServicesSetNew( intf_thread_t
*p_intf
, char *psz_name
)
343 mvar_t
*s
= mvar_New( psz_name
, "set" );
345 char **names
= vlc_sd_GetNames( p_intf
, &longnames
, NULL
);
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
);
355 free( longnames
[i
] );
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
;
373 if( p_input
== NULL
)
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 )
394 switch( i_type
& VLC_VAR_TYPE
)
398 case VLC_VAR_VARIABLE
:
400 case VLC_VAR_INTEGER
:
403 /* Variable doesn't exist or isn't handled */
407 if( var_Get( p_sys
->p_input
, psz_variable
, &val
) < 0 )
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
);
419 for( i
= 0; i
< val_list
.p_list
->i_count
; i
++ )
424 switch( i_type
& VLC_VAR_TYPE
)
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
);
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
);
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
);
462 mvar_t
*mvar_HttpdInfoSetNew( char *name
, httpd_t
*p_httpd
, int i_type
)
464 mvar_t
*s
= mvar_New( name
, "set" );
468 if( !p_httpd
->pf_control( p_httpd
, i_type
, &info
, NULL
) )
470 for( i
= 0; i
< info
.i_count
; )
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
);
483 } while( i
< info
.i_count
&& strcmp( info
.info
[i
].psz_name
, "id" ) );
484 mvar_AppendVar( s
, inf
);
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 )
503 mvar_t
*mvar_FileSetNew( intf_thread_t
*p_intf
, char *name
,
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
);
521 for( i
= 0; i
< i_dir_content
; i
++ )
523 #ifdef HAVE_SYS_STAT_H
524 struct stat stat_info
;
526 char *psz_name
= ppsz_dir_content
[i
], *psz_ext
, *psz_dummy
;
527 char psz_tmp
[strlen( psz_dir
) + 1 + strlen( psz_name
) + 1];
531 if( psz_dir
[0] == '\0' || (psz_dir
[0] == '\\' && psz_dir
[1] == '\0') )
533 strcpy( psz_tmp
, psz_name
);
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 )
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
);
560 if( psz_dir
[0] == '\0' || (psz_dir
[0] == '\\' && psz_dir
[1] == '\0') )
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" );
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" );
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 */
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
);
604 mvar_AppendNewVar( f
, "type", "unknown" );
605 mvar_AppendNewVar( f
, "size", "unknown" );
606 mvar_AppendNewVar( f
, "date", "unknown" );
610 mvar_AppendVar( s
, f
);
616 free( ppsz_dir_content
);
620 static void mvar_VlmSetNewLoop( char *name
, vlm_t
*vlm
, mvar_t
*s
,
621 vlm_message_t
*el
, bool b_name
)
627 /* Add a node with name and info */
628 set
= mvar_New( name
, "set" );
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 );
645 mvar_AppendNewVar( set
, ch
->psz_name
, ch
->psz_value
);
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" );
664 if( vlm
== NULL
) return s
;
666 if( vlm_ExecuteCommand( vlm
, "show", &msg
) )
669 for( i
= 0; i
< msg
->i_child
; i
++ )
671 /* Over media, schedule */
672 vlm_message_t
*ch
= msg
->child
[i
];
675 for( j
= 0; j
< ch
->i_child
; j
++ )
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
) )
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 */