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);
}