vlm.c 79.8 KB
Newer Older
1
/*****************************************************************************
2
 * vlm.c: VLM interface plugin
3
 *****************************************************************************
Antoine Cellerier's avatar
Antoine Cellerier 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>
Gildas Bazin's avatar
Gildas Bazin committed
9
 *          Gildas Bazin <gbazin@videolan.org>
10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 25 26 27 28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
29 30 31
#include <vlc/vlc.h>

#include <stdio.h>
32
#include <stdlib.h>                                      /* malloc(), free() */
33
#include <ctype.h>                                              /* tolower() */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
34
#include <assert.h>
35

36 37
#ifdef ENABLE_VLM

38

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

Clément Stenac's avatar
Clément Stenac committed
44
#include <vlc_input.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
45
#include "input_internal.h"
Clément Stenac's avatar
Clément Stenac committed
46
#include <vlc_stream.h>
47
#include <vlc_vlm.h>
48
#include "vlm_internal.h"
49
#include <vlc_vod.h>
Clément Stenac's avatar
Clément Stenac committed
50
#include <vlc_charset.h>
51 52
#include <vlc_sout.h>
#include "../stream_output/stream_output.h"
53

54 55 56
/*****************************************************************************
 * Local prototypes.
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
57
static vlm_message_t *vlm_Show( vlm_t *, vlm_media_t *, vlm_schedule_t *, const char * );
58 59
static vlm_message_t *vlm_Help( vlm_t *, char * );

60
static vlm_media_instance_t *vlm_MediaInstanceSearch( vlm_t *, vlm_media_t *, const char * );
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 75 76 77 78 79 80
static int vlm_Save( vlm_t *p_vlm, const char *psz_file );
static int vlm_Load( vlm_t *p_vlm, const char *psz_file );


static vlm_schedule_t *vlm_ScheduleNew( vlm_t *vlm, const char *psz_name );
static void vlm_ScheduleDelete( vlm_t *vlm, vlm_schedule_t *sched, const char *psz_name );
static int vlm_ScheduleSetup( vlm_schedule_t *schedule, const char *psz_cmd,
                       const char *psz_value );

static int vlm_MediaVodControl( void *, vod_media_t *, const char *, int, va_list );


81 82 83 84 85 86
static vlm_media_t *vlm_MediaNew( vlm_t *, const char *, int );
static void         vlm_MediaDelete( vlm_t *, vlm_media_t *, const char * );
static int          vlm_MediaSetup( vlm_t *, vlm_media_t *, const char *, const char * );
static int          vlm_MediaControl( vlm_t *, vlm_media_t *, const char *, const char *, const char * );
static vlm_media_t *vlm_MediaSearch( vlm_t *, const char *);

87 88 89 90 91 92
/*****************************************************************************
 * vlm_New:
 *****************************************************************************/
vlm_t *__vlm_New ( vlc_object_t *p_this )
{
    vlc_value_t lockval;
Clément Stenac's avatar
Clément Stenac committed
93
    vlm_t *p_vlm = NULL;
94
    char *psz_vlmconf;
95

96 97 98 99 100
    /* Avoid multiple creation */
    if( var_Create( p_this->p_libvlc_global, "vlm_mutex", VLC_VAR_MUTEX ) ||
        var_Get( p_this->p_libvlc_global, "vlm_mutex", &lockval ) )
        return NULL;

101 102
    vlc_mutex_lock( lockval.p_address );

103 104
    p_vlm = vlc_object_find( p_this, VLC_OBJECT_VLM, FIND_ANYWHERE );
    if( p_vlm )
105
    {
106 107 108 109
        vlc_object_yield( p_vlm );
        vlc_mutex_unlock( lockval.p_address );
        return p_vlm;
    }
110

111
    msg_Dbg( p_this, "creating VLM" );
112

113 114 115 116 117
    p_vlm = vlc_object_create( p_this, VLC_OBJECT_VLM );
    if( !p_vlm )
    {
        vlc_mutex_unlock( lockval.p_address );
        return NULL;
118
    }
119 120 121 122 123 124 125 126

    vlc_mutex_init( p_this->p_libvlc, &p_vlm->lock );
    TAB_INIT( p_vlm->i_media, p_vlm->media );
    TAB_INIT( p_vlm->i_schedule, p_vlm->schedule );
    p_vlm->i_vod = 0;
    p_vlm->vod = NULL;
    vlc_object_yield( p_vlm );
    vlc_object_attach( p_vlm, p_this->p_libvlc );
127

Clément Stenac's avatar
Clément Stenac committed
128
    if( vlc_thread_create( p_vlm, "vlm thread",
129 130
                           Manage, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
    {
Clément Stenac's avatar
Clément Stenac committed
131 132
        vlc_mutex_destroy( &p_vlm->lock );
        vlc_object_destroy( p_vlm );
133 134
        return NULL;
    }
135

136 137
    /* Load our configuration file */
    psz_vlmconf = var_CreateGetString( p_vlm, "vlm-conf" );
138 139 140 141 142
    if( psz_vlmconf && *psz_vlmconf )
    {
        vlm_message_t *p_message = NULL;
        char *psz_buffer = NULL;

143
        msg_Dbg( p_this, "loading VLM configuration" );
144 145 146
        asprintf(&psz_buffer, "load %s", psz_vlmconf );
        if( psz_buffer )
        {
147 148
            msg_Dbg( p_this, psz_buffer );
            if( vlm_ExecuteCommand( p_vlm, psz_buffer, &p_message ) )
149
                msg_Warn( p_this, "error while loading the configuration file" );
150

151
            vlm_MessageDelete(p_message);
152 153
            free(psz_buffer);
        }
154 155
    }
    free(psz_vlmconf);
156

157 158 159
    vlc_mutex_unlock( lockval.p_address );

    return p_vlm;
160 161 162 163 164
}

/*****************************************************************************
 * vlm_Delete:
 *****************************************************************************/
Clément Stenac's avatar
Clément Stenac committed
165
void vlm_Delete( vlm_t *p_vlm )
166 167 168
{
    vlc_value_t lockval;

169
    var_Get( p_vlm->p_libvlc_global, "vlm_mutex", &lockval );
170 171
    vlc_mutex_lock( lockval.p_address );

Clément Stenac's avatar
Clément Stenac committed
172
    vlc_object_release( p_vlm );
173

Clément Stenac's avatar
Clément Stenac committed
174
    if( p_vlm->i_refcount > 0 )
175 176 177 178 179
    {
        vlc_mutex_unlock( lockval.p_address );
        return;
    }

Clément Stenac's avatar
Clément Stenac committed
180 181
    p_vlm->b_die = VLC_TRUE;
    vlc_thread_join( p_vlm );
182

183 184 185 186 187
    vlc_object_detach( p_vlm );

    while( p_vlm->i_media )
        vlm_MediaDelete( p_vlm, p_vlm->media[0], NULL );
    TAB_CLEAN( p_vlm->i_media, p_vlm->media );
188

189 190 191
    while( p_vlm->i_schedule )
        vlm_ScheduleDelete( p_vlm, p_vlm->schedule[0], NULL );
    TAB_CLEAN( p_vlm->schedule, p_vlm->schedule );
192

193 194
    vlc_mutex_destroy( &p_vlm->lock );

Clément Stenac's avatar
Clément Stenac committed
195
    vlc_object_destroy( p_vlm );
196 197 198 199 200 201
    vlc_mutex_unlock( lockval.p_address );
}

/*****************************************************************************
 * vlm_ExecuteCommand:
 *****************************************************************************/
202
int vlm_ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
Clément Stenac's avatar
Clément Stenac committed
203
                        vlm_message_t **pp_message)
204
{
Clément Stenac's avatar
Clément Stenac committed
205
    int i_result;
206

Clément Stenac's avatar
Clément Stenac committed
207 208 209
    vlc_mutex_lock( &p_vlm->lock );
    i_result = ExecuteCommand( p_vlm, psz_command, pp_message );
    vlc_mutex_unlock( &p_vlm->lock );
210

Clément Stenac's avatar
Clément Stenac committed
211
    return i_result;
212 213
}

214 215

static const char quotes[] = "\"'";
216 217 218
/**
 * FindCommandEnd: look for the end of a possibly quoted string
 * @return NULL on mal-formatted string,
219
 * pointer past the last character otherwise.
220
 */
221
static const char *FindCommandEnd( const char *psz_sent )
222
{
223
    char c, quote = 0;
224

225
    while( (c = *psz_sent) != '\0' )
226
    {
227
        if( !quote )
Gildas Bazin's avatar
Gildas Bazin committed
228
        {
229
            if( strchr(quotes,c) )   // opening quote
230
                quote = c;
231
            else if( isspace(c) )         // non-escaped space
232
                return psz_sent;
233
            else if( c == '\\' )
234 235
            {
                psz_sent++;         // skip escaped character
236
                if( *psz_sent == '\0' )
237 238
                    return psz_sent;
            }
Gildas Bazin's avatar
Gildas Bazin committed
239
        }
240
        else
241
        {
242
            if( c == quote )         // non-escaped matching quote
243
                quote = 0;
244
            else if( (quote == '"') && (c == '\\') )
245 246 247 248 249 250
            {
                psz_sent++;         // skip escaped character
                if (*psz_sent == '\0')
                    return NULL;    // error, closing quote missing
            }
        }
Gildas Bazin's avatar
Gildas Bazin committed
251
        psz_sent++;
252
    }
253

254 255 256
    // error (NULL) if we could not find a matching quote
    return quote ? NULL : psz_sent;
}
257

Gildas Bazin's avatar
Gildas Bazin committed
258

259
/**
260
 * Unescape a nul-terminated string.
261 262 263 264 265 266 267
 * Note that in and out can be identical.
 *
 * @param out output buffer (at least <strlen (in) + 1> characters long)
 * @param in nul-terminated string to be unescaped
 *
 * @return 0 on success, -1 on error.
 */
268
static int Unescape( char *out, const char *in )
269
{
270
    char c, quote = 0;
271

272
    while( (c = *in++) != '\0' )
273
    {
274
        if( !quote )
Gildas Bazin's avatar
Gildas Bazin committed
275
        {
276
            if (strchr(quotes,c))   // opening quote
277
            {
278 279 280
                quote = c;
                continue;
            }
281
            else if( c == '\\' )
282 283 284 285 286 287 288 289 290 291 292 293 294
            {
                switch (c = *in++)
                {
                    case '"':
                    case '\'':
                    case '\\':
                        *out++ = c;
                        continue;

                    case '\0':
                        *out = '\0';
                        return 0;
                }
295
                if( isspace(c) )
296 297
                {
                    *out++ = c;
298
                    continue;
299 300 301 302 303 304 305
                }
                /* None of the special cases - copy the backslash */
                *out++ = '\\';
            }
        }
        else
        {
306
            if( c == quote )         // non-escaped matching quote
307 308 309 310
            {
                quote = 0;
                continue;
            }
311
            if( (quote == '"') && (c == '\\') )
312
            {
313
                switch( c = *in++ )
314 315 316 317 318 319 320 321 322 323 324 325
                {
                    case '"':
                    case '\\':
                        *out++ = c;
                        continue;

                    case '\0':   // should never happen
                        *out = '\0';
                        return -1;
                }
                /* None of the special cases - copy the backslash */
                *out++ = '\\';
326 327
            }
        }
328
        *out++ = c;
329
    }
330 331 332

    *out = '\0';
    return 0;
333 334
}

335

Gildas Bazin's avatar
Gildas Bazin committed
336 337 338 339 340
/*****************************************************************************
 * ExecuteCommand: The main state machine
 *****************************************************************************
 * Execute a command which ends with '\0' (string)
 *****************************************************************************/
341
static int ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
Clément Stenac's avatar
Clément Stenac committed
342
                           vlm_message_t **pp_message )
343
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
344 345 346
    size_t i_command = 0;
    char buf[strlen (psz_command) + 1], *psz_buf = buf;
    char *ppsz_command[sizeof (buf) / 2];
Clément Stenac's avatar
Clément Stenac committed
347
    vlm_message_t *p_message = NULL;
348 349

    /* First, parse the line and cut it */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
350
    while( *psz_command != '\0' )
351
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
352 353
        const char *psz_temp;

354
        if(isspace (*psz_command))
355
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
356 357
            psz_command++;
            continue;
358
        }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
359 360 361

        /* support for comments */
        if( i_command == 0 && *psz_command == '#')
362
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
363 364 365
            p_message = vlm_MessageNew( "", NULL );
            goto success;
        }
366

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
367 368 369 370 371 372 373
        psz_temp = FindCommandEnd( psz_command );

        if( psz_temp == NULL )
        {
            p_message = vlm_MessageNew( "Incomplete command", psz_command );
            goto error;
        }
374

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
375
        assert (i_command < (sizeof (ppsz_command) / sizeof (ppsz_command[0])));
376

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
377 378 379
        ppsz_command[i_command] = psz_buf;
        memcpy (psz_buf, psz_command, psz_temp - psz_command);
        psz_buf[psz_temp - psz_command] = '\0';
380

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
381
        Unescape (psz_buf, psz_buf);
Antoine Cellerier's avatar
Antoine Cellerier committed
382

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
383 384 385
        i_command++;
        psz_buf += psz_temp - psz_command + 1;
        psz_command = psz_temp;
386

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
387
        assert (buf + sizeof (buf) >= psz_buf);
388 389
    }

Gildas Bazin's avatar
Gildas Bazin committed
390 391 392
    /*
     * And then Interpret it
     */
393 394 395

    if( i_command == 0 )
    {
Clément Stenac's avatar
Clément Stenac committed
396
        p_message = vlm_MessageNew( "", NULL );
Gildas Bazin's avatar
Gildas Bazin committed
397
        goto success;
398 399
    }

400
    if( !strcmp(ppsz_command[0], "new") )
401
    {
Gildas Bazin's avatar
Gildas Bazin committed
402
        int i_type;
403

Gildas Bazin's avatar
Gildas Bazin committed
404 405
        /* Check the number of arguments */
        if( i_command < 3 ) goto syntax_error;
406

Gildas Bazin's avatar
Gildas Bazin committed
407
        /* Get type */
408
        if( !strcmp(ppsz_command[2], "vod") )
Gildas Bazin's avatar
Gildas Bazin committed
409 410 411
        {
            i_type = VOD_TYPE;
        }
412
        else if( !strcmp(ppsz_command[2], "broadcast") )
Gildas Bazin's avatar
Gildas Bazin committed
413 414 415
        {
            i_type = BROADCAST_TYPE;
        }
416
        else if( !strcmp(ppsz_command[2], "schedule") )
Gildas Bazin's avatar
Gildas Bazin committed
417 418 419 420 421
        {
            i_type = SCHEDULE_TYPE;
        }
        else
        {
422 423 424
            p_message =
                vlm_MessageNew( "new", "%s: Choose between vod, "
                                "broadcast or schedule", ppsz_command[1] );
Gildas Bazin's avatar
Gildas Bazin committed
425 426
            goto error;
        }
427

Gildas Bazin's avatar
Gildas Bazin committed
428
        /* Check for forbidden media names */
429 430 431
        if( !strcmp(ppsz_command[1], "all") ||
            !strcmp(ppsz_command[1], "media") ||
            !strcmp(ppsz_command[1], "schedule") )
Gildas Bazin's avatar
Gildas Bazin committed
432
        {
Clément Stenac's avatar
Clément Stenac committed
433
            p_message = vlm_MessageNew( "new", "\"all\", \"media\" and "
434
                                        "\"schedule\" are reserved names" );
Gildas Bazin's avatar
Gildas Bazin committed
435 436
            goto error;
        }
437

Gildas Bazin's avatar
Gildas Bazin committed
438
        /* Check the name is not already in use */
Clément Stenac's avatar
Clément Stenac committed
439 440
        if( vlm_ScheduleSearch( p_vlm, ppsz_command[1] ) ||
            vlm_MediaSearch( p_vlm, ppsz_command[1] ) )
Gildas Bazin's avatar
Gildas Bazin committed
441
        {
Clément Stenac's avatar
Clément Stenac committed
442 443
            p_message = vlm_MessageNew( "new", "%s: Name already in use",
                                        ppsz_command[1] );
Gildas Bazin's avatar
Gildas Bazin committed
444 445
            goto error;
        }
446

Gildas Bazin's avatar
Gildas Bazin committed
447 448 449
        /* Schedule */
        if( i_type == SCHEDULE_TYPE )
        {
Clément Stenac's avatar
Clément Stenac committed
450 451 452
            vlm_schedule_t *p_schedule;
            p_schedule = vlm_ScheduleNew( p_vlm, ppsz_command[1] );
            if( !p_schedule )
453
            {
Clément Stenac's avatar
Clément Stenac committed
454
                p_message = vlm_MessageNew( "new", "could not create schedule" );
Gildas Bazin's avatar
Gildas Bazin committed
455
                goto error;
456
            }
Gildas Bazin's avatar
Gildas Bazin committed
457
        }
458

Gildas Bazin's avatar
Gildas Bazin committed
459 460 461
        /* Media */
        else
        {
Clément Stenac's avatar
Clément Stenac committed
462 463 464
            vlm_media_t *p_media;
            p_media = vlm_MediaNew( p_vlm, ppsz_command[1], i_type );
            if( !p_media )
465
            {
Clément Stenac's avatar
Clément Stenac committed
466
                p_message = vlm_MessageNew( "new", "could not create media" );
Gildas Bazin's avatar
Gildas Bazin committed
467
                goto error;
468 469
            }
        }
Gildas Bazin's avatar
Gildas Bazin committed
470 471

        if( i_command <= 3 )
472
        {
Clément Stenac's avatar
Clément Stenac committed
473
            p_message = vlm_MessageNew( "new", NULL );
Gildas Bazin's avatar
Gildas Bazin committed
474
            goto success;
475
        }
Gildas Bazin's avatar
Gildas Bazin committed
476 477 478 479

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

480
    else if( !strcmp(ppsz_command[0], "setup") )
Gildas Bazin's avatar
Gildas Bazin committed
481 482 483 484
    {
        if( i_command < 2 ) goto syntax_error;

        /* Properties will be dealt with later on */
485
    }
Clément Stenac's avatar
Clément Stenac committed
486

487
    else if( !strcmp(ppsz_command[0], "del") )
488
    {
Clément Stenac's avatar
Clément Stenac committed
489 490
        vlm_media_t *p_media;
        vlm_schedule_t *p_schedule;
491

Gildas Bazin's avatar
Gildas Bazin committed
492
        if( i_command < 2 ) goto syntax_error;
493

Clément Stenac's avatar
Clément Stenac committed
494 495
        p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] );
        p_schedule = vlm_ScheduleSearch( p_vlm, ppsz_command[1] );
496

Clément Stenac's avatar
Clément Stenac committed
497
        if( p_schedule != NULL )
Gildas Bazin's avatar
Gildas Bazin committed
498
        {
Clément Stenac's avatar
Clément Stenac committed
499
            vlm_ScheduleDelete( p_vlm, p_schedule, NULL );
Gildas Bazin's avatar
Gildas Bazin committed
500
        }
Clément Stenac's avatar
Clément Stenac committed
501
        else if( p_media != NULL )
Gildas Bazin's avatar
Gildas Bazin committed
502
        {
Clément Stenac's avatar
Clément Stenac committed
503
            vlm_MediaDelete( p_vlm, p_media, NULL );
Gildas Bazin's avatar
Gildas Bazin committed
504
        }
505
        else if( !strcmp(ppsz_command[1], "media") )
Gildas Bazin's avatar
Gildas Bazin committed
506
        {
Clément Stenac's avatar
Clément Stenac committed
507 508
            while( p_vlm->i_media ) vlm_MediaDelete( p_vlm, p_vlm->media[0],
                                                     NULL );
Gildas Bazin's avatar
Gildas Bazin committed
509
        }
510
        else if( !strcmp(ppsz_command[1], "schedule") )
Gildas Bazin's avatar
Gildas Bazin committed
511
        {
Clément Stenac's avatar
Clément Stenac committed
512 513
            while( p_vlm->i_schedule )
                vlm_ScheduleDelete( p_vlm, p_vlm->schedule[0], NULL );
Gildas Bazin's avatar
Gildas Bazin committed
514
        }
515
        else if( !strcmp(ppsz_command[1], "all") )
Gildas Bazin's avatar
Gildas Bazin committed
516
        {
Clément Stenac's avatar
Clément Stenac committed
517 518
            while( p_vlm->i_media ) vlm_MediaDelete( p_vlm, p_vlm->media[0],
                                                     NULL );
Gildas Bazin's avatar
Gildas Bazin committed
519

Clément Stenac's avatar
Clément Stenac committed
520 521
            while( p_vlm->i_schedule )
                vlm_ScheduleDelete( p_vlm, p_vlm->schedule[0], NULL );
522 523 524
        }
        else
        {
Clément Stenac's avatar
Clément Stenac committed
525 526
            p_message = vlm_MessageNew( "del", "%s: media unknown",
                                      ppsz_command[1] );
Gildas Bazin's avatar
Gildas Bazin committed
527
            goto error;
528
        }
Gildas Bazin's avatar
Gildas Bazin committed
529

Clément Stenac's avatar
Clément Stenac committed
530
        p_message = vlm_MessageNew( "del", NULL );
Gildas Bazin's avatar
Gildas Bazin committed
531
        goto success;
532
    }
Gildas Bazin's avatar
Gildas Bazin committed
533

534
    else if( !strcmp(ppsz_command[0], "show") )
535
    {
Clément Stenac's avatar
Clément Stenac committed
536 537
        vlm_media_t *p_media;
        vlm_schedule_t *p_schedule;
Gildas Bazin's avatar
Gildas Bazin committed
538

539 540
        if( i_command == 1 )
        {
Clément Stenac's avatar
Clément Stenac committed
541
            p_message = vlm_Show( p_vlm, NULL, NULL, NULL );
Gildas Bazin's avatar
Gildas Bazin committed
542
            goto success;
543
        }
Gildas Bazin's avatar
Gildas Bazin committed
544
        else if( i_command > 2 ) goto syntax_error;
545

Clément Stenac's avatar
Clément Stenac committed
546 547
        p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] );
        p_schedule = vlm_ScheduleSearch( p_vlm, ppsz_command[1] );
548

Clément Stenac's avatar
Clément Stenac committed
549
        if( p_schedule != NULL )
550
        {
Clément Stenac's avatar
Clément Stenac committed
551
            p_message = vlm_Show( p_vlm, NULL, p_schedule, NULL );
552
        }
Clément Stenac's avatar
Clément Stenac committed
553
        else if( p_media != NULL )
554
        {
Clément Stenac's avatar
Clément Stenac committed
555
            p_message = vlm_Show( p_vlm, p_media, NULL, NULL );
556 557 558
        }
        else
        {
Clément Stenac's avatar
Clément Stenac committed
559
            p_message = vlm_Show( p_vlm, NULL, NULL, ppsz_command[1] );
560
        }
Gildas Bazin's avatar
Gildas Bazin committed
561 562

        goto success;
563 564
    }

565
    else if( !strcmp(ppsz_command[0], "help") )
Gildas Bazin's avatar
Gildas Bazin committed
566 567
    {
        if( i_command != 1 ) goto syntax_error;
568

Clément Stenac's avatar
Clément Stenac committed
569
        p_message = vlm_Help( p_vlm, NULL );
Gildas Bazin's avatar
Gildas Bazin committed
570 571
        goto success;
    }
572

573
    else if( !strcmp(ppsz_command[0], "control") )
Gildas Bazin's avatar
Gildas Bazin committed
574
    {
Clément Stenac's avatar
Clément Stenac committed
575
        vlm_media_t *p_media;
576

Gildas Bazin's avatar
Gildas Bazin committed
577
        if( i_command < 3 ) goto syntax_error;
578

Clément Stenac's avatar
Clément Stenac committed
579
        if( !(p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] ) ) )
580
        {
Clément Stenac's avatar
Clément Stenac committed
581 582
            p_message = vlm_MessageNew( "control", "%s: media unknown",
                                      ppsz_command[1] );
Gildas Bazin's avatar
Gildas Bazin committed
583
            goto error;
584
        }
Gildas Bazin's avatar
Gildas Bazin committed
585
        else
586
        {
Gildas Bazin's avatar
Gildas Bazin committed
587
            char *psz_command, *psz_arg = 0, *psz_instance = 0;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
588
            size_t i_index = 2;
589

590 591 592
            if( strcmp( ppsz_command[2], "play" ) &&
                strcmp( ppsz_command[2], "stop" ) &&
                strcmp( ppsz_command[2], "pause" ) &&
593
                strcmp( ppsz_command[2], "seek" ) )
594
            {
Gildas Bazin's avatar
Gildas Bazin committed
595
                i_index++;
Clément Stenac's avatar
Clément Stenac committed
596
                psz_instance = ppsz_command[2];
Gildas Bazin's avatar
Gildas Bazin committed
597 598

                if( i_command < 4 ) goto syntax_error;
599 600 601 602

                if( strcmp( ppsz_command[3], "play" ) &&
                    strcmp( ppsz_command[3], "stop" ) &&
                    strcmp( ppsz_command[3], "pause" ) &&
603
                    strcmp( ppsz_command[3], "seek" ) )
604
                    goto syntax_error;
605 606
            }

Clément Stenac's avatar
Clément Stenac committed
607
            psz_command = ppsz_command[i_index];
608

Clément Stenac's avatar
Clément Stenac committed
609
            if( i_command >= i_index + 2 ) psz_arg = ppsz_command[i_index + 1];
Gildas Bazin's avatar
Gildas Bazin committed
610

Clément Stenac's avatar
Clément Stenac committed
611 612 613
            vlm_MediaControl( p_vlm, p_media, psz_instance, psz_command,
                             psz_arg );
            p_message = vlm_MessageNew( "control", NULL );
Gildas Bazin's avatar
Gildas Bazin committed
614
            goto success;
615 616
        }
    }
Gildas Bazin's avatar
Gildas Bazin committed
617

618
    else if( !strcmp(ppsz_command[0], "save") )
619
    {
Gildas Bazin's avatar
Gildas Bazin committed
620
        if( i_command != 2 ) goto syntax_error;
621

622
        if( vlm_Save( p_vlm, ppsz_command[1] ) )
Gildas Bazin's avatar
Gildas Bazin committed
623
        {
Clément Stenac's avatar
Clément Stenac committed
624
            p_message = vlm_MessageNew( "save", "Unable to save to file" );
Gildas Bazin's avatar
Gildas Bazin committed
625
            goto error;
626 627 628
        }
        else
        {
Clément Stenac's avatar
Clément Stenac committed
629
            p_message = vlm_MessageNew( "save", NULL );
Gildas Bazin's avatar
Gildas Bazin committed
630
            goto success;
631 632
        }
    }
Gildas Bazin's avatar
Gildas Bazin committed
633

634 635 636 637 638 639 640 641 642 643 644 645
    else if( !strcmp(ppsz_command[0], "export" ) )
    {
        char *psz_buf;

        if( i_command != 1 ) goto syntax_error;

        p_message = vlm_MessageNew( "export", psz_buf = Save( p_vlm ) );
        free( psz_buf );

        goto success;
    }

646
    else if( !strcmp(ppsz_command[0], "load") )
647
    {
Gildas Bazin's avatar
Gildas Bazin committed
648
        if( i_command != 2 ) goto syntax_error;
649

650
        switch( vlm_Load( p_vlm, ppsz_command[1] ) )
Gildas Bazin's avatar
Gildas Bazin committed
651
        {
652 653 654 655
            case 0:
                p_message = vlm_MessageNew( "load", NULL );
                goto success;
            case 2:
656
                p_message = vlm_MessageNew( "load", "Read file error" );
Gildas Bazin's avatar
Gildas Bazin committed
657
                goto error;
658 659
            case 3:
                p_message =
660
                    vlm_MessageNew( "load", "Error while loading file" );
661 662 663 664 665
                goto error;
            default:
                p_message =
                    vlm_MessageNew( "load", "Unable to load from file" );
                goto error;
Gildas Bazin's avatar
Gildas Bazin committed
666 667 668 669 670
        }
    }

    else
    {
Clément Stenac's avatar
Clément Stenac committed
671
        p_message = vlm_MessageNew( ppsz_command[0], "Unknown command" );
Gildas Bazin's avatar
Gildas Bazin committed
672 673 674 675
        goto error;
    }

    /* Common code between "new" and "setup" */
676 677
    if( !strcmp(ppsz_command[0], "new") ||
        !strcmp(ppsz_command[0], "setup") )
Gildas Bazin's avatar
Gildas Bazin committed
678
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
679
        size_t i_command_start = strcmp(ppsz_command[0], "new") ? 2 : 3;
Clément Stenac's avatar
Clément Stenac committed
680 681
        vlm_media_t *p_media;
        vlm_schedule_t *p_schedule;
Gildas Bazin's avatar
Gildas Bazin committed
682 683 684

        if( i_command < i_command_start ) goto syntax_error;

Clément Stenac's avatar
Clément Stenac committed
685 686
        p_media = vlm_MediaSearch( p_vlm, ppsz_command[1] );
        p_schedule = vlm_ScheduleSearch( p_vlm, ppsz_command[1] );
Gildas Bazin's avatar
Gildas Bazin committed
687

Clément Stenac's avatar
Clément Stenac committed
688
        if( !p_media && !p_schedule )
Gildas Bazin's avatar
Gildas Bazin committed
689
        {
Clément Stenac's avatar
Clément Stenac committed
690 691
            p_message = vlm_MessageNew( ppsz_command[0], "%s unknown",
                                        ppsz_command[1] );
Gildas Bazin's avatar
Gildas Bazin committed
692 693 694
            goto error;
        }

Clément Stenac's avatar
Clément Stenac committed
695
        if( p_schedule != NULL )
Gildas Bazin's avatar
Gildas Bazin committed
696
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
697 698
            size_t i;

Gildas Bazin's avatar
Gildas Bazin committed
699 700
            for( i = i_command_start ; i < i_command ; i++ )
            {
701 702
                if( !strcmp( ppsz_command[i], "enabled" ) ||
                    !strcmp( ppsz_command[i], "disabled" ) )
Gildas Bazin's avatar
Gildas Bazin committed
703
                {
Clément Stenac's avatar
Clément Stenac committed
704
                    vlm_ScheduleSetup( p_schedule, ppsz_command[i], NULL );
Gildas Bazin's avatar
Gildas Bazin committed
705
                }
706

Clément Stenac's avatar
Clément Stenac committed
707
                /* Beware: everything behind append is considered as
Gildas Bazin's avatar
Gildas Bazin committed
708
                 * command line */
709
                else if( !strcmp( ppsz_command[i], "append" ) )
710
                {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
711 712
                    size_t j;

Gildas Bazin's avatar
Gildas Bazin committed
713 714 715
                    if( ++i >= i_command ) break;

                    for( j = i + 1; j < i_command; j++ )
716
                    {
Clément Stenac's avatar
Clément Stenac committed
717 718 719 720 721
                        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] );
722
                    }
Gildas Bazin's avatar
Gildas Bazin committed
723

Clément Stenac's avatar
Clément Stenac committed
724 725
                    vlm_ScheduleSetup( p_schedule, ppsz_command[i - 1],
                                       ppsz_command[i] );
Gildas Bazin's avatar
Gildas Bazin committed
726
                    break;
727 728 729
                }
                else
                {
730
                    if( i + 1 >= i_command && !strcmp(ppsz_command[0], "new") )
Gildas Bazin's avatar
Gildas Bazin committed
731
                    {
Clément Stenac's avatar
Clément Stenac committed
732
                        vlm_ScheduleDelete( p_vlm, p_schedule, NULL );
733 734 735
                        p_message =
                            vlm_MessageNew( ppsz_command[0],
                                            "Wrong properties syntax" );
Gildas Bazin's avatar
Gildas Bazin committed
736 737 738 739
                        goto error;
                    }
                    else if( i + 1 >= i_command )
                    {
740 741 742
                        p_message =
                            vlm_MessageNew( ppsz_command[0],
                                            "Wrong properties syntax" );
Gildas Bazin's avatar
Gildas Bazin committed
743 744 745
                        goto error;
                    }

Clément Stenac's avatar
Clément Stenac committed
746 747
                    vlm_ScheduleSetup( p_schedule, ppsz_command[i],
                                       ppsz_command[i+1] );
Gildas Bazin's avatar
Gildas Bazin committed
748
                    i++;
749 750 751
                }
            }
        }
Gildas Bazin's avatar
Gildas Bazin committed
752

Clément Stenac's avatar
Clément Stenac committed
753
        else if( p_media != NULL )
754
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
755 756
            size_t i;

Gildas Bazin's avatar
Gildas Bazin committed
757 758
            for( i = i_command_start ; i < i_command ; i++ )
            {
759 760
                if( !strcmp( ppsz_command[i], "enabled" ) ||
                    !strcmp( ppsz_command[i], "disabled" ) )
Gildas Bazin's avatar
Gildas Bazin committed
761
                {
Clément Stenac's avatar
Clément Stenac committed
762
                    vlm_MediaSetup( p_vlm, p_media, ppsz_command[i], NULL );
Gildas Bazin's avatar
Gildas Bazin committed
763
                }
764 765
                else if( i + 1 >= i_command &&
                         !strcmp( ppsz_command[i], "mux") )
766
                {
Clément Stenac's avatar
Clément Stenac committed
767
                    if( p_media->i_type != VOD_TYPE )
768
                    {
Clément Stenac's avatar
Clément Stenac committed
769
                        p_message = vlm_MessageNew( ppsz_command[0],
770 771 772 773
                                  "mux only available for broadcast" );
                    }
                    else
                    {
Clément Stenac's avatar
Clément Stenac committed
774 775
                        vlm_MediaSetup( p_vlm, p_media, ppsz_command[i],
                                        ppsz_command[i+1] );
776
                        i++;
777 778
                    }
                }
779 780
                else if( !strcmp( ppsz_command[i], "loop" ) ||
                         !strcmp( ppsz_command[i], "unloop" ) )
Gildas Bazin's avatar
Gildas Bazin committed
781
                {
Clément Stenac's avatar
Clément Stenac committed
782
                    if( p_media->i_type != BROADCAST_TYPE )
Gildas Bazin's avatar
Gildas Bazin committed
783
                    {
Clément Stenac's avatar
Clément Stenac committed
784
                        p_message = vlm_MessageNew( ppsz_command[0],
Gildas Bazin's avatar
Gildas Bazin committed
785 786 787 788
                                  "loop only available for broadcast" );
                    }
                    else
                    {
Clément Stenac's avatar
Clément Stenac committed
789
                        vlm_MediaSetup( p_vlm, p_media, ppsz_command[i], NULL );
Gildas Bazin's avatar
Gildas Bazin committed
790 791 792 793
                    }
                }
                else
                {
794
                    if( ( (i + 1) >= i_command ) &&
795
                        !strcmp(ppsz_command[0], "new"