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