Your IP : 216.73.216.48
/*
* circular.cpp -- Circular lists handler module
*
* Copyright (C) 2004 Tony Sin(x) '76 <administrator@tortugalabs.it>
* All rights reserved.
*
*/
/*
* GNU GENERAL PUBLIC LICENSE
* Version 2, June 1991
*
* Copyright (C) 1989, 1991 Free Software Foundation, Inc.
* 675 Mass Ave, Cambridge, MA 02139, USA
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*
* 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-1307 USA
*
*/
#ifdef HAVE_CONFIG_H
#ifndef __main_config_h__
#define __main_config_h__
#include "../config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#ifdef HAVE_NDIR_H
#include <ndir.h>
#endif
#ifdef HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#ifdef HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#ifdef HAVE_MYSQL
#define NO_CLIENT_LONG_LONG
#include <mysql.h>
#endif
#ifdef HAVE_PGSQL
#include <libpq-fe.h>
#endif
#endif
#include <stdio.h>
#include "circular.h"
/* ****************************************************************************** */
/* Double-linked circular list handler */
/* ****************************************************************************** */
#ifdef HAVE_ID3
struct ID3TableType ID3Table[MAX_ID3_TAGS] = { { ID3FID_COMMENT, "ID3COMMENT" },
{ ID3FID_ALBUM, "ID3ALBUM" },
{ ID3FID_COMPOSER, "ID3COMPOSER" },
{ ID3FID_COPYRIGHT, "ID3COPYRIGHT" },
{ ID3FID_ENCODEDBY, "ID3ENCODEDBY" },
{ ID3FID_LYRICIST, "ID3LYRICIST" },
{ ID3FID_TITLE, "ID3TITLE" },
{ ID3FID_SUBTITLE, "ID3SUBTITLE" },
{ ID3FID_LEADARTIST, "ID3LEADARTIST" },
{ ID3FID_BAND, "ID3BAND" },
{ ID3FID_CONDUCTOR, "ID3CONDUCTOR" },
{ ID3FID_PUBLISHER, "ID3PUBLISHER" },
{ ID3FID_NETRADIOSTATION, "ID3NETRADIOSTATION" },
{ ID3FID_NETRADIOOWNER, "ID3NETRADIOOWNER" },
{ ID3FID_USERTEXT, "ID3USERTEXT" },
{ ID3FID_TERMSOFUSE, "ID3TERMSOFUSE" } };
#endif
cDoubleLinkedItem::cDoubleLinkedItem(const char *buf, unsigned char ofs)
{
Data = NULL;
Prev = Next = NULL;
#ifdef HAVE_ID3
int i;
for (i = 0; i < MAX_ID3_TAGS; i++)
{
ID3[i].ID3Type = ID3Table[i].ID3Type;
ID3[i].str = NULL;
}
#endif
Data = new char[strlen(buf)+1];
strcpy(Data,buf);
offset = ofs;
}
cDoubleLinkedItem::~cDoubleLinkedItem()
{
if (Data != NULL)
delete [] Data;
#ifdef HAVE_ID3
int i;
for (i = 0; i < MAX_ID3_TAGS; i++)
if (ID3[i].str != NULL)
{
delete [] ID3[i].str;
ID3[i].str = NULL;
}
#endif
}
void cDoubleLinkedItem::ConnectBefore(cDoubleLinkedItem *object)
{
Prev = object;
}
void cDoubleLinkedItem::ConnectAfter(cDoubleLinkedItem *object)
{
Next = object;
}
cDoubleLinkedItem * cDoubleLinkedItem::GetPrevious() const
{
return Prev;
}
cDoubleLinkedItem * cDoubleLinkedItem::GetNext() const
{
return Next;
}
void cDoubleLinkedItem::GetPath(char *buf)
{
if (offset != '\0')
strncpy(buf,Data,offset);
buf[offset] = '\0';
}
void cDoubleLinkedItem::GetFile(char *buf)
{
strncpy(buf,(Data+offset+1),strlen(Data)-offset);
}
char *cDoubleLinkedItem::GetData() const
{
return Data;
}
void cDoubleLinkedItem::SetData(const char *buf, unsigned char ofs)
{
if (Data != NULL)
delete [] Data;
Data = new char[strlen(buf)+1];
strcpy(Data,buf);
offset = ofs;
}
#ifdef HAVE_ID3
void cDoubleLinkedItem::LoadID3()
{
ID3_Tag *my_tag;
if ((Data != NULL) && (my_tag = new ID3_Tag))
{
ID3_Frame *my_frame;
ID3_Field *my_field;
int i;
char *temp;
my_tag->Link(Data);
temp = new char[255];
for (i = 0; i < MAX_ID3_TAGS; i++)
{
if ((my_frame = my_tag->Find(ID3[i].ID3Type)) != NULL)
{
if ((my_field = my_frame->GetField(ID3FN_TEXT)) != NULL)
{
bzero(temp,255);
my_field->Get(temp,255);
if (strlen(temp) > 0)
{
ID3[i].str = new char[strlen(temp)+1];
strcpy(ID3[i].str,temp);
}
my_field->Clear();
}
my_frame->Clear();
}
}
my_tag->Clear();
delete my_tag;
delete [] temp;
}
}
char *cDoubleLinkedItem::GetID3String(int i)
{
return ((i < MAX_ID3_TAGS)? ID3Table[i].str : NULL);
}
void cDoubleLinkedItem::GetID3Table(struct ID3TableType *ID3t)
{
int i;
for (i = 0; i < MAX_ID3_TAGS; i++)
{
if (ID3[i].str != NULL)
strcpy(ID3t[i].str,ID3[i].str);
else
ID3t[i].str[0] = '\0';
}
}
#endif
cCircularList::cCircularList()
{
Ptr = NULL;
int_buf = new char[INTERNAL_BUF_SIZE];
}
cCircularList::~cCircularList()
{
if (Ptr != NULL)
{
Ptr->GetPrevious()->ConnectAfter(NULL); // break chain
while (Ptr != NULL)
{
cDoubleLinkedItem *temp = Ptr;
StepFwd();
delete temp;
}
}
delete [] int_buf;
}
void cCircularList::Insert(cDoubleLinkedItem *object)
{
if (Ptr == NULL)
{
Ptr = object; // first element
Ptr->ConnectAfter(Ptr); // chain is closed in a loop
Ptr->ConnectBefore(Ptr);
}
else
{
/* NOTE: it connects after Ptr */
object->ConnectBefore(Ptr); // link to upper object
Ptr->GetNext()->ConnectBefore(object); // lower object link
object->ConnectAfter(Ptr->GetNext()); // link to lower object
Ptr->ConnectAfter(object); // upper object link
}
}
void cCircularList::Insert(const char *buf)
{
int i;
cDoubleLinkedItem *item;
for (i = strlen(buf)-1; ((i >= 0) && (buf[i] != '/')); i--);
if (i == -1)
i = 0;
item = new cDoubleLinkedItem(buf,((unsigned char) i));
Insert(item);
#ifdef HAVE_ID3
item->LoadID3();
#endif
}
cDoubleLinkedItem * cCircularList::Remove()
{
cDoubleLinkedItem *temp = Ptr;
if (Ptr != NULL)
if (Ptr->GetPrevious() == Ptr)
Ptr = NULL;
else
{
Ptr->GetPrevious()->ConnectAfter(Ptr->GetNext()); // bypass upper link
Ptr->GetNext()->ConnectBefore(Ptr->GetPrevious()); // bypass lower link
Ptr = Ptr->GetPrevious(); // point elsewhere
temp->ConnectBefore(NULL); // detach object from chain
temp->ConnectAfter(NULL);
}
return temp;
}
void cCircularList::StepFwd(int steps)
{
while (steps-- && (Ptr != NULL))
Ptr = Ptr->GetNext();
}
void cCircularList::StepRev(int steps)
{
while (steps-- && (Ptr != NULL))
Ptr = Ptr->GetPrevious();
}
void cCircularList::GetPath(char *buf)
{
Ptr->GetPath(buf);
}
void cCircularList::GetFile(char *buf)
{
Ptr->GetFile(buf);
}
char * cCircularList::GetData() const
{
return Ptr->GetData();
}
bool cCircularList::Empty() const
{
return (Ptr == NULL);
}
bool cCircularList::IsMedia(const char *buf, file_type ft) const
{
int len = strlen(buf);
bool result = false;
if (len > 4)
{
switch(ft)
{
case _mp3: result = ((buf[len-1] == '3') && (toupper(buf[len-2]) == 'P') && (toupper(buf[len-3]) == 'M'));
break;
case _ogg: result = ((toupper(buf[len-1]) == 'G') && (toupper(buf[len-2]) == 'G') && (toupper(buf[len-3]) == 'O'));
break;
case _unknown: break;
default: break;
}
result &= (buf[len-4] == '.');
}
return result;
}
bool cCircularList::FillWithPath(const char *buf, file_type ft, int recursive)
{
bool result = false;
char temp[255];
struct dirent *ptr;
DIR *fd;
fd = opendir(buf);
if (fd != NULL)
{
while ((ptr = readdir(fd)) != NULL)
if (strcmp(ptr->d_name,".") && strcmp(ptr->d_name,".."))
{
struct stat s;
strcpy(temp,buf);
if (temp[strlen(temp)-1] != '/')
strcat(temp,"/");
strcat(temp,ptr->d_name);
if (!stat(temp,&s))
{
if (recursive && S_ISDIR(s.st_mode))
result |= FillWithPath(temp,ft,recursive);
if (IsMedia(temp,ft))
{
result = true;
if (Ptr != NULL)
while (!HereFits(temp))
StepFwd();
Insert(temp);
}
}
}
closedir(fd);
}
return result;
}
bool cCircularList::GreaterThan(const char *s1, const char *s2) const
{
while ((*s1) && (*s2) && (toupper(*s1) == toupper(*s2)))
s1++, s2++;
return (toupper(*s1) >= toupper(*s2));
}
bool cCircularList::HereStarts() const
{
return ((Ptr == NULL) || GreaterThan(Ptr->GetData(),Ptr->GetNext()->GetData()));
}
bool cCircularList::HereFits(const char *buf) const
{
return ((Ptr != NULL) && (((!GreaterThan(Ptr->GetData(),buf)) && (GreaterThan(Ptr->GetNext()->GetData(),buf))) ||
((!GreaterThan(Ptr->GetData(),buf)) && (!GreaterThan(Ptr->GetNext()->GetData(),buf)) && HereStarts()) ||
((GreaterThan(Ptr->GetData(),buf)) && (GreaterThan(Ptr->GetNext()->GetData(),buf)) && HereStarts())));
}
void cCircularList::SetStart()
{
while (!HereStarts())
StepFwd();
}
#ifdef HAVE_MYSQL
bool cCircularList::FillWithMySQL(const char *host, unsigned int port, const char *user, const char *passwd,
const char *db, const char *table, const char *field)
{
MYSQL sql_obj;
MYSQL_RES *sql_query_rows;
MYSQL_ROW row;
bool result = false;
struct stat s;
if (mysql_init(&sql_obj) == NULL)
{
strcpy(ErrStr,"MySQL initialization error");
throw 0;
}
if (mysql_real_connect(&sql_obj,host,user,passwd,db,port,NULL,0) == NULL)
{
sprintf(ErrStr,"MySQL: %s",mysql_error(&sql_obj));
throw 0;
}
sprintf(int_buf,"SELECT %s FROM %s",field,table);
if (mysql_query(&sql_obj,int_buf))
{
sprintf(ErrStr,"MySQL: %s",mysql_error(&sql_obj));
throw 0;
}
if ((sql_query_rows = mysql_store_result(&sql_obj)) == NULL)
{
sprintf(ErrStr,"MySQL: %s",mysql_error(&sql_obj));
throw 0;
}
result = (mysql_num_rows(sql_query_rows) != 0);
while ((row = mysql_fetch_row(sql_query_rows)) != NULL)
if (!stat(((const char *) row[0]),&s))
{
result = true;
Insert((const char *) row[0]);
}
mysql_free_result(sql_query_rows);
mysql_close(&sql_obj);
return result;
}
#endif
#ifdef HAVE_PGSQL
bool cCircularList::FillWithPgSQL(const char *host, unsigned int port, const char *user, const char *passwd,
const char *db, const char *table, const char *field)
{
PGconn *sql_obj;
PGresult *sql_query_rows;
int row_idx, sql_query_num_rows;
bool result = false;
struct stat s;
if (port)
sprintf(int_buf,"host='%s' port='%d' user='%s' password='%s' dbname='%s'",host,port,user,passwd,db);
else
sprintf(int_buf,"host='%s' user='%s' password='%s' dbname='%s'",host,user,passwd,db);
sql_obj = PQconnectdb(int_buf);
if (PQstatus(sql_obj) == CONNECTION_OK)
{
sprintf(int_buf,"SELECT %s FROM %s",field,table);
sql_query_rows = PQexec(sql_obj,int_buf);
sql_query_num_rows = PQntuples(sql_query_rows);
for (row_idx = 0; row_idx < sql_query_num_rows; row_idx++)
{
strcpy(int_buf,PQgetvalue(sql_query_rows,row_idx,0));
if (!stat(int_buf,&s))
{
result = true;
Insert(int_buf);
}
}
PQclear(sql_query_rows);
}
PQfinish(sql_obj);
return result;
}
#endif
bool cCircularList::FillWithM3U(const char *m3u_filename)
{
bool result = false;
FILE *m3u_file;
struct stat s;
m3u_file = fopen(m3u_filename,"r");
while (fgets(int_buf,127,m3u_file))
{
int i;
if (int_buf[strlen(int_buf)-1] == '\n')
int_buf[strlen(int_buf)-1] = '\0';
for (i = 0; ((int_buf[i] != '\0') && (int_buf[i] == ' ')); i++);
if (!strncmp(&(int_buf[i]),"file://",7))
i += 7;
if ((int_buf[i] != '#') && (int_buf[i] != '\0') && (!stat(&(int_buf[i]),&s)))
{
result = true;
Insert(&(int_buf[i]));
}
int_buf[0] = '\0';
}
fclose(m3u_file);
return result;
}
bool cCircularList::FillWithPLS(const char *pls_filename)
{
bool result = false;
FILE *pls_file;
struct stat s;
pls_file = fopen(pls_filename,"r");
while (fgets(int_buf,127,pls_file))
{
int i;
if (int_buf[strlen(int_buf)-1] == '\n')
int_buf[strlen(int_buf)-1] = '\0';
for (i = 0; ((int_buf[i] != '\0') && (int_buf[i] == ' ')); i++);
if (!strncmp(&(int_buf[i]),"File",4))
for (; ((int_buf[i] != '\0') && (int_buf[i] != '=')); i++);
if (int_buf[i] != '\0')
i++;
if (!strncmp(&(int_buf[i]),"file://",7))
i += 7;
if ((int_buf[i] != '\0') && (!stat(&(int_buf[i]),&s)))
{
result = true;
Insert(&(int_buf[i]));
}
int_buf[0] = '\0';
}
fclose(pls_file);
return result;
}
void cCircularList::ParsePlayList(cConfig *object)
{
char *parsed_strs[20], *str_ptr;
struct stat temp_stat;
int i = 0, strs_ind = 1;
parsed_strs[0] = new char[4];
strcpy(parsed_strs[0],strtok(object->GetValue(_mp3path),":"));
while ((parsed_strs[0][i] = toupper(parsed_strs[0][i])))
i++;
while ((str_ptr = strtok(NULL,";")) != NULL)
{
parsed_strs[strs_ind] = new char[strlen(str_ptr)+1];
strcpy(parsed_strs[strs_ind++],str_ptr);
}
if (!strcmp(parsed_strs[0],"PTH"))
{
for (i = 1; i < strs_ind; i++)
if (stat(parsed_strs[i],&temp_stat) != -1)
FillWithPath(parsed_strs[i],((atoi(object->GetValue(_format)))? _mp3 : _ogg),((object->GetValue(_recurse) != NULL) && atoi(object->GetValue(_recurse))));
}
else if (!strcmp(parsed_strs[0],"SQL"))
{
#ifdef HAVE_MYSQL
if (strs_ind == 8)
FillWithMySQL(parsed_strs[1],atoi(parsed_strs[2]),parsed_strs[3],parsed_strs[4],
parsed_strs[5],parsed_strs[6],parsed_strs[7]);
#endif
}
else if (!strcmp(parsed_strs[0],"PQL"))
{
#ifdef HAVE_PGSQL
if (strs_ind == 8)
FillWithPgSQL(parsed_strs[1],atoi(parsed_strs[2]),parsed_strs[3],parsed_strs[4],
parsed_strs[5],parsed_strs[6],parsed_strs[7]);
#endif
}
else if (!strcmp(parsed_strs[0],"M3U"))
FillWithM3U(parsed_strs[1]);
else if (!strcmp(parsed_strs[0],"PLS"))
FillWithPLS(parsed_strs[1]);
for (i = 0; i < strs_ind; i++)
delete [] parsed_strs[i];
}
#ifdef HAVE_ID3
void cCircularList::GetID3Table(struct ID3TableType *ID3t)
{
Ptr->GetID3Table(ID3t);
}
#endif
/* ****************************************************************************** */