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