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