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