Subversion Repositories mdb

Rev

Rev 8 | Rev 14 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2015 by Andreas Theofilu <andreas@theosys.at>
 *
 * All rights reserved. No warranty, explicit or implicit, provided.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Andreas Theofilu and his suppliers, if any.
 * The intellectual and technical concepts contained
 * herein are proprietary to Andreas Theofilu and its suppliers and
 * may be covered by European and Foreign Patents, patents in process,
 * and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Andreas Theofilu.
 */
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <libgen.h>
#include <ctype.h>
#include <math.h>
#include <syslog.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sqlite3.h>
#include <ao/ao.h>
#include <mpg123.h>
#include "config.h"
#include "helplib.h"
#include "play.h"
#include "user.h"

#define CMD_SET_NONE    0
#define CMD_SET1                1
#define CMD_SET2                2

#define NOWPLAY                 "/nowplaying.list"
#define BITS                    8

int actCmdSet;
int nextCommand = PLAY_NONE;
int playStatus;
int playerActive = FALSE;
/* Prototypes */
static int playCallback(void *hint, int argc, char **argv, char **azColName);
void playMP3(int s1, char *file);
int check_command(int s1);
int checkQueueDouble(int id, char *fname);

/*
 * This function is called as a thread.
 * It uses the libmpg123 library to decode a MP3 file and the library libao
 * to play the decoded samples.
 * TODO: Implement the selection for a different audio hardware.
 * TODO: Implement a player for the formats FLAC, OGG and WAV
 */
void *pthr_playfile(void *pV_data)
{
        FILE *fp;
        char line[8192], buffer[1024], fname[256], query[8192], hv0[256];
        int rc;
        sqlite3 *db;
        char *zErrMsg = 0;
        struct ST_PlayPars *_playPars;

        playerActive = TRUE;                            /* Kind of locking :-) */
        _playPars = (struct ST_PlayPars *)pV_data;

        if (_playPars == NULL)
        {
                syslog(LOG_DAEMON, "Internal error: Invalid or no parameters for thread \"pthr_playfile\"!");
                playerActive = FALSE;
                return;
        }

        /* retrieve the data from the database */
        strcpy(fname, configs.home);
        strcat(fname, MUSICDB);

        rc = sqlite3_open(fname, &db);

        if (rc)
        {
                syslog(LOG_WARNING, "Error opening database %s: %s", fname, sqlite3_errmsg(db));
                strcpy(query, "ERROR:PLAY:Error opening database;");
                write (_playPars->s1, query, strlen(query));
                playerActive = FALSE;
                return;
        }

        strcpy (query, "select id, path, title, interpret, album, genre from \"main\".\"musicdb\" where ");

        if (strcasecmp(_playPars->type, "ID") == 0)
        {
                strcat(query, "id = ");
                strcat(query, _playPars->what);
                strcpy(fname, configs.home);
                strcat(fname, NOWPLAY);
                unlink(fname);
        }
        else if (strcasecmp(_playPars->type, "TITLE") == 0)
        {
                strcat(query, "title = \"");
                strcat(query, _playPars->what);
                strcat(query, "\" order by title");
        }
        else if (strcasecmp(_playPars->type, "ARTIST") == 0)
        {
                strcat(query, "interpret = \"");
                strcat(query, _playPars->what);
                strcat(query, "\" order by interpret");
        }
        else if (strcasecmp(_playPars->type, "ALBUM") == 0)
        {
                strcat(query, "album = \"");
                strcat(query, _playPars->what);
                strcat(query, "\" order by album");
        }
        else if (strcasecmp(_playPars->type, "GENRE") == 0)
        {
                strcat(query, "genre = \"");
                strcat(query, _playPars->what);
                strcat(query, "\" order by genre");
        }
        else if (strcasecmp(_playPars->type, "QUEUE") && strcasecmp(_playPars->type, "PLAYLIST"))
        {
                strcpy(hv0, "ERROR:PLAY:Missing type of argument;");
                write(_playPars->s1, hv0, strlen(hv0));
                sqlite3_close(db);
                playerActive = FALSE;
                return;
        }

        strcpy(fname, configs.home);
        strcat(fname, NOWPLAY);

        if (strcasecmp(_playPars->type, "QUEUE") == 0)
        {
                if (access(fname, R_OK))
                {
                        strcpy (hv0, "ERROR:PLAY:No or empty queue;");
                        write (_playPars->s1, hv0, strlen(hv0));
                        sqlite3_close(db);
                        playerActive = FALSE;
                        return;
                }
        }
        else if (!strcasecmp(_playPars->type, "PLAYLIST"))
        {
                USERS *act;

                if (userchain == NULL)
                {
                        strcpy (hv0, "ERROR:PLAY:No user selected;");
                        write (_playPars->s1, hv0, strlen(hv0));
                        sqlite3_close(db);
                        playerActive = FALSE;
                        return;
                }

                /* find uid */
                if ((act = findPlaylist(_playPars->what)) != NULL)
                {
                        if (!playlistToQueue(_playPars->s1, act->id))
                        {
                                sqlite3_close(db);
                                playerActive = FALSE;
                                return;
                        }
                }
                else
                {
                        strcpy (hv0, "ERROR:PLAY:No playlist found;");
                        write (_playPars->s1, hv0, strlen(hv0));
                        sqlite3_close(db);
                        playerActive = FALSE;
                        return;
                }
        }
        else if ((rc = sqlite3_exec(db, query, playCallback, (void *)_playPars->what, &zErrMsg)) != SQLITE_OK)
        {
                syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
                sqlite3_free(zErrMsg);
                sqlite3_close(db);
                strcpy(query, "ERROR:PLAY:SQL error;");
                write (_playPars->s1, query, strlen(query));
                playerActive = FALSE;
                return;
        }

        /* start the player and play the file(s) */
        if (!access(fname, R_OK))
        {
                int fd, flag, num, nextNum;
                
                if ((fd = open(fname, O_RDONLY)) < 0)
                {
                        syslog(LOG_WARNING, "Error opening file %s: %s", fname, strerror(errno));
                        playerActive = FALSE;
                        return;
                }

                flag = FALSE;
                num = 0;
                nextNum = -1;

                while (readLine(fd, &line[0], sizeof(line)) != NULL)
                {
                        char *t;
                        char path[512], id3_title[256], id3_artist[256], id3_album[256], id3_genre[256];
                        char *title, *artist, *album;
                        int x, id;

                        if (nextNum >= 0)
                        {
                                if (num == nextNum)
                                        nextNum = -1;
                                else
                                {
                                        num++;
                                        continue;
                                }
                        }

                        memset(path, 0, sizeof(path));
                        memset(id3_title, 0, sizeof(id3_title));
                        memset(id3_artist, 0, sizeof(id3_artist));
                        memset(id3_album, 0, sizeof(id3_album));
                        memset(id3_genre, 0, sizeof(id3_genre));
                        x = 0;
                        t = strtok(line, "\t");

                        while (t)
                        {
                                switch (x)
                                {
                                        case 0: strncpy(path, t, sizeof(path)); break;
                                        case 1: id = atoi(t); break;
                                        case 2: strncpy(id3_title, t, sizeof(id3_title)); break;
                                        case 3: strncpy(id3_artist, t, sizeof(id3_artist)); break;
                                        case 4: strncpy(id3_album, t, sizeof(id3_album)); break;
                                        case 5: strncpy(id3_genre, t, sizeof(id3_genre)); break;
                                }

                                t = strtok(NULL, "\t");
                                x++;
                        }

                        flag = TRUE;
                        title = urlencode(id3_title);
                        artist = urlencode(id3_artist);
                        album = urlencode(id3_album);
                        sprintf(query, "PLAYING:%d:", id);

                        if (title != NULL)
                        {
                                strcat(query, title);
                                free(title);
                        }
                        else
                                strcat(query, id3_title);

                        strcat(query, ":");

                        if (artist != NULL)
                        {
                                strcat(query, artist);
                                free(artist);
                        }
                        else
                                strcat(query, id3_artist);

                        strcat(query, ":");

                        if (album != NULL)
                        {
                                strcat(query, album);
                                free(album);
                        }
                        else
                                strcat(query, id3_album);

                        strcat(query, ":");
                        strcat(query, id3_genre);
                        strcat(query, ";");
                        write(_playPars->s1, query, strlen(query));
                        playMP3(_playPars->s1, path);

                        if (playStatus == PLAY_STATUS_SKIPF)
                                playStatus = PLAY_STATUS_STOP;
                        else if (playStatus == PLAY_STATUS_SKIPR)
                        {
                                if (num > 0)
                                {
                                        lseek (fd, 0L, SEEK_SET);
                                        nextNum = num - 1;
                                        num = 0;
                                        continue;
                                }

                                playStatus = PLAY_STATUS_STOP;
                        }
                        else if (playStatus == PLAY_STATUS_STOP)
                                break;

                        num++;
                }

                if (!flag)
                        syslog(LOG_WARNING, "Found no files to play!");

                close (fd);
        }
        else
                syslog(LOG_WARNING, "Error accessing file %s: %s", fname, strerror(errno));

        playerActive = FALSE;
}

static int playCallback(void *hint, int argc, char **argv, char **azColName)
{
        int i, id, fd;
        char path[512], id3_title[256], id3_artist[256], id3_album[256], id3_genre[256];
        char buffer[8192], *what;
        
        what = (char *)hint;
        memset(path, 0, sizeof(path));
        memset(id3_title, 0, sizeof(id3_title));
        memset(id3_artist, 0, sizeof(id3_artist));
        memset(id3_album, 0, sizeof(id3_album));
        memset(id3_genre, 0, sizeof(id3_genre));
        id = -1;

        for(i = 0; i < argc; i++)
        {
                if (strcasecmp(azColName[i], "id") == 0)
                        if (argv[i])
                                id = atoi(argv[i]);

                if (strcasecmp(azColName[i], "path") == 0)
                        if (argv[i])
                                strncpy(path, argv[i], sizeof(path));

                if (strcasecmp(azColName[i], "title") == 0)
                        if (argv[i])
                                strncpy(id3_title, argv[i], sizeof(id3_title));

                if (strcasecmp(azColName[i], "interpret") == 0)
                        if (argv[i])
                                strncpy(id3_artist, argv[i], sizeof(id3_artist));

                if (strcasecmp(azColName[i], "album") == 0)
                        if (argv[i])
                                strncpy(id3_album, argv[i], sizeof(id3_album));

                if (strcasecmp(azColName[i], "genre") == 0)
                        if (argv[i])
                                strncpy(id3_genre, argv[i], sizeof(id3_genre));
        }

        if (id != -1 && strlen(path) > 0)
        {
                char fname[512];

                strcpy(fname, configs.home);
                strcat(fname, NOWPLAY);

                if (checkQueueDouble(id, fname) == TRUE)        /* Make sure every ID in the queue is unique */
                        return 0;

                if ((fd = open(fname, O_RDWR | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP)) < 0)
                {
                        syslog(LOG_WARNING, "Error creating or writing to file %s: %s", fname, strerror(errno));
                        return 1;
                }

                sprintf (buffer, "%s\t%d\t%s\t%s\t%s\t%s\n", path, id, id3_title, id3_artist, id3_album, id3_genre);
                write (fd, buffer, strlen(buffer));
                close (fd);
        }
        else
                syslog(LOG_WARNING, "Found no data to play");

        return 0;
}

void playMP3(int s1, char *file)
{
        mpg123_handle *mh;
        unsigned char *buffer;
        size_t buffer_size;
        size_t done;
        int err;
        char hv0[128];
        
        int driver;
        ao_device *dev;
        
        ao_sample_format format;
        int channels, encoding;
        long rate;
        double current_seconds, seconds_left;
        off_t current_frame, frames_left;

        if(file == NULL || strlen(file) == 0)
        {
                syslog(LOG_DAEMON, "No or invalid file was passed to player!");
                return;
        }

        /* initializations */
        ao_initialize();
        
        if ((driver = ao_default_driver_id()) == -1)
        {
                syslog(LOG_DAEMON, "Error finding a default audio driver!");
                ao_shutdown();
                return;
        }

        mpg123_init();
        
        if ((mh = mpg123_new(NULL, &err)) == NULL)
        {
                syslog(LOG_DAEMON, "Error creating new MP3 handle: %s", mpg123_plain_strerror(err));
                ao_shutdown();
                return;
        }

        buffer_size = mpg123_outblock(mh);

        if ((buffer = (unsigned char*)malloc(buffer_size * sizeof(unsigned char))) == NULL)
        {
                syslog(LOG_DAEMON, "Error allocating memory for MP3 player: %s", strerror(errno));
                mpg123_close(mh);
                mpg123_delete(mh);
                mpg123_exit();
                ao_shutdown();
                return;
        }
        
        /* open the file and get the decoding format */
        if (mpg123_open(mh, file) != MPG123_OK)
        {
                syslog(LOG_DAEMON, "Error opening MP3 file %s", file);
                free(buffer);
                mpg123_close(mh);
                mpg123_delete(mh);
                mpg123_exit();
                ao_shutdown();
                return;
        }

        mpg123_scan(mh);
        mpg123_getformat(mh, &rate, &channels, &encoding);

        /* set the output format and open the output device */
        format.bits = mpg123_encsize(encoding) * BITS;
        format.rate = rate;
        format.channels = channels;
        format.byte_format = AO_FMT_NATIVE;
        format.matrix = 0;
        
        if ((dev = ao_open_live(driver, &format, NULL)) == NULL)
        {
                syslog(LOG_DAEMON, "Error opening live playback device: %s", strerror(errno));
                free(buffer);
                mpg123_close(mh);
                mpg123_delete(mh);
                mpg123_exit();
                ao_shutdown();
                return;
        }

        playStatus = PLAY_STATUS_PLAY;
        strcpy (hv0, "PLAYER:PLAY;");
        write(s1, hv0, strlen(hv0));
        /* decode and play */
        while (mpg123_read(mh, buffer, buffer_size, &done) == MPG123_OK)
        {
                int todo;
                char hv1[32], hv2[32], hv3[32];

                todo = check_command(s1);

                if (todo == PLAY_STATUS_STOP)
                        break;
                else if (todo == PLAY_STATUS_FWD)
                {
                        mpg123_seek_frame(mh, 100, SEEK_CUR);
                        playStatus = PLAY_STATUS_PLAY;
                        continue;
                }
                else if (todo == PLAY_STATUS_REW)
                {
                        off_t fr;
                        
                        fr =  mpg123_tellframe(mh);
                        
                        if (fr > 100)
                                fr -= 100;
                        else
                                fr = 0;

                        mpg123_seek_frame(mh, fr, SEEK_SET);
                        playStatus = PLAY_STATUS_PLAY;
                        continue;
                }

                /* get position */
                mpg123_position(mh, mpg123_tellframe(mh), done, &current_frame, &frames_left, &current_seconds, &seconds_left);
                sprintf(hv0, "POSITION:%s:%s:%s;", secondsToString(current_seconds, &hv1[0]), secondsToString(seconds_left, &hv2[0]), secondsToString(current_seconds + seconds_left, &hv3[0]));
                write(s1, hv0, strlen(hv0));
                ao_play(dev, (char *)buffer, done);
        }
        
        /* clean up */
/*      playStatus = PLAY_STATUS_STOP; */
        strcpy(hv0, "PLAYER:STOP;");
        write (s1, hv0, strlen(hv0));

        free(buffer);
        ao_close(dev);
        mpg123_close(mh);
        mpg123_delete(mh);
        mpg123_exit();
        ao_shutdown();
}

int check_command(int s1)
{
        char hv0[64];

        if (nextCommand == PLAY_STOP_NOW)
        {
                playStatus = PLAY_STATUS_STOP;
                return playStatus;
        }

        if (nextCommand == PLAY_PLAY && (playStatus == PLAY_STATUS_FWD || playStatus == PLAY_STATUS_REW))
        {
                playStatus = PLAY_STATUS_PLAY;
                return playStatus;
        }

        if (nextCommand == PLAY_STOP && (playStatus == PLAY_STATUS_PLAY || playStatus == PLAY_STATUS_PAUSE))
        {
                nextCommand = PLAY_NONE;
                playStatus = PLAY_STATUS_STOP;
                return playStatus;
        }

        if ((nextCommand == PLAY_PAUSE || nextCommand == PLAY_PLAYPAUSE) && playStatus == PLAY_STATUS_PLAY)
        {
                nextCommand = PLAY_NONE;
                playStatus = PLAY_STATUS_PAUSE;
                strcpy (hv0, "PLAYER:PAUSE;");
                write (s1, hv0, strlen(hv0));

                while (nextCommand != PLAY_PLAY && nextCommand != PLAY_PLAYPAUSE)
                        sleep(1);

                playStatus = PLAY_STATUS_PLAY;
                strcpy (hv0, "PLAYER:PLAY;");
                write (s1, hv0, strlen(hv0));
                nextCommand = PLAY_NONE;
        }

        if (nextCommand == PLAY_FWD)
        {
                nextCommand = PLAY_NONE;
                playStatus = PLAY_STATUS_FWD;
                return PLAY_STATUS_FWD;
        }

        if (nextCommand == PLAY_REW)
        {
                nextCommand = PLAY_NONE;
                playStatus = PLAY_STATUS_REW;
                return PLAY_STATUS_REW;
        }

        if (nextCommand == PLAY_SKIP_FWD)
        {
                nextCommand = PLAY_NONE;
                playStatus = PLAY_STATUS_SKIPF;
                return PLAY_STATUS_STOP;
        }

        if (nextCommand == PLAY_SKIP_REW)
        {
                nextCommand = PLAY_NONE;
                playStatus = PLAY_STATUS_SKIPR;
                return PLAY_STATUS_STOP;
        }

        return 0;
}

int checkQueueDouble(int id, char *fname)
{
        int fd;
        char line[8192];

        if ((fd = open(fname, O_RDONLY)) <= 0)
        {
                syslog(LOG_WARNING, "Error opening queue file %s: %s", fname, strerror(errno));
                return FALSE;
        }

        while (readLine(fd, &line[0], sizeof(line)) != NULL)
        {
                char *t;
                int x, nID;

                t = strtok(line, "\t");
                x = 0;
                
                while (t)
                {
                        if (x == 1)
                        {
                                nID = atoi(t);

                                if (nID == id)
                                {
                                        close (fd);
                                        return TRUE;
                                }

                                break;
                        }

                        x++;
                }
        }

        close(fd);
        return FALSE;
}

void appendToQueue(int s1, char *type, char *what)
{
        char fname[256], query[1024];
        int rc;
        sqlite3 *db;
        char *zErrMsg = 0;
        
        /* retrieve the data from the database */
        strcpy(fname, configs.home);
        strcat(fname, MUSICDB);
        
        rc = sqlite3_open(fname, &db);
        
        if (rc)
        {
                syslog(LOG_WARNING, "Error opening database %s: %s", fname, sqlite3_errmsg(db));
                strcpy(query, "ERROR:PLAY:Error opening database;");
                write (s1, query, strlen(query));
                playerActive = FALSE;
                return;
        }
        
        strcpy (query, "select id, path, title, interpret, album, genre from \"main\".\"musicdb\" where ");

        if (strcasecmp(type, "ID") == 0)
        {
                strcat(query, "id = ");
                strcat(query, what);
        }
        else if (strcasecmp(type, "TITLE") == 0)
        {
                strcat(query, "title = \"");
                strcat(query, what);
                strcat(query, "\" order by title");
        }
        else if (strcasecmp(type, "ARTIST") == 0)
        {
                strcat(query, "interpret = \"");
                strcat(query, what);
                strcat(query, "\" order by interpret");
        }
        else if (strcasecmp(type, "ALBUM") == 0)
        {
                strcat(query, "album = \"");
                strcat(query, what);
                strcat(query, "\" order by album");
        }
        else if (strcasecmp(type, "GENRE") == 0)
        {
                strcat(query, "genre = \"");
                strcat(query, what);
                strcat(query, "\" order by genre");
        }
        else if (strcasecmp(type, "PLAYLIST") == 0)
        {
                USERS *act;

                sqlite3_close(db);
                act = userchain;

                while (act)
                {
                        if (strcmp(act->playlist, what) == 0)
                        {
                                playlistToQueue(act->id, FALSE);
                                break;
                        }

                        act = act->next;
                }

                if (act == NULL)
                {
                        strcpy(query, "ERROR:PLAY:Error transfering playlist entries to queue;");
                        write (s1, query, strlen(query));
                }

                return;
        }

        if ((rc = sqlite3_exec(db, query, playCallback, (void *)what, &zErrMsg)) != SQLITE_OK)
        {
                syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
                sqlite3_free(zErrMsg);
                sqlite3_close(db);
                strcpy(query, "ERROR:PLAY:SQL error;");
                write (s1, query, strlen(query));
        }
}

/*
 * This function copies the content of a playlist into the queue.
 * The parameter defines whether the current queue should be deleted or not.
 * If the queue should not be deleted, the playlist will be appended.
 */
int playlistToQueue(int uid, int del)
{
        char fname[256], query[1024], hv0[256], buffer[8192];
        int rc;
        sqlite3 *db;
        char *zErrMsg = 0;
        sqlite3_stmt *res;
        char path[512], id3_title[256], id3_artist[256], id3_album[256], id3_genre[256];
        char *t;
        int id, fd;
        unsigned int mode;

        strcpy(fname, configs.home);
        strcat(fname, MUSICDB);
        
        rc = sqlite3_open(fname, &db);
        
        if (rc)
        {
                syslog(LOG_WARNING, "Error opening database %s: %s", fname, sqlite3_errmsg(db));
                return FALSE;
        }
        
        strcpy (query, "select id, path, title, interpret, album, genre from \"main\".\"musicdb\" as a where ");
        strcat (query, "(select musicid from \"main\".\"playlists\"  as b where a.id = b.musicid and b.userid = ");
        sprintf(hv0, "%d", uid);
        strcat (query, hv0);
        strcat (query, ")");

        if (sqlite3_prepare(db, query, -1, &res, NULL) != SQLITE_OK)
        {
                syslog(LOG_DAEMON, "Error preparing SQL statement [%s]: %s", query, sqlite3_errmsg(db));
                sqlite3_close(db);
                return FALSE;
        }

        /* Open the queue */
        strcpy(fname, configs.home);
        strcat(fname, NOWPLAY);

        if (!del)
                mode = O_RDWR | O_APPEND | O_CREAT;
        else
                mode = O_RDWR | O_TRUNC | O_CREAT;

        if ((fd = open(fname, mode, S_IWUSR | S_IRUSR | S_IRGRP)) <= 0)
        {
                syslog(LOG_WARNING, "Error opening file %s: %s", fname, strerror(errno));
                sqlite3_finalize(res);
                sqlite3_close(db);
                return FALSE;
        }

        while ((rc = sqlite3_step(res)) == SQLITE_ROW)
        {
                memset(path, 0, sizeof(path));
                memset(id3_title, 0, sizeof(id3_title));
                memset(id3_artist, 0, sizeof(id3_artist));
                memset(id3_album, 0, sizeof(id3_album));
                memset(id3_genre, 0, sizeof(id3_genre));
                id = sqlite3_column_int(res, 0);
                strncpy(path, (const char *)sqlite3_column_text(res, 1), sizeof(path));
                strncpy(id3_title, (const char *)sqlite3_column_text(res, 2), sizeof(id3_title));
                strncpy(id3_artist, (const char *)sqlite3_column_text(res, 3), sizeof(id3_artist));
                strncpy(id3_album, (const char *)sqlite3_column_text(res, 4), sizeof(id3_album));
                strncpy(id3_genre, (const char *)sqlite3_column_text(res, 5), sizeof(id3_genre));
                sprintf (buffer, "%s\t%d\t%s\t%s\t%s\t%s\n", path, id, id3_title, id3_artist, id3_album, id3_genre);
                write (fd, buffer, strlen(buffer));
        }

        close(fd);
        sqlite3_finalize(res);
        sqlite3_close(db);
        return TRUE;
}

int QueueToPlaylist(int s1, char *user, char *playlist)
{
        char fname[256], query[1024], hv0[256], buffer[8192];
        int rc;
        sqlite3 *db;
        char *zErrMsg = 0;
        sqlite3_stmt *res;
        char path[512], id3_title[256], id3_artist[256], id3_album[256], id3_genre[256];
        char *t;
        int id, fd, num;
        unsigned int mode;
        USERS *usp;
        
        strcpy(fname, configs.home);
        strcat(fname, MUSICDB);
        
        rc = sqlite3_open(fname, &db);
        
        if (rc)
        {
                syslog(LOG_WARNING, "Error opening database %s: %s", fname, sqlite3_errmsg(db));
                return FALSE;
        }

        if ((usp = findPlaylist(playlist)) != NULL)
        {
                sprintf(query, "delete from playlists where userid = %d", usp->id);

                if (sqlite3_prepare(db, query, -1, &res, NULL) != SQLITE_OK)
                {
                        syslog(LOG_DAEMON, "Error preparing SQL statement [%s]: %s", query, sqlite3_errmsg(db));
                        sqlite3_close(db);
                        return FALSE;
                }

                sqlite3_step(res);
        }

        /* Open the queue */
        strcpy(fname, configs.home);
        strcat(fname, NOWPLAY);
        
        if ((fd = open(fname, O_RDONLY)) <= 0)
        {
                syslog(LOG_WARNING, "Error opening file %s: %s", fname, strerror(errno));
                sqlite3_close(db);
                return FALSE;
        }
        
        num = 0;

        while (readLine(fd, buffer, sizeof(buffer)) != NULL)
        {
                int x;

                num++;
                memset(path, 0, sizeof(path));
                memset(id3_title, 0, sizeof(id3_title));
                memset(id3_artist, 0, sizeof(id3_artist));
                memset(id3_album, 0, sizeof(id3_album));
                memset(id3_genre, 0, sizeof(id3_genre));

                x = 0;
                t = strtok(buffer, "\t");
                
                while (t)
                {
                        switch(x)
                        {
                                case 0: strncpy(path, t, sizeof(path)-1); break;
                                case 1: id = atoi(t); break;
                                case 2: strncpy(id3_title, t, sizeof(id3_title) - 1); break;
                                case 3: strncpy(id3_artist, t, sizeof(id3_artist) - 1); break;
                                case 4: strncpy(id3_album, t, sizeof(id3_album) - 1); break;
                                case 5: strncpy(id3_genre, t, sizeof(id3_genre) - 1); break;
                        }
                        
                        x++;
                        t = strtok(NULL, "\t");
                }
                
                strcpy (query, "insert into playlists (userid, musicid) values (");
                sprintf(hv0, "%d", userchain->id);
                strcat (query, hv0);
                strcat (query, ",");
                sprintf(hv0, "%d", id);
                strcat (query, hv0);
                strcat (query, ")");

                if ((rc = sqlite3_exec(db, query, NULL, NULL, &zErrMsg)) != SQLITE_OK)
                {
                        syslog(LOG_WARNING, "SQL error [%s]: %s", query, zErrMsg);
                        sqlite3_free(zErrMsg);
                        sqlite3_close(db);
                        close(fd);
                        return FALSE;
                }
        }
        
        close(fd);
        sqlite3_close(db);
        sprintf(hv0, "TRANSFERED:%d;", num);
        write (s1, hv0, strlen(hv0));
        return TRUE;
}