Switch to the new database code

This commit is contained in:
Julien BLACHE 2009-06-07 18:58:02 +02:00
parent f2c677462b
commit a200703393
16 changed files with 334 additions and 432 deletions

View File

@ -31,9 +31,7 @@ options {
#include <errno.h> #include <errno.h>
#include "logger.h" #include "logger.h"
#include "ff-dbstruct.h" #include "db.h"
#include "db-generic.h"
#include "db-sql.h"
#include "daap_query.h" #include "daap_query.h"
} }
@ -217,7 +215,7 @@ expr returns [ pANTLR3_STRING result, int valid ]
goto STR_result_valid_0; /* ABORT */ goto STR_result_valid_0; /* ABORT */
} }
escaped = (pANTLR3_UINT8)db_sql_escape_dup("\%q", val); escaped = (pANTLR3_UINT8)db_escape_string((char *)val);
if (!escaped) if (!escaped)
{ {
DPRINTF(E_LOG, L_DAAP, "Could not escape value\n"); DPRINTF(E_LOG, L_DAAP, "Could not escape value\n");

View File

@ -24,6 +24,7 @@ ANTLR_PRODUCTS =
mt_daapd_CPPFLAGS = -D_GNU_SOURCE @AVAHI_CFLAGS@ @SQLITE3_CFLAGS@ @FFMPEG_CFLAGS@ @CONFUSE_CFLAGS@ @TAGLIB_CFLAGS@ @MINIXML_CFLAGS@ mt_daapd_CPPFLAGS = -D_GNU_SOURCE @AVAHI_CFLAGS@ @SQLITE3_CFLAGS@ @FFMPEG_CFLAGS@ @CONFUSE_CFLAGS@ @TAGLIB_CFLAGS@ @MINIXML_CFLAGS@
mt_daapd_LDADD = @AVAHI_LIBS@ @SQLITE3_LIBS@ @FFMPEG_LIBS@ @CONFUSE_LIBS@ @FLAC_LIBS@ @TAGLIB_LIBS@ @LIBEVENT_LIBS@ @LIBAVL_LIBS@ @MINIXML_LIBS@ @ANTLR3C_LIBS@ mt_daapd_LDADD = @AVAHI_LIBS@ @SQLITE3_LIBS@ @FFMPEG_LIBS@ @CONFUSE_LIBS@ @FLAC_LIBS@ @TAGLIB_LIBS@ @LIBEVENT_LIBS@ @LIBAVL_LIBS@ @MINIXML_LIBS@ @ANTLR3C_LIBS@
mt_daapd_SOURCES = main.c \ mt_daapd_SOURCES = main.c \
db.c db.h \
logger.c logger.h \ logger.c logger.h \
conffile.c conffile.h \ conffile.c conffile.h \
filescanner.c filescanner.h \ filescanner.c filescanner.h \
@ -38,10 +39,7 @@ mt_daapd_SOURCES = main.c \
misc.c misc.h \ misc.c misc.h \
rsp_query.c rsp_query.h \ rsp_query.c rsp_query.h \
daap_query.c daap_query.h \ daap_query.c daap_query.h \
db-generic.c db-generic.h \
scan-wma.c \ scan-wma.c \
db-sql-updates.c \
db-sql.c db-sql.h db-sql-sqlite3.c db-sql-sqlite3.h\
$(FLACSRC) $(MUSEPACKSRC) $(FLACSRC) $(MUSEPACKSRC)
nodist_mt_daapd_SOURCES = \ nodist_mt_daapd_SOURCES = \
@ -50,9 +48,7 @@ nodist_mt_daapd_SOURCES = \
EXTRA_DIST = \ EXTRA_DIST = \
$(ANTLR_GRAMMARS) \ $(ANTLR_GRAMMARS) \
scan-mpc.c \ scan-mpc.c \
scan-flac.c \ scan-flac.c
ff-dbstruct.h
# Let's help the dependencies a little. # Let's help the dependencies a little.
rsp_query.c: RSPLexer.h RSPParser.h RSP2SQL.h rsp_query.c: RSPLexer.h RSPParser.h RSP2SQL.h

View File

@ -32,9 +32,7 @@ options {
#include <time.h> #include <time.h>
#include "logger.h" #include "logger.h"
#include "ff-dbstruct.h" #include "db.h"
#include "db-generic.h"
#include "db-sql.h"
#include "misc.h" #include "misc.h"
#include "rsp_query.h" #include "rsp_query.h"
} }
@ -181,7 +179,7 @@ strcrit returns [ pANTLR3_STRING result, int valid ]
goto strcrit_valid_0; /* ABORT */ goto strcrit_valid_0; /* ABORT */
} }
escaped = db_sql_escape_dup("\%q", $s->getText($s)->chars); escaped = db_escape_string((char *)$s->getText($s)->chars);
if (!escaped) if (!escaped)
{ {
DPRINTF(E_LOG, L_RSP, "Could not escape value\n"); DPRINTF(E_LOG, L_RSP, "Could not escape value\n");

View File

@ -43,7 +43,7 @@
#include <avl.h> #include <avl.h>
#include "logger.h" #include "logger.h"
#include "db-generic.h" #include "db.h"
#include "filescanner.h" #include "filescanner.h"
#include "conffile.h" #include "conffile.h"
@ -144,55 +144,6 @@ pop_dir(void)
return ret; return ret;
} }
static void
free_mfi(struct media_file_info *mfi)
{
if (mfi->path)
free(mfi->path);
if (mfi->fname)
free(mfi->fname);
if (mfi->title)
free(mfi->title);
if (mfi->artist)
free(mfi->artist);
if (mfi->album)
free(mfi->album);
if (mfi->genre)
free(mfi->genre);
if (mfi->comment)
free(mfi->comment);
if (mfi->type)
free(mfi->type);
if (mfi->composer)
free(mfi->composer);
if (mfi->orchestra)
free(mfi->orchestra);
if (mfi->conductor)
free(mfi->conductor);
if (mfi->grouping)
free(mfi->grouping);
if (mfi->description)
free(mfi->description);
if (mfi->codectype)
free(mfi->codectype);
if (mfi->album_artist)
free(mfi->album_artist);
}
static void static void
fixup_tags(struct media_file_info *mfi) fixup_tags(struct media_file_info *mfi)
@ -256,32 +207,42 @@ fixup_tags(struct media_file_info *mfi)
static void static void
process_media_file(char *file, time_t mtime, off_t size, int compilation) process_media_file(char *file, time_t mtime, off_t size, int compilation)
{ {
struct media_file_info *db_mfi;
struct media_file_info *mfi; struct media_file_info *mfi;
char *filename; char *filename;
char *ext; char *ext;
int need_update; int need_update;
int ret; int ret;
db_mfi = db_fetch_path(NULL, file, 0); mfi = db_file_fetch_bypath(file);
need_update = (!db_mfi || (db_mfi->db_timestamp < mtime) || db_mfi->force_update); need_update = (!mfi || (mfi->db_timestamp < mtime) || mfi->force_update);
db_dispose_item(db_mfi);
if (!need_update) if (!need_update)
return; {
db_file_ping(mfi->id);
free_mfi(mfi, 0);
return;
}
if (mfi)
{
ret = mfi->id;
free_mfi(mfi, 1);
}
else
{
ret = 0;
mfi = (struct media_file_info *)malloc(sizeof(struct media_file_info)); mfi = (struct media_file_info *)malloc(sizeof(struct media_file_info));
if (!mfi) if (!mfi)
{ {
DPRINTF(E_WARN, L_SCAN, "Out of memory for media_file_info\n"); DPRINTF(E_WARN, L_SCAN, "Out of memory for media_file_info\n");
db_dispose_item(db_mfi);
return; return;
} }
}
memset(mfi, 0, sizeof(struct media_file_info)); memset(mfi, 0, sizeof(struct media_file_info));
mfi->id = ret;
filename = strrchr(file, '/'); filename = strrchr(file, '/');
if (!filename) if (!filename)
@ -340,8 +301,7 @@ process_media_file(char *file, time_t mtime, off_t size, int compilation)
{ {
DPRINTF(E_LOG, L_SCAN, "Could not extract metadata for %s\n"); DPRINTF(E_LOG, L_SCAN, "Could not extract metadata for %s\n");
free_mfi(mfi); free_mfi(mfi, 0);
free(mfi);
return; return;
} }
@ -350,10 +310,12 @@ process_media_file(char *file, time_t mtime, off_t size, int compilation)
fixup_tags(mfi); fixup_tags(mfi);
db_add(NULL, mfi, NULL); if (mfi->id == 0)
db_file_add(mfi);
else
db_file_update(mfi);
free_mfi(mfi); free_mfi(mfi, 0);
free(mfi);
} }
static void static void
@ -669,6 +631,8 @@ bulk_scan(void)
} }
} }
db_pl_update_all();
if (playlists) if (playlists)
process_deferred_playlists(); process_deferred_playlists();
@ -681,10 +645,22 @@ bulk_scan(void)
static void * static void *
filescanner(void *arg) filescanner(void *arg)
{ {
int ret;
ret = db_perthread_init();
if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Error: DB init failed\n");
pthread_exit(NULL);
}
bulk_scan(); bulk_scan();
if (!scan_exit) if (!scan_exit)
{ {
db_pl_update_all();
/* Enable inotify */ /* Enable inotify */
event_add(&inoev, NULL); event_add(&inoev, NULL);
@ -694,6 +670,8 @@ filescanner(void *arg)
if (!scan_exit) if (!scan_exit)
DPRINTF(E_FATAL, L_SCAN, "Scan event loop terminated ahead of time!\n"); DPRINTF(E_FATAL, L_SCAN, "Scan event loop terminated ahead of time!\n");
db_perthread_deinit();
pthread_exit(NULL); pthread_exit(NULL);
} }

View File

@ -2,7 +2,7 @@
#ifndef __FILESCANNER_H__ #ifndef __FILESCANNER_H__
#define __FILESCANNER_H__ #define __FILESCANNER_H__
#include "ff-dbstruct.h" #include "db.h"
int int
filescanner_init(void); filescanner_init(void);

View File

@ -41,12 +41,12 @@
/* Legacy format-specific scanners */ /* Legacy format-specific scanners */
extern int scan_get_wmainfo(char *filename, MP3FILE *pmp3); extern int scan_get_wmainfo(char *filename, struct media_file_info *pmp3);
#ifdef FLAC #ifdef FLAC
extern int scan_get_flacinfo(char *filename, MP3FILE *pmp3); extern int scan_get_flacinfo(char *filename, struct media_file_info *pmp3);
#endif #endif
#ifdef MUSEPACK #ifdef MUSEPACK
extern int scan_get_mpcinfo(char *filename, MP3FILE *pmp3); extern int scan_get_mpcinfo(char *filename, struct media_file_info *pmp3);
#endif #endif

View File

@ -34,8 +34,7 @@
#include <errno.h> #include <errno.h>
#include "logger.h" #include "logger.h"
#include "ff-dbstruct.h" #include "db.h"
#include "db-generic.h"
#include "filescanner.h" #include "filescanner.h"
@ -44,7 +43,6 @@ scan_m3u_playlist(char *file)
{ {
FILE *fp; FILE *fp;
struct playlist_info *pli; struct playlist_info *pli;
struct media_file_info *mfi;
struct stat sb; struct stat sb;
char buf[PATH_MAX]; char buf[PATH_MAX];
char rel_entry[PATH_MAX]; char rel_entry[PATH_MAX];
@ -52,9 +50,9 @@ scan_m3u_playlist(char *file)
char *entry; char *entry;
char *filename; char *filename;
char *ptr; char *ptr;
char *db_errmsg;
size_t len; size_t len;
int pl_id; int pl_id;
int mf_id;
int ret; int ret;
DPRINTF(E_INFO, L_SCAN, "Processing static playlist: %s\n", file); DPRINTF(E_INFO, L_SCAN, "Processing static playlist: %s\n", file);
@ -73,7 +71,7 @@ scan_m3u_playlist(char *file)
else else
filename++; filename++;
pli = db_fetch_playlist(NULL, file, 0); pli = db_pl_fetch_bypath(file);
if (pli) if (pli)
{ {
@ -81,15 +79,17 @@ scan_m3u_playlist(char *file)
{ {
DPRINTF(E_DBG, L_SCAN, "Playlist up-to-date\n"); DPRINTF(E_DBG, L_SCAN, "Playlist up-to-date\n");
db_dispose_playlist(pli); db_pl_ping(pli->id);
free_pli(pli, 0);
return; return;
} }
else else
{ {
DPRINTF(E_DBG, L_SCAN, "Playlist needs update\n"); DPRINTF(E_DBG, L_SCAN, "Playlist needs update\n");
db_delete_playlist(NULL, pli->id); db_pl_delete(pli->id);
db_dispose_playlist(pli); free_pli(pli, 0);
} }
} }
@ -113,13 +113,11 @@ scan_m3u_playlist(char *file)
if (ptr) if (ptr)
*ptr = '.'; *ptr = '.';
ret = db_add_playlist(&db_errmsg, buf, PL_STATICFILE, NULL, file, 0, &pl_id); ret = db_pl_add(buf, file, &pl_id);
if (ret < 0)
if (ret != DB_E_SUCCESS)
{ {
DPRINTF(E_LOG, L_SCAN, "Error adding m3u playlist '%s': %s\n", file, db_errmsg); DPRINTF(E_LOG, L_SCAN, "Error adding m3u playlist '%s'\n", file);
free(db_errmsg);
return; return;
} }
@ -197,19 +195,19 @@ scan_m3u_playlist(char *file)
DPRINTF(E_DBG, L_SCAN, "Checking %s\n", filename); DPRINTF(E_DBG, L_SCAN, "Checking %s\n", filename);
mfi = db_fetch_path(&db_errmsg, filename, 0); ret = db_file_id_bypath(filename, &mf_id);
if (!mfi) if (ret < 0)
{ {
DPRINTF(E_WARN, L_SCAN, "Playlist entry '%s' not found: %s\n", entry, db_errmsg); DPRINTF(E_WARN, L_SCAN, "Playlist entry '%s' not found\n", entry);
free(db_errmsg);
free(filename); free(filename);
continue; continue;
} }
DPRINTF(E_DBG, L_SCAN, "Resolved %s to %d\n", filename, mfi->id); DPRINTF(E_DBG, L_SCAN, "Resolved %s to %d\n", filename, mf_id);
db_add_playlist_item(NULL, pl_id, mfi->id); ret = db_pl_add_item(pl_id, mf_id);
db_dispose_item(mfi); if (ret < 0)
DPRINTF(E_WARN, L_SCAN, "Could not add %s to playlist\n", filename);
} }
if (!feof(fp)) if (!feof(fp))
@ -222,5 +220,7 @@ scan_m3u_playlist(char *file)
fclose(fp); fclose(fp);
db_pl_update(pl_id);
DPRINTF(E_INFO, L_SCAN, "Done processing playlist\n"); DPRINTF(E_INFO, L_SCAN, "Done processing playlist\n");
} }

View File

@ -31,7 +31,7 @@
#include <errno.h> #include <errno.h>
#include "logger.h" #include "logger.h"
#include "ff-dbstruct.h" #include "db.h"
#include "filescanner.h" #include "filescanner.h"

View File

@ -35,8 +35,7 @@
#include "evhttp/evhttp.h" #include "evhttp/evhttp.h"
#include "logger.h" #include "logger.h"
#include "ff-dbstruct.h" #include "db.h"
#include "db-generic.h"
#include "conffile.h" #include "conffile.h"
#include "misc.h" #include "misc.h"
#include "httpd.h" #include "httpd.h"
@ -199,7 +198,7 @@ stream_chunk_xcode_cb(int fd, short event, void *arg)
if (!st->marked && (st->offset > ((st->size * 80) / 100))) if (!st->marked && (st->offset > ((st->size * 80) / 100)))
{ {
st->marked = 1; st->marked = 1;
db_playcount_increment(NULL, st->id); db_file_inc_playcount(st->id);
} }
return; return;
@ -245,7 +244,7 @@ stream_chunk_raw_cb(int fd, short event, void *arg)
if (!st->marked && (st->offset > ((st->size * 80) / 100))) if (!st->marked && (st->offset > ((st->size * 80) / 100)))
{ {
st->marked = 1; st->marked = 1;
db_playcount_increment(NULL, st->id); db_file_inc_playcount(st->id);
} }
} }
@ -302,7 +301,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
} }
} }
mfi = db_fetch_item(NULL, id); mfi = db_file_fetch_byid(id);
if (!mfi) if (!mfi)
{ {
DPRINTF(E_LOG, L_HTTPD, "Item %d not found\n", id); DPRINTF(E_LOG, L_HTTPD, "Item %d not found\n", id);
@ -315,7 +314,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
{ {
evhttp_send_error(req, 500, "Cannot stream radio station"); evhttp_send_error(req, 500, "Cannot stream radio station");
db_dispose_item(mfi); free_mfi(mfi, 0);
return; return;
} }
@ -326,7 +325,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error"); evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
db_dispose_item(mfi); free_mfi(mfi, 0);
return; return;
} }
memset(st, 0, sizeof(struct stream_ctx)); memset(st, 0, sizeof(struct stream_ctx));
@ -348,7 +347,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error"); evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
free(st); free(st);
db_dispose_item(mfi); free_mfi(mfi, 0);
return; return;
} }
@ -370,7 +369,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
evhttp_send_error(req, HTTP_NOTFOUND, "Not Found"); evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");
free(st); free(st);
db_dispose_item(mfi); free_mfi(mfi, 0);
return; return;
} }
@ -383,7 +382,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
close(st->fd); close(st->fd);
free(st); free(st);
db_dispose_item(mfi); free_mfi(mfi, 0);
return; return;
} }
st->size = sb.st_size; st->size = sb.st_size;
@ -397,7 +396,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
close(st->fd); close(st->fd);
free(st); free(st);
db_dispose_item(mfi); free_mfi(mfi, 0);
return; return;
} }
st->offset = offset; st->offset = offset;
@ -425,7 +424,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
else else
close(st->fd); close(st->fd);
free(st); free(st);
db_dispose_item(mfi); free_mfi(mfi, 0);
return; return;
} }
@ -443,7 +442,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
close(st->fd); close(st->fd);
evbuffer_free(st->evbuf); evbuffer_free(st->evbuf);
free(st); free(st);
db_dispose_item(mfi); free_mfi(mfi, 0);
return; return;
} }
@ -464,7 +463,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
close(st->fd); close(st->fd);
evbuffer_free(st->evbuf); evbuffer_free(st->evbuf);
free(st); free(st);
db_dispose_item(mfi); free_mfi(mfi, 0);
return; return;
} }
@ -494,7 +493,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
DPRINTF(E_INFO, L_HTTPD, "Kicking off streaming for %s\n", mfi->path); DPRINTF(E_INFO, L_HTTPD, "Kicking off streaming for %s\n", mfi->path);
db_dispose_item(mfi); free_mfi(mfi, 0);
} }
/* Thread: httpd */ /* Thread: httpd */
@ -745,11 +744,23 @@ httpd_gen_cb(struct evhttp_request *req, void *arg)
static void * static void *
httpd(void *arg) httpd(void *arg)
{ {
int ret;
ret = db_perthread_init();
if (ret < 0)
{
DPRINTF(E_LOG, L_HTTPD, "Error: DB init failed\n");
pthread_exit(NULL);
}
event_base_dispatch(evbase_httpd); event_base_dispatch(evbase_httpd);
if (!httpd_exit) if (!httpd_exit)
DPRINTF(E_FATAL, L_HTTPD, "HTTPd event loop terminated ahead of time!\n"); DPRINTF(E_FATAL, L_HTTPD, "HTTPd event loop terminated ahead of time!\n");
db_perthread_deinit();
pthread_exit(NULL); pthread_exit(NULL);
} }

View File

@ -26,6 +26,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <errno.h> #include <errno.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/types.h> #include <sys/types.h>
@ -39,8 +40,7 @@
#include <avl.h> #include <avl.h>
#include "logger.h" #include "logger.h"
#include "ff-dbstruct.h" #include "db.h"
#include "db-generic.h"
#include "conffile.h" #include "conffile.h"
#include "misc.h" #include "misc.h"
#include "httpd.h" #include "httpd.h"
@ -569,16 +569,18 @@ dmap_find_field(uint32_t hash)
return (struct dmap_field_map *)node->item; return (struct dmap_field_map *)node->item;
} }
static void static void
get_query_params(struct evkeyvalq *query, DBQUERYINFO *qi) get_query_params(struct evkeyvalq *query, struct query_params *qp)
{ {
const char *param; const char *param;
char *ptr; char *ptr;
int val; int low;
int high;
int ret; int ret;
qi->index_low = 0; low = 0;
qi->index_high = 9999999; /* Arbitrarily high number */ high = -1; /* No limit */
param = evhttp_find_header(query, "index"); param = evhttp_find_header(query, "index");
if (param) if (param)
@ -587,38 +589,40 @@ get_query_params(struct evkeyvalq *query, DBQUERYINFO *qi)
DPRINTF(E_LOG, L_DAAP, "Unsupported index range: %s\n", param); DPRINTF(E_LOG, L_DAAP, "Unsupported index range: %s\n", param);
else else
{ {
ret = safe_atoi(param, &val); ret = safe_atoi(param, &low);
if (ret < 0) if (ret < 0)
DPRINTF(E_LOG, L_DAAP, "Could not parse index range: %s\n", param); DPRINTF(E_LOG, L_DAAP, "Could not parse index range: %s\n", param);
else else
{ {
qi->index_low = val;
ptr = strchr(param, '-'); ptr = strchr(param, '-');
if (!ptr) /* single item */ if (!ptr) /* single item */
qi->index_high = qi->index_low; high = low;
else else
{ {
ptr++; ptr++;
if (*ptr != '\0') /* low-high */ if (*ptr != '\0') /* low-high */
{ {
ret = safe_atoi(ptr, &val); ret = safe_atoi(ptr, &high);
if (ret < 0) if (ret < 0)
DPRINTF(E_LOG, L_DAAP, "Could not parse high index in range: %s\n", param); DPRINTF(E_LOG, L_DAAP, "Could not parse high index in range: %s\n", param);
}
}
}
}
DPRINTF(E_DBG, L_DAAP, "Index range %s: low %d, high %d (offset %d, limit %d)\n", param, low, high, qp->offset, qp->limit);
}
if (high < low)
high = -1; /* No limit */
qp->offset = low;
if (high < 0)
qp->limit = -1; /* No limit */
else else
qi->index_high = val; qp->limit = (high - low) + 1;
}
}
}
}
DPRINTF(E_DBG, L_DAAP, "Index range %s: low %d, high %d\n", param, qi->index_low, qi->index_high); qp->idx_type = I_SUB;
}
if (qi->index_high < qi->index_low)
qi->index_high = 9999999; /* Arbitrarily high number */
qi->index_type = indexTypeSub;
param = evhttp_find_header(query, "query"); param = evhttp_find_header(query, "query");
if (!param) if (!param)
@ -628,13 +632,10 @@ get_query_params(struct evkeyvalq *query, DBQUERYINFO *qi)
{ {
DPRINTF(E_DBG, L_DAAP, "DAAP browse query filter: %s\n", param); DPRINTF(E_DBG, L_DAAP, "DAAP browse query filter: %s\n", param);
qi->filter = daap_query_parse_sql(param); qp->filter = daap_query_parse_sql(param);
if (!qi->filter) if (!qp->filter)
DPRINTF(E_LOG, L_DAAP, "Ignoring improper DAAP query\n"); DPRINTF(E_LOG, L_DAAP, "Ignoring improper DAAP query\n");
} }
qi->want_count = 1;
qi->correct_order = 1;
} }
static void static void
@ -879,7 +880,7 @@ daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
{ {
int ret; int ret;
/* Just send back the current db revision. /* Just send back the current time.
* *
* This probably doesn't cut it, but then again we don't claim to support * This probably doesn't cut it, but then again we don't claim to support
* updates, so... that support should be added eventually. * updates, so... that support should be added eventually.
@ -896,7 +897,7 @@ daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
dmap_add_container(evbuf, "mupd", 24); dmap_add_container(evbuf, "mupd", 24);
dmap_add_int(evbuf, "mstt", 200); /* 12 */ dmap_add_int(evbuf, "mstt", 200); /* 12 */
dmap_add_int(evbuf, "musr", db_revision()); /* 12 */ dmap_add_int(evbuf, "musr", (int)time(NULL)); /* 12 */
evhttp_send_reply(req, HTTP_OK, "OK", evbuf); evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
} }
@ -904,12 +905,10 @@ daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
static void static void
daap_reply_dblist(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) daap_reply_dblist(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{ {
int count;
cfg_t *lib; cfg_t *lib;
char *db_errmsg;
char *name; char *name;
int namelen; int namelen;
int count;
int ret; int ret;
lib = cfg_getnsec(cfg, "library", 0); lib = cfg_getnsec(cfg, "library", 0);
@ -936,23 +935,21 @@ daap_reply_dblist(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
dmap_add_long(evbuf, "mper", 1); /* 16 */ dmap_add_long(evbuf, "mper", 1); /* 16 */
dmap_add_string(evbuf, "minm", name); /* 8 + namelen */ dmap_add_string(evbuf, "minm", name); /* 8 + namelen */
ret = db_get_song_count(&db_errmsg, &count); ret = db_files_get_count(&count);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DAAP, "Could not get song count: %s\n", db_errmsg); DPRINTF(E_LOG, L_DAAP, "Could not get song count\n");
count = 0; count = 0;
free(db_errmsg);
} }
dmap_add_int(evbuf, "mimc", count); /* 12 */ dmap_add_int(evbuf, "mimc", count); /* 12 */
ret = db_get_playlist_count(&db_errmsg, &count); ret = db_pl_get_count(&count);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DAAP, "Could not get playlist count: %s\n", db_errmsg); DPRINTF(E_LOG, L_DAAP, "Could not get playlist count\n");
count = 0; count = 0;
free(db_errmsg);
} }
dmap_add_int(evbuf, "mctc", count); /* 12 */ dmap_add_int(evbuf, "mctc", count); /* 12 */
@ -962,12 +959,11 @@ daap_reply_dblist(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
static void static void
daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf, int playlist, struct evkeyvalq *query) daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf, int playlist, struct evkeyvalq *query)
{ {
DBQUERYINFO qi; struct query_params qp;
struct db_media_file_info *dbmfi; struct db_media_file_info dbmfi;
struct evbuffer *song; struct evbuffer *song;
struct evbuffer *songlist; struct evbuffer *songlist;
struct dmap_field_map *dfm; struct dmap_field_map *dfm;
char *db_errmsg;
const char *param; const char *param;
char *tag; char *tag;
char **strval; char **strval;
@ -1071,26 +1067,29 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
nmeta = 0; nmeta = 0;
} }
memset(&qi, 0, sizeof(DBQUERYINFO)); memset(&qp, 0, sizeof(struct query_params));
get_query_params(query, &qi); get_query_params(query, &qp);
qi.query_type = queryTypePlaylistItems;
if (playlist != -1) if (playlist < 2)
qi.playlist_id = playlist; qp.type = Q_ITEMS;
else
ret = db_enum_start(&db_errmsg, &qi);
if (ret != DB_E_SUCCESS)
{ {
DPRINTF(E_LOG, L_DAAP, "Could not fetch song list: %s\n", db_errmsg); qp.type = Q_PLITEMS;
qp.pl_id = playlist;
}
daap_send_error(req, tag, db_errmsg); ret = db_query_start(&qp);
if (ret < 0)
{
DPRINTF(E_LOG, L_DAAP, "Could not start query\n");
daap_send_error(req, tag, "Could not stat query");
free(db_errmsg);
free(meta); free(meta);
evbuffer_free(song); evbuffer_free(song);
evbuffer_free(songlist); evbuffer_free(songlist);
if (qi.filter) if (qp.filter)
free(qi.filter); free(qp.filter);
return; return;
} }
@ -1098,11 +1097,11 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
want_asdk = 0; want_asdk = 0;
oom = 0; oom = 0;
nsongs = 0; nsongs = 0;
while (((ret = db_enum_fetch_row(&db_errmsg, &dbmfi, &qi)) == DB_E_SUCCESS) && (dbmfi)) while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
{ {
nsongs++; nsongs++;
transcode = transcode_needed(req->input_headers, dbmfi->codectype); transcode = transcode_needed(req->input_headers, dbmfi.codectype);
i = -1; i = -1;
while (1) while (1)
@ -1151,7 +1150,7 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
DPRINTF(E_DBG, L_DAAP, "Investigating %s\n", dfm->desc); DPRINTF(E_DBG, L_DAAP, "Investigating %s\n", dfm->desc);
strval = (char **) ((char *)dbmfi + dfm->mfi_offset); strval = (char **) ((char *)&dbmfi + dfm->mfi_offset);
if (!(*strval) || (**strval == '\0')) if (!(*strval) || (**strval == '\0'))
continue; continue;
@ -1174,7 +1173,7 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
case dbmfi_offsetof(bitrate): case dbmfi_offsetof(bitrate):
val = 0; val = 0;
ret = safe_atoi(dbmfi->samplerate, &val); ret = safe_atoi(dbmfi.samplerate, &val);
if ((ret < 0) || (val == 0)) if ((ret < 0) || (val == 0))
val = 1411; val = 1411;
else else
@ -1220,14 +1219,14 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
if (want_mikd) if (want_mikd)
{ {
/* dmap.itemkind must come first */ /* dmap.itemkind must come first */
ret = safe_atoi(dbmfi->item_kind, &val); ret = safe_atoi(dbmfi.item_kind, &val);
if (ret < 0) if (ret < 0)
val = 2; /* music by default */ val = 2; /* music by default */
dmap_add_char(songlist, "mikd", val); dmap_add_char(songlist, "mikd", val);
} }
if (want_asdk) if (want_asdk)
{ {
ret = safe_atoi(dbmfi->data_kind, &val); ret = safe_atoi(dbmfi.data_kind, &val);
if (ret < 0) if (ret < 0)
val = 0; val = 0;
dmap_add_char(songlist, "asdk", val); dmap_add_char(songlist, "asdk", val);
@ -1248,34 +1247,25 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
evbuffer_free(song); evbuffer_free(song);
if (qi.filter) if (qp.filter)
free(qi.filter); free(qp.filter);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DAAP, "Error fetching results: %s\n", db_errmsg); DPRINTF(E_LOG, L_DAAP, "Error fetching results\n");
daap_send_error(req, tag, db_errmsg); daap_send_error(req, tag, "Error fetching query results");
db_query_end(&qp);
free(db_errmsg);
evbuffer_free(songlist); evbuffer_free(songlist);
return; return;
} }
ret = db_enum_end(&db_errmsg);
if (ret != DB_E_SUCCESS)
{
DPRINTF(E_LOG, L_DAAP, "Error cleaning up DB enum: %s\n", db_errmsg);
free(db_errmsg);
}
if (oom) if (oom)
{ {
DPRINTF(E_LOG, L_DAAP, "Could not add song to song list for DAAP song list reply\n"); DPRINTF(E_LOG, L_DAAP, "Could not add song to song list for DAAP song list reply\n");
daap_send_error(req, tag, "Out of memory"); daap_send_error(req, tag, "Out of memory");
db_query_end(&qp);
evbuffer_free(songlist); evbuffer_free(songlist);
return; return;
} }
@ -1284,10 +1274,12 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
dmap_add_container(evbuf, tag, EVBUFFER_LENGTH(songlist) + 53); dmap_add_container(evbuf, tag, EVBUFFER_LENGTH(songlist) + 53);
dmap_add_int(evbuf, "mstt", 200); /* 12 */ dmap_add_int(evbuf, "mstt", 200); /* 12 */
dmap_add_char(evbuf, "muty", 0); /* 9 */ dmap_add_char(evbuf, "muty", 0); /* 9 */
dmap_add_int(evbuf, "mtco", qi.specifiedtotalcount); /* 12 */ dmap_add_int(evbuf, "mtco", qp.results); /* 12 */
dmap_add_int(evbuf, "mrco", nsongs); /* 12 */ dmap_add_int(evbuf, "mrco", nsongs); /* 12 */
dmap_add_container(evbuf, "mlcl", EVBUFFER_LENGTH(songlist)); dmap_add_container(evbuf, "mlcl", EVBUFFER_LENGTH(songlist));
db_query_end(&qp);
ret = evbuffer_add_buffer(evbuf, songlist); ret = evbuffer_add_buffer(evbuf, songlist);
evbuffer_free(songlist); evbuffer_free(songlist);
if (ret < 0) if (ret < 0)
@ -1327,13 +1319,12 @@ daap_reply_plsonglist(struct evhttp_request *req, struct evbuffer *evbuf, char *
static void static void
daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{ {
DBQUERYINFO qi; struct query_params qp;
struct db_playlist_info dbpli;
struct evbuffer *playlistlist; struct evbuffer *playlistlist;
struct evbuffer *playlist; struct evbuffer *playlist;
struct db_playlist_info *dbpli;
struct dmap_field_map *dfm; struct dmap_field_map *dfm;
const char *param; const char *param;
char *db_errmsg;
char **strval; char **strval;
uint32_t *meta; uint32_t *meta;
int nmeta; int nmeta;
@ -1415,29 +1406,28 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
return; return;
} }
memset(&qi, 0, sizeof(DBQUERYINFO)); memset(&qp, 0, sizeof(struct query_params));
get_query_params(query, &qi); get_query_params(query, &qp);
qi.query_type = queryTypePlaylists; qp.type = Q_PL;
ret = db_enum_start(&db_errmsg, &qi); ret = db_query_start(&qp);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DAAP, "Could not fetch playlist list: %s\n", db_errmsg); DPRINTF(E_LOG, L_DAAP, "Could not start query\n");
daap_send_error(req, "aply", db_errmsg); daap_send_error(req, "aply", "Could not start query");
free(db_errmsg);
free(meta); free(meta);
evbuffer_free(playlist); evbuffer_free(playlist);
evbuffer_free(playlistlist); evbuffer_free(playlistlist);
if (qi.filter) if (qp.filter)
free(qi.filter); free(qp.filter);
return; return;
} }
npls = 0; npls = 0;
oom = 0; oom = 0;
while (((ret = db_enum_fetch_row(&db_errmsg, (struct db_media_file_info **)&dbpli, &qi)) == DB_E_SUCCESS) && (dbpli)) while (((ret = db_query_fetch_pl(&qp, &dbpli)) == 0) && (dbpli.id))
{ {
npls++; npls++;
@ -1451,11 +1441,11 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
if (meta[i] == 0x670fc55e) if (meta[i] == 0x670fc55e)
{ {
val = 0; val = 0;
ret = safe_atoi(dbpli->type, &val); ret = safe_atoi(dbpli.type, &val);
if ((ret == 0) && (val == 1)) if ((ret == 0) && (val == 1))
{ {
val = 1; val = 1;
ret = safe_atoi(dbpli->id, &val); ret = safe_atoi(dbpli.id, &val);
if ((ret == 0) && (val != 1)) if ((ret == 0) && (val != 1))
dmap_add_char(playlist, "aeSP", 1); dmap_add_char(playlist, "aeSP", 1);
} }
@ -1474,7 +1464,7 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
if (dfm->pli_offset < 0) if (dfm->pli_offset < 0)
continue; continue;
strval = (char **) ((char *)dbpli + dfm->pli_offset); strval = (char **) ((char *)&dbpli + dfm->pli_offset);
if (!(*strval) || (**strval == '\0')) if (!(*strval) || (**strval == '\0'))
continue; continue;
@ -1486,13 +1476,13 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
/* Item count (mimc) */ /* Item count (mimc) */
val = 0; val = 0;
ret = safe_atoi(dbpli->items, &val); ret = safe_atoi(dbpli.items, &val);
if ((ret == 0) && (val > 0)) if ((ret == 0) && (val > 0))
dmap_add_int(playlist, "mimc", val); dmap_add_int(playlist, "mimc", val);
/* Base playlist (abpl), id = 1 */ /* Base playlist (abpl), id = 1 */
val = 0; val = 0;
ret = safe_atoi(dbpli->id, &val); ret = safe_atoi(dbpli.id, &val);
if ((ret == 0) && (val == 1)) if ((ret == 0) && (val == 1))
dmap_add_char(playlist, "abpl", 1); dmap_add_char(playlist, "abpl", 1);
@ -1512,34 +1502,25 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
free(meta); free(meta);
evbuffer_free(playlist); evbuffer_free(playlist);
if (qi.filter) if (qp.filter)
free(qi.filter); free(qp.filter);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DAAP, "Error fetching results: %s\n", db_errmsg); DPRINTF(E_LOG, L_DAAP, "Error fetching results\n");
daap_send_error(req, "aply", db_errmsg); daap_send_error(req, "aply", "Error fetching query results");
db_query_end(&qp);
free(db_errmsg);
evbuffer_free(playlistlist); evbuffer_free(playlistlist);
return; return;
} }
ret = db_enum_end(&db_errmsg);
if (ret != DB_E_SUCCESS)
{
DPRINTF(E_LOG, L_DAAP, "Error cleaning up DB enum: %s\n", db_errmsg);
free(db_errmsg);
}
if (oom) if (oom)
{ {
DPRINTF(E_LOG, L_DAAP, "Could not add playlist to playlist list for DAAP playlists reply\n"); DPRINTF(E_LOG, L_DAAP, "Could not add playlist to playlist list for DAAP playlists reply\n");
daap_send_error(req, "aply", "Out of memory"); daap_send_error(req, "aply", "Out of memory");
db_query_end(&qp);
evbuffer_free(playlistlist); evbuffer_free(playlistlist);
return; return;
} }
@ -1548,10 +1529,12 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
dmap_add_container(evbuf, "aply", EVBUFFER_LENGTH(playlistlist) + 53); dmap_add_container(evbuf, "aply", EVBUFFER_LENGTH(playlistlist) + 53);
dmap_add_int(evbuf, "mstt", 200); /* 12 */ dmap_add_int(evbuf, "mstt", 200); /* 12 */
dmap_add_char(evbuf, "muty", 0); /* 9 */ dmap_add_char(evbuf, "muty", 0); /* 9 */
dmap_add_int(evbuf, "mtco", qi.specifiedtotalcount); /* 12 */ dmap_add_int(evbuf, "mtco", qp.results); /* 12 */
dmap_add_int(evbuf,"mrco", npls); /* 12 */ dmap_add_int(evbuf,"mrco", npls); /* 12 */
dmap_add_container(evbuf, "mlcl", EVBUFFER_LENGTH(playlistlist)); dmap_add_container(evbuf, "mlcl", EVBUFFER_LENGTH(playlistlist));
db_query_end(&qp);
ret = evbuffer_add_buffer(evbuf, playlistlist); ret = evbuffer_add_buffer(evbuf, playlistlist);
evbuffer_free(playlistlist); evbuffer_free(playlistlist);
if (ret < 0) if (ret < 0)
@ -1568,35 +1551,34 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
static void static void
daap_reply_browse(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query) daap_reply_browse(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{ {
DBQUERYINFO qi; struct query_params qp;
struct evbuffer *itemlist; struct evbuffer *itemlist;
char **item; char *browse_item;
char *tag; char *tag;
char *db_errmsg;
int nitems; int nitems;
int ret; int ret;
memset(&qi, 0, sizeof(DBQUERYINFO)); memset(&qp, 0, sizeof(struct query_params));
if (strcmp(uri[3], "artists") == 0) if (strcmp(uri[3], "artists") == 0)
{ {
tag = "abar"; tag = "abar";
qi.query_type = queryTypeBrowseArtists; qp.type = Q_BROWSE_ARTISTS;
} }
else if (strcmp(uri[3], "genres") == 0) else if (strcmp(uri[3], "genres") == 0)
{ {
tag = "abgn"; tag = "abgn";
qi.query_type = queryTypeBrowseGenres; qp.type = Q_BROWSE_GENRES;
} }
else if (strcmp(uri[3], "albums") == 0) else if (strcmp(uri[3], "albums") == 0)
{ {
tag = "abal"; tag = "abal";
qi.query_type = queryTypeBrowseAlbums; qp.type = Q_BROWSE_ALBUMS;
} }
else if (strcmp(uri[3], "composers") == 0) else if (strcmp(uri[3], "composers") == 0)
{ {
tag = "abcp"; tag = "abcp";
qi.query_type = queryTypeBrowseComposers; qp.type = Q_BROWSE_COMPOSERS;
} }
else else
{ {
@ -1636,58 +1618,50 @@ daap_reply_browse(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
return; return;
} }
get_query_params(query, &qi); get_query_params(query, &qp);
ret = db_enum_start(&db_errmsg, &qi); ret = db_query_start(&qp);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DAAP, "Could not fetch browse item list: %s\n", db_errmsg); DPRINTF(E_LOG, L_DAAP, "Could not start query\n");
daap_send_error(req, "abro", db_errmsg); daap_send_error(req, "abro", "Could not start query");
free(db_errmsg);
evbuffer_free(itemlist); evbuffer_free(itemlist);
if (qi.filter) if (qp.filter)
free(qi.filter); free(qp.filter);
return; return;
} }
nitems = 0; nitems = 0;
while (((ret = db_enum_fetch_row(&db_errmsg, (struct db_media_file_info **)&item, &qi)) == DB_E_SUCCESS) && (item)) while (((ret = db_query_fetch_string(&qp, &browse_item)) == 0) && (browse_item))
{ {
nitems++; nitems++;
dmap_add_string(itemlist, "mlit", *item); dmap_add_string(itemlist, "mlit", browse_item);
} }
if (qi.filter) if (qp.filter)
free(qi.filter); free(qp.filter);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DAAP, "Error fetching results: %s\n", db_errmsg); DPRINTF(E_LOG, L_DAAP, "Error fetching results\n");
daap_send_error(req, "abro", db_errmsg); daap_send_error(req, "abro", "Error fetching query results");
db_query_end(&qp);
free(db_errmsg);
evbuffer_free(itemlist); evbuffer_free(itemlist);
return; return;
} }
ret = db_enum_end(&db_errmsg);
if (ret != DB_E_SUCCESS)
{
DPRINTF(E_LOG, L_DAAP, "Error cleaning up DB enum: %s\n", db_errmsg);
free(db_errmsg);
}
dmap_add_container(evbuf, "abro", EVBUFFER_LENGTH(itemlist) + 44); dmap_add_container(evbuf, "abro", EVBUFFER_LENGTH(itemlist) + 44);
dmap_add_int(evbuf, "mstt", 200); /* 12 */ dmap_add_int(evbuf, "mstt", 200); /* 12 */
dmap_add_int(evbuf, "mtco", qi.specifiedtotalcount); /* 12 */ dmap_add_int(evbuf, "mtco", qp.results); /* 12 */
dmap_add_int(evbuf, "mrco", nitems); /* 12 */ dmap_add_int(evbuf, "mrco", nitems); /* 12 */
dmap_add_container(evbuf, tag, EVBUFFER_LENGTH(itemlist)); dmap_add_container(evbuf, tag, EVBUFFER_LENGTH(itemlist));
db_query_end(&qp);
ret = evbuffer_add_buffer(evbuf, itemlist); ret = evbuffer_add_buffer(evbuf, itemlist);
evbuffer_free(itemlist); evbuffer_free(itemlist);
if (ret < 0) if (ret < 0)

View File

@ -38,8 +38,7 @@
#include <mxml.h> #include <mxml.h>
#include "logger.h" #include "logger.h"
#include "ff-dbstruct.h" #include "db.h"
#include "db-generic.h"
#include "conffile.h" #include "conffile.h"
#include "misc.h" #include "misc.h"
#include "httpd.h" #include "httpd.h"
@ -176,16 +175,16 @@ static void
rsp_send_error(struct evhttp_request *req, char *errmsg); rsp_send_error(struct evhttp_request *req, char *errmsg);
static int static int
get_query_params(struct evhttp_request *req, struct evkeyvalq *query, DBQUERYINFO *qi, int *offset, int *limit) get_query_params(struct evhttp_request *req, struct evkeyvalq *query, struct query_params *qp)
{ {
const char *param; const char *param;
int ret; int ret;
*offset = 0; qp->offset = 0;
param = evhttp_find_header(query, "offset"); param = evhttp_find_header(query, "offset");
if (param) if (param)
{ {
ret = safe_atoi(param, offset); ret = safe_atoi(param, &qp->offset);
if (ret < 0) if (ret < 0)
{ {
rsp_send_error(req, "Invalid offset"); rsp_send_error(req, "Invalid offset");
@ -193,11 +192,11 @@ get_query_params(struct evhttp_request *req, struct evkeyvalq *query, DBQUERYINF
} }
} }
*limit = 0; qp->limit = 0;
param = evhttp_find_header(query, "limit"); param = evhttp_find_header(query, "limit");
if (param) if (param)
{ {
ret = safe_atoi(param, limit); ret = safe_atoi(param, &qp->limit);
if (ret < 0) if (ret < 0)
{ {
rsp_send_error(req, "Invalid limit"); rsp_send_error(req, "Invalid limit");
@ -205,29 +204,18 @@ get_query_params(struct evhttp_request *req, struct evkeyvalq *query, DBQUERYINF
} }
} }
if (*offset || *limit) if (qp->offset || qp->limit)
{ qp->idx_type = I_SUB;
qi->index_low = *offset;
qi->index_high = *offset + *limit - 1;
if (qi->index_high < qi->index_low)
qi->index_high = 9999999; /* Arbitrarily high number */
qi->index_type = indexTypeSub;
}
else else
qi->index_type = indexTypeNone; qp->idx_type = I_NONE;
qi->want_count = 1;
qi->correct_order = 1;
param = evhttp_find_header(query, "query"); param = evhttp_find_header(query, "query");
if (param) if (param)
{ {
DPRINTF(E_DBG, L_RSP, "RSP browse query filter: %s\n", param); DPRINTF(E_DBG, L_RSP, "RSP browse query filter: %s\n", param);
qi->filter = rsp_query_parse_sql(param); qp->filter = rsp_query_parse_sql(param);
if (!qi->filter) if (!qp->filter)
DPRINTF(E_LOG, L_RSP, "Ignoring improper RSP query\n"); DPRINTF(E_LOG, L_RSP, "Ignoring improper RSP query\n");
} }
@ -291,18 +279,15 @@ rsp_reply_info(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
mxml_node_t *node; mxml_node_t *node;
cfg_t *lib; cfg_t *lib;
char *library; char *library;
char *db_errmsg;
int songcount; int songcount;
int ret; int ret;
ret = db_get_song_count(&db_errmsg, &songcount); ret = db_files_get_count(&songcount);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_RSP, "Could not get song count: %s\n", db_errmsg); DPRINTF(E_LOG, L_RSP, "Could not get song count\n");
songcount = 0; songcount = 0;
free(db_errmsg);
} }
lib = cfg_getnsec(cfg, "library", 0); lib = cfg_getnsec(cfg, "library", 0);
@ -363,10 +348,9 @@ rsp_reply_info(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
static void static void
rsp_reply_db(struct evhttp_request *req, char **uri, struct evkeyvalq *query) rsp_reply_db(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
{ {
DBQUERYINFO qi; struct query_params qp;
struct db_playlist_info *dbpli; struct db_playlist_info dbpli;
struct evbuffer *evbuf; struct evbuffer *evbuf;
char *db_errmsg;
char **strval; char **strval;
mxml_node_t *reply; mxml_node_t *reply;
mxml_node_t *status; mxml_node_t *status;
@ -376,20 +360,17 @@ rsp_reply_db(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
int i; int i;
int ret; int ret;
memset(&qi, 0, sizeof(DBQUERYINFO)); memset(&qp, 0, sizeof(struct db_playlist_info));
qi.query_type = queryTypePlaylists; qp.type = Q_PL;
qi.index_type = indexTypeNone; qp.idx_type = I_NONE;
qi.want_count = 1;
ret = db_enum_start(&db_errmsg, &qi); ret = db_query_start(&qp);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_RSP, "Could not fetch playlists: %s\n", db_errmsg); DPRINTF(E_LOG, L_RSP, "Could not start query\n");
rsp_send_error(req, db_errmsg); rsp_send_error(req, "Could not start query");
free(db_errmsg);
return; return;
} }
@ -410,13 +391,13 @@ rsp_reply_db(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
mxmlNewText(node, 0, ""); mxmlNewText(node, 0, "");
node = mxmlNewElement(status, "records"); node = mxmlNewElement(status, "records");
mxmlNewTextf(node, 0, "%d", qi.specifiedtotalcount); mxmlNewTextf(node, 0, "%d", qp.results);
node = mxmlNewElement(status, "totalrecords"); node = mxmlNewElement(status, "totalrecords");
mxmlNewTextf(node, 0, "%d", qi.specifiedtotalcount); mxmlNewTextf(node, 0, "%d", qp.results);
/* Playlists block (all playlists) */ /* Playlists block (all playlists) */
while (((ret = db_enum_fetch_row(&db_errmsg, (struct db_media_file_info **)&dbpli, &qi)) == DB_E_SUCCESS) && (dbpli)) while (((ret = db_query_fetch_pl(&qp, &dbpli)) == 0) && (dbpli.id))
{ {
/* Playlist block (one playlist) */ /* Playlist block (one playlist) */
pl = mxmlNewElement(pls, "playlist"); pl = mxmlNewElement(pls, "playlist");
@ -425,7 +406,7 @@ rsp_reply_db(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
{ {
if (pl_fields[i].flags & F_FULL) if (pl_fields[i].flags & F_FULL)
{ {
strval = (char **) ((char *)dbpli + pl_fields[i].offset); strval = (char **) ((char *)&dbpli + pl_fields[i].offset);
node = mxmlNewElement(pl, pl_fields[i].field); node = mxmlNewElement(pl, pl_fields[i].field);
mxmlNewText(node, 0, *strval); mxmlNewText(node, 0, *strval);
@ -433,34 +414,26 @@ rsp_reply_db(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
} }
} }
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_RSP, "Error fetching results: %s\n", db_errmsg); DPRINTF(E_LOG, L_RSP, "Error fetching results\n");
mxmlDelete(reply); mxmlDelete(reply);
db_query_end(&qp);
rsp_send_error(req, db_errmsg); rsp_send_error(req, "Error fetching query results");
free(db_errmsg);
return; return;
} }
ret = db_enum_end(&db_errmsg);
if (ret != DB_E_SUCCESS)
{
DPRINTF(E_LOG, L_RSP, "Error cleaning up DB enum: %s\n", db_errmsg);
free(db_errmsg);
}
/* HACK /* HACK
* Add a dummy empty string to the playlists element if there is no data * Add a dummy empty string to the playlists element if there is no data
* to return - this prevents mxml from sending out an empty <playlists/> * to return - this prevents mxml from sending out an empty <playlists/>
* tag that the SoundBridge does not handle. It's hackish, but it works. * tag that the SoundBridge does not handle. It's hackish, but it works.
*/ */
if (qi.specifiedtotalcount == 0) if (qp.results == 0)
mxmlNewText(pls, 0, ""); mxmlNewText(pls, 0, "");
db_query_end(&qp);
evbuf = mxml_to_evbuf(reply); evbuf = mxml_to_evbuf(reply);
mxmlDelete(reply); mxmlDelete(reply);
@ -481,10 +454,9 @@ rsp_reply_db(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
static void static void
rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *query) rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
{ {
DBQUERYINFO qi; struct query_params qp;
struct db_media_file_info *dbmfi; struct db_media_file_info dbmfi;
struct evbuffer *evbuf; struct evbuffer *evbuf;
char *db_errmsg;
const char *param; const char *param;
char **strval; char **strval;
mxml_node_t *reply; mxml_node_t *reply;
@ -493,25 +465,26 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
mxml_node_t *item; mxml_node_t *item;
mxml_node_t *node; mxml_node_t *node;
int mode; int mode;
int limit;
int offset;
int records; int records;
int transcode; int transcode;
int bitrate; int bitrate;
int i; int i;
int ret; int ret;
memset(&qi, 0, sizeof(DBQUERYINFO)); memset(&qp, 0, sizeof(struct query_params));
qi.query_type = queryTypePlaylistItems; ret = safe_atoi(uri[2], &qp.pl_id);
ret = safe_atoi(uri[2], &qi.playlist_id);
if (ret < 0) if (ret < 0)
{ {
rsp_send_error(req, "Invalid playlist ID"); rsp_send_error(req, "Invalid playlist ID");
return; return;
} }
if (qp.pl_id == 0)
qp.type = Q_ITEMS;
else
qp.type = Q_PLITEMS;
mode = F_FULL; mode = F_FULL;
param = evhttp_find_header(query, "type"); param = evhttp_find_header(query, "type");
if (param) if (param)
@ -528,29 +501,28 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
DPRINTF(E_LOG, L_RSP, "Unknown browse mode %s\n", param); DPRINTF(E_LOG, L_RSP, "Unknown browse mode %s\n", param);
} }
ret = get_query_params(req, query, &qi, &offset, &limit); ret = get_query_params(req, query, &qp);
if (ret < 0) if (ret < 0)
return; return;
ret = db_enum_start(&db_errmsg, &qi); ret = db_query_start(&qp);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_RSP, "Could not fetch data: %s\n", db_errmsg); DPRINTF(E_LOG, L_RSP, "Could not start query\n");
rsp_send_error(req, db_errmsg); rsp_send_error(req, "Could not start query");
if (qi.filter) if (qp.filter)
free(qi.filter); free(qp.filter);
free(db_errmsg);
return; return;
} }
if (offset > qi.specifiedtotalcount) if (qp.offset > qp.results)
records = 0; records = 0;
else if (limit > (qi.specifiedtotalcount - offset)) else if (qp.limit > (qp.results - qp.offset))
records = qi.specifiedtotalcount - offset; records = qp.results - qp.offset;
else else
records = limit; records = qp.limit;
/* We'd use mxmlNewXML(), but then we can't put any attributes /* We'd use mxmlNewXML(), but then we can't put any attributes
* on the root node and we need some. * on the root node and we need some.
@ -572,12 +544,12 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
mxmlNewTextf(node, 0, "%d", records); mxmlNewTextf(node, 0, "%d", records);
node = mxmlNewElement(status, "totalrecords"); node = mxmlNewElement(status, "totalrecords");
mxmlNewTextf(node, 0, "%d", qi.specifiedtotalcount); mxmlNewTextf(node, 0, "%d", qp.results);
/* Items block (all items) */ /* Items block (all items) */
while (((ret = db_enum_fetch_row(&db_errmsg, &dbmfi, &qi)) == DB_E_SUCCESS) && (dbmfi)) while (((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id))
{ {
transcode = transcode_needed(req->input_headers, dbmfi->codectype); transcode = transcode_needed(req->input_headers, dbmfi.codectype);
/* Item block (one item) */ /* Item block (one item) */
item = mxmlNewElement(items, "item"); item = mxmlNewElement(items, "item");
@ -587,7 +559,7 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
if (!(rsp_fields[i].flags & mode)) if (!(rsp_fields[i].flags & mode))
continue; continue;
strval = (char **) ((char *)dbmfi + rsp_fields[i].offset); strval = (char **) ((char *)&dbmfi + rsp_fields[i].offset);
if (!(*strval) || (strlen(*strval) == 0)) if (!(*strval) || (strlen(*strval) == 0))
continue; continue;
@ -606,7 +578,7 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
case dbmfi_offsetof(bitrate): case dbmfi_offsetof(bitrate):
bitrate = 0; bitrate = 0;
ret = safe_atoi(dbmfi->samplerate, &bitrate); ret = safe_atoi(dbmfi.samplerate, &bitrate);
if ((ret < 0) || (bitrate == 0)) if ((ret < 0) || (bitrate == 0))
bitrate = 1411; bitrate = 1411;
else else
@ -634,37 +606,29 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
} }
} }
if (qi.filter) if (qp.filter)
free(qi.filter); free(qp.filter);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_RSP, "Error fetching results: %s\n", db_errmsg); DPRINTF(E_LOG, L_RSP, "Error fetching results\n");
mxmlDelete(reply); mxmlDelete(reply);
db_query_end(&qp);
rsp_send_error(req, db_errmsg); rsp_send_error(req, "Error fetching query results");
free(db_errmsg);
return; return;
} }
ret = db_enum_end(&db_errmsg);
if (ret != DB_E_SUCCESS)
{
DPRINTF(E_LOG, L_RSP, "Error cleaning up DB enum: %s\n", db_errmsg);
free(db_errmsg);
}
/* HACK /* HACK
* Add a dummy empty string to the items element if there is no data * Add a dummy empty string to the items element if there is no data
* to return - this prevents mxml from sending out an empty <items/> * to return - this prevents mxml from sending out an empty <items/>
* tag that the SoundBridge does not handle. It's hackish, but it works. * tag that the SoundBridge does not handle. It's hackish, but it works.
*/ */
if (qi.specifiedtotalcount == 0) if (qp.results == 0)
mxmlNewText(items, 0, ""); mxmlNewText(items, 0, "");
db_query_end(&qp);
evbuf = mxml_to_evbuf(reply); evbuf = mxml_to_evbuf(reply);
mxmlDelete(reply); mxmlDelete(reply);
@ -685,29 +649,26 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
static void static void
rsp_reply_browse(struct evhttp_request *req, char **uri, struct evkeyvalq *query) rsp_reply_browse(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
{ {
DBQUERYINFO qi; struct query_params qp;
struct db_media_file_info *dbmfi;
struct evbuffer *evbuf; struct evbuffer *evbuf;
char *db_errmsg; char *browse_item;
mxml_node_t *reply; mxml_node_t *reply;
mxml_node_t *status; mxml_node_t *status;
mxml_node_t *items; mxml_node_t *items;
mxml_node_t *node; mxml_node_t *node;
int limit;
int offset;
int records; int records;
int ret; int ret;
memset(&qi, 0, sizeof(DBQUERYINFO)); memset(&qp, 0, sizeof(struct query_params));
if (strcmp(uri[3], "artist") == 0) if (strcmp(uri[3], "artist") == 0)
qi.query_type = queryTypeBrowseArtists; qp.type = Q_BROWSE_ARTISTS;
else if (strcmp(uri[3], "genre") == 0) else if (strcmp(uri[3], "genre") == 0)
qi.query_type = queryTypeBrowseGenres; qp.type = Q_BROWSE_GENRES;
else if (strcmp(uri[3], "album") == 0) else if (strcmp(uri[3], "album") == 0)
qi.query_type = queryTypeBrowseAlbums; qp.type = Q_BROWSE_ALBUMS;
else if (strcmp(uri[3], "composer") == 0) else if (strcmp(uri[3], "composer") == 0)
qi.query_type = queryTypeBrowseComposers; qp.type = Q_BROWSE_COMPOSERS;
else else
{ {
DPRINTF(E_LOG, L_RSP, "Unsupported browse type '%s'\n", uri[3]); DPRINTF(E_LOG, L_RSP, "Unsupported browse type '%s'\n", uri[3]);
@ -716,36 +677,35 @@ rsp_reply_browse(struct evhttp_request *req, char **uri, struct evkeyvalq *query
return; return;
} }
ret = safe_atoi(uri[2], &qi.playlist_id); ret = safe_atoi(uri[2], &qp.pl_id);
if (ret < 0) if (ret < 0)
{ {
rsp_send_error(req, "Invalid playlist ID"); rsp_send_error(req, "Invalid playlist ID");
return; return;
} }
ret = get_query_params(req, query, &qi, &offset, &limit); ret = get_query_params(req, query, &qp);
if (ret < 0) if (ret < 0)
return; return;
ret = db_enum_start(&db_errmsg, &qi); ret = db_query_start(&qp);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_RSP, "Could not fetch data: %s\n", db_errmsg); DPRINTF(E_LOG, L_RSP, "Could not start query\n");
rsp_send_error(req, db_errmsg); rsp_send_error(req, "Could not start query");
if (qi.filter) if (qp.filter)
free(qi.filter); free(qp.filter);
free(db_errmsg);
return; return;
} }
if (offset > qi.specifiedtotalcount) if (qp.offset > qp.results)
records = 0; records = 0;
else if (limit > (qi.specifiedtotalcount - offset)) else if (qp.limit > (qp.results - qp.offset))
records = qi.specifiedtotalcount - offset; records = qp.results - qp.offset;
else else
records = limit; records = qp.limit;
/* We'd use mxmlNewXML(), but then we can't put any attributes /* We'd use mxmlNewXML(), but then we can't put any attributes
* on the root node and we need some. * on the root node and we need some.
@ -767,46 +727,38 @@ rsp_reply_browse(struct evhttp_request *req, char **uri, struct evkeyvalq *query
mxmlNewTextf(node, 0, "%d", records); mxmlNewTextf(node, 0, "%d", records);
node = mxmlNewElement(status, "totalrecords"); node = mxmlNewElement(status, "totalrecords");
mxmlNewTextf(node, 0, "%d", qi.specifiedtotalcount); mxmlNewTextf(node, 0, "%d", qp.results);
/* Items block (all items) */ /* Items block (all items) */
while (((ret = db_enum_fetch_row(&db_errmsg, &dbmfi, &qi)) == DB_E_SUCCESS) && (dbmfi)) while (((ret = db_query_fetch_string(&qp, &browse_item)) == 0) && (browse_item))
{ {
node = mxmlNewElement(items, "item"); node = mxmlNewElement(items, "item");
mxmlNewText(node, 0, dbmfi->id); mxmlNewText(node, 0, browse_item);
} }
if (qi.filter) if (qp.filter)
free(qi.filter); free(qp.filter);
if (ret != DB_E_SUCCESS) if (ret < 0)
{ {
DPRINTF(E_LOG, L_RSP, "Error fetching results: %s\n", db_errmsg); DPRINTF(E_LOG, L_RSP, "Error fetching results\n");
mxmlDelete(reply); mxmlDelete(reply);
db_query_end(&qp);
rsp_send_error(req, db_errmsg); rsp_send_error(req, "Error fetching query results");
free(db_errmsg);
return; return;
} }
ret = db_enum_end(&db_errmsg);
if (ret != DB_E_SUCCESS)
{
DPRINTF(E_LOG, L_RSP, "Error cleaning up DB enum: %s\n", db_errmsg);
free(db_errmsg);
}
/* HACK /* HACK
* Add a dummy empty string to the items element if there is no data * Add a dummy empty string to the items element if there is no data
* to return - this prevents mxml from sending out an empty <items/> * to return - this prevents mxml from sending out an empty <items/>
* tag that the SoundBridge does not handle. It's hackish, but it works. * tag that the SoundBridge does not handle. It's hackish, but it works.
*/ */
if (qi.specifiedtotalcount == 0) if (qp.results == 0);
mxmlNewText(items, 0, ""); mxmlNewText(items, 0, "");
db_query_end(&qp);
evbuf = mxml_to_evbuf(reply); evbuf = mxml_to_evbuf(reply);
mxmlDelete(reply); mxmlDelete(reply);

View File

@ -47,11 +47,11 @@
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include "conffile.h" #include "conffile.h"
#include "db.h"
#include "logger.h" #include "logger.h"
#include "misc.h" #include "misc.h"
#include "filescanner.h" #include "filescanner.h"
#include "httpd.h" #include "httpd.h"
#include "db-generic.h"
#include "mdns_avahi.h" #include "mdns_avahi.h"
@ -334,7 +334,6 @@ main(int argc, char **argv)
char *logdomains; char *logdomains;
char *logfile; char *logfile;
char *ffid; char *ffid;
char *perr;
char *pidfile; char *pidfile;
sigset_t sigs; sigset_t sigs;
int sigfd; int sigfd;
@ -500,23 +499,17 @@ main(int argc, char **argv)
goto mdns_fail; goto mdns_fail;
} }
/* this will require that the db be readable by the runas user */ /* Initialize the database before starting */
ret = db_open(&perr, "sqlite3", "/var/cache/mt-daapd"); /* FIXME */ DPRINTF(E_INFO, L_MAIN, "Initializing database\n");
if (ret != 0) ret = db_init();
if (ret < 0)
{ {
DPRINTF(E_FATAL, L_MAIN, "Error opening db: %s\n", perr); DPRINTF(E_FATAL, L_MAIN, "Database init failed\n");
ret = EXIT_FAILURE; ret = EXIT_FAILURE;
goto db_fail; goto db_fail;
} }
/* Initialize the database before starting */
DPRINTF(E_INFO, L_MAIN, "Initializing database\n");
if (db_init(0))
{
DPRINTF(E_FATAL, L_MAIN, "Error in db_init: %s\n", strerror(errno));
}
/* Spawn file scanner thread */ /* Spawn file scanner thread */
ret = filescanner_init(); ret = filescanner_init();
if (ret != 0) if (ret != 0)
@ -582,9 +575,6 @@ main(int argc, char **argv)
filescanner_deinit(); filescanner_deinit();
filescanner_fail: filescanner_fail:
DPRINTF(E_LOG, L_MAIN, "Closing database\n");
db_deinit();
db_fail: db_fail:
if (ret == EXIT_FAILURE) if (ret == EXIT_FAILURE)
{ {

View File

@ -40,13 +40,15 @@
#include <sys/stat.h> #include <sys/stat.h>
#include "logger.h" #include "logger.h"
#include "ff-dbstruct.h" #include "db.h"
#include <FLAC/metadata.h> #include <FLAC/metadata.h>
#define TRUE ((1 == 1)) #define TRUE ((1 == 1))
#define FALSE (!TRUE) #define FALSE (!TRUE)
typedef struct media_file_info MP3FILE;
#define GET_VORBIS_COMMENT(comment, name, len) (char*) \ #define GET_VORBIS_COMMENT(comment, name, len) (char*) \
(((strncasecmp(name, (char*)(comment).entry, strlen(name)) == 0) && \ (((strncasecmp(name, (char*)(comment).entry, strlen(name)) == 0) && \
((comment).entry[strlen(name)] == '=')) ? \ ((comment).entry[strlen(name)] == '=')) ? \

View File

@ -31,11 +31,12 @@
#include <taglib/tag_c.h> #include <taglib/tag_c.h>
#include "logger.h" #include "logger.h"
#include "ff-dbstruct.h" #include "db.h"
#define TRUE ((1 == 1)) #define TRUE ((1 == 1))
#define FALSE (!TRUE) #define FALSE (!TRUE)
typedef struct media_file_info MP3FILE;
/** /**
* scan a musepack file for metainfo. * scan a musepack file for metainfo.

View File

@ -34,11 +34,13 @@
#include <unistd.h> #include <unistd.h>
#include "logger.h" #include "logger.h"
#include "ff-dbstruct.h" #include "db.h"
#define TRUE ((1 == 1)) #define TRUE ((1 == 1))
#define FALSE (!TRUE) #define FALSE (!TRUE)
typedef struct media_file_info MP3FILE;
typedef struct tag_wma_guidlist { typedef struct tag_wma_guidlist {
char *name; char *name;
char *guid; char *guid;

View File

@ -41,7 +41,7 @@
#include "logger.h" #include "logger.h"
#include "conffile.h" #include "conffile.h"
#include "ff-dbstruct.h" #include "db.h"
#include "transcode.h" #include "transcode.h"