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 "logger.h"
#include "ff-dbstruct.h"
#include "db-generic.h"
#include "db-sql.h"
#include "db.h"
#include "daap_query.h"
}
@ -217,7 +215,7 @@ expr returns [ pANTLR3_STRING result, int valid ]
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)
{
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_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 \
db.c db.h \
logger.c logger.h \
conffile.c conffile.h \
filescanner.c filescanner.h \
@ -38,10 +39,7 @@ mt_daapd_SOURCES = main.c \
misc.c misc.h \
rsp_query.c rsp_query.h \
daap_query.c daap_query.h \
db-generic.c db-generic.h \
scan-wma.c \
db-sql-updates.c \
db-sql.c db-sql.h db-sql-sqlite3.c db-sql-sqlite3.h\
$(FLACSRC) $(MUSEPACKSRC)
nodist_mt_daapd_SOURCES = \
@ -50,9 +48,7 @@ nodist_mt_daapd_SOURCES = \
EXTRA_DIST = \
$(ANTLR_GRAMMARS) \
scan-mpc.c \
scan-flac.c \
ff-dbstruct.h
scan-flac.c
# Let's help the dependencies a little.
rsp_query.c: RSPLexer.h RSPParser.h RSP2SQL.h

View File

@ -32,9 +32,7 @@ options {
#include <time.h>
#include "logger.h"
#include "ff-dbstruct.h"
#include "db-generic.h"
#include "db-sql.h"
#include "db.h"
#include "misc.h"
#include "rsp_query.h"
}
@ -181,7 +179,7 @@ strcrit returns [ pANTLR3_STRING result, int valid ]
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)
{
DPRINTF(E_LOG, L_RSP, "Could not escape value\n");

View File

@ -43,7 +43,7 @@
#include <avl.h>
#include "logger.h"
#include "db-generic.h"
#include "db.h"
#include "filescanner.h"
#include "conffile.h"
@ -144,55 +144,6 @@ pop_dir(void)
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
fixup_tags(struct media_file_info *mfi)
@ -256,32 +207,42 @@ fixup_tags(struct media_file_info *mfi)
static void
process_media_file(char *file, time_t mtime, off_t size, int compilation)
{
struct media_file_info *db_mfi;
struct media_file_info *mfi;
char *filename;
char *ext;
int need_update;
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);
db_dispose_item(db_mfi);
need_update = (!mfi || (mfi->db_timestamp < mtime) || mfi->force_update);
if (!need_update)
return;
mfi = (struct media_file_info *)malloc(sizeof(struct media_file_info));
if (!mfi)
{
DPRINTF(E_WARN, L_SCAN, "Out of memory for media_file_info\n");
db_file_ping(mfi->id);
db_dispose_item(db_mfi);
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));
if (!mfi)
{
DPRINTF(E_WARN, L_SCAN, "Out of memory for media_file_info\n");
return;
}
}
memset(mfi, 0, sizeof(struct media_file_info));
mfi->id = ret;
filename = strrchr(file, '/');
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");
free_mfi(mfi);
free(mfi);
free_mfi(mfi, 0);
return;
}
@ -350,10 +310,12 @@ process_media_file(char *file, time_t mtime, off_t size, int compilation)
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);
free_mfi(mfi, 0);
}
static void
@ -669,6 +631,8 @@ bulk_scan(void)
}
}
db_pl_update_all();
if (playlists)
process_deferred_playlists();
@ -681,10 +645,22 @@ bulk_scan(void)
static void *
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();
if (!scan_exit)
{
db_pl_update_all();
/* Enable inotify */
event_add(&inoev, NULL);
@ -694,6 +670,8 @@ filescanner(void *arg)
if (!scan_exit)
DPRINTF(E_FATAL, L_SCAN, "Scan event loop terminated ahead of time!\n");
db_perthread_deinit();
pthread_exit(NULL);
}

View File

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

View File

@ -41,12 +41,12 @@
/* 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
extern int scan_get_flacinfo(char *filename, MP3FILE *pmp3);
extern int scan_get_flacinfo(char *filename, struct media_file_info *pmp3);
#endif
#ifdef MUSEPACK
extern int scan_get_mpcinfo(char *filename, MP3FILE *pmp3);
extern int scan_get_mpcinfo(char *filename, struct media_file_info *pmp3);
#endif

View File

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

View File

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

View File

@ -35,8 +35,7 @@
#include "evhttp/evhttp.h"
#include "logger.h"
#include "ff-dbstruct.h"
#include "db-generic.h"
#include "db.h"
#include "conffile.h"
#include "misc.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)))
{
st->marked = 1;
db_playcount_increment(NULL, st->id);
db_file_inc_playcount(st->id);
}
return;
@ -245,7 +244,7 @@ stream_chunk_raw_cb(int fd, short event, void *arg)
if (!st->marked && (st->offset > ((st->size * 80) / 100)))
{
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)
{
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");
db_dispose_item(mfi);
free_mfi(mfi, 0);
return;
}
@ -326,7 +325,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal Server Error");
db_dispose_item(mfi);
free_mfi(mfi, 0);
return;
}
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");
free(st);
db_dispose_item(mfi);
free_mfi(mfi, 0);
return;
}
@ -370,7 +369,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");
free(st);
db_dispose_item(mfi);
free_mfi(mfi, 0);
return;
}
@ -383,7 +382,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
close(st->fd);
free(st);
db_dispose_item(mfi);
free_mfi(mfi, 0);
return;
}
st->size = sb.st_size;
@ -397,7 +396,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
close(st->fd);
free(st);
db_dispose_item(mfi);
free_mfi(mfi, 0);
return;
}
st->offset = offset;
@ -425,7 +424,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
else
close(st->fd);
free(st);
db_dispose_item(mfi);
free_mfi(mfi, 0);
return;
}
@ -443,7 +442,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
close(st->fd);
evbuffer_free(st->evbuf);
free(st);
db_dispose_item(mfi);
free_mfi(mfi, 0);
return;
}
@ -464,7 +463,7 @@ httpd_stream_file(struct evhttp_request *req, int id)
close(st->fd);
evbuffer_free(st->evbuf);
free(st);
db_dispose_item(mfi);
free_mfi(mfi, 0);
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);
db_dispose_item(mfi);
free_mfi(mfi, 0);
}
/* Thread: httpd */
@ -745,11 +744,23 @@ httpd_gen_cb(struct evhttp_request *req, void *arg)
static void *
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);
if (!httpd_exit)
DPRINTF(E_FATAL, L_HTTPD, "HTTPd event loop terminated ahead of time!\n");
db_perthread_deinit();
pthread_exit(NULL);
}

View File

@ -26,6 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <sys/queue.h>
#include <sys/types.h>
@ -39,8 +40,7 @@
#include <avl.h>
#include "logger.h"
#include "ff-dbstruct.h"
#include "db-generic.h"
#include "db.h"
#include "conffile.h"
#include "misc.h"
#include "httpd.h"
@ -569,16 +569,18 @@ dmap_find_field(uint32_t hash)
return (struct dmap_field_map *)node->item;
}
static void
get_query_params(struct evkeyvalq *query, DBQUERYINFO *qi)
get_query_params(struct evkeyvalq *query, struct query_params *qp)
{
const char *param;
char *ptr;
int val;
int low;
int high;
int ret;
qi->index_low = 0;
qi->index_high = 9999999; /* Arbitrarily high number */
low = 0;
high = -1; /* No limit */
param = evhttp_find_header(query, "index");
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);
else
{
ret = safe_atoi(param, &val);
ret = safe_atoi(param, &low);
if (ret < 0)
DPRINTF(E_LOG, L_DAAP, "Could not parse index range: %s\n", param);
else
{
qi->index_low = val;
ptr = strchr(param, '-');
if (!ptr) /* single item */
qi->index_high = qi->index_low;
high = low;
else
{
ptr++;
if (*ptr != '\0') /* low-high */
{
ret = safe_atoi(ptr, &val);
ret = safe_atoi(ptr, &high);
if (ret < 0)
DPRINTF(E_LOG, L_DAAP, "Could not parse high index in range: %s\n", param);
else
qi->index_high = val;
}
}
}
}
DPRINTF(E_DBG, L_DAAP, "Index range %s: low %d, high %d\n", param, qi->index_low, qi->index_high);
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 (qi->index_high < qi->index_low)
qi->index_high = 9999999; /* Arbitrarily high number */
if (high < low)
high = -1; /* No limit */
qi->index_type = indexTypeSub;
qp->offset = low;
if (high < 0)
qp->limit = -1; /* No limit */
else
qp->limit = (high - low) + 1;
qp->idx_type = I_SUB;
param = evhttp_find_header(query, "query");
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);
qi->filter = daap_query_parse_sql(param);
if (!qi->filter)
qp->filter = daap_query_parse_sql(param);
if (!qp->filter)
DPRINTF(E_LOG, L_DAAP, "Ignoring improper DAAP query\n");
}
qi->want_count = 1;
qi->correct_order = 1;
}
static void
@ -879,7 +880,7 @@ daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
{
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
* updates, so... that support should be added eventually.
@ -895,8 +896,8 @@ daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
}
dmap_add_container(evbuf, "mupd", 24);
dmap_add_int(evbuf, "mstt", 200); /* 12 */
dmap_add_int(evbuf, "musr", db_revision()); /* 12 */
dmap_add_int(evbuf, "mstt", 200); /* 12 */
dmap_add_int(evbuf, "musr", (int)time(NULL)); /* 12 */
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
daap_reply_dblist(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{
int count;
cfg_t *lib;
char *db_errmsg;
char *name;
int namelen;
int count;
int ret;
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_string(evbuf, "minm", name); /* 8 + namelen */
ret = db_get_song_count(&db_errmsg, &count);
if (ret != DB_E_SUCCESS)
ret = db_files_get_count(&count);
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;
free(db_errmsg);
}
dmap_add_int(evbuf, "mimc", count); /* 12 */
ret = db_get_playlist_count(&db_errmsg, &count);
if (ret != DB_E_SUCCESS)
ret = db_pl_get_count(&count);
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;
free(db_errmsg);
}
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
daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf, int playlist, struct evkeyvalq *query)
{
DBQUERYINFO qi;
struct db_media_file_info *dbmfi;
struct query_params qp;
struct db_media_file_info dbmfi;
struct evbuffer *song;
struct evbuffer *songlist;
struct dmap_field_map *dfm;
char *db_errmsg;
const char *param;
char *tag;
char **strval;
@ -1071,26 +1067,29 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
nmeta = 0;
}
memset(&qi, 0, sizeof(DBQUERYINFO));
get_query_params(query, &qi);
qi.query_type = queryTypePlaylistItems;
memset(&qp, 0, sizeof(struct query_params));
get_query_params(query, &qp);
if (playlist != -1)
qi.playlist_id = playlist;
ret = db_enum_start(&db_errmsg, &qi);
if (ret != DB_E_SUCCESS)
if (playlist < 2)
qp.type = Q_ITEMS;
else
{
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);
evbuffer_free(song);
evbuffer_free(songlist);
if (qi.filter)
free(qi.filter);
if (qp.filter)
free(qp.filter);
return;
}
@ -1098,11 +1097,11 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
want_asdk = 0;
oom = 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++;
transcode = transcode_needed(req->input_headers, dbmfi->codectype);
transcode = transcode_needed(req->input_headers, dbmfi.codectype);
i = -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);
strval = (char **) ((char *)dbmfi + dfm->mfi_offset);
strval = (char **) ((char *)&dbmfi + dfm->mfi_offset);
if (!(*strval) || (**strval == '\0'))
continue;
@ -1174,7 +1173,7 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
case dbmfi_offsetof(bitrate):
val = 0;
ret = safe_atoi(dbmfi->samplerate, &val);
ret = safe_atoi(dbmfi.samplerate, &val);
if ((ret < 0) || (val == 0))
val = 1411;
else
@ -1220,14 +1219,14 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
if (want_mikd)
{
/* dmap.itemkind must come first */
ret = safe_atoi(dbmfi->item_kind, &val);
ret = safe_atoi(dbmfi.item_kind, &val);
if (ret < 0)
val = 2; /* music by default */
dmap_add_char(songlist, "mikd", val);
}
if (want_asdk)
{
ret = safe_atoi(dbmfi->data_kind, &val);
ret = safe_atoi(dbmfi.data_kind, &val);
if (ret < 0)
val = 0;
dmap_add_char(songlist, "asdk", val);
@ -1248,34 +1247,25 @@ daap_reply_songlist_generic(struct evhttp_request *req, struct evbuffer *evbuf,
evbuffer_free(song);
if (qi.filter)
free(qi.filter);
if (qp.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);
free(db_errmsg);
daap_send_error(req, tag, "Error fetching query results");
db_query_end(&qp);
evbuffer_free(songlist);
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)
{
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");
db_query_end(&qp);
evbuffer_free(songlist);
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_int(evbuf, "mstt", 200); /* 12 */
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_container(evbuf, "mlcl", EVBUFFER_LENGTH(songlist));
db_query_end(&qp);
ret = evbuffer_add_buffer(evbuf, songlist);
evbuffer_free(songlist);
if (ret < 0)
@ -1327,13 +1319,12 @@ daap_reply_plsonglist(struct evhttp_request *req, struct evbuffer *evbuf, char *
static void
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 *playlist;
struct db_playlist_info *dbpli;
struct dmap_field_map *dfm;
const char *param;
char *db_errmsg;
char **strval;
uint32_t *meta;
int nmeta;
@ -1415,29 +1406,28 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
return;
}
memset(&qi, 0, sizeof(DBQUERYINFO));
get_query_params(query, &qi);
qi.query_type = queryTypePlaylists;
memset(&qp, 0, sizeof(struct query_params));
get_query_params(query, &qp);
qp.type = Q_PL;
ret = db_enum_start(&db_errmsg, &qi);
if (ret != DB_E_SUCCESS)
ret = db_query_start(&qp);
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);
evbuffer_free(playlist);
evbuffer_free(playlistlist);
if (qi.filter)
free(qi.filter);
if (qp.filter)
free(qp.filter);
return;
}
npls = 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++;
@ -1451,11 +1441,11 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
if (meta[i] == 0x670fc55e)
{
val = 0;
ret = safe_atoi(dbpli->type, &val);
ret = safe_atoi(dbpli.type, &val);
if ((ret == 0) && (val == 1))
{
val = 1;
ret = safe_atoi(dbpli->id, &val);
ret = safe_atoi(dbpli.id, &val);
if ((ret == 0) && (val != 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)
continue;
strval = (char **) ((char *)dbpli + dfm->pli_offset);
strval = (char **) ((char *)&dbpli + dfm->pli_offset);
if (!(*strval) || (**strval == '\0'))
continue;
@ -1486,13 +1476,13 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
/* Item count (mimc) */
val = 0;
ret = safe_atoi(dbpli->items, &val);
ret = safe_atoi(dbpli.items, &val);
if ((ret == 0) && (val > 0))
dmap_add_int(playlist, "mimc", val);
/* Base playlist (abpl), id = 1 */
val = 0;
ret = safe_atoi(dbpli->id, &val);
ret = safe_atoi(dbpli.id, &val);
if ((ret == 0) && (val == 1))
dmap_add_char(playlist, "abpl", 1);
@ -1512,34 +1502,25 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
free(meta);
evbuffer_free(playlist);
if (qi.filter)
free(qi.filter);
if (qp.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);
free(db_errmsg);
daap_send_error(req, "aply", "Error fetching query results");
db_query_end(&qp);
evbuffer_free(playlistlist);
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)
{
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");
db_query_end(&qp);
evbuffer_free(playlistlist);
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_int(evbuf, "mstt", 200); /* 12 */
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_container(evbuf, "mlcl", EVBUFFER_LENGTH(playlistlist));
db_query_end(&qp);
ret = evbuffer_add_buffer(evbuf, playlistlist);
evbuffer_free(playlistlist);
if (ret < 0)
@ -1568,35 +1551,34 @@ daap_reply_playlists(struct evhttp_request *req, struct evbuffer *evbuf, char **
static void
daap_reply_browse(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
{
DBQUERYINFO qi;
struct query_params qp;
struct evbuffer *itemlist;
char **item;
char *browse_item;
char *tag;
char *db_errmsg;
int nitems;
int ret;
memset(&qi, 0, sizeof(DBQUERYINFO));
memset(&qp, 0, sizeof(struct query_params));
if (strcmp(uri[3], "artists") == 0)
{
tag = "abar";
qi.query_type = queryTypeBrowseArtists;
qp.type = Q_BROWSE_ARTISTS;
}
else if (strcmp(uri[3], "genres") == 0)
{
tag = "abgn";
qi.query_type = queryTypeBrowseGenres;
qp.type = Q_BROWSE_GENRES;
}
else if (strcmp(uri[3], "albums") == 0)
{
tag = "abal";
qi.query_type = queryTypeBrowseAlbums;
qp.type = Q_BROWSE_ALBUMS;
}
else if (strcmp(uri[3], "composers") == 0)
{
tag = "abcp";
qi.query_type = queryTypeBrowseComposers;
qp.type = Q_BROWSE_COMPOSERS;
}
else
{
@ -1636,58 +1618,50 @@ daap_reply_browse(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
return;
}
get_query_params(query, &qi);
get_query_params(query, &qp);
ret = db_enum_start(&db_errmsg, &qi);
if (ret != DB_E_SUCCESS)
ret = db_query_start(&qp);
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);
if (qi.filter)
free(qi.filter);
if (qp.filter)
free(qp.filter);
return;
}
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++;
dmap_add_string(itemlist, "mlit", *item);
dmap_add_string(itemlist, "mlit", browse_item);
}
if (qi.filter)
free(qi.filter);
if (qp.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);
free(db_errmsg);
daap_send_error(req, "abro", "Error fetching query results");
db_query_end(&qp);
evbuffer_free(itemlist);
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_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_container(evbuf, tag, EVBUFFER_LENGTH(itemlist));
db_query_end(&qp);
ret = evbuffer_add_buffer(evbuf, itemlist);
evbuffer_free(itemlist);
if (ret < 0)

View File

@ -38,8 +38,7 @@
#include <mxml.h>
#include "logger.h"
#include "ff-dbstruct.h"
#include "db-generic.h"
#include "db.h"
#include "conffile.h"
#include "misc.h"
#include "httpd.h"
@ -176,16 +175,16 @@ static void
rsp_send_error(struct evhttp_request *req, char *errmsg);
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;
int ret;
*offset = 0;
qp->offset = 0;
param = evhttp_find_header(query, "offset");
if (param)
{
ret = safe_atoi(param, offset);
ret = safe_atoi(param, &qp->offset);
if (ret < 0)
{
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");
if (param)
{
ret = safe_atoi(param, limit);
ret = safe_atoi(param, &qp->limit);
if (ret < 0)
{
rsp_send_error(req, "Invalid limit");
@ -205,29 +204,18 @@ get_query_params(struct evhttp_request *req, struct evkeyvalq *query, DBQUERYINF
}
}
if (*offset || *limit)
{
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;
}
if (qp->offset || qp->limit)
qp->idx_type = I_SUB;
else
qi->index_type = indexTypeNone;
qi->want_count = 1;
qi->correct_order = 1;
qp->idx_type = I_NONE;
param = evhttp_find_header(query, "query");
if (param)
{
DPRINTF(E_DBG, L_RSP, "RSP browse query filter: %s\n", param);
qi->filter = rsp_query_parse_sql(param);
if (!qi->filter)
qp->filter = rsp_query_parse_sql(param);
if (!qp->filter)
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;
cfg_t *lib;
char *library;
char *db_errmsg;
int songcount;
int ret;
ret = db_get_song_count(&db_errmsg, &songcount);
if (ret != DB_E_SUCCESS)
ret = db_files_get_count(&songcount);
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;
free(db_errmsg);
}
lib = cfg_getnsec(cfg, "library", 0);
@ -363,10 +348,9 @@ rsp_reply_info(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
static void
rsp_reply_db(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
{
DBQUERYINFO qi;
struct db_playlist_info *dbpli;
struct query_params qp;
struct db_playlist_info dbpli;
struct evbuffer *evbuf;
char *db_errmsg;
char **strval;
mxml_node_t *reply;
mxml_node_t *status;
@ -376,20 +360,17 @@ rsp_reply_db(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
int i;
int ret;
memset(&qi, 0, sizeof(DBQUERYINFO));
memset(&qp, 0, sizeof(struct db_playlist_info));
qi.query_type = queryTypePlaylists;
qi.index_type = indexTypeNone;
qi.want_count = 1;
qp.type = Q_PL;
qp.idx_type = I_NONE;
ret = db_enum_start(&db_errmsg, &qi);
if (ret != DB_E_SUCCESS)
ret = db_query_start(&qp);
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);
free(db_errmsg);
rsp_send_error(req, "Could not start query");
return;
}
@ -410,13 +391,13 @@ rsp_reply_db(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
mxmlNewText(node, 0, "");
node = mxmlNewElement(status, "records");
mxmlNewTextf(node, 0, "%d", qi.specifiedtotalcount);
mxmlNewTextf(node, 0, "%d", qp.results);
node = mxmlNewElement(status, "totalrecords");
mxmlNewTextf(node, 0, "%d", qi.specifiedtotalcount);
mxmlNewTextf(node, 0, "%d", qp.results);
/* 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) */
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)
{
strval = (char **) ((char *)dbpli + pl_fields[i].offset);
strval = (char **) ((char *)&dbpli + pl_fields[i].offset);
node = mxmlNewElement(pl, pl_fields[i].field);
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);
rsp_send_error(req, db_errmsg);
free(db_errmsg);
db_query_end(&qp);
rsp_send_error(req, "Error fetching query results");
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
* 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/>
* tag that the SoundBridge does not handle. It's hackish, but it works.
*/
if (qi.specifiedtotalcount == 0)
if (qp.results == 0)
mxmlNewText(pls, 0, "");
db_query_end(&qp);
evbuf = mxml_to_evbuf(reply);
mxmlDelete(reply);
@ -481,10 +454,9 @@ rsp_reply_db(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
static void
rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
{
DBQUERYINFO qi;
struct db_media_file_info *dbmfi;
struct query_params qp;
struct db_media_file_info dbmfi;
struct evbuffer *evbuf;
char *db_errmsg;
const char *param;
char **strval;
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 *node;
int mode;
int limit;
int offset;
int records;
int transcode;
int bitrate;
int i;
int ret;
memset(&qi, 0, sizeof(DBQUERYINFO));
memset(&qp, 0, sizeof(struct query_params));
qi.query_type = queryTypePlaylistItems;
ret = safe_atoi(uri[2], &qi.playlist_id);
ret = safe_atoi(uri[2], &qp.pl_id);
if (ret < 0)
{
rsp_send_error(req, "Invalid playlist ID");
return;
}
if (qp.pl_id == 0)
qp.type = Q_ITEMS;
else
qp.type = Q_PLITEMS;
mode = F_FULL;
param = evhttp_find_header(query, "type");
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);
}
ret = get_query_params(req, query, &qi, &offset, &limit);
ret = get_query_params(req, query, &qp);
if (ret < 0)
return;
ret = db_enum_start(&db_errmsg, &qi);
if (ret != DB_E_SUCCESS)
ret = db_query_start(&qp);
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)
free(qi.filter);
free(db_errmsg);
if (qp.filter)
free(qp.filter);
return;
}
if (offset > qi.specifiedtotalcount)
if (qp.offset > qp.results)
records = 0;
else if (limit > (qi.specifiedtotalcount - offset))
records = qi.specifiedtotalcount - offset;
else if (qp.limit > (qp.results - qp.offset))
records = qp.results - qp.offset;
else
records = limit;
records = qp.limit;
/* We'd use mxmlNewXML(), but then we can't put any attributes
* 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);
node = mxmlNewElement(status, "totalrecords");
mxmlNewTextf(node, 0, "%d", qi.specifiedtotalcount);
mxmlNewTextf(node, 0, "%d", qp.results);
/* 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 = 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))
continue;
strval = (char **) ((char *)dbmfi + rsp_fields[i].offset);
strval = (char **) ((char *)&dbmfi + rsp_fields[i].offset);
if (!(*strval) || (strlen(*strval) == 0))
continue;
@ -606,7 +578,7 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
case dbmfi_offsetof(bitrate):
bitrate = 0;
ret = safe_atoi(dbmfi->samplerate, &bitrate);
ret = safe_atoi(dbmfi.samplerate, &bitrate);
if ((ret < 0) || (bitrate == 0))
bitrate = 1411;
else
@ -634,37 +606,29 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
}
}
if (qi.filter)
free(qi.filter);
if (qp.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);
rsp_send_error(req, db_errmsg);
free(db_errmsg);
db_query_end(&qp);
rsp_send_error(req, "Error fetching query results");
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
* 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/>
* tag that the SoundBridge does not handle. It's hackish, but it works.
*/
if (qi.specifiedtotalcount == 0)
if (qp.results == 0)
mxmlNewText(items, 0, "");
db_query_end(&qp);
evbuf = mxml_to_evbuf(reply);
mxmlDelete(reply);
@ -685,29 +649,26 @@ rsp_reply_playlist(struct evhttp_request *req, char **uri, struct evkeyvalq *que
static void
rsp_reply_browse(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
{
DBQUERYINFO qi;
struct db_media_file_info *dbmfi;
struct query_params qp;
struct evbuffer *evbuf;
char *db_errmsg;
char *browse_item;
mxml_node_t *reply;
mxml_node_t *status;
mxml_node_t *items;
mxml_node_t *node;
int limit;
int offset;
int records;
int ret;
memset(&qi, 0, sizeof(DBQUERYINFO));
memset(&qp, 0, sizeof(struct query_params));
if (strcmp(uri[3], "artist") == 0)
qi.query_type = queryTypeBrowseArtists;
qp.type = Q_BROWSE_ARTISTS;
else if (strcmp(uri[3], "genre") == 0)
qi.query_type = queryTypeBrowseGenres;
qp.type = Q_BROWSE_GENRES;
else if (strcmp(uri[3], "album") == 0)
qi.query_type = queryTypeBrowseAlbums;
qp.type = Q_BROWSE_ALBUMS;
else if (strcmp(uri[3], "composer") == 0)
qi.query_type = queryTypeBrowseComposers;
qp.type = Q_BROWSE_COMPOSERS;
else
{
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;
}
ret = safe_atoi(uri[2], &qi.playlist_id);
ret = safe_atoi(uri[2], &qp.pl_id);
if (ret < 0)
{
rsp_send_error(req, "Invalid playlist ID");
return;
}
ret = get_query_params(req, query, &qi, &offset, &limit);
ret = get_query_params(req, query, &qp);
if (ret < 0)
return;
ret = db_enum_start(&db_errmsg, &qi);
if (ret != DB_E_SUCCESS)
ret = db_query_start(&qp);
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)
free(qi.filter);
free(db_errmsg);
if (qp.filter)
free(qp.filter);
return;
}
if (offset > qi.specifiedtotalcount)
if (qp.offset > qp.results)
records = 0;
else if (limit > (qi.specifiedtotalcount - offset))
records = qi.specifiedtotalcount - offset;
else if (qp.limit > (qp.results - qp.offset))
records = qp.results - qp.offset;
else
records = limit;
records = qp.limit;
/* We'd use mxmlNewXML(), but then we can't put any attributes
* 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);
node = mxmlNewElement(status, "totalrecords");
mxmlNewTextf(node, 0, "%d", qi.specifiedtotalcount);
mxmlNewTextf(node, 0, "%d", qp.results);
/* 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");
mxmlNewText(node, 0, dbmfi->id);
mxmlNewText(node, 0, browse_item);
}
if (qi.filter)
free(qi.filter);
if (qp.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);
rsp_send_error(req, db_errmsg);
free(db_errmsg);
db_query_end(&qp);
rsp_send_error(req, "Error fetching query results");
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
* 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/>
* tag that the SoundBridge does not handle. It's hackish, but it works.
*/
if (qi.specifiedtotalcount == 0)
if (qp.results == 0);
mxmlNewText(items, 0, "");
db_query_end(&qp);
evbuf = mxml_to_evbuf(reply);
mxmlDelete(reply);

View File

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

View File

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

View File

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

View File

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

View File

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