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