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