Subversion Repositories mdb

Rev

Rev 3 | 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 <unistd.h>
#include <stdlib.h>
#include <libgen.h>
#include <math.h>
#include <time.h>
#include <signal.h>
#include <syslog.h>
#include <errno.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <dirent.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sqlite3.h>
#include <id3.h>
#include "config.h"
#include "helplib.h"
#include "mdb.h"

static pthread_mutex_t fastmutex_proc = PTHREAD_MUTEX_INITIALIZER;
int musicFilter(const struct dirent *dir);
int grabMusicFiles(char *dir);
static int callback(void *hint, int argc, char **argv, char **azColName);
void evaluateMusicFile(char *file);

// Global variables
int file_found = 0;

void *processCommands(void *pV_data)
{
        char ch, buf[128];
        int i, s1, s;
        struct SOCKETS *soc;
        
        soc = (struct SOCKETS *)pV_data;
        s1 = soc->newfd;
        s = soc->sockfd;
        memset(&buf[0], 0, sizeof(buf));
        i = 0;
        
        while (read(s1,&ch,1) > 0)
        {
                if (i < (sizeof(buf) - 1))
                {
                        buf[i] = ch;
                        
                        if (ch == ';' || ch == 0x0d)
                        {
                                int pstat;
                                
                                pthread_mutex_lock (&fastmutex_proc);
                                
                                if (!strncmp(buf, "quit", 4))
                                        break;
                                
                                if ((pstat = parseCommand(s1,buf)) == 0)
                                {
                                        char hv0[128];
                                        
                                        sprintf(&hv0[0],"INVALID COMMAND: %s;",buf);
                                        write(s1,hv0,strlen(hv0));
                                }
                                else if (pstat == 2)
                                        write(s1, "NAK;", 4);
                                else
                                        write(s1,"OK;",3);
                                
                                memset(&buf[0], 0, sizeof(buf));
                                i = 0;
                                pthread_mutex_unlock(&fastmutex_proc);
                                continue;
                        }
                }
                
                i++;
        }
        
        close(s1);
}

/*
 * This function parses the commands given by a network client.
 */
int parseCommand(int s1, char *cmd)
{
        return 1;               // cmd was OK
}

/*
 * Callback function of directory scan.
 * This function desides whether a directory entry will be treated as a
 * music file or not.
 */
int musicFilter(const struct dirent *dir)
{
        if (dir->d_type == DT_REG && strcasestr(dir->d_name, ".mp3") != NULL)
                return 1;

        return 0;
}

/*
 * This function scans a directory for music files. If it finds some file name
 * who is a possible music file, it gives it to a function to evaluate and
 * store it.
 */
int grabMusicFiles(char *dir)
{
        struct dirent **namelist;
        int n;

        if (dir == NULL || strlen(dir) == 0)
                return FALSE;

        n = scandir(dir, &namelist, musicFilter, alphasort);

        if (n < 0)
        {
                syslog(LOG_DAEMON, "Error scanning directory %s: %s", configs.Pathfile, strerror(errno));
                return FALSE;
        }
        else
        { 
                while(n--)
                {
                        printf("%s\n", namelist[n]->d_name); 
                        free(namelist[n]); 
                } 

                free(namelist); 
        } 
}

static int callback(void *hint, int argc, char **argv, char **azColName)
{
//      int i;

        if (hint != NULL && strcmp(hint, "EXIST"))
        {
                file_found = TRUE;
                return 0;
        }

/*      for(i = 0; i < argc; i++)
        {
                printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
        }

        printf("\n");
*/
        return 0;
}

void evaluateMusicFile(char *file)
{
        sqlite3 *db;
        char *zErrMsg = 0;
        int rc;
        char fname[256];
        char query[1024];
        ID3Tag *id3;
        ID3Frame *frame;
        ID3Field *field;
        char id3_title[64];
        char id3_singer[128];
        char id3_album[64];
        char id3_genre[64];
        
        if (access(file, R_OK))
                return;

        strcpy(fname, configs.home);
        strcat(fname, "music.db");
        
        if (!access(fname, R_OK))
                file_found = TRUE;

        rc = sqlite3_open(fname, &db);
        
        if (rc)
        {
                syslog(LOG_WARNING, "Error opening database %s: %s", fname, sqlite3_errmsg(db));
                return;
        }

        if (!file_found)
        {
                strcpy(query, "create table \"main\".\"musicdb\" (\"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,");
                strcat(query, "\"path\" TEXT NOT NULL DEFAULT (512), \"title\" TEXT DEFAULT (64), \"interpret\" TEXT DEFAULT (128),");
                strcat(query, "\"album\" TEXT DEFAULT (64), \"genre\" TEXT DEFAULT (64));");
                rc = sqlite3_exec(db, query, callback, (void *)"CREATE", &zErrMsg);

                if (rc != SQLITE_OK)
                {
                        syslog(LOG_WARNING, "SQL error: %s", zErrMsg);
                        sqlite3_free(zErrMsg);
                        sqlite3_close(db);
                        return;
                }
        }

        file_found = FALSE;
        // Make sure, the file is not already in the database
        sprintf(query, "select path from musicdb where path = \"%s\"", file);

        if ((rc = sqlite3_exec(db, query, callback, (void *)"EXIST", &zErrMsg)) != SQLITE_OK)
        {
                syslog(LOG_DAEMON, "SQL Error: %s", zErrMsg);
                sqlite3_free(zErrMsg);
                sqlite3_close(db);
                return;
        }

        if (file_found)                         // This is true, if the file is already in the database.
        {
                file_found = FALSE;
                sqlite3_close(db);
                return;
        }

        // Open the file and get the ID3 tag.
        id3 = ID3Tag_New();
        ID3Tag_Link(id3, file);
        memset(&id3_title, 0, sizeof(id3_title));
        memset(&id3_singer, 0, sizeof(id3_singer));
        memset(&id3_album, 0, sizeof(id3_album));
        memset(&id3_genre, 0, sizeof(id3_genre));
        // Get the required frames
        if ((frame = ID3Tag_FindFrameWithID(id3, ID3FID_TITLE)) != NULL)
        {
                field = ID3Frame_GetField(frame, ID3FN_TEXT);
                ID3Field_GetASCII(field, &id3_title[0], sizeof(id3_title));
        }

        if ((frame = ID3Tag_FindFrameWithID(id3, ID3FID_LEADARTIST)) != NULL)
        {
                field = ID3Frame_GetField(frame, ID3FN_TEXT);
                ID3Field_GetASCII(field, &id3_singer[0], sizeof(id3_singer));
        }

        if ((frame = ID3Tag_FindFrameWithID(id3, ID3FID_ALBUM)) != NULL)
        {
                field = ID3Frame_GetField(frame, ID3FN_TEXT);
                ID3Field_GetASCII(field, &id3_album[0], sizeof(id3_album));
        }

        if ((frame = ID3Tag_FindFrameWithID(id3, ID3FID_CONTENTTYPE)) != NULL)
        {
                field = ID3Frame_GetField(frame, ID3FN_TEXT);
                ID3Field_GetASCII(field, &id3_genre[0], sizeof(id3_genre));
        }

        strcpy (query, "insert into musicdb (\"path\", \"title\", \"interpret\", \"album\", \"genre\") values ");
        strcat (query, "(\"");
        strcat (query, file);
        strcat (query, "\", \"");
        strcat (query, id3_title);
        strcat (query, "\", \"");
        strcat (query, id3_singer);
        strcat (query, "\", \"");
        strcat (query, id3_album);
        strcat (query, "\", \"");
        strcat (query, id3_genre);
        strcat (query, "\")");

        if ((rc = sqlite3_exec(db, query, callback, (void *)"INSERT", &zErrMsg)) != SQLITE_OK)
        {
                syslog(LOG_DAEMON, "SQL Error: %s", zErrMsg);
                sqlite3_free(zErrMsg);
                sqlite3_close(db);
                return;
        }

        sqlite3_close(db);
}