]> git.sesse.net Git - vlc/blob - src/misc/vlm.c
* src/misc/vlm.c: added 'inputdeln <num>' to delete input #num (starts from 1)
[vlc] / src / misc / vlm.c
1 /*****************************************************************************
2  * vlm.c: VLM interface plugin
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id$
6  *
7  * Authors: Simon Latapie <garf@videolan.org>
8  *          Laurent Aimar <fenrir@videolan.org>
9  *          Gildas Bazin <gbazin@videolan.org>
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 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <ctype.h>                                              /* tolower() */
31
32 #include <vlc/vlc.h>
33
34 #ifdef ENABLE_VLM
35
36 #include <vlc/intf.h>
37 #include <vlc/input.h>
38
39 #ifdef HAVE_TIME_H
40 #   include <time.h>                                              /* ctime() */
41 #endif
42
43 #include "vlc_vlm.h"
44 #include "vlc_vod.h"
45
46 #define FREE( p ) \
47         if( p ) { free( p ); (p) = NULL; }
48
49 /*****************************************************************************
50  * Local prototypes.
51  *****************************************************************************/
52 static vlm_message_t *vlm_Show( vlm_t *, vlm_media_t *, vlm_schedule_t *, char * );
53 static vlm_message_t *vlm_Help( vlm_t *, char * );
54
55 static vlm_media_t *vlm_MediaSearch ( vlm_t *, char * );
56 static vlm_media_instance_t *vlm_MediaInstanceSearch( vlm_t *, vlm_media_t *, char * );
57
58 static vlm_message_t *vlm_MessageNew( char *, const char *, ... );
59 static vlm_message_t *vlm_MessageAdd( vlm_message_t *, vlm_message_t * );
60
61 static vlm_schedule_t *vlm_ScheduleSearch( vlm_t *, char * );
62
63 static char *Save( vlm_t * );
64 static int Load( vlm_t *, char * );
65 static int ExecuteCommand( vlm_t *, char *, vlm_message_t ** );
66 static int Manage( vlc_object_t * );
67
68 /*****************************************************************************
69  * vlm_New:
70  *****************************************************************************/
71 vlm_t *__vlm_New ( vlc_object_t *p_this )
72 {
73     vlc_value_t lockval;
74     vlm_t *p_vlm = NULL;
75     char *psz_vlmconf;
76
77     /* to be sure to avoid multiple creation */
78     var_Create( p_this->p_libvlc, "vlm_mutex", VLC_VAR_MUTEX );
79     var_Get( p_this->p_libvlc, "vlm_mutex", &lockval );
80     vlc_mutex_lock( lockval.p_address );
81
82     if( !(p_vlm = vlc_object_find( p_this, VLC_OBJECT_VLM, FIND_ANYWHERE )) )
83     {
84         msg_Info( p_this, "creating vlm" );
85         if( ( p_vlm = vlc_object_create( p_this, VLC_OBJECT_VLM ) ) == NULL )
86         {
87             vlc_mutex_unlock( lockval.p_address );
88             return NULL;
89         }
90
91         vlc_mutex_init( p_this->p_vlc, &p_vlm->lock );
92         p_vlm->i_media      = 0;
93         p_vlm->media        = NULL;
94         p_vlm->i_vod        = 0;
95         p_vlm->i_schedule   = 0;
96         p_vlm->schedule     = NULL;
97
98         vlc_object_yield( p_vlm );
99         vlc_object_attach( p_vlm, p_this->p_vlc );
100     }
101     vlc_mutex_unlock( lockval.p_address );
102
103     if( vlc_thread_create( p_vlm, "vlm thread",
104                            Manage, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
105     {
106         vlc_mutex_destroy( &p_vlm->lock );
107         vlc_object_destroy( p_vlm );
108         return NULL;
109     }
110
111     /* Try loading the vlm conf file given by --vlm-conf */
112     psz_vlmconf = config_GetPsz( p_vlm, "vlm-conf" );
113
114     if( psz_vlmconf && *psz_vlmconf )
115     {
116         vlm_message_t *p_message = NULL;
117         char *psz_buffer = NULL;
118
119         msg_Dbg( p_this, "loading vlm conf ..." );
120         asprintf(&psz_buffer, "load %s", psz_vlmconf );
121         if( psz_buffer )
122         {
123             msg_Dbg( p_this, psz_buffer);
124             if( vlm_ExecuteCommand( p_vlm, psz_buffer, &p_message ) ){
125                 msg_Warn( p_this, "error while loading the vlm conf file" );
126             }
127             free(p_message);
128             free(psz_buffer);
129         }
130    }
131    free(psz_vlmconf);
132
133    return p_vlm;
134 }
135
136 /*****************************************************************************
137  * vlm_Delete:
138  *****************************************************************************/
139 void vlm_Delete( vlm_t *p_vlm )
140 {
141     vlc_value_t lockval;
142
143     var_Get( p_vlm->p_libvlc, "vlm_mutex", &lockval );
144     vlc_mutex_lock( lockval.p_address );
145
146     vlc_object_release( p_vlm );
147
148     if( p_vlm->i_refcount > 0 )
149     {
150         vlc_mutex_unlock( lockval.p_address );
151         return;
152     }
153
154     p_vlm->b_die = VLC_TRUE;
155     vlc_thread_join( p_vlm );
156
157     vlc_mutex_destroy( &p_vlm->lock );
158
159     while( p_vlm->i_media ) vlm_MediaDelete( p_vlm, p_vlm->media[0], NULL );
160     FREE( p_vlm->media );
161
162     while( p_vlm->i_schedule ) vlm_ScheduleDelete( p_vlm,
163                                                    p_vlm->schedule[0], NULL );
164     FREE( p_vlm->schedule );
165
166     vlc_object_detach( p_vlm );
167     vlc_object_destroy( p_vlm );
168     vlc_mutex_unlock( lockval.p_address );
169 }
170
171 /*****************************************************************************
172  * vlm_ExecuteCommand:
173  *****************************************************************************/
174 int vlm_ExecuteCommand( vlm_t *p_vlm, char *psz_command,
175                         vlm_message_t **pp_message)
176 {
177     int i_result;
178
179     vlc_mutex_lock( &p_vlm->lock );
180     i_result = ExecuteCommand( p_vlm, psz_command, pp_message );
181     vlc_mutex_unlock( &p_vlm->lock );
182
183     return i_result;
184 }
185
186 /*****************************************************************************
187  * vlm_Save:
188  *****************************************************************************/
189 int vlm_Save( vlm_t *p_vlm, char *psz_file )
190 {
191     FILE *file;
192     char *psz_save;
193
194     if( !p_vlm || !psz_file ) return 1;
195
196     file = fopen( psz_file, "w" );
197     if( file == NULL ) return 1;
198
199     psz_save = Save( p_vlm );
200     if( psz_save == NULL )
201     {
202         fclose( file );
203         return 1;
204     }
205     fwrite( psz_save, strlen( psz_save ), 1, file );
206     fclose( file );
207     free( psz_save );
208
209     return 0;
210 }
211
212 /*****************************************************************************
213  * vlm_Load:
214  *****************************************************************************/
215 int vlm_Load( vlm_t *p_vlm, char *psz_file )
216 {
217     FILE *file;
218     int64_t i_size;
219     char *psz_buffer;
220
221     if( !p_vlm || !psz_file ) return 1;
222
223     file = fopen( psz_file, "r" );
224     if( file == NULL ) return 1;
225
226     if( fseek( file, 0, SEEK_END) != 0 ) return 2;
227
228     i_size = ftell( file );
229     fseek( file, 0, SEEK_SET);
230     psz_buffer = malloc( i_size + 1 );
231     if( !psz_buffer )
232     {
233         fclose( file );
234         return 2;
235     }
236     fread( psz_buffer, 1, i_size, file);
237     psz_buffer[ i_size ] = '\0';
238     if( Load( p_vlm, psz_buffer ) )
239     {
240         free( psz_buffer );
241         return 3;
242     }
243     free( psz_buffer );
244
245     fclose( file );
246
247     return 0;
248 }
249
250 /*****************************************************************************
251  * FindEndCommand
252  *****************************************************************************/
253 static char *FindEndCommand( char *psz )
254 {
255     char *psz_sent = psz;
256
257     switch( *psz_sent )
258     {
259     case '\"':
260         psz_sent++;
261
262         while( ( *psz_sent != '\"' ) && ( *psz_sent != '\0' ) )
263         {
264             if( *psz_sent == '\'' )
265             {
266                 psz_sent = FindEndCommand( psz_sent );
267                 if( psz_sent == NULL ) return NULL;
268             }
269             else psz_sent++;
270         }
271
272         if( *psz_sent == '\"' )
273         {
274             psz_sent++;
275             return psz_sent;
276         }
277
278         /* *psz_sent == '\0' -> number of " is incorrect */
279         else return NULL;
280
281         break;
282
283     case '\'':
284         psz_sent++;
285
286         while( ( *psz_sent != '\'' ) && ( *psz_sent != '\0' ) )
287         {
288             if( *psz_sent == '\"' )
289             {
290                 psz_sent = FindEndCommand( psz_sent );
291                 if( psz_sent == NULL ) return NULL;
292             }
293             else psz_sent++;
294         }
295
296         if( *psz_sent == '\'' )
297         {
298             psz_sent++;
299             return psz_sent;
300         }
301
302         /* *psz_sent == '\0' -> number of " is incorrect */
303         else return NULL;
304
305         break;
306
307     default: /* now we can look for spaces */
308         while( ( *psz_sent != ' ' ) && ( *psz_sent != '\0' ) )
309         {
310             if( ( *psz_sent == '\'' ) || ( *psz_sent == '\"' ) )
311             {
312                 psz_sent = FindEndCommand( psz_sent );
313             }
314             else psz_sent++;
315         }
316
317         return psz_sent;
318     }
319 }
320
321 /*****************************************************************************
322  * ExecuteCommand: The main state machine
323  *****************************************************************************
324  * Execute a command which ends with '\0' (string)
325  *****************************************************************************/
326 static int ExecuteCommand( vlm_t *p_vlm, char *psz_command,
327                            vlm_message_t **pp_message )
328 {
329     int i_command = 0;
330     char **ppsz_command = NULL;
331     char *psz_cmd = psz_command;
332     vlm_message_t *p_message = NULL;
333     int i, j;
334
335     /* First, parse the line and cut it */
336     while( *psz_cmd != '\0' )
337     {
338
339         if( *psz_cmd == ' ' || *psz_cmd == '\t' )
340         {
341             psz_cmd++;
342         }
343         else
344         {
345             char *psz_temp;
346             int   i_temp;
347
348             /* support for comments */
349             if( i_command == 0 && *psz_cmd == '#')
350             {
351                 p_message = vlm_MessageNew( "", NULL );
352                 goto success;
353             }
354
355             psz_temp = FindEndCommand( psz_cmd );
356
357             if( psz_temp == NULL ) goto error;
358
359             i_temp = psz_temp - psz_cmd;
360
361             ppsz_command = realloc( ppsz_command, (i_command + 1) *
362                                     sizeof(char*) );
363             ppsz_command[ i_command ] = malloc( (i_temp + 1) * sizeof(char) );
364             strncpy( ppsz_command[ i_command ], psz_cmd, i_temp );
365             ppsz_command[ i_command ][ i_temp ] = '\0';
366
367             i_command++;
368
369             psz_cmd = psz_temp;
370         }
371     }
372
373     /*
374      * And then Interpret it
375      */
376
377     if( i_command == 0 )
378     {
379         p_message = vlm_MessageNew( "", NULL );
380         goto success;
381     }
382
383     if( !strcmp(ppsz_command[0], "new") )
384     {
385         int i_type;
386
387         /* Check the number of arguments */
388         if( i_command < 3 ) goto syntax_error;
389
390         /* Get type */
391         if( !strcmp(ppsz_command[2], "vod") )
392         {
393             i_type = VOD_TYPE;
394         }
395         else if( !strcmp(ppsz_command[2], "broadcast") )
396         {
397             i_type = BROADCAST_TYPE;
398         }
399         else if( !strcmp(ppsz_command[2], "schedule") )
400         {
401             i_type = SCHEDULE_TYPE;
402         }
403         else
404         {
405             p_message =
406                 vlm_MessageNew( "new", "%s: Choose between vod, "
407                                 "broadcast or schedule", ppsz_command[1] );
408             goto error;
409         }
410
411         /* Check for forbidden media names */
412         if( !strcmp(ppsz_command[1], "all") ||
413             !strcmp(ppsz_command[1], "media") ||
414             !strcmp(ppsz_command[1], "schedule") )
415         {
416             p_message = vlm_MessageNew( "new", "\"all\", \"media\" and "
417                                         "\"schedule\" are reserved names" );
418             goto error;
419         }
420
421         /* Check the name is not already in use */
422         if( vlm_ScheduleSearch( p_vlm, ppsz_command[1] ) ||
423             vlm_MediaSearch( p_vlm, ppsz_command[1] ) )
424         {
425             p_message = vlm_MessageNew( "new", "%s: Name already in use",
426                                         ppsz_command[1] );
427             goto error;
428         }
429
430         /* Schedule */
431         if( i_type == SCHEDULE_TYPE )
432         {
433             vlm_schedule_t *p_schedule;
434             p_schedule = vlm_ScheduleNew( p_vlm, ppsz_command[1] );
435             if( !p_schedule )
436             {
437                 p_message = vlm_MessageNew( "new", "could not create schedule" );
438                 goto error;
439             }
440         }
441
442         /* Media */
443         else
444         {
445             vlm_media_t *p_media;
446             p_media = vlm_MediaNew( p_vlm, ppsz_command[1], i_type );
447             if( !p_media )
448             {
449                 p_message = vlm_MessageNew( "new", "could not create media" );
450                 goto error;
451             }
452         }
453
454         if( i_command <= 3 )
455         {
456             p_message = vlm_MessageNew( "new", NULL );
457             goto success;
458         }
459
460         /* Properties will be dealt with later on */
461     }
462
463     else if( !strcmp(ppsz_command[0], "setup") )
464     {
465         if( i_command < 2 ) goto syntax_error;
466
467         /* Properties will be dealt with later on */
468     }
469
470     else if( !strcmp(ppsz_command[0], "del") )
471     {
472         vlm_media_t *p_media;
473         vlm_schedule_t *p_schedule;
474
475         if( i_command < 2 ) goto syntax_error;
476
477         p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] );
478         p_schedule = vlm_ScheduleSearch( p_vlm, ppsz_command[1] );
479
480         if( p_schedule != NULL )
481         {
482             vlm_ScheduleDelete( p_vlm, p_schedule, NULL );
483         }
484         else if( p_media != NULL )
485         {
486             vlm_MediaDelete( p_vlm, p_media, NULL );
487         }
488         else if( !strcmp(ppsz_command[1], "media") )
489         {
490             while( p_vlm->i_media ) vlm_MediaDelete( p_vlm, p_vlm->media[0],
491                                                      NULL );
492         }
493         else if( !strcmp(ppsz_command[1], "schedule") )
494         {
495             while( p_vlm->i_schedule )
496                 vlm_ScheduleDelete( p_vlm, p_vlm->schedule[0], NULL );
497         }
498         else if( !strcmp(ppsz_command[1], "all") )
499         {
500             while( p_vlm->i_media ) vlm_MediaDelete( p_vlm, p_vlm->media[0],
501                                                      NULL );
502
503             while( p_vlm->i_schedule )
504                 vlm_ScheduleDelete( p_vlm, p_vlm->schedule[0], NULL );
505         }
506         else
507         {
508             p_message = vlm_MessageNew( "del", "%s: media unknown",
509                                       ppsz_command[1] );
510             goto error;
511         }
512
513         p_message = vlm_MessageNew( "del", NULL );
514         goto success;
515     }
516
517     else if( !strcmp(ppsz_command[0], "show") )
518     {
519         vlm_media_t *p_media;
520         vlm_schedule_t *p_schedule;
521
522         if( i_command == 1 )
523         {
524             p_message = vlm_Show( p_vlm, NULL, NULL, NULL );
525             goto success;
526         }
527         else if( i_command > 2 ) goto syntax_error;
528
529         p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] );
530         p_schedule = vlm_ScheduleSearch( p_vlm, ppsz_command[1] );
531
532         if( p_schedule != NULL )
533         {
534             p_message = vlm_Show( p_vlm, NULL, p_schedule, NULL );
535         }
536         else if( p_media != NULL )
537         {
538             p_message = vlm_Show( p_vlm, p_media, NULL, NULL );
539         }
540         else
541         {
542             p_message = vlm_Show( p_vlm, NULL, NULL, ppsz_command[1] );
543         }
544
545         goto success;
546     }
547
548     else if( !strcmp(ppsz_command[0], "help") )
549     {
550         if( i_command != 1 ) goto syntax_error;
551
552         p_message = vlm_Help( p_vlm, NULL );
553         goto success;
554     }
555
556     else if( !strcmp(ppsz_command[0], "control") )
557     {
558         vlm_media_t *p_media;
559
560         if( i_command < 3 ) goto syntax_error;
561
562         if( !(p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] ) ) )
563         {
564             p_message = vlm_MessageNew( "control", "%s: media unknown",
565                                       ppsz_command[1] );
566             goto error;
567         }
568         else
569         {
570             char *psz_command, *psz_arg = 0, *psz_instance = 0;
571             int i_index = 2;
572
573             if( strcmp( ppsz_command[2], "play" ) &&
574                 strcmp( ppsz_command[2], "stop" ) &&
575                 strcmp( ppsz_command[2], "pause" ) &&
576                 strcmp( ppsz_command[2], "seek" ) )
577             {
578                 i_index++;
579                 psz_instance = ppsz_command[2];
580
581                 if( i_command < 4 ) goto syntax_error;
582             }
583
584             psz_command = ppsz_command[i_index];
585
586             if( i_command >= i_index + 2 ) psz_arg = ppsz_command[i_index + 1];
587
588             vlm_MediaControl( p_vlm, p_media, psz_instance, psz_command,
589                              psz_arg );
590             p_message = vlm_MessageNew( "control", NULL );
591             goto success;
592         }
593     }
594
595     else if( !strcmp(ppsz_command[0], "save") )
596     {
597         if( i_command != 2 ) goto syntax_error;
598
599         if( vlm_Save( p_vlm, ppsz_command[1] ) )
600         {
601             p_message = vlm_MessageNew( "save", "Unable to save to file" );
602             goto error;
603         }
604         else
605         {
606             p_message = vlm_MessageNew( "save", NULL );
607             goto success;
608         }
609     }
610
611     else if( !strcmp(ppsz_command[0], "load") )
612     {
613         if( i_command != 2 ) goto syntax_error;
614
615         switch( vlm_Load( p_vlm, ppsz_command[1] ) )
616         {
617             case 0:
618                 p_message = vlm_MessageNew( "load", NULL );
619                 goto success;
620             case 2:
621                 p_message = vlm_MessageNew( "load", "read file error" );
622                 goto error;
623             case 3:
624                 p_message =
625                     vlm_MessageNew( "load", "error while loading file" );
626                 goto error;
627             default:
628                 p_message =
629                     vlm_MessageNew( "load", "Unable to load from file" );
630                 goto error;
631         }
632     }
633
634     else
635     {
636         p_message = vlm_MessageNew( ppsz_command[0], "Unknown command" );
637         goto error;
638     }
639
640     /* Common code between "new" and "setup" */
641     if( !strcmp(ppsz_command[0], "new") ||
642         !strcmp(ppsz_command[0], "setup") )
643     {
644         int i_command_start = strcmp(ppsz_command[0], "new") ? 2 : 3;
645         vlm_media_t *p_media;
646         vlm_schedule_t *p_schedule;
647
648         if( i_command < i_command_start ) goto syntax_error;
649
650         p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] );
651         p_schedule = vlm_ScheduleSearch( p_vlm, ppsz_command[1] );
652
653         if( !p_media && !p_schedule )
654         {
655             p_message = vlm_MessageNew( ppsz_command[0], "%s unknown",
656                                         ppsz_command[1] );
657             goto error;
658         }
659
660         if( p_schedule != NULL )
661         {
662             for( i = i_command_start ; i < i_command ; i++ )
663             {
664                 if( !strcmp( ppsz_command[i], "enabled" ) ||
665                     !strcmp( ppsz_command[i], "disabled" ) )
666                 {
667                     vlm_ScheduleSetup( p_schedule, ppsz_command[i], NULL );
668                 }
669
670                 /* Beware: everything behind append is considered as
671                  * command line */
672                 else if( !strcmp( ppsz_command[i], "append" ) )
673                 {
674                     if( ++i >= i_command ) break;
675
676                     for( j = i + 1; j < i_command; j++ )
677                     {
678                         ppsz_command[i] =
679                             realloc( ppsz_command[i], strlen(ppsz_command[i]) +
680                                      strlen(ppsz_command[j]) + 1 + 1 );
681                         strcat( ppsz_command[i], " " );
682                         strcat( ppsz_command[i], ppsz_command[j] );
683                     }
684
685                     vlm_ScheduleSetup( p_schedule, ppsz_command[i - 1],
686                                        ppsz_command[i] );
687                     break;
688                 }
689                 else
690                 {
691                     if( i + 1 >= i_command && !strcmp(ppsz_command[0], "new") )
692                     {
693                         vlm_ScheduleDelete( p_vlm, p_schedule, NULL );
694                         p_message =
695                             vlm_MessageNew( ppsz_command[0],
696                                             "Wrong properties syntax" );
697                         goto error;
698                     }
699                     else if( i + 1 >= i_command )
700                     {
701                         p_message =
702                             vlm_MessageNew( ppsz_command[0],
703                                             "Wrong properties syntax" );
704                         goto error;
705                     }
706
707                     vlm_ScheduleSetup( p_schedule, ppsz_command[i],
708                                        ppsz_command[i+1] );
709                     i++;
710                 }
711             }
712         }
713
714         else if( p_media != NULL )
715         {
716             for( i = i_command_start ; i < i_command ; i++ )
717             {
718                 if( !strcmp( ppsz_command[i], "enabled" ) ||
719                     !strcmp( ppsz_command[i], "disabled" ) )
720                 {
721                     vlm_MediaSetup( p_vlm, p_media, ppsz_command[i], NULL );
722                 }
723                 else if( i + 1 >= i_command &&
724                          !strcmp( ppsz_command[i], "mux") )
725                 {
726                     if( p_media->i_type != VOD_TYPE )
727                     {
728                         p_message = vlm_MessageNew( ppsz_command[0],
729                                   "mux only available for broadcast" );
730                     }
731                     else
732                     {
733                         vlm_MediaSetup( p_vlm, p_media, ppsz_command[i],
734                                         ppsz_command[i+1] );
735                         i++;
736                     }
737                 }
738                 else if( !strcmp( ppsz_command[i], "loop" ) ||
739                          !strcmp( ppsz_command[i], "unloop" ) )
740                 {
741                     if( p_media->i_type != BROADCAST_TYPE )
742                     {
743                         p_message = vlm_MessageNew( ppsz_command[0],
744                                   "loop only available for broadcast" );
745                     }
746                     else
747                     {
748                         vlm_MediaSetup( p_vlm, p_media, ppsz_command[i], NULL );
749                     }
750                 }
751                 else
752                 {
753                     if( i + 1 >= i_command &&
754                         !strcmp(ppsz_command[0], "new") )
755                     {
756                         vlm_MediaDelete( p_vlm, p_media, NULL );
757                         p_message =
758                             vlm_MessageNew( ppsz_command[0],
759                                             "Wrong properties syntax" );
760                         goto error;
761                     }
762                     else if( i + 1 >= i_command )
763                     {
764                         p_message =
765                             vlm_MessageNew( ppsz_command[0],
766                                             "Wrong properties syntax" );
767                         goto error;
768                     }
769
770                     vlm_MediaSetup( p_vlm, p_media, ppsz_command[i],
771                                     ppsz_command[i+1] );
772                     i++;
773                 }
774             }
775         }
776
777         p_message = vlm_MessageNew( ppsz_command[0], NULL );
778         goto success;
779     }
780
781 success:
782     for( i = 0 ; i < i_command ; i++ ) FREE( ppsz_command[i] );
783     FREE( ppsz_command );
784     *pp_message = p_message;
785
786     return VLC_SUCCESS;
787
788 syntax_error:
789     p_message = vlm_MessageNew( ppsz_command[0], "Wrong command syntax" );
790
791 error:
792     for( i = 0 ; i < i_command ; i++ ) FREE( ppsz_command[i] );
793     FREE( ppsz_command );
794     *pp_message = p_message;
795
796     return VLC_EGENERIC;
797 }
798
799 static vlm_media_t *vlm_MediaSearch( vlm_t *vlm, char *psz_name )
800 {
801     int i;
802
803     for( i = 0; i < vlm->i_media; i++ )
804     {
805         if( strcmp( psz_name, vlm->media[i]->psz_name ) == 0 )
806         {
807             return vlm->media[i];
808         }
809     }
810
811     return NULL;
812 }
813
814 /*****************************************************************************
815  * Media handling
816  *****************************************************************************/
817 static vlm_media_instance_t *
818 vlm_MediaInstanceSearch( vlm_t *vlm, vlm_media_t *media, char *psz_name )
819 {
820     int i;
821
822     for( i = 0; i < media->i_instance; i++ )
823     {
824         if( ( !psz_name && !media->instance[i]->psz_name ) ||
825             ( psz_name && media->instance[i]->psz_name &&
826               !strcmp( psz_name, media->instance[i]->psz_name ) ) )
827         {
828             return media->instance[i];
829         }
830     }
831
832     return NULL;
833 }
834
835 vlm_media_t *vlm_MediaNew( vlm_t *vlm, char *psz_name, int i_type )
836 {
837     vlm_media_t *media = malloc( sizeof( vlm_media_t ) );
838
839     if( !media )
840     {
841         msg_Err( vlm, "out of memory" );
842         return NULL;
843     }
844
845     /* Check if we need to load the VOD server */
846     if( i_type == VOD_TYPE && !vlm->i_vod )
847     {
848         vlm->vod = vlc_object_create( vlm, VLC_OBJECT_VOD );
849         vlc_object_attach( vlm->vod, vlm );
850         vlm->vod->p_module = module_Need( vlm->vod, "vod server", 0, 0 );
851         if( !vlm->vod->p_module )
852         {
853             msg_Err( vlm, "cannot find vod server" );
854             vlc_object_detach( vlm->vod );
855             vlc_object_destroy( vlm->vod );
856             vlm->vod = 0;
857             free( media );
858             return NULL;
859         }
860
861         vlm->vod->p_data = vlm;
862         vlm->vod->pf_media_control = vlm_MediaVodControl;
863     }
864
865     if( i_type == VOD_TYPE ) vlm->i_vod++;
866
867     media->psz_name = strdup( psz_name );
868     media->b_enabled = VLC_FALSE;
869     media->b_loop = VLC_FALSE;
870     media->vod_media = NULL;
871     media->psz_vod_output = NULL;
872     media->psz_mux = NULL;
873     media->i_input = 0;
874     media->input = NULL;
875     media->psz_output = NULL;
876     media->i_option = 0;
877     media->option = NULL;
878     media->i_type = i_type;
879     media->i_instance = 0;
880     media->instance = NULL;
881
882     media->item.psz_uri = strdup( psz_name );
883     vlc_input_item_Init( VLC_OBJECT(vlm), &media->item );
884
885     TAB_APPEND( vlm->i_media, vlm->media, media );
886
887     return media;
888 }
889
890 /* for now, simple delete. After, del with options (last arg) */
891 void vlm_MediaDelete( vlm_t *vlm, vlm_media_t *media, char *psz_name )
892 {
893     if( media == NULL ) return;
894
895     while( media->i_instance )
896     {
897         vlm_media_instance_t *p_instance = media->instance[0];
898         vlm_MediaControl( vlm, media, p_instance->psz_name, "stop", 0 );
899     }
900
901     TAB_REMOVE( vlm->i_media, vlm->media, media );
902
903     if( media->i_type == VOD_TYPE )
904     {
905         vlm_MediaSetup( vlm, media, "disabled", 0 );
906         vlm->i_vod--;
907     }
908
909     /* Check if we need to unload the VOD server */
910     if( media->i_type == VOD_TYPE && !vlm->i_vod )
911     {
912         module_Unneed( vlm->vod, vlm->vod->p_module );
913         vlc_object_detach( vlm->vod );
914         vlc_object_destroy( vlm->vod );
915         vlm->vod = 0;
916     }
917
918     if( vlm->i_media == 0 && vlm->media ) free( vlm->media );
919
920     free( media->psz_name );
921
922     while( media->i_input-- ) free( media->input[media->i_input] );
923     if( media->input ) free( media->input );
924
925     if( media->psz_output ) free( media->psz_output );
926     if( media->psz_mux ) free( media->psz_mux );
927
928     while( media->i_option-- ) free( media->option[media->i_option] );
929     if( media->option ) free( media->option );
930
931     vlc_input_item_Clean( &media->item );
932
933     free( media );
934 }
935
936 int vlm_MediaSetup( vlm_t *vlm, vlm_media_t *media, char *psz_cmd,
937                     char *psz_value )
938 {
939     if( !psz_cmd) return VLC_EGENERIC;
940
941     if( !strcmp( psz_cmd, "loop" ) )
942     {
943         media->b_loop = VLC_TRUE;
944     }
945     else if( !strcmp( psz_cmd, "unloop" ) )
946     {
947         media->b_loop = VLC_FALSE;
948     }
949     else if( !strcmp( psz_cmd, "enabled" ) )
950     {
951         media->b_enabled = VLC_TRUE;
952     }
953     else if( !strcmp( psz_cmd, "disabled" ) )
954     {
955         media->b_enabled = VLC_FALSE;
956     }
957     else if( !strcmp( psz_cmd, "mux" ) )
958     {
959         if( media->psz_mux ) free( media->psz_mux );
960         media->psz_mux = NULL;
961         if( psz_value ) media->psz_mux = strdup( psz_value );
962     }
963     else if( !strcmp( psz_cmd, "input" ) )
964     {
965         char *input;
966
967         if( psz_value != NULL && strlen(psz_value) > 1 &&
968             ( psz_value[0] == '\'' || psz_value[0] == '\"' ) &&
969             ( psz_value[ strlen(psz_value) - 1 ] == '\'' ||
970               psz_value[ strlen(psz_value) - 1 ] == '\"' )  )
971         {
972             input = malloc( strlen(psz_value) - 1 );
973
974             memcpy( input, psz_value + 1, strlen(psz_value) - 2 );
975             input[ strlen(psz_value) - 2 ] = '\0';
976         }
977         else
978         {
979             input = strdup( psz_value );
980         }
981
982         TAB_APPEND( media->i_input, media->input, input );
983     }
984     else if( !strcmp( psz_cmd, "inputdel" ) && !strcmp( psz_value, "all" ) )
985     {
986         while( media->i_input > 0 )
987         {
988             TAB_REMOVE( media->i_input, media->input, media->input[0] );
989         }
990     }
991     else if( !strcmp( psz_cmd, "inputdel" ) )
992     {
993         char *input;
994         int i;
995
996         if( psz_value != NULL && strlen(psz_value) > 1 &&
997             ( psz_value[0] == '\'' || psz_value[0] == '\"' ) &&
998             ( psz_value[ strlen(psz_value) - 1 ] == '\'' ||
999               psz_value[ strlen(psz_value) - 1 ] == '\"' )  )
1000         {
1001             input = malloc( strlen(psz_value) - 1 );
1002
1003             memcpy( input, psz_value + 1, strlen(psz_value) - 2 );
1004             input[ strlen(psz_value) - 2 ] = '\0';
1005         }
1006         else
1007         {
1008             input = strdup( psz_value );
1009         }
1010
1011         for( i = 0; i < media->i_input; i++ )
1012         {
1013             if( !strcmp( input, media->input[i] ) )
1014             {
1015                 TAB_REMOVE( media->i_input, media->input, media->input[i] );
1016                 break;
1017             }
1018         }
1019     }
1020     else if( !strcmp( psz_cmd, "inputdeln" ) )
1021     {
1022         int index = atoi( psz_value );
1023         if( index > 0 && index <= media->i_input )
1024         {
1025             TAB_REMOVE( media->i_input, media->input, media->input[index-1] );
1026         }
1027     }
1028     else if( !strcmp( psz_cmd, "output" ) )
1029     {
1030         if( media->psz_output != NULL )
1031         {
1032             free( media->psz_output );
1033         }
1034         media->psz_output = strdup( psz_value );
1035     }
1036     else if( !strcmp( psz_cmd, "option" ) )
1037     {
1038         char *psz_option;
1039         psz_option = strdup( psz_value );
1040
1041         TAB_APPEND( media->i_option, media->option, psz_option );
1042     }
1043     else
1044     {
1045         return VLC_EGENERIC;
1046     }
1047
1048     /* Check if we need to create/delete a vod media */
1049     if( media->i_type == VOD_TYPE )
1050     {
1051         if( !media->b_enabled && media->vod_media )
1052         {
1053             vlm->vod->pf_media_del( vlm->vod, media->vod_media );
1054             media->vod_media = 0;
1055         }
1056         else if( media->b_enabled && !media->vod_media && media->i_input )
1057         {
1058             /* Pre-parse the input */
1059             input_thread_t *p_input;
1060             char *psz_output;
1061             int i;
1062
1063             vlc_input_item_Clean( &media->item );
1064             vlc_input_item_Init( VLC_OBJECT(vlm), &media->item );
1065
1066             if( media->psz_output )
1067                 asprintf( &psz_output, "%s:description", media->psz_output );
1068             else
1069                 asprintf( &psz_output, "#description" );
1070
1071             media->item.psz_uri = strdup( media->input[0] );
1072             media->item.ppsz_options = malloc( sizeof( char* ) );
1073             asprintf( &media->item.ppsz_options[0], "sout=%s", psz_output);
1074             media->item.i_options = 1;
1075             for( i = 0; i < media->i_option; i++ )
1076             {
1077                 media->item.i_options++;
1078                 media->item.ppsz_options =
1079                     realloc( media->item.ppsz_options,
1080                              media->item.i_options * sizeof( char* ) );
1081                 media->item.ppsz_options[ media->item.i_options - 1 ] =
1082                     strdup( media->option[i] );
1083             }
1084
1085             if( (p_input = input_CreateThread( vlm, &media->item ) ) )
1086             {
1087                 while( !p_input->b_eof && !p_input->b_error ) msleep( 100000 );
1088
1089                 input_StopThread( p_input );
1090                 input_DestroyThread( p_input );
1091                 vlc_object_detach( p_input );
1092                 vlc_object_destroy( p_input );
1093             }
1094             free( psz_output );
1095
1096             if( media->psz_mux )
1097             {
1098                 input_item_t item;
1099                 es_format_t es, *p_es = &es;
1100                 char fourcc[5];
1101
1102                 sprintf( fourcc, "%4.4s", media->psz_mux );
1103                 fourcc[0] = tolower(fourcc[0]); fourcc[1] = tolower(fourcc[1]);
1104                 fourcc[2] = tolower(fourcc[2]); fourcc[3] = tolower(fourcc[3]);
1105
1106                 item = media->item;
1107                 item.i_es = 1;
1108                 item.es = &p_es;
1109                 es_format_Init( &es, VIDEO_ES, *((int *)fourcc) );
1110
1111                 media->vod_media =
1112                   vlm->vod->pf_media_new( vlm->vod, media->psz_name, &item );
1113                 return VLC_SUCCESS;
1114             }
1115
1116             media->vod_media =
1117                 vlm->vod->pf_media_new( vlm->vod, media->psz_name,
1118                                         &media->item );
1119         }
1120     }
1121
1122     return VLC_SUCCESS;
1123 }
1124
1125 int vlm_MediaControl( vlm_t *vlm, vlm_media_t *media, char *psz_id,
1126                       char *psz_command, char *psz_args )
1127 {
1128     vlm_media_instance_t *p_instance;
1129     int i;
1130
1131     p_instance = vlm_MediaInstanceSearch( vlm, media, psz_id );
1132
1133     if( !strcmp( psz_command, "play" ) && !p_instance )
1134     {
1135         if( !media->b_enabled || media->i_input == 0 ) return 0;
1136
1137         if( !p_instance )
1138         {
1139             p_instance = malloc( sizeof(vlm_media_instance_t) );
1140             if( !p_instance ) return VLC_EGENERIC;
1141             memset( p_instance, 0, sizeof(vlm_media_instance_t) );
1142             vlc_input_item_Init( VLC_OBJECT(vlm), &p_instance->item );
1143             p_instance->p_input = NULL;
1144
1145             if( media->psz_output != NULL || media->psz_vod_output != NULL )
1146             {
1147                 p_instance->item.ppsz_options = malloc( sizeof( char* ) );
1148                 asprintf( &p_instance->item.ppsz_options[0], "sout=%s%s%s",
1149                           media->psz_output ? media->psz_output : "",
1150                           (media->psz_output && media->psz_vod_output) ?
1151                           ":" : media->psz_vod_output ? "#" : "",
1152                           media->psz_vod_output ? media->psz_vod_output : "" );
1153                 p_instance->item.i_options = 1;
1154             }
1155
1156             for( i = 0; i < media->i_option; i++ )
1157             {
1158                 p_instance->item.i_options++;
1159                 p_instance->item.ppsz_options =
1160                     realloc( p_instance->item.ppsz_options,
1161                              p_instance->item.i_options * sizeof( char* ) );
1162                 p_instance->item.ppsz_options[p_instance->item.i_options - 1] =
1163                     strdup( media->option[i] );
1164             }
1165
1166             p_instance->psz_name = psz_id ? strdup( psz_id ) : NULL;
1167             TAB_APPEND( media->i_instance, media->instance, p_instance );
1168         }
1169
1170         if( psz_args && sscanf(psz_args, "%d", &i) == 1 && i < media->i_input )
1171         {
1172             p_instance->i_index = i;
1173         }
1174
1175         if( p_instance->item.psz_uri ) free( p_instance->item.psz_uri );
1176         p_instance->item.psz_uri =
1177             strdup( media->input[p_instance->i_index] );
1178
1179         if( p_instance->p_input )
1180         {
1181             input_StopThread( p_instance->p_input );
1182             input_DestroyThread( p_instance->p_input );
1183             vlc_object_detach( p_instance->p_input );
1184             vlc_object_destroy( p_instance->p_input );
1185         }
1186
1187         p_instance->p_input = input_CreateThread( vlm, &p_instance->item );
1188         if( !p_instance->p_input )
1189         {
1190             TAB_REMOVE( media->i_instance, media->instance, p_instance );
1191             vlc_input_item_Clean( &p_instance->item );
1192             if( p_instance->psz_name ) free( p_instance->psz_name );
1193         }
1194
1195         return VLC_SUCCESS;
1196     }
1197
1198     if( !p_instance ) return VLC_EGENERIC;
1199
1200     if( !strcmp( psz_command, "seek" ) )
1201     {
1202         vlc_value_t val;
1203         float f_percentage;
1204
1205         if( psz_args && sscanf( psz_args, "%f", &f_percentage ) == 1 )
1206         {
1207             val.f_float = f_percentage / 100.0 ;
1208             var_Set( p_instance->p_input, "position", val );
1209             return VLC_SUCCESS;
1210         }
1211     }
1212     else if( !strcmp( psz_command, "stop" ) )
1213     {
1214         TAB_REMOVE( media->i_instance, media->instance, p_instance );
1215
1216         if( p_instance->p_input )
1217         {
1218             input_StopThread( p_instance->p_input );
1219             input_DestroyThread( p_instance->p_input );
1220             vlc_object_detach( p_instance->p_input );
1221             vlc_object_destroy( p_instance->p_input );
1222         }
1223
1224         vlc_input_item_Clean( &p_instance->item );
1225         if( p_instance->psz_name ) free( p_instance->psz_name );
1226         free( p_instance );
1227
1228         return VLC_SUCCESS;
1229     }
1230     else if( !strcmp( psz_command, "pause" ) )
1231     {
1232         vlc_value_t val;
1233
1234         if( !p_instance->p_input ) return VLC_SUCCESS;
1235
1236         var_Get( p_instance->p_input, "state", &val );
1237
1238         if( val.i_int == PAUSE_S ) val.i_int = PLAYING_S;
1239         else val.i_int = PAUSE_S;
1240         var_Set( p_instance->p_input, "state", val );
1241
1242         return VLC_SUCCESS;
1243     }
1244
1245     return VLC_EGENERIC;
1246 }
1247
1248 /*****************************************************************************
1249  * Schedule handling
1250  *****************************************************************************/
1251 vlm_schedule_t *vlm_ScheduleNew( vlm_t *vlm, char *psz_name )
1252 {
1253     vlm_schedule_t *p_sched = malloc( sizeof( vlm_schedule_t ) );
1254
1255     if( !p_sched )
1256     {
1257         return NULL;
1258     }
1259
1260     if( !psz_name )
1261     {
1262         return NULL;
1263     }
1264
1265     p_sched->psz_name = strdup( psz_name );
1266     p_sched->b_enabled = VLC_FALSE;
1267     p_sched->i_command = 0;
1268     p_sched->command = NULL;
1269     p_sched->i_date = 0;
1270     p_sched->i_period = 0;
1271     p_sched->i_repeat = -1;
1272
1273     TAB_APPEND( vlm->i_schedule, vlm->schedule, p_sched );
1274
1275     return p_sched;
1276 }
1277
1278 /* for now, simple delete. After, del with options (last arg) */
1279 void vlm_ScheduleDelete( vlm_t *vlm, vlm_schedule_t *sched,
1280                          char *psz_name )
1281 {
1282     if( sched == NULL ) return;
1283
1284     TAB_REMOVE( vlm->i_schedule, vlm->schedule, sched );
1285
1286     if( vlm->i_schedule == 0 && vlm->schedule ) free( vlm->schedule );
1287     free( sched->psz_name );
1288     while( sched->i_command-- ) free( sched->command[sched->i_command] );
1289     free( sched );
1290 }
1291
1292 static vlm_schedule_t *vlm_ScheduleSearch( vlm_t *vlm, char *psz_name )
1293 {
1294     int i;
1295
1296     for( i = 0; i < vlm->i_schedule; i++ )
1297     {
1298         if( strcmp( psz_name, vlm->schedule[i]->psz_name ) == 0 )
1299         {
1300             return vlm->schedule[i];
1301         }
1302     }
1303
1304     return NULL;
1305 }
1306
1307 /* Ok, setup schedule command will be able to support only one (argument value) at a time  */
1308 int vlm_ScheduleSetup( vlm_schedule_t *schedule, char *psz_cmd,
1309                        char *psz_value )
1310 {
1311     if( !strcmp( psz_cmd, "enabled" ) )
1312     {
1313         schedule->b_enabled = VLC_TRUE;
1314     }
1315     else if( !strcmp( psz_cmd, "disabled" ) )
1316     {
1317         schedule->b_enabled = VLC_FALSE;
1318     }
1319 #if !defined( UNDER_CE )
1320     else if( !strcmp( psz_cmd, "date" ) )
1321     {
1322         struct tm time;
1323         char *p;
1324         time_t date;
1325
1326         time.tm_sec = 0;         /* seconds */
1327         time.tm_min = 0;         /* minutes */
1328         time.tm_hour = 0;        /* hours */
1329         time.tm_mday = 0;        /* day of the month */
1330         time.tm_mon = 0;         /* month */
1331         time.tm_year = 0;        /* year */
1332         time.tm_wday = 0;        /* day of the week */
1333         time.tm_yday = 0;        /* day in the year */
1334         time.tm_isdst = 0;       /* daylight saving time */
1335
1336         /* date should be year/month/day-hour:minutes:seconds */
1337         p = strchr( psz_value, '-' );
1338
1339         if( !strcmp( psz_value, "now" ) )
1340         {
1341             schedule->i_date = 0;
1342         }
1343         else if( p == NULL && sscanf( psz_value, "%d:%d:%d", &time.tm_hour, &time.tm_min, &time.tm_sec ) != 3 ) /* it must be a hour:minutes:seconds */
1344         {
1345             return 1;
1346         }
1347         else
1348         {
1349             int i,j,k;
1350
1351             switch( sscanf( p + 1, "%d:%d:%d", &i, &j, &k ) )
1352             {
1353                 case 1:
1354                     time.tm_sec = i;
1355                     break;
1356                 case 2:
1357                     time.tm_min = i;
1358                     time.tm_sec = j;
1359                     break;
1360                 case 3:
1361                     time.tm_hour = i;
1362                     time.tm_min = j;
1363                     time.tm_sec = k;
1364                     break;
1365                 default:
1366                     return 1;
1367             }
1368
1369             *p = '\0';
1370
1371             switch( sscanf( psz_value, "%d/%d/%d", &i, &j, &k ) )
1372             {
1373                 case 1:
1374                     time.tm_mday = i;
1375                     break;
1376                 case 2:
1377                     time.tm_mon = i - 1;
1378                     time.tm_mday = j;
1379                     break;
1380                 case 3:
1381                     time.tm_year = i - 1900;
1382                     time.tm_mon = j - 1;
1383                     time.tm_mday = k;
1384                     break;
1385                 default:
1386                     return 1;
1387             }
1388
1389             date = mktime( &time );
1390             schedule->i_date = ((mtime_t) date) * 1000000;
1391         }
1392     }
1393     else if( !strcmp( psz_cmd, "period" ) )
1394     {
1395         struct tm time;
1396         char *p;
1397         char *psz_time = NULL, *psz_date = NULL;
1398         time_t date;
1399         int i,j,k;
1400
1401         /* First, if date or period are modified, repeat should be equal to -1 */
1402         schedule->i_repeat = -1;
1403
1404         time.tm_sec = 0;         /* seconds */
1405         time.tm_min = 0;         /* minutes */
1406         time.tm_hour = 0;        /* hours */
1407         time.tm_mday = 0;        /* day of the month */
1408         time.tm_mon = 0;         /* month */
1409         time.tm_year = 0;        /* year */
1410         time.tm_wday = 0;        /* day of the week */
1411         time.tm_yday = 0;        /* day in the year */
1412         time.tm_isdst = 0;       /* daylight saving time */
1413
1414         /* date should be year/month/day-hour:minutes:seconds */
1415         p = strchr( psz_value, '-' );
1416         if( p )
1417         {
1418             psz_date = psz_value;
1419             psz_time = p + 1;
1420
1421             *p = '\0';
1422         }
1423         else
1424         {
1425             psz_time = psz_value;
1426         }
1427
1428
1429         switch( sscanf( psz_time, "%d:%d:%d", &i, &j, &k ) )
1430         {
1431             case 1:
1432                 time.tm_sec = i;
1433                 break;
1434             case 2:
1435                 time.tm_min = i;
1436                 time.tm_sec = j;
1437                 break;
1438             case 3:
1439                 time.tm_hour = i;
1440                 time.tm_min = j;
1441                 time.tm_sec = k;
1442                 break;
1443             default:
1444                 return 1;
1445         }
1446         if( psz_date )
1447         {
1448             switch( sscanf( psz_date, "%d/%d/%d", &i, &j, &k ) )
1449             {
1450                 case 1:
1451                     time.tm_mday = i;
1452                     break;
1453                 case 2:
1454                     time.tm_mon = i;
1455                     time.tm_mday = j;
1456                     break;
1457                 case 3:
1458                     time.tm_year = i;
1459                     time.tm_mon = j;
1460                     time.tm_mday = k;
1461                     break;
1462                 default:
1463                     return 1;
1464             }
1465         }
1466
1467         /* ok, that's stupid... who is going to schedule streams every 42 years ? */
1468         date = (((( time.tm_year * 12 + time.tm_mon ) * 30 + time.tm_mday ) * 24 + time.tm_hour ) * 60 + time.tm_min ) * 60 + time.tm_sec ;
1469         schedule->i_period = ((mtime_t) date) * 1000000;
1470     }
1471 #endif /* UNDER_CE */
1472     else if( !strcmp( psz_cmd, "repeat" ) )
1473     {
1474         int i;
1475
1476         if( sscanf( psz_value, "%d", &i ) == 1 )
1477         {
1478             schedule->i_repeat = i;
1479         }
1480         else
1481         {
1482             return 1;
1483         }
1484     }
1485     else if( !strcmp( psz_cmd, "append" ) )
1486     {
1487         char *command = strdup( psz_value );
1488
1489         TAB_APPEND( schedule->i_command, schedule->command, command );
1490     }
1491     else
1492     {
1493         return 1;
1494     }
1495     return 0;
1496 }
1497
1498 /*****************************************************************************
1499  * Message handling functions
1500  *****************************************************************************/
1501 static vlm_message_t *vlm_MessageNew( char *psz_name,
1502                                       const char *psz_format, ... )
1503 {
1504     vlm_message_t *p_message;
1505     va_list args;
1506
1507     if( !psz_name ) return 0;
1508
1509     p_message = malloc( sizeof(vlm_message_t) );
1510     if( !p_message)
1511     {
1512         return NULL;
1513     }
1514
1515     p_message->psz_value = 0;
1516
1517     if( psz_format )
1518     {
1519         va_start( args, psz_format );
1520         if( vasprintf( &p_message->psz_value, psz_format, args ) < 0 )
1521         {
1522             va_end( args );
1523             free( p_message );
1524             return 0;
1525         }
1526         va_end( args );
1527     }
1528
1529     p_message->psz_name = strdup( psz_name );
1530     p_message->i_child = 0;
1531     p_message->child = NULL;
1532
1533     return p_message;
1534 }
1535
1536 void vlm_MessageDelete( vlm_message_t *p_message )
1537 {
1538     if( p_message->psz_name ) free( p_message->psz_name );
1539     if( p_message->psz_value ) free( p_message->psz_value );
1540     while( p_message->i_child-- )
1541         vlm_MessageDelete( p_message->child[p_message->i_child] );
1542     if( p_message->child ) free( p_message->child );
1543     free( p_message );
1544 }
1545
1546 /* Add a child */
1547 static vlm_message_t *vlm_MessageAdd( vlm_message_t *p_message,
1548                                       vlm_message_t *p_child )
1549 {
1550     if( p_message == NULL ) return NULL;
1551
1552     if( p_child )
1553     {
1554         TAB_APPEND( p_message->i_child, p_message->child, p_child );
1555     }
1556
1557     return p_child;
1558 }
1559
1560 /*****************************************************************************
1561  * Misc utility functions
1562  *****************************************************************************/
1563 static vlm_message_t *vlm_Show( vlm_t *vlm, vlm_media_t *media,
1564                                 vlm_schedule_t *schedule, char *psz_filter )
1565 {
1566     if( media != NULL )
1567     {
1568         int i;
1569         vlm_message_t *msg;
1570         vlm_message_t *msg_media;
1571         vlm_message_t *msg_child;
1572
1573         msg = vlm_MessageNew( "show", NULL );
1574         msg_media = vlm_MessageAdd( msg, vlm_MessageNew( media->psz_name, 0 ));
1575
1576         vlm_MessageAdd( msg_media,
1577                         vlm_MessageNew( "type", media->i_type == VOD_TYPE ?
1578                                         "vod" : "broadcast" ) );
1579         vlm_MessageAdd( msg_media,
1580                         vlm_MessageNew( "enabled", media->b_enabled ?
1581                                         "yes" : "no" ) );
1582
1583         vlm_MessageAdd( msg_media,
1584                         vlm_MessageNew( "loop", media->b_loop ?
1585                                         "yes" : "no" ) );
1586
1587         if( media->i_type == VOD_TYPE && media->psz_mux )
1588             vlm_MessageAdd( msg_media,
1589                             vlm_MessageNew( "mux", media->psz_mux ) );
1590
1591         msg_child = vlm_MessageAdd( msg_media,
1592                                     vlm_MessageNew( "inputs", NULL ) );
1593
1594         for( i = 0; i < media->i_input; i++ )
1595         {
1596             vlm_MessageAdd( msg_child,
1597                             vlm_MessageNew( media->input[i], NULL ) );
1598         }
1599
1600         vlm_MessageAdd( msg_media,
1601                         vlm_MessageNew( "output", media->psz_output ?
1602                                         media->psz_output : "" ) );
1603
1604         msg_child = vlm_MessageAdd( msg_media, vlm_MessageNew( "options", 0 ));
1605
1606         for( i = 0; i < media->i_option; i++ )
1607         {
1608             vlm_MessageAdd( msg_child, vlm_MessageNew( media->option[i], 0 ) );
1609         }
1610
1611         msg_child = vlm_MessageAdd( msg_media,
1612                                     vlm_MessageNew( "instances", NULL ) );
1613
1614         for( i = 0; i < media->i_instance; i++ )
1615         {
1616             vlm_media_instance_t *p_instance = media->instance[i];
1617             vlc_value_t val;
1618
1619             if( !p_instance->p_input ) val.i_int = END_S;
1620             else var_Get( p_instance->p_input, "state", &val );
1621
1622             vlm_MessageAdd( msg_child,
1623                 vlm_MessageNew( p_instance->psz_name ?
1624                                 p_instance->psz_name : "default",
1625                                 val.i_int == PLAYING_S ? "playing" :
1626                                 val.i_int == PAUSE_S ? "paused" :
1627                                 "stopped" ) );
1628         }
1629
1630         return msg;
1631
1632     }
1633
1634     else if( schedule != NULL )
1635     {
1636         int i;
1637         vlm_message_t *msg;
1638         vlm_message_t *msg_schedule;
1639         vlm_message_t *msg_child;
1640         char buffer[100];
1641
1642         msg = vlm_MessageNew( "show", NULL );
1643         msg_schedule =
1644             vlm_MessageAdd( msg, vlm_MessageNew( schedule->psz_name, 0 ) );
1645
1646         vlm_MessageAdd( msg_schedule, vlm_MessageNew("type", "schedule") );
1647
1648         vlm_MessageAdd( msg_schedule,
1649                         vlm_MessageNew( "enabled", schedule->b_enabled ?
1650                                         "yes" : "no" ) );
1651
1652 #if !defined( UNDER_CE )
1653         if( schedule->i_date != 0 )
1654         {
1655             struct tm date;
1656             time_t i_time = (time_t)( schedule->i_date / 1000000 );
1657             char *psz_date;
1658
1659 #ifdef HAVE_LOCALTIME_R
1660             localtime_r( &i_time, &date);
1661 #else
1662             struct tm *p_date = localtime( &i_time );
1663             date = *p_date;
1664 #endif
1665
1666             asprintf( &psz_date, "%d/%d/%d-%d:%d:%d",
1667                       date.tm_year + 1900, date.tm_mon + 1, date.tm_mday,
1668                       date.tm_hour, date.tm_min, date.tm_sec );
1669
1670             vlm_MessageAdd( msg_schedule,
1671                             vlm_MessageNew( "date", psz_date ) );
1672             free( psz_date );
1673         }
1674         else
1675         {
1676             vlm_MessageAdd( msg_schedule, vlm_MessageNew("date", "now") );
1677         }
1678
1679         if( schedule->i_period != 0 )
1680         {
1681             time_t i_time = (time_t) ( schedule->i_period / 1000000 );
1682             struct tm date;
1683
1684             date.tm_sec = (int)( i_time % 60 );
1685             i_time = i_time / 60;
1686             date.tm_min = (int)( i_time % 60 );
1687             i_time = i_time / 60;
1688             date.tm_hour = (int)( i_time % 24 );
1689             i_time = i_time / 24;
1690             date.tm_mday = (int)( i_time % 30 );
1691             i_time = i_time / 30;
1692             /* okay, okay, months are not always 30 days long */
1693             date.tm_mon = (int)( i_time % 12 );
1694             i_time = i_time / 12;
1695             date.tm_year = (int)i_time;
1696
1697             sprintf( buffer, "%d/%d/%d-%d:%d:%d", date.tm_year, date.tm_mon,
1698                      date.tm_mday, date.tm_hour, date.tm_min, date.tm_sec);
1699
1700             vlm_MessageAdd( msg_schedule, vlm_MessageNew("period", buffer) );
1701         }
1702         else
1703         {
1704             vlm_MessageAdd( msg_schedule, vlm_MessageNew("period", "0") );
1705         }
1706 #endif /* UNDER_CE */
1707
1708         sprintf( buffer, "%d", schedule->i_repeat );
1709         vlm_MessageAdd( msg_schedule, vlm_MessageNew( "repeat", buffer ) );
1710
1711         msg_child =
1712             vlm_MessageAdd( msg_schedule, vlm_MessageNew("commands", 0) );
1713
1714         for( i = 0; i < schedule->i_command; i++ )
1715         {
1716            vlm_MessageAdd( msg_child,
1717                            vlm_MessageNew( schedule->command[i], NULL ) );
1718         }
1719
1720         return msg;
1721
1722     }
1723
1724     else if( psz_filter && !strcmp( psz_filter, "media" ) )
1725     {
1726         int i, j;
1727         vlm_message_t *msg;
1728         vlm_message_t *msg_child;
1729
1730         msg = vlm_MessageNew( "show", NULL );
1731         msg_child = vlm_MessageAdd( msg, vlm_MessageNew( "media", NULL ) );
1732
1733         for( i = 0; i < vlm->i_media; i++ )
1734         {
1735             vlm_media_t *m = vlm->media[i];
1736             vlm_message_t *msg_media, *msg_instance;
1737
1738             msg_media = vlm_MessageAdd( msg_child,
1739                                         vlm_MessageNew( m->psz_name, 0 ) );
1740
1741             vlm_MessageAdd( msg_media,
1742                             vlm_MessageNew( "type", m->i_type == VOD_TYPE ?
1743                                             "vod" : "broadcast" ) );
1744
1745             vlm_MessageAdd( msg_media,
1746                             vlm_MessageNew( "enabled", m->b_enabled ?
1747                                             "yes" : "no" ) );
1748
1749             if( m->i_type == VOD_TYPE && m->psz_mux )
1750                 vlm_MessageAdd( msg_media,
1751                                 vlm_MessageNew( "mux", m->psz_mux ) );
1752
1753             msg_instance = vlm_MessageAdd( msg_media,
1754                                            vlm_MessageNew( "instances", 0 ) );
1755
1756             for( j = 0; j < m->i_instance; j++ )
1757             {
1758                 vlm_media_instance_t *p_instance = m->instance[j];
1759                 vlc_value_t val;
1760
1761                 if( !p_instance->p_input ) val.i_int = END_S;
1762                 else var_Get( p_instance->p_input, "state", &val );
1763
1764                 vlm_MessageAdd( msg_instance,
1765                     vlm_MessageNew( p_instance->psz_name ?
1766                                     p_instance->psz_name : "default",
1767                                     val.i_int == PLAYING_S ? "playing" :
1768                                     val.i_int == PAUSE_S ? "paused" :
1769                                     "stopped" ) );
1770             }
1771         }
1772
1773         return msg;
1774     }
1775
1776     else if( psz_filter && !strcmp( psz_filter, "schedule" ) )
1777     {
1778         int i;
1779         vlm_message_t *msg;
1780         vlm_message_t *msg_child;
1781
1782         msg = vlm_MessageNew( "show", NULL );
1783         msg_child = vlm_MessageAdd( msg, vlm_MessageNew( "schedule", NULL ) );
1784
1785         for( i = 0; i < vlm->i_schedule; i++ )
1786         {
1787             vlm_schedule_t *s = vlm->schedule[i];
1788             vlm_message_t *msg_schedule;
1789             mtime_t i_time, i_next_date;
1790
1791             msg_schedule = vlm_MessageAdd( msg_child,
1792                                            vlm_MessageNew( s->psz_name, 0 ) );
1793             vlm_MessageAdd( msg_schedule,
1794                             vlm_MessageNew( "enabled", s->b_enabled ?
1795                                             "yes" : "no" ) );
1796
1797             if( !s->b_enabled ) return msg;
1798
1799
1800             vlm_MessageAdd( msg_schedule,
1801                             vlm_MessageNew( "enabled", "yes" ) );
1802
1803             /* calculate next date */
1804             i_time = mdate();
1805             i_next_date = s->i_date;
1806
1807             if( s->i_period != 0 )
1808             {
1809                 int j = 0;
1810                 while( s->i_date + j * s->i_period <= i_time &&
1811                        s->i_repeat > j )
1812                 {
1813                     j++;
1814                 }
1815
1816                 i_next_date = s->i_date + j * s->i_period;
1817             }
1818
1819             if( i_next_date > i_time )
1820             {
1821                 time_t i_date = (time_t) (i_next_date / 1000000) ;
1822
1823 #if !defined( UNDER_CE )
1824 #ifdef HAVE_CTIME_R
1825                 char psz_date[500];
1826                 ctime_r( &i_date, psz_date );
1827 #else
1828                 char *psz_date = ctime( &i_date );
1829 #endif
1830
1831                 vlm_MessageAdd( msg_schedule,
1832                                 vlm_MessageNew( "next launch", psz_date ) );
1833 #endif
1834             }
1835         }
1836
1837         return msg;
1838     }
1839
1840     else if( psz_filter == NULL && media == NULL && schedule == NULL )
1841     {
1842         vlm_message_t *show1 = vlm_Show( vlm, NULL, NULL, "media" );
1843         vlm_message_t *show2 = vlm_Show( vlm, NULL, NULL, "schedule" );
1844
1845         vlm_MessageAdd( show1, show2->child[0] );
1846
1847         /* We must destroy the parent node "show" of show2
1848          * and not the children */
1849         free( show2->psz_name );
1850         free( show2 );
1851
1852         return show1;
1853     }
1854
1855     else
1856     {
1857         return vlm_MessageNew( "show", NULL );
1858     }
1859 }
1860
1861 static vlm_message_t *vlm_Help( vlm_t *vlm, char *psz_filter )
1862 {
1863     vlm_message_t *message, *message_child;
1864
1865 #define MessageAdd( a ) \
1866         vlm_MessageAdd( message, vlm_MessageNew( a, NULL ) );
1867 #define MessageAddChild( a ) \
1868         vlm_MessageAdd( message_child, vlm_MessageNew( a, NULL ) );
1869
1870     if( psz_filter == NULL )
1871     {
1872         message = vlm_MessageNew( "help", NULL );
1873
1874         message_child = MessageAdd( "Commands Syntax:" );
1875         MessageAddChild( "new (name) vod|broadcast|schedule [properties]" );
1876         MessageAddChild( "setup (name) (properties)" );
1877         MessageAddChild( "show [(name)|media|schedule]" );
1878         MessageAddChild( "del (name)|all|media|schedule" );
1879         MessageAddChild( "control (name) [instance_name] (command)" );
1880         MessageAddChild( "save (config_file)" );
1881         MessageAddChild( "load (config_file)" );
1882
1883         message_child = MessageAdd( "Media Proprieties Syntax:" );
1884         MessageAddChild( "input (input_name)" );
1885         MessageAddChild( "inputdel (input_name)|all" );
1886         MessageAddChild( "output (output_name)" );
1887         MessageAddChild( "enabled|disabled" );
1888         MessageAddChild( "loop|unloop (broadcast only)" );
1889         MessageAddChild( "mux (mux_name)" );
1890
1891         message_child = MessageAdd( "Schedule Proprieties Syntax:" );
1892         MessageAddChild( "enabled|disabled" );
1893         MessageAddChild( "append (command_until_rest_of_the_line)" );
1894         MessageAddChild( "date (year)/(month)/(day)-(hour):(minutes):"
1895                          "(seconds)|now" );
1896         MessageAddChild( "period (years_aka_12_months)/(months_aka_30_days)/"
1897                          "(days)-(hours):(minutes):(seconds)" );
1898         MessageAddChild( "repeat (number_of_repetitions)" );
1899
1900         message_child = MessageAdd( "Control Commands Syntax:" );
1901         MessageAddChild( "play" );
1902         MessageAddChild( "pause" );
1903         MessageAddChild( "stop" );
1904         MessageAddChild( "seek (percentage)" );
1905
1906         return message;
1907     }
1908
1909     return vlm_MessageNew( "help", NULL );
1910 }
1911
1912 /*****************************************************************************
1913  * Config handling functions
1914  *****************************************************************************/
1915 static int Load( vlm_t *vlm, char *file )
1916 {
1917     char *pf = file;
1918
1919     while( *pf != '\0' )
1920     {
1921         vlm_message_t *message = NULL;
1922         int i_temp = 0;
1923         int i_next;
1924
1925         while( pf[i_temp] != '\n' && pf[i_temp] != '\0' && pf[i_temp] != '\r' )
1926         {
1927             i_temp++;
1928         }
1929
1930         if( pf[i_temp] == '\r' || pf[i_temp] == '\n' )
1931         {
1932             pf[i_temp] = '\0';
1933             i_next = i_temp + 1;
1934         }
1935         else
1936         {
1937             i_next = i_temp;
1938         }
1939
1940         if( ExecuteCommand( vlm, pf, &message ) )
1941         {
1942             free( message );
1943             return 1;
1944         }
1945         free( message );
1946
1947         pf += i_next;
1948     }
1949
1950     return 0;
1951 }
1952
1953 static char *Save( vlm_t *vlm )
1954 {
1955     char *save = NULL;
1956     char *p;
1957     int i,j;
1958     int i_length = 0;
1959
1960     for( i = 0; i < vlm->i_media; i++ )
1961     {
1962         vlm_media_t *media = vlm->media[i];
1963
1964         if( media->i_type == VOD_TYPE )
1965         {
1966             i_length += strlen( "new  vod " ) + strlen(media->psz_name);
1967         }
1968         else
1969         {
1970             i_length += strlen( "new  broadcast " ) + strlen(media->psz_name);
1971         }
1972
1973         if( media->b_enabled == VLC_TRUE )
1974         {
1975             i_length += strlen( "enabled" );
1976         }
1977         else
1978         {
1979             i_length += strlen( "disabled" );
1980         }
1981
1982         if( media->b_loop == VLC_TRUE )
1983         {
1984             i_length += strlen( " loop\n" );
1985         }
1986         else
1987         {
1988             i_length += strlen( "\n" );
1989         }
1990
1991         for( j = 0; j < media->i_input; j++ )
1992         {
1993             i_length += strlen( "setup  input \"\"\n" ) +
1994                 strlen( media->psz_name ) + strlen( media->input[j] );
1995         }
1996
1997         if( media->psz_output != NULL )
1998         {
1999             i_length += strlen(media->psz_name) + strlen(media->psz_output) +
2000                 strlen( "setup  output \n" );
2001         }
2002
2003         for( j=0 ; j < media->i_option ; j++ )
2004         {
2005             i_length += strlen(media->psz_name) + strlen(media->option[j]) +
2006                 strlen("setup  option \n");
2007         }
2008     }
2009
2010     for( i = 0; i < vlm->i_schedule; i++ )
2011     {
2012         vlm_schedule_t *schedule = vlm->schedule[i];
2013
2014         i_length += strlen( "new  schedule " ) + strlen( schedule->psz_name );
2015
2016         if( schedule->b_enabled == VLC_TRUE )
2017         {
2018             i_length += strlen( "date //-:: enabled\n" ) + 14;
2019         }
2020         else
2021         {
2022             i_length += strlen( "date //-:: disabled\n" ) + 14;
2023         }
2024
2025
2026         if( schedule->i_period != 0 )
2027         {
2028             i_length += strlen( "setup  " ) + strlen( schedule->psz_name ) +
2029                 strlen( "period //-::\n" ) + 14;
2030         }
2031
2032         if( schedule->i_repeat >= 0 )
2033         {
2034             char buffer[12];
2035
2036             sprintf( buffer, "%d", schedule->i_repeat );
2037             i_length += strlen( "setup  repeat \n" ) +
2038                 strlen( schedule->psz_name ) + strlen( buffer );
2039         }
2040         else
2041         {
2042             i_length++;
2043         }
2044
2045         for( j = 0; j < schedule->i_command; j++ )
2046         {
2047             i_length += strlen( "setup  append \n" ) +
2048                 strlen( schedule->psz_name ) + strlen( schedule->command[j] );
2049         }
2050
2051     }
2052
2053     /* Don't forget the '\0' */
2054     i_length++;
2055     /* now we have the length of save */
2056
2057     p = save = malloc( i_length );
2058     *save = '\0';
2059
2060     /* finally we can write in it */
2061     for( i = 0; i < vlm->i_media; i++ )
2062     {
2063         vlm_media_t *media = vlm->media[i];
2064
2065         if( media->i_type == VOD_TYPE )
2066         {
2067             p += sprintf( p, "new %s vod ", media->psz_name);
2068         }
2069         else
2070         {
2071             p += sprintf( p, "new %s broadcast ", media->psz_name);
2072         }
2073
2074         if( media->b_enabled == VLC_TRUE )
2075         {
2076             p += sprintf( p, "enabled" );
2077         }
2078         else
2079         {
2080             p += sprintf( p, "disabled" );
2081         }
2082
2083         if( media->b_loop == VLC_TRUE )
2084         {
2085             p += sprintf( p, " loop\n" );
2086         }
2087         else
2088         {
2089             p += sprintf( p, "\n" );
2090         }
2091
2092         for( j = 0; j < media->i_input; j++ )
2093         {
2094             p += sprintf( p, "setup %s input \"%s\"\n", media->psz_name,
2095                           media->input[j] );
2096         }
2097
2098         if( media->psz_output != NULL )
2099         {
2100             p += sprintf( p, "setup %s output %s\n", media->psz_name,
2101                           media->psz_output );
2102         }
2103
2104         for( j = 0; j < media->i_option; j++ )
2105         {
2106             p += sprintf( p, "setup %s option %s\n", media->psz_name,
2107                           media->option[j] );
2108         }
2109     }
2110
2111     /* and now, the schedule scripts */
2112 #if !defined( UNDER_CE )
2113     for( i = 0; i < vlm->i_schedule; i++ )
2114     {
2115         vlm_schedule_t *schedule = vlm->schedule[i];
2116         struct tm date;
2117         time_t i_time = (time_t) ( schedule->i_date / 1000000 );
2118
2119 #ifdef HAVE_LOCALTIME_R
2120         localtime_r( &i_time, &date);
2121 #else
2122         struct tm *p_date = localtime( &i_time );
2123         date = *p_date;
2124 #endif
2125
2126         p += sprintf( p, "new %s schedule ", schedule->psz_name);
2127
2128         if( schedule->b_enabled == VLC_TRUE )
2129         {
2130             p += sprintf( p, "date %d/%d/%d-%d:%d:%d enabled\n",
2131                           date.tm_year + 1900, date.tm_mon + 1, date.tm_mday,
2132                           date.tm_hour, date.tm_min, date.tm_sec );
2133         }
2134         else
2135         {
2136             p += sprintf( p, "date %d/%d/%d-%d:%d:%d disabled\n",
2137                           date.tm_year + 1900, date.tm_mon + 1, date.tm_mday,
2138                           date.tm_hour, date.tm_min, date.tm_sec);
2139         }
2140
2141         if( schedule->i_period != 0 )
2142         {
2143             p += sprintf( p, "setup %s ", schedule->psz_name );
2144
2145             i_time = (time_t) ( schedule->i_period / 1000000 );
2146
2147             date.tm_sec = (int)( i_time % 60 );
2148             i_time = i_time / 60;
2149             date.tm_min = (int)( i_time % 60 );
2150             i_time = i_time / 60;
2151             date.tm_hour = (int)( i_time % 24 );
2152             i_time = i_time / 24;
2153             date.tm_mday = (int)( i_time % 30 );
2154             i_time = i_time / 30;
2155             /* okay, okay, months are not always 30 days long */
2156             date.tm_mon = (int)( i_time % 12 );
2157             i_time = i_time / 12;
2158             date.tm_year = (int)i_time;
2159
2160             p += sprintf( p, "period %d/%d/%d-%d:%d:%d\n",
2161                           date.tm_year, date.tm_mon, date.tm_mday,
2162                           date.tm_hour, date.tm_min, date.tm_sec);
2163         }
2164
2165         if( schedule->i_repeat >= 0 )
2166         {
2167             p += sprintf( p, "setup %s repeat %d\n",
2168                           schedule->psz_name, schedule->i_repeat );
2169         }
2170         else
2171         {
2172             p += sprintf( p, "\n" );
2173         }
2174
2175         for( j = 0; j < schedule->i_command; j++ )
2176         {
2177             p += sprintf( p, "setup %s append %s\n",
2178                           schedule->psz_name, schedule->command[j] );
2179         }
2180
2181     }
2182 #endif /* UNDER_CE */
2183
2184     return save;
2185 }
2186
2187 /*****************************************************************************
2188  * Manage:
2189  *****************************************************************************/
2190 int vlm_MediaVodControl( void *p_private, vod_media_t *p_vod_media,
2191                          char *psz_id, int i_query, va_list args )
2192 {
2193     vlm_t *vlm = (vlm_t *)p_private;
2194     int i, i_ret = VLC_EGENERIC;
2195
2196     if( !p_private || !p_vod_media ) return VLC_EGENERIC;
2197
2198     vlc_mutex_lock( &vlm->lock );
2199
2200     /* Find media */
2201     for( i = 0; i < vlm->i_media; i++ )
2202     {
2203         if( p_vod_media == vlm->media[i]->vod_media ) break;
2204     }
2205
2206     if( i == vlm->i_media )
2207     {
2208         vlc_mutex_unlock( &vlm->lock );
2209         return VLC_EGENERIC;
2210     }
2211
2212     switch( i_query )
2213     {
2214     case VOD_MEDIA_PLAY:
2215         vlm->media[i]->psz_vod_output = (char *)va_arg( args, char * );
2216         i_ret = vlm_MediaControl( vlm, vlm->media[i], psz_id, "play", 0 );
2217         vlm->media[i]->psz_vod_output = 0;
2218         break;
2219
2220     case VOD_MEDIA_PAUSE:
2221         i_ret = vlm_MediaControl( vlm, vlm->media[i], psz_id, "pause", 0 );
2222         break;
2223
2224     case VOD_MEDIA_STOP:
2225         i_ret = vlm_MediaControl( vlm, vlm->media[i], psz_id, "stop", 0 );
2226         break;
2227
2228     case VOD_MEDIA_SEEK:
2229     {
2230         double f_pos = (double)va_arg( args, double );
2231         char psz_pos[50];
2232
2233         sprintf( psz_pos, "%f", f_pos );
2234         i_ret = vlm_MediaControl( vlm, vlm->media[i], psz_id, "seek", psz_pos);
2235         break;
2236     }
2237
2238     default:
2239         break;
2240     }
2241
2242     vlc_mutex_unlock( &vlm->lock );
2243
2244     return i_ret;
2245 }
2246
2247 /*****************************************************************************
2248  * Manage:
2249  *****************************************************************************/
2250 static int Manage( vlc_object_t* p_object )
2251 {
2252     vlm_t *vlm = (vlm_t*)p_object;
2253     int i, j;
2254     mtime_t i_lastcheck;
2255     mtime_t i_time;
2256
2257     i_lastcheck = mdate();
2258
2259     msleep( 100000 );
2260
2261     while( !vlm->b_die )
2262     {
2263         vlc_mutex_lock( &vlm->lock );
2264
2265         /* destroy the inputs that wants to die, and launch the next input */
2266         for( i = 0; i < vlm->i_media; i++ )
2267         {
2268             vlm_media_t *p_media = vlm->media[i];
2269
2270             for( j = 0; j < p_media->i_instance; j++ )
2271             {
2272                 vlm_media_instance_t *p_instance = p_media->instance[j];
2273
2274                 if( !p_instance->p_input ||
2275                     ( !p_instance->p_input->b_eof &&
2276                       !p_instance->p_input->b_error ) ) continue;
2277
2278                 input_StopThread( p_instance->p_input );
2279                 input_DestroyThread( p_instance->p_input );
2280                 vlc_object_detach( p_instance->p_input );
2281                 vlc_object_destroy( p_instance->p_input );
2282
2283                 p_instance->i_index++;
2284                 if( p_instance->i_index == p_media->i_input &&
2285                     p_media->b_loop ) p_instance->i_index = 0;
2286
2287                 if( p_instance->i_index < p_media->i_input )
2288                 {
2289                     /* FIXME, find a way to select the right instance */
2290                     char buffer[12];
2291                     sprintf( buffer, "%d", p_instance->i_index );
2292                     vlm_MediaControl( vlm, p_media, p_instance->psz_name,
2293                                       "play", buffer );
2294                 }
2295                 else
2296                 {
2297                     if( vlm_MediaControl( vlm, p_media, p_instance->psz_name,
2298                                           "stop", 0 ) == VLC_SUCCESS ) i--;
2299                 }
2300             }
2301         }
2302
2303         /* scheduling */
2304         i_time = mdate();
2305
2306         for( i = 0; i < vlm->i_schedule; i++ )
2307         {
2308             mtime_t i_real_date = vlm->schedule[i]->i_date;
2309
2310             if( vlm->schedule[i]->b_enabled == VLC_TRUE )
2311             {
2312                 if( vlm->schedule[i]->i_date == 0 ) // now !
2313                 {
2314                     vlm->schedule[i]->i_date = (i_time / 1000000) * 1000000 ;
2315                     i_real_date = i_time;
2316                 }
2317                 else if( vlm->schedule[i]->i_period != 0 )
2318                 {
2319                     int j = 0;
2320                     while( vlm->schedule[i]->i_date + j *
2321                            vlm->schedule[i]->i_period <= i_lastcheck &&
2322                            ( vlm->schedule[i]->i_repeat > j ||
2323                              vlm->schedule[i]->i_repeat == -1 ) )
2324                     {
2325                         j++;
2326                     }
2327
2328                     i_real_date = vlm->schedule[i]->i_date + j *
2329                         vlm->schedule[i]->i_period;
2330                 }
2331
2332                 if( i_real_date <= i_time && i_real_date > i_lastcheck )
2333                 {
2334                     for( j = 0; j < vlm->schedule[i]->i_command; j++ )
2335                     {
2336                         vlm_message_t *message = NULL;
2337
2338                         ExecuteCommand( vlm, vlm->schedule[i]->command[j],
2339                                         &message );
2340
2341                         /* for now, drop the message */
2342                         free( message );
2343                     }
2344                 }
2345             }
2346         }
2347
2348         i_lastcheck = i_time;
2349
2350         vlc_mutex_unlock( &vlm->lock );
2351
2352         msleep( 100000 );
2353     }
2354
2355     return VLC_SUCCESS;
2356 }
2357
2358 #else /* ENABLE_VLM */
2359
2360 /* We just define an empty wrapper */
2361 vlm_t *__vlm_New( vlc_object_t *a )
2362 {
2363     msg_Err( a, "VideoLAN manager support is disabled" );
2364     return 0;
2365 }
2366 void vlm_Delete( vlm_t *a ){}
2367 int vlm_ExecuteCommand( vlm_t *a, char *b, vlm_message_t **c ){ return -1; }
2368 void vlm_MessageDelete( vlm_message_t *a ){}
2369 vlm_media_t *vlm_MediaNew( vlm_t *a, char *b, int c ){ return NULL; }
2370 void vlm_MediaDelete( vlm_t *a, vlm_media_t *b, char *c ){}
2371 int vlm_MediaSetup( vlm_t *a, vlm_media_t *b, char *c, char *d ){ return -1; }
2372 int vlm_MediaControl( vlm_t *a, vlm_media_t *b, char *c, char *d, char *e )
2373     { return -1; }
2374 vlm_schedule_t * vlm_ScheduleNew( vlm_t *a, char *b ){ return NULL; }
2375 void  vlm_ScheduleDelete( vlm_t *a, vlm_schedule_t *b, char *c ){}
2376 int vlm_ScheduleSetup( vlm_schedule_t *a, char *b, char *c ){ return -1; }
2377 int vlm_MediaVodControl( void *a, vod_media_t *b, char *c, int d, va_list e )
2378     { return -1; }
2379 int vlm_Save( vlm_t *a, char *b ){ return -1; }
2380 int vlm_Load( vlm_t *a, char *b ){ return -1; }
2381
2382 #endif /* ENABLE_VLM */