vlm.c 71.6 KB
Newer Older
1
/*****************************************************************************
2
 * vlm.c: VLM interface plugin
3
 *****************************************************************************
dionoea's avatar
dionoea committed
4
 * Copyright (C) 2000-2005 the VideoLAN team
5
 * $Id$
6
7
8
 *
 * Authors: Simon Latapie <garf@videolan.org>
 *          Laurent Aimar <fenrir@videolan.org>
gbazin's avatar
gbazin committed
9
 *          Gildas Bazin <gbazin@videolan.org>
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
30
#include <ctype.h>                                              /* tolower() */
31
32

#include <vlc/vlc.h>
33
34
35

#ifdef ENABLE_VLM

36
37
38
#include <vlc/intf.h>
#include <vlc/input.h>

39
40
#ifdef HAVE_TIME_H
#   include <time.h>                                              /* ctime() */
41
#   include <sys/timeb.h>                                         /* ftime() */
42
43
#endif

44
#include "vlc_vlm.h"
45
#include "vlc_vod.h"
46

zorglub's avatar
zorglub committed
47
48
49
#define FREE( p ) \
        if( p ) { free( p ); (p) = NULL; }

50
51
52
/*****************************************************************************
 * Local prototypes.
 *****************************************************************************/
53
54
55
static vlm_message_t *vlm_Show( vlm_t *, vlm_media_t *, vlm_schedule_t *, char * );
static vlm_message_t *vlm_Help( vlm_t *, char * );

56
57
static vlm_media_t *vlm_MediaSearch ( vlm_t *, const char * );
static vlm_media_instance_t *vlm_MediaInstanceSearch( vlm_t *, vlm_media_t *, const char * );
58

gbazin's avatar
gbazin committed
59
static vlm_message_t *vlm_MessageNew( char *, const char *, ... );
60
static vlm_message_t *vlm_MessageAdd( vlm_message_t *, vlm_message_t * );
61

62
static vlm_schedule_t *vlm_ScheduleSearch( vlm_t *, const char * );
63

64
65
static char *Save( vlm_t * );
static int Load( vlm_t *, char * );
66
static int ExecuteCommand( vlm_t *, const char *, vlm_message_t ** );
67
static int Manage( vlc_object_t * );
68

69
70
71
72
73
74
/*****************************************************************************
 * vlm_New:
 *****************************************************************************/
vlm_t *__vlm_New ( vlc_object_t *p_this )
{
    vlc_value_t lockval;
zorglub's avatar
zorglub committed
75
    vlm_t *p_vlm = NULL;
76
    char *psz_vlmconf;
77
78
79
80
81
82

    /* to be sure to avoid multiple creation */
    var_Create( p_this->p_libvlc, "vlm_mutex", VLC_VAR_MUTEX );
    var_Get( p_this->p_libvlc, "vlm_mutex", &lockval );
    vlc_mutex_lock( lockval.p_address );

zorglub's avatar
zorglub committed
83
    if( !(p_vlm = vlc_object_find( p_this, VLC_OBJECT_VLM, FIND_ANYWHERE )) )
84
85
    {
        msg_Info( p_this, "creating vlm" );
zorglub's avatar
zorglub committed
86
        if( ( p_vlm = vlc_object_create( p_this, VLC_OBJECT_VLM ) ) == NULL )
87
88
89
90
91
        {
            vlc_mutex_unlock( lockval.p_address );
            return NULL;
        }

zorglub's avatar
zorglub committed
92
93
94
95
96
97
        vlc_mutex_init( p_this->p_vlc, &p_vlm->lock );
        p_vlm->i_media      = 0;
        p_vlm->media        = NULL;
        p_vlm->i_vod        = 0;
        p_vlm->i_schedule   = 0;
        p_vlm->schedule     = NULL;
98

zorglub's avatar
zorglub committed
99
100
        vlc_object_yield( p_vlm );
        vlc_object_attach( p_vlm, p_this->p_vlc );
101
102
103
    }
    vlc_mutex_unlock( lockval.p_address );

zorglub's avatar
zorglub committed
104
    if( vlc_thread_create( p_vlm, "vlm thread",
105
106
                           Manage, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
    {
zorglub's avatar
zorglub committed
107
108
        vlc_mutex_destroy( &p_vlm->lock );
        vlc_object_destroy( p_vlm );
109
110
        return NULL;
    }
111

112
113
    /* Try loading the vlm conf file given by --vlm-conf */
    psz_vlmconf = config_GetPsz( p_vlm, "vlm-conf" );
dionoea's avatar
dionoea committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

    if( psz_vlmconf && *psz_vlmconf )
    {
        vlm_message_t *p_message = NULL;
        char *psz_buffer = NULL;

        msg_Dbg( p_this, "loading vlm conf ..." );
        asprintf(&psz_buffer, "load %s", psz_vlmconf );
        if( psz_buffer )
        {
            msg_Dbg( p_this, psz_buffer);
            if( vlm_ExecuteCommand( p_vlm, psz_buffer, &p_message ) ){
                msg_Warn( p_this, "error while loading the vlm conf file" );
            }
            free(p_message);
            free(psz_buffer);
        }
   }
   free(psz_vlmconf);

   return p_vlm;
135
136
137
138
139
}

/*****************************************************************************
 * vlm_Delete:
 *****************************************************************************/
zorglub's avatar
zorglub committed
140
void vlm_Delete( vlm_t *p_vlm )
141
142
143
{
    vlc_value_t lockval;

zorglub's avatar
zorglub committed
144
    var_Get( p_vlm->p_libvlc, "vlm_mutex", &lockval );
145
146
    vlc_mutex_lock( lockval.p_address );

zorglub's avatar
zorglub committed
147
    vlc_object_release( p_vlm );
148

zorglub's avatar
zorglub committed
149
    if( p_vlm->i_refcount > 0 )
150
151
152
153
154
    {
        vlc_mutex_unlock( lockval.p_address );
        return;
    }

zorglub's avatar
zorglub committed
155
156
    p_vlm->b_die = VLC_TRUE;
    vlc_thread_join( p_vlm );
157

zorglub's avatar
zorglub committed
158
    vlc_mutex_destroy( &p_vlm->lock );
159

zorglub's avatar
zorglub committed
160
161
    while( p_vlm->i_media ) vlm_MediaDelete( p_vlm, p_vlm->media[0], NULL );
    FREE( p_vlm->media );
162

zorglub's avatar
zorglub committed
163
164
165
    while( p_vlm->i_schedule ) vlm_ScheduleDelete( p_vlm,
                                                   p_vlm->schedule[0], NULL );
    FREE( p_vlm->schedule );
166

zorglub's avatar
zorglub committed
167
168
    vlc_object_detach( p_vlm );
    vlc_object_destroy( p_vlm );
169
170
171
172
173
174
    vlc_mutex_unlock( lockval.p_address );
}

/*****************************************************************************
 * vlm_ExecuteCommand:
 *****************************************************************************/
175
int vlm_ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
zorglub's avatar
zorglub committed
176
                        vlm_message_t **pp_message)
177
{
zorglub's avatar
zorglub committed
178
    int i_result;
179

zorglub's avatar
zorglub committed
180
181
182
    vlc_mutex_lock( &p_vlm->lock );
    i_result = ExecuteCommand( p_vlm, psz_command, pp_message );
    vlc_mutex_unlock( &p_vlm->lock );
183

zorglub's avatar
zorglub committed
184
    return i_result;
185
186
}

187
188
189
/*****************************************************************************
 * vlm_Save:
 *****************************************************************************/
190
int vlm_Save( vlm_t *p_vlm, const char *psz_file )
191
192
193
194
195
196
{
    FILE *file;
    char *psz_save;

    if( !p_vlm || !psz_file ) return 1;

197
    file = fopen( psz_file, "wt" );
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
    if( file == NULL ) return 1;

    psz_save = Save( p_vlm );
    if( psz_save == NULL )
    {
        fclose( file );
        return 1;
    }
    fwrite( psz_save, strlen( psz_save ), 1, file );
    fclose( file );
    free( psz_save );

    return 0;
}

/*****************************************************************************
 * vlm_Load:
 *****************************************************************************/
216
int vlm_Load( vlm_t *p_vlm, const char *psz_file )
217
218
219
220
221
222
223
224
225
226
{
    FILE *file;
    int64_t i_size;
    char *psz_buffer;

    if( !p_vlm || !psz_file ) return 1;

    file = fopen( psz_file, "r" );
    if( file == NULL ) return 1;

227
228
229
230
231
    if( fseek( file, 0, SEEK_END) != 0 )
    {
        fclose( file );
        return 2;
    }
232
233

    i_size = ftell( file );
234
    fseek( file, 0, SEEK_SET );
235
236
237
238
239
240
    psz_buffer = malloc( i_size + 1 );
    if( !psz_buffer )
    {
        fclose( file );
        return 2;
    }
241
    fread( psz_buffer, 1, i_size, file );
242
243
244
    psz_buffer[ i_size ] = '\0';
    if( Load( p_vlm, psz_buffer ) )
    {
245
        fclose( file );
246
247
248
249
        free( psz_buffer );
        return 3;
    }

250
    free( psz_buffer );
251
252
253
254
255
    fclose( file );

    return 0;
}

256
/*****************************************************************************
gbazin's avatar
gbazin committed
257
 * FindEndCommand
258
 *****************************************************************************/
259
static const char *FindEndCommand( const char *psz_sent )
260
{
gbazin's avatar
gbazin committed
261
    switch( *psz_sent )
262
    {
gbazin's avatar
gbazin committed
263
264
    case '\"':
        psz_sent++;
265

gbazin's avatar
gbazin committed
266
267
268
        while( ( *psz_sent != '\"' ) && ( *psz_sent != '\0' ) )
        {
            if( *psz_sent == '\'' )
269
            {
gbazin's avatar
gbazin committed
270
271
                psz_sent = FindEndCommand( psz_sent );
                if( psz_sent == NULL ) return NULL;
272
            }
gbazin's avatar
gbazin committed
273
            else psz_sent++;
274
        }
gbazin's avatar
gbazin committed
275
276

        if( *psz_sent == '\"' )
277
        {
gbazin's avatar
gbazin committed
278
279
280
            psz_sent++;
            return psz_sent;
        }
281

gbazin's avatar
gbazin committed
282
283
        /* *psz_sent == '\0' -> number of " is incorrect */
        else return NULL;
284

gbazin's avatar
gbazin committed
285
        break;
286

gbazin's avatar
gbazin committed
287
288
289
290
    case '\'':
        psz_sent++;

        while( ( *psz_sent != '\'' ) && ( *psz_sent != '\0' ) )
291
        {
gbazin's avatar
gbazin committed
292
            if( *psz_sent == '\"' )
293
            {
gbazin's avatar
gbazin committed
294
295
                psz_sent = FindEndCommand( psz_sent );
                if( psz_sent == NULL ) return NULL;
296
            }
gbazin's avatar
gbazin committed
297
            else psz_sent++;
298
299
        }

gbazin's avatar
gbazin committed
300
        if( *psz_sent == '\'' )
301
        {
gbazin's avatar
gbazin committed
302
303
304
            psz_sent++;
            return psz_sent;
        }
305

gbazin's avatar
gbazin committed
306
307
308
309
310
311
312
313
314
        /* *psz_sent == '\0' -> number of " is incorrect */
        else return NULL;

        break;

    default: /* now we can look for spaces */
        while( ( *psz_sent != ' ' ) && ( *psz_sent != '\0' ) )
        {
            if( ( *psz_sent == '\'' ) || ( *psz_sent == '\"' ) )
315
            {
gbazin's avatar
gbazin committed
316
                psz_sent = FindEndCommand( psz_sent );
317
                if( psz_sent == NULL ) return NULL;
318
            }
gbazin's avatar
gbazin committed
319
            else psz_sent++;
320
        }
gbazin's avatar
gbazin committed
321
322

        return psz_sent;
323
324
325
    }
}

gbazin's avatar
gbazin committed
326
327
328
329
330
/*****************************************************************************
 * ExecuteCommand: The main state machine
 *****************************************************************************
 * Execute a command which ends with '\0' (string)
 *****************************************************************************/
331
static int ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
zorglub's avatar
zorglub committed
332
                           vlm_message_t **pp_message )
333
334
{
    int i_command = 0;
zorglub's avatar
zorglub committed
335
    char **ppsz_command = NULL;
336
    const char *psz_cmd = psz_command;
zorglub's avatar
zorglub committed
337
    vlm_message_t *p_message = NULL;
gbazin's avatar
gbazin committed
338
    int i, j;
339
340

    /* First, parse the line and cut it */
zorglub's avatar
zorglub committed
341
    while( *psz_cmd != '\0' )
342
343
    {

zorglub's avatar
zorglub committed
344
        if( *psz_cmd == ' ' || *psz_cmd == '\t' )
345
        {
zorglub's avatar
zorglub committed
346
            psz_cmd++;
347
348
349
        }
        else
        {
350
            const char *psz_temp;
351
352
            int   i_temp;

353
            /* support for comments */
zorglub's avatar
zorglub committed
354
            if( i_command == 0 && *psz_cmd == '#')
355
            {
zorglub's avatar
zorglub committed
356
                p_message = vlm_MessageNew( "", NULL );
357
358
359
                goto success;
            }

zorglub's avatar
zorglub committed
360
            psz_temp = FindEndCommand( psz_cmd );
361

362
363
364
365
366
            if( psz_temp == NULL )
            {
                p_message = vlm_MessageNew( "Incomplete command", psz_cmd );
                goto error;
            }
367

zorglub's avatar
zorglub committed
368
            i_temp = psz_temp - psz_cmd;
369

zorglub's avatar
zorglub committed
370
371
372
373
374
            ppsz_command = realloc( ppsz_command, (i_command + 1) *
                                    sizeof(char*) );
            ppsz_command[ i_command ] = malloc( (i_temp + 1) * sizeof(char) );
            strncpy( ppsz_command[ i_command ], psz_cmd, i_temp );
            ppsz_command[ i_command ][ i_temp ] = '\0';
375
376

            i_command++;
377

zorglub's avatar
zorglub committed
378
            psz_cmd = psz_temp;
379
380
381
        }
    }

gbazin's avatar
gbazin committed
382
383
384
    /*
     * And then Interpret it
     */
385
386
387

    if( i_command == 0 )
    {
zorglub's avatar
zorglub committed
388
        p_message = vlm_MessageNew( "", NULL );
gbazin's avatar
gbazin committed
389
        goto success;
390
391
    }

392
    if( !strcmp(ppsz_command[0], "new") )
393
    {
gbazin's avatar
gbazin committed
394
        int i_type;
395

gbazin's avatar
gbazin committed
396
397
        /* Check the number of arguments */
        if( i_command < 3 ) goto syntax_error;
398

gbazin's avatar
gbazin committed
399
        /* Get type */
400
        if( !strcmp(ppsz_command[2], "vod") )
gbazin's avatar
gbazin committed
401
402
403
        {
            i_type = VOD_TYPE;
        }
404
        else if( !strcmp(ppsz_command[2], "broadcast") )
gbazin's avatar
gbazin committed
405
406
407
        {
            i_type = BROADCAST_TYPE;
        }
408
        else if( !strcmp(ppsz_command[2], "schedule") )
gbazin's avatar
gbazin committed
409
410
411
412
413
        {
            i_type = SCHEDULE_TYPE;
        }
        else
        {
414
415
416
            p_message =
                vlm_MessageNew( "new", "%s: Choose between vod, "
                                "broadcast or schedule", ppsz_command[1] );
gbazin's avatar
gbazin committed
417
418
            goto error;
        }
419

gbazin's avatar
gbazin committed
420
        /* Check for forbidden media names */
421
422
423
        if( !strcmp(ppsz_command[1], "all") ||
            !strcmp(ppsz_command[1], "media") ||
            !strcmp(ppsz_command[1], "schedule") )
gbazin's avatar
gbazin committed
424
        {
zorglub's avatar
zorglub committed
425
            p_message = vlm_MessageNew( "new", "\"all\", \"media\" and "
426
                                        "\"schedule\" are reserved names" );
gbazin's avatar
gbazin committed
427
428
            goto error;
        }
429

gbazin's avatar
gbazin committed
430
        /* Check the name is not already in use */
zorglub's avatar
zorglub committed
431
432
        if( vlm_ScheduleSearch( p_vlm, ppsz_command[1] ) ||
            vlm_MediaSearch( p_vlm, ppsz_command[1] ) )
gbazin's avatar
gbazin committed
433
        {
zorglub's avatar
zorglub committed
434
435
            p_message = vlm_MessageNew( "new", "%s: Name already in use",
                                        ppsz_command[1] );
gbazin's avatar
gbazin committed
436
437
            goto error;
        }
438

gbazin's avatar
gbazin committed
439
440
441
        /* Schedule */
        if( i_type == SCHEDULE_TYPE )
        {
zorglub's avatar
zorglub committed
442
443
444
            vlm_schedule_t *p_schedule;
            p_schedule = vlm_ScheduleNew( p_vlm, ppsz_command[1] );
            if( !p_schedule )
445
            {
zorglub's avatar
zorglub committed
446
                p_message = vlm_MessageNew( "new", "could not create schedule" );
gbazin's avatar
gbazin committed
447
                goto error;
448
            }
gbazin's avatar
gbazin committed
449
        }
450

gbazin's avatar
gbazin committed
451
452
453
        /* Media */
        else
        {
zorglub's avatar
zorglub committed
454
455
456
            vlm_media_t *p_media;
            p_media = vlm_MediaNew( p_vlm, ppsz_command[1], i_type );
            if( !p_media )
457
            {
zorglub's avatar
zorglub committed
458
                p_message = vlm_MessageNew( "new", "could not create media" );
gbazin's avatar
gbazin committed
459
                goto error;
460
461
            }
        }
gbazin's avatar
gbazin committed
462
463

        if( i_command <= 3 )
464
        {
zorglub's avatar
zorglub committed
465
            p_message = vlm_MessageNew( "new", NULL );
gbazin's avatar
gbazin committed
466
            goto success;
467
        }
gbazin's avatar
gbazin committed
468
469
470
471

        /* Properties will be dealt with later on */
    }

472
    else if( !strcmp(ppsz_command[0], "setup") )
gbazin's avatar
gbazin committed
473
474
475
476
    {
        if( i_command < 2 ) goto syntax_error;

        /* Properties will be dealt with later on */
477
    }
zorglub's avatar
zorglub committed
478

479
    else if( !strcmp(ppsz_command[0], "del") )
480
    {
zorglub's avatar
zorglub committed
481
482
        vlm_media_t *p_media;
        vlm_schedule_t *p_schedule;
483

gbazin's avatar
gbazin committed
484
        if( i_command < 2 ) goto syntax_error;
485

zorglub's avatar
zorglub committed
486
487
        p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] );
        p_schedule = vlm_ScheduleSearch( p_vlm, ppsz_command[1] );
488

zorglub's avatar
zorglub committed
489
        if( p_schedule != NULL )
gbazin's avatar
gbazin committed
490
        {
zorglub's avatar
zorglub committed
491
            vlm_ScheduleDelete( p_vlm, p_schedule, NULL );
gbazin's avatar
gbazin committed
492
        }
zorglub's avatar
zorglub committed
493
        else if( p_media != NULL )
gbazin's avatar
gbazin committed
494
        {
zorglub's avatar
zorglub committed
495
            vlm_MediaDelete( p_vlm, p_media, NULL );
gbazin's avatar
gbazin committed
496
        }
497
        else if( !strcmp(ppsz_command[1], "media") )
gbazin's avatar
gbazin committed
498
        {
zorglub's avatar
zorglub committed
499
500
            while( p_vlm->i_media ) vlm_MediaDelete( p_vlm, p_vlm->media[0],
                                                     NULL );
gbazin's avatar
gbazin committed
501
        }
502
        else if( !strcmp(ppsz_command[1], "schedule") )
gbazin's avatar
gbazin committed
503
        {
zorglub's avatar
zorglub committed
504
505
            while( p_vlm->i_schedule )
                vlm_ScheduleDelete( p_vlm, p_vlm->schedule[0], NULL );
gbazin's avatar
gbazin committed
506
        }
507
        else if( !strcmp(ppsz_command[1], "all") )
gbazin's avatar
gbazin committed
508
        {
zorglub's avatar
zorglub committed
509
510
            while( p_vlm->i_media ) vlm_MediaDelete( p_vlm, p_vlm->media[0],
                                                     NULL );
gbazin's avatar
gbazin committed
511

zorglub's avatar
zorglub committed
512
513
            while( p_vlm->i_schedule )
                vlm_ScheduleDelete( p_vlm, p_vlm->schedule[0], NULL );
514
515
516
        }
        else
        {
zorglub's avatar
zorglub committed
517
518
            p_message = vlm_MessageNew( "del", "%s: media unknown",
                                      ppsz_command[1] );
gbazin's avatar
gbazin committed
519
            goto error;
520
        }
gbazin's avatar
gbazin committed
521

zorglub's avatar
zorglub committed
522
        p_message = vlm_MessageNew( "del", NULL );
gbazin's avatar
gbazin committed
523
        goto success;
524
    }
gbazin's avatar
gbazin committed
525

526
    else if( !strcmp(ppsz_command[0], "show") )
527
    {
zorglub's avatar
zorglub committed
528
529
        vlm_media_t *p_media;
        vlm_schedule_t *p_schedule;
gbazin's avatar
gbazin committed
530

531
532
        if( i_command == 1 )
        {
zorglub's avatar
zorglub committed
533
            p_message = vlm_Show( p_vlm, NULL, NULL, NULL );
gbazin's avatar
gbazin committed
534
            goto success;
535
        }
gbazin's avatar
gbazin committed
536
        else if( i_command > 2 ) goto syntax_error;
537

zorglub's avatar
zorglub committed
538
539
        p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] );
        p_schedule = vlm_ScheduleSearch( p_vlm, ppsz_command[1] );
540

zorglub's avatar
zorglub committed
541
        if( p_schedule != NULL )
542
        {
zorglub's avatar
zorglub committed
543
            p_message = vlm_Show( p_vlm, NULL, p_schedule, NULL );
544
        }
zorglub's avatar
zorglub committed
545
        else if( p_media != NULL )
546
        {
zorglub's avatar
zorglub committed
547
            p_message = vlm_Show( p_vlm, p_media, NULL, NULL );
548
549
550
        }
        else
        {
zorglub's avatar
zorglub committed
551
            p_message = vlm_Show( p_vlm, NULL, NULL, ppsz_command[1] );
552
        }
gbazin's avatar
gbazin committed
553
554

        goto success;
555
556
    }

557
    else if( !strcmp(ppsz_command[0], "help") )
gbazin's avatar
gbazin committed
558
559
    {
        if( i_command != 1 ) goto syntax_error;
560

zorglub's avatar
zorglub committed
561
        p_message = vlm_Help( p_vlm, NULL );
gbazin's avatar
gbazin committed
562
563
        goto success;
    }
564

565
    else if( !strcmp(ppsz_command[0], "control") )
gbazin's avatar
gbazin committed
566
    {
zorglub's avatar
zorglub committed
567
        vlm_media_t *p_media;
568

gbazin's avatar
gbazin committed
569
        if( i_command < 3 ) goto syntax_error;
570

zorglub's avatar
zorglub committed
571
        if( !(p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] ) ) )
572
        {
zorglub's avatar
zorglub committed
573
574
            p_message = vlm_MessageNew( "control", "%s: media unknown",
                                      ppsz_command[1] );
gbazin's avatar
gbazin committed
575
            goto error;
576
        }
gbazin's avatar
gbazin committed
577
        else
578
        {
gbazin's avatar
gbazin committed
579
580
            char *psz_command, *psz_arg = 0, *psz_instance = 0;
            int i_index = 2;
581

582
583
584
585
            if( strcmp( ppsz_command[2], "play" ) &&
                strcmp( ppsz_command[2], "stop" ) &&
                strcmp( ppsz_command[2], "pause" ) &&
                strcmp( ppsz_command[2], "seek" ) )
586
            {
gbazin's avatar
gbazin committed
587
                i_index++;
zorglub's avatar
zorglub committed
588
                psz_instance = ppsz_command[2];
gbazin's avatar
gbazin committed
589
590

                if( i_command < 4 ) goto syntax_error;
591
592
            }

zorglub's avatar
zorglub committed
593
            psz_command = ppsz_command[i_index];
594

zorglub's avatar
zorglub committed
595
            if( i_command >= i_index + 2 ) psz_arg = ppsz_command[i_index + 1];
gbazin's avatar
gbazin committed
596

zorglub's avatar
zorglub committed
597
598
599
            vlm_MediaControl( p_vlm, p_media, psz_instance, psz_command,
                             psz_arg );
            p_message = vlm_MessageNew( "control", NULL );
gbazin's avatar
gbazin committed
600
            goto success;
601
602
        }
    }
gbazin's avatar
gbazin committed
603

604
    else if( !strcmp(ppsz_command[0], "save") )
605
    {
gbazin's avatar
gbazin committed
606
        if( i_command != 2 ) goto syntax_error;
607

608
        if( vlm_Save( p_vlm, ppsz_command[1] ) )
gbazin's avatar
gbazin committed
609
        {
zorglub's avatar
zorglub committed
610
            p_message = vlm_MessageNew( "save", "Unable to save to file" );
gbazin's avatar
gbazin committed
611
            goto error;
612
613
614
        }
        else
        {
zorglub's avatar
zorglub committed
615
            p_message = vlm_MessageNew( "save", NULL );
gbazin's avatar
gbazin committed
616
            goto success;
617
618
        }
    }
gbazin's avatar
gbazin committed
619

620
    else if( !strcmp(ppsz_command[0], "load") )
621
    {
gbazin's avatar
gbazin committed
622
        if( i_command != 2 ) goto syntax_error;
623

624
        switch( vlm_Load( p_vlm, ppsz_command[1] ) )
gbazin's avatar
gbazin committed
625
        {
626
627
628
629
            case 0:
                p_message = vlm_MessageNew( "load", NULL );
                goto success;
            case 2:
zorglub's avatar
zorglub committed
630
                p_message = vlm_MessageNew( "load", "read file error" );
gbazin's avatar
gbazin committed
631
                goto error;
632
633
634
635
636
637
638
639
            case 3:
                p_message =
                    vlm_MessageNew( "load", "error while loading file" );
                goto error;
            default:
                p_message =
                    vlm_MessageNew( "load", "Unable to load from file" );
                goto error;
gbazin's avatar
gbazin committed
640
641
642
643
644
        }
    }

    else
    {
zorglub's avatar
zorglub committed
645
        p_message = vlm_MessageNew( ppsz_command[0], "Unknown command" );
gbazin's avatar
gbazin committed
646
647
648
649
        goto error;
    }

    /* Common code between "new" and "setup" */
650
651
    if( !strcmp(ppsz_command[0], "new") ||
        !strcmp(ppsz_command[0], "setup") )
gbazin's avatar
gbazin committed
652
    {
653
        int i_command_start = strcmp(ppsz_command[0], "new") ? 2 : 3;
zorglub's avatar
zorglub committed
654
655
        vlm_media_t *p_media;
        vlm_schedule_t *p_schedule;
gbazin's avatar
gbazin committed
656
657
658

        if( i_command < i_command_start ) goto syntax_error;

zorglub's avatar
zorglub committed
659
660
        p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] );
        p_schedule = vlm_ScheduleSearch( p_vlm, ppsz_command[1] );
gbazin's avatar
gbazin committed
661

zorglub's avatar
zorglub committed
662
        if( !p_media && !p_schedule )
gbazin's avatar
gbazin committed
663
        {
zorglub's avatar
zorglub committed
664
665
            p_message = vlm_MessageNew( ppsz_command[0], "%s unknown",
                                        ppsz_command[1] );
gbazin's avatar
gbazin committed
666
667
668
            goto error;
        }

zorglub's avatar
zorglub committed
669
        if( p_schedule != NULL )
gbazin's avatar
gbazin committed
670
671
672
        {
            for( i = i_command_start ; i < i_command ; i++ )
            {
673
674
                if( !strcmp( ppsz_command[i], "enabled" ) ||
                    !strcmp( ppsz_command[i], "disabled" ) )
gbazin's avatar
gbazin committed
675
                {
zorglub's avatar
zorglub committed
676
                    vlm_ScheduleSetup( p_schedule, ppsz_command[i], NULL );
gbazin's avatar
gbazin committed
677
                }
678

zorglub's avatar
zorglub committed
679
                /* Beware: everything behind append is considered as
gbazin's avatar
gbazin committed
680
                 * command line */
681
                else if( !strcmp( ppsz_command[i], "append" ) )
682
                {
gbazin's avatar
gbazin committed
683
684
685
                    if( ++i >= i_command ) break;

                    for( j = i + 1; j < i_command; j++ )
686
                    {
zorglub's avatar
zorglub committed
687
688
689
690
691
                        ppsz_command[i] =
                            realloc( ppsz_command[i], strlen(ppsz_command[i]) +
                                     strlen(ppsz_command[j]) + 1 + 1 );
                        strcat( ppsz_command[i], " " );
                        strcat( ppsz_command[i], ppsz_command[j] );
692
                    }
gbazin's avatar
gbazin committed
693

zorglub's avatar
zorglub committed
694
695
                    vlm_ScheduleSetup( p_schedule, ppsz_command[i - 1],
                                       ppsz_command[i] );
gbazin's avatar
gbazin committed
696
                    break;
697
698
699
                }
                else
                {
700
                    if( i + 1 >= i_command && !strcmp(ppsz_command[0], "new") )
gbazin's avatar
gbazin committed
701
                    {
zorglub's avatar
zorglub committed
702
                        vlm_ScheduleDelete( p_vlm, p_schedule, NULL );
703
704
705
                        p_message =
                            vlm_MessageNew( ppsz_command[0],
                                            "Wrong properties syntax" );
gbazin's avatar
gbazin committed
706
707
708
709
                        goto error;
                    }
                    else if( i + 1 >= i_command )
                    {
710
711
712
                        p_message =
                            vlm_MessageNew( ppsz_command[0],
                                            "Wrong properties syntax" );
gbazin's avatar
gbazin committed
713
714
715
                        goto error;
                    }

zorglub's avatar
zorglub committed
716
717
                    vlm_ScheduleSetup( p_schedule, ppsz_command[i],
                                       ppsz_command[i+1] );
gbazin's avatar
gbazin committed
718
                    i++;
719
720
721
                }
            }
        }
gbazin's avatar
gbazin committed
722

zorglub's avatar
zorglub committed
723
        else if( p_media != NULL )
724
        {
gbazin's avatar
gbazin committed
725
726
            for( i = i_command_start ; i < i_command ; i++ )
            {
727
728
                if( !strcmp( ppsz_command[i], "enabled" ) ||
                    !strcmp( ppsz_command[i], "disabled" ) )
gbazin's avatar
gbazin committed
729
                {
zorglub's avatar
zorglub committed
730
                    vlm_MediaSetup( p_vlm, p_media, ppsz_command[i], NULL );
gbazin's avatar
gbazin committed
731
                }
732
733
                else if( i + 1 >= i_command &&
                         !strcmp( ppsz_command[i], "mux") )
734
                {
zorglub's avatar
zorglub committed
735
                    if( p_media->i_type != VOD_TYPE )
736
                    {
zorglub's avatar
zorglub committed
737
                        p_message = vlm_MessageNew( ppsz_command[0],
738
739
740
741
                                  "mux only available for broadcast" );
                    }
                    else
                    {
zorglub's avatar
zorglub committed
742
743
                        vlm_MediaSetup( p_vlm, p_media, ppsz_command[i],
                                        ppsz_command[i+1] );
744
                        i++;
745
746
                    }
                }
747
748
                else if( !strcmp( ppsz_command[i], "loop" ) ||
                         !strcmp( ppsz_command[i], "unloop" ) )
gbazin's avatar
gbazin committed
749
                {
zorglub's avatar
zorglub committed
750
                    if( p_media->i_type != BROADCAST_TYPE )
gbazin's avatar
gbazin committed
751
                    {
zorglub's avatar
zorglub committed
752
                        p_message = vlm_MessageNew( ppsz_command[0],
gbazin's avatar
gbazin committed
753
754
755
756
                                  "loop only available for broadcast" );
                    }
                    else
                    {
zorglub's avatar
zorglub committed
757
                        vlm_MediaSetup( p_vlm, p_media, ppsz_command[i], NULL );
gbazin's avatar
gbazin committed
758
759
760
761
                    }
                }
                else
                {
762
763
                    if( i + 1 >= i_command &&
                        !strcmp(ppsz_command[0], "new") )
gbazin's avatar
gbazin committed
764
                    {
zorglub's avatar
zorglub committed
765
                        vlm_MediaDelete( p_vlm, p_media, NULL );
766
767
768
                        p_message =
                            vlm_MessageNew( ppsz_command[0],
                                            "Wrong properties syntax" );
gbazin's avatar
gbazin committed
769
770
771
772
                        goto error;
                    }
                    else if( i + 1 >= i_command )
                    {
773
774
775
                        p_message =
                            vlm_MessageNew( ppsz_command[0],
                                            "Wrong properties syntax" );
gbazin's avatar
gbazin committed
776
777
778
                        goto error;
                    }

zorglub's avatar
zorglub committed
779
                    vlm_MediaSetup( p_vlm, p_media, ppsz_command[i],
780
                                    ppsz_command[i+1] );
gbazin's avatar
gbazin committed
781
782
783
                    i++;
                }
            }
784
        }
gbazin's avatar
gbazin committed
785

zorglub's avatar
zorglub committed
786
        p_message = vlm_MessageNew( ppsz_command[0], NULL );
gbazin's avatar
gbazin committed
787
        goto success;
788
789
    }

gbazin's avatar
gbazin committed
790
success:
zorglub's avatar
zorglub committed
791
792
793
    for( i = 0 ; i < i_command ; i++ ) FREE( ppsz_command[i] );
    FREE( ppsz_command );
    *pp_message = p_message;
794

gbazin's avatar
gbazin committed
795
796
797
    return VLC_SUCCESS;

syntax_error:
zorglub's avatar
zorglub committed
798
    p_message = vlm_MessageNew( ppsz_command[0], "Wrong command syntax" );
799

gbazin's avatar
gbazin committed
800
error:
zorglub's avatar
zorglub committed
801
802
803
    for( i = 0 ; i < i_command ; i++ ) FREE( ppsz_command[i] );
    FREE( ppsz_command );
    *pp_message = p_message;
804

gbazin's avatar
gbazin committed
805
    return VLC_EGENERIC;
806
807
}

808
static vlm_media_t *vlm_MediaSearch( vlm_t *vlm, const char *psz_name )
809
810
811
812
813
814
815
816
817
818
819
820
821
822
{
    int i;

    for( i = 0; i < vlm->i_media; i++ )
    {
        if( strcmp( psz_name, vlm->media[i]->psz_name ) == 0 )
        {
            return vlm->media[i];
        }
    }

    return NULL;
}

gbazin's avatar
gbazin committed
823
824
825
826
/*****************************************************************************
 * Media handling
 *****************************************************************************/
static vlm_media_instance_t *
827
828
vlm_MediaInstanceSearch( vlm_t *vlm, vlm_media_t *media,
                         const char *psz_name )
gbazin's avatar
gbazin committed
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
{
    int i;

    for( i = 0; i < media->i_instance; i++ )
    {
        if( ( !psz_name && !media->instance[i]->psz_name ) ||
            ( psz_name && media->instance[i]->psz_name &&
              !strcmp( psz_name, media->instance[i]->psz_name ) ) )
        {
            return media->instance[i];
        }
    }

    return NULL;
}

845
vlm_media_t *vlm_MediaNew( vlm_t *vlm, const char *psz_name, int i_type )
846
{
847
848
    vlm_media_t *media = malloc( sizeof( vlm_media_t ) );

zorglub's avatar
zorglub committed
849
850
851
852
853
854
    if( !media )
    {
        msg_Err( vlm, "out of memory" );
        return NULL;
    }

855
856
857
    /* Check if we need to load the VOD server */
    if( i_type == VOD_TYPE && !vlm->i_vod )
    {
858
        vlm->vod = vlc_object_create( vlm, VLC_OBJECT_VOD );
859
860
861
862
863
        vlc_object_attach( vlm->vod, vlm );
        vlm->vod->p_module = module_Need( vlm->vod, "vod server", 0, 0 );
        if( !vlm->vod->p_module )
        {
            msg_Err( vlm, "cannot find vod server" );
gbazin's avatar
gbazin committed
864
865
866
            vlc_object_detach( vlm->vod );
            vlc_object_destroy( vlm->vod );
            vlm->vod = 0;
867
868
869
            free( media );
            return NULL;
        }
870
871
872

        vlm->vod->p_data = vlm;
        vlm->vod->pf_media_control = vlm_MediaVodControl;
873
    }
zorglub's avatar
zorglub committed
874

875
    if( i_type == VOD_TYPE ) vlm->i_vod++;
876
877
878
879

    media->psz_name = strdup( psz_name );
    media->b_enabled = VLC_FALSE;
    media->b_loop = VLC_FALSE;
880
    media->vod_media = NULL;
881
    media->psz_vod_output = NULL;
882
    media->psz_mux = NULL;
883
884
885
886
887
888
    media->i_input = 0;
    media->input = NULL;
    media->psz_output = NULL;
    media->i_option = 0;
    media->option = NULL;
    media->i_type = i_type;
gbazin's avatar
gbazin committed
889
890
    media->i_instance = 0;
    media->instance = NULL;
891

892
    media->item.psz_uri = strdup( psz_name );
gbazin's avatar
gbazin committed
893
    vlc_input_item_Init( VLC_OBJECT(vlm), &media->item );
894
895

    TAB_APPEND( vlm->i_media, vlm->media, media );
896
897
898
899
900

    return media;
}

/* for now, simple delete. After, del with options (last arg) */
901
void vlm_MediaDelete( vlm_t *vlm, vlm_media_t *media, const char *psz_name )
902
{
gbazin's avatar
gbazin committed
903
    if( media == NULL ) return;
904

gbazin's avatar
gbazin committed
905
    while( media->i_instance )
906
    {
gbazin's avatar
gbazin committed
907
908
        vlm_media_instance_t *p_instance = media->instance[0];
        vlm_MediaControl( vlm, media, p_instance->psz_name, "stop", 0 );
909
910
    }

gbazin's avatar