mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-24 06:05:56 -05:00
Merged win32-branch
This commit is contained in:
parent
bb894c5895
commit
9a133dcbdc
@ -6,6 +6,10 @@ body
|
||||
color: #3C5C6B;
|
||||
}
|
||||
|
||||
img
|
||||
{ border: 0px;
|
||||
}
|
||||
|
||||
table.main
|
||||
{ border: 0px;
|
||||
|
||||
|
@ -13,6 +13,9 @@ dnl AM_PROG_LEX
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
AC_CHECK_HEADERS([sys/wait.h])
|
||||
AC_CHECK_FUNCS(strptime)
|
||||
AC_CHECK_FUNCS(strtok_r)
|
||||
AM_CONDITIONAL(COND_REND_OSX,false)
|
||||
|
||||
rend_posix=true
|
||||
|
@ -3,7 +3,7 @@
|
||||
mv configure.in configure.in.mkdist
|
||||
cat configure.in.mkdist | sed -e s/AM_INIT_AUTOMAKE.*$/AM_INIT_AUTOMAKE\(mt-daapd,cvs-`date +%Y%m%d`\)/ > configure.in
|
||||
./reconf
|
||||
./configure --with-id3tag=/sw
|
||||
./configure --with-id3tag=/sw --enable-sqlite --enable-sqlite3
|
||||
make dist
|
||||
mv configure.in.mkdist configure.in
|
||||
|
||||
|
@ -52,13 +52,17 @@ mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \
|
||||
rxml.c rxml.h redblack.c redblack.h scan-mp3.c scan-mp4.c \
|
||||
scan-xml.c scan-wma.c scan-aac.c scan-aac.h scan-wav.c scan-url.c \
|
||||
smart-parser.c smart-parser.h xml-rpc.c xml-rpc.h \
|
||||
os.h strptime.c strptime.h \
|
||||
strtok_r.c strtok_r.h os-unix.h os-unix.c os.h \
|
||||
$(PRENDSRC) $(ORENDSRC) $(HRENDSRC) $(OGGVORBISSRC) $(FLACSRC) \
|
||||
$(MUSEPACKSRC) $(SQLITEDB) $(SQLITE3DB) $(SQLDB)
|
||||
|
||||
EXTRA_DIST = mDNS.c mDNSClientAPI.h mDNSDebug.h mDNSPosix.c \
|
||||
mDNSUNP.c mDNSPlatformFunctions.h mDNSPosix.h mDNSUNP.h \
|
||||
rend-howl.c rend-posix.c rend-osx.c scan-mpc.c \
|
||||
strcasestr.h scan-ogg.c scan-flac.c db-sql.c db-sql.h \
|
||||
scan-ogg.c scan-flac.c db-sql.c db-sql.h \
|
||||
db-sql-sqlite2.h db-sql-sqlite2.c \
|
||||
db-sql-sqlite3.h db-sql-sqlite3.c
|
||||
db-sql-sqlite3.h db-sql-sqlite3.c \
|
||||
w32-eventlog.c w32-eventlog.h w32-service.c w32-service.h \
|
||||
os-win32.h os-win32.c win32.h
|
||||
|
||||
|
@ -35,7 +35,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <restart.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
@ -45,11 +44,14 @@
|
||||
#include <zlib.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include "configfile.h"
|
||||
#include "db-generic.h"
|
||||
#include "err.h"
|
||||
#include "restart.h"
|
||||
#include "xml-rpc.h"
|
||||
|
||||
#ifndef WITHOUT_MDNS
|
||||
@ -71,6 +73,7 @@ static void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg
|
||||
static void config_emit_user(WS_CONNINFO *pwsc, void *value, char *arg);
|
||||
static void config_emit_readonly(WS_CONNINFO *pwsc, void *value, char *arg);
|
||||
static void config_emit_version(WS_CONNINFO *pwsc, void *value, char *arg);
|
||||
static void config_emit_debuglevel(WS_CONNINFO *pwsc, void *value, char *arg);
|
||||
static void config_emit_system(WS_CONNINFO *pwsc, void *value, char *arg);
|
||||
static void config_emit_flags(WS_CONNINFO *pwsc, void *value, char *arg);
|
||||
static void config_emit_host(WS_CONNINFO *pwsc, void *value, char *arg);
|
||||
@ -119,7 +122,7 @@ CONFIGELEMENT config_elements[] = {
|
||||
{ 1,0,0,CONFIG_TYPE_STRING,"db_dir",(void*)&config.dbdir,config_emit_string },
|
||||
{ 1,0,0,CONFIG_TYPE_STRING,"db_type",(void*)&config.dbtype,config_emit_string },
|
||||
{ 1,0,0,CONFIG_TYPE_STRING,"db_parms",(void*)&config.dbparms,config_emit_string },
|
||||
{ 1,0,0,CONFIG_TYPE_INT,"debuglevel",(void*)&err_debuglevel,config_emit_int },
|
||||
{ 1,0,0,CONFIG_TYPE_INT,"debuglevel",(void*)NULL,config_emit_debuglevel },
|
||||
{ 1,1,0,CONFIG_TYPE_STRING,"servername",(void*)&config.servername,config_emit_string },
|
||||
{ 1,0,0,CONFIG_TYPE_INT,"rescan_interval",(void*)&config.rescan_interval,config_emit_int },
|
||||
{ 1,0,0,CONFIG_TYPE_INT,"always_scan",(void*)&config.always_scan,config_emit_int },
|
||||
@ -491,7 +494,7 @@ int config_read(char *file) {
|
||||
*term_end='\0';
|
||||
|
||||
while(strlen(term_begin) && term_begin[strlen(term_begin)-1]==' ')
|
||||
term_begin[strlen(term_begin)-1] == '\0';
|
||||
term_begin[strlen(term_begin)-1] = '\0';
|
||||
|
||||
if(strlen(term_begin)) {
|
||||
config.complist[currentterm++] = term_begin;
|
||||
@ -866,8 +869,10 @@ void config_emit_int(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||
* \param arg any args passwd with the meta command. Also unused
|
||||
*/
|
||||
void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||
#ifndef WITHOUT_MDNS
|
||||
int mdns_running;
|
||||
char *html;
|
||||
#endif
|
||||
char buf[256];
|
||||
int r_days, r_hours, r_mins, r_secs;
|
||||
int scanning;
|
||||
@ -919,7 +924,7 @@ void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||
ws_writefd(pwsc,"<tr>\n");
|
||||
ws_writefd(pwsc," <th>Uptime</th>\n");
|
||||
|
||||
r_secs=time(NULL)-config.stats.start_time;
|
||||
r_secs=(int)(time(NULL)-config.stats.start_time);
|
||||
|
||||
r_days=r_secs/(3600 * 24);
|
||||
r_secs -= ((3600 * 24) * r_days);
|
||||
@ -1317,6 +1322,16 @@ void config_emit_version(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||
ws_writefd(pwsc,"%s",VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* implement the DEBUGLEVEL command
|
||||
*
|
||||
* @param pwsc web connection
|
||||
* @param value the variable that was requested. Unused.
|
||||
* @param arg any args passed with the meta command. Unused.
|
||||
*/
|
||||
void config_emit_debuglevel(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||
ws_writefd(pwsc,"%d",err_getlevel());
|
||||
}
|
||||
|
||||
/**
|
||||
* implement the SYSTEM command.
|
||||
|
@ -59,7 +59,6 @@ typedef struct tag_config {
|
||||
int process_m3u; /**< Should we process m3u files? */
|
||||
int scan_type; /**< Method for finding playtime. see scan-mp3.c */
|
||||
int compress; /**< Should we compress? */
|
||||
int pid; /**< pid that will accept INT to terminate */
|
||||
int latin1_tags; /**< interpret all tags as latin1 rather than utf8 */
|
||||
char *adminpassword; /**< Password to web management pages */
|
||||
char *readpassword; /**< iTunes password */
|
||||
@ -83,7 +82,4 @@ typedef struct tag_config {
|
||||
|
||||
extern CONFIG config;
|
||||
|
||||
/* Forwards */
|
||||
extern int drop_privs(char *user);
|
||||
|
||||
#endif /* _DAAPD_H_ */
|
||||
|
@ -231,12 +231,12 @@ DAAP_ITEMS taglist[] = {
|
||||
{ 0x05, "aeSI", "com.apple.iTunes.itms-songid" },
|
||||
{ 0x05, "aeSF", "com.apple.iTunes.itms-storefrontid" },
|
||||
|
||||
/* iTunes 5.0+ */
|
||||
{ 0x01, "ascr", "daap.songcontentrating" },
|
||||
{ 0x05, "f" "\x8d" "ch", "dmap.haschildcontainers" }, /* wtf - content codes says it's 1 */
|
||||
|
||||
/* iTunes 6.0.2+ */
|
||||
{ 0x01, "aeHV", "com.apple.itunes.has-video" },
|
||||
/* iTunes 5.0+ */
|
||||
{ 0x01, "ascr", "daap.songcontentrating" },
|
||||
{ 0x05, "f" "\x8d" "ch", "dmap.haschildcontainers" }, /* wtf - content codes says it's 1 */
|
||||
|
||||
/* iTunes 6.0.2+ */
|
||||
{ 0x01, "aeHV", "com.apple.itunes.has-video" },
|
||||
|
||||
/* mt-daapd specific */
|
||||
{ 0x09, "MSPS", "org.mt-daapd.smart-playlist-spec" },
|
||||
@ -361,7 +361,7 @@ MetaField_t db_encode_meta(char *meta) {
|
||||
if(0 == (end = strchr(start, ',')))
|
||||
end = start + strlen(start);
|
||||
|
||||
len = end - start;
|
||||
len = (int)(end - start);
|
||||
|
||||
if(*end != 0)
|
||||
end++;
|
||||
@ -789,11 +789,11 @@ int db_end_scan(void) {
|
||||
}
|
||||
|
||||
void db_dispose_item(MP3FILE *pmp3) {
|
||||
return db_current->dbs_dispose_item(pmp3);
|
||||
db_current->dbs_dispose_item(pmp3);
|
||||
}
|
||||
|
||||
void db_dispose_playlist(M3UFILE *pm3u) {
|
||||
return db_current->dbs_dispose_playlist(pm3u);
|
||||
db_current->dbs_dispose_playlist(pm3u);
|
||||
}
|
||||
|
||||
int db_get_count(char **pe, int *count, CountType_t type) {
|
||||
@ -899,7 +899,7 @@ int db_dmap_add_int(unsigned char *where, char *tag, int value) {
|
||||
*/
|
||||
|
||||
int db_dmap_add_string(unsigned char *where, char *tag, char *value) {
|
||||
int len=strlen(value);
|
||||
int len=(int)strlen(value);
|
||||
|
||||
/* tag */
|
||||
memcpy(where,tag,4);
|
||||
@ -911,7 +911,7 @@ int db_dmap_add_string(unsigned char *where, char *tag, char *value) {
|
||||
where[7]=len & 0xFF;
|
||||
|
||||
strncpy((char*)where+8,value,strlen(value));
|
||||
return 8 + strlen(value);
|
||||
return 8 + (int) strlen(value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,7 +41,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sqlite.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "err.h"
|
||||
#include "db-generic.h"
|
||||
|
@ -20,10 +20,10 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles sqlite2 databases. SQLite2 databases
|
||||
* This file handles sqlite3 databases. SQLite3 databases
|
||||
* should have a dsn of:
|
||||
*
|
||||
* sqlite2:/path/to/folder
|
||||
* sqlite3:/path/to/folder
|
||||
*
|
||||
* The actual db will be appended to the passed path.
|
||||
*/
|
||||
@ -41,7 +41,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sqlite3.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "err.h"
|
||||
#include "db-generic.h"
|
||||
@ -287,7 +290,7 @@ int db_sqlite3_enum_fetch(char **pe, SQL_ROW *pr) {
|
||||
}
|
||||
|
||||
for(idx=0; idx < cols; idx++) {
|
||||
db_sqlite3_row[idx] = sqlite3_column_text(db_sqlite3_stmt,idx);
|
||||
db_sqlite3_row[idx] = (char*) sqlite3_column_text(db_sqlite3_stmt,idx);
|
||||
}
|
||||
|
||||
*pr = db_sqlite3_row;
|
||||
|
30
src/db-sql.c
30
src/db-sql.c
@ -238,9 +238,9 @@ int db_sql_parse_smart(char **pe, char **clause, char *phrase) {
|
||||
|
||||
if(!sp_parse(pt,phrase)) {
|
||||
if(pe) *pe = strdup(sp_get_error(pt));
|
||||
|
||||
|
||||
DPRINTF(E_LOG,L_DB,"Error parsing playlist: %s\n",sp_get_error(pt));
|
||||
|
||||
|
||||
sp_dispose(pt);
|
||||
return FALSE;
|
||||
} else {
|
||||
@ -1202,7 +1202,7 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
|
||||
case queryTypeBrowseAlbums:
|
||||
case queryTypeBrowseGenres:
|
||||
case queryTypeBrowseComposers:
|
||||
return valarray[0] ? (8 + strlen(valarray[0])) : 0;
|
||||
return valarray[0] ? (8 + (int) strlen(valarray[0])) : 0;
|
||||
case queryTypePlaylists:
|
||||
size = 8; /* mlit */
|
||||
size += 12; /* mimc - you get it whether you want it or not */
|
||||
@ -1213,10 +1213,10 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
|
||||
size += 9; /* aeSP */
|
||||
}
|
||||
if(db_wantsmeta(pinfo->meta, metaItemName))
|
||||
size += (8 + strlen(valarray[plTitle])); /* minm */
|
||||
size += (8 + (int) strlen(valarray[plTitle])); /* minm */
|
||||
if(valarray[plType] && (atoi(valarray[plType])==1) &&
|
||||
db_wantsmeta(pinfo->meta, metaMPlaylistSpec))
|
||||
size += (8 + strlen(valarray[plQuery])); /* MSPS */
|
||||
size += (8 + (int) strlen(valarray[plQuery])); /* MSPS */
|
||||
if(db_wantsmeta(pinfo->meta, metaMPlaylistType))
|
||||
size += 9; /* MPTY */
|
||||
return size;
|
||||
@ -1244,13 +1244,13 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
|
||||
size += 9;
|
||||
if(ISSTR(valarray[13]) && db_wantsmeta(pinfo->meta, metaSongDataURL))
|
||||
/* asul */
|
||||
size += (8 + strlen(valarray[13]));
|
||||
size += (8 + (int) strlen(valarray[13]));
|
||||
if(ISSTR(valarray[5]) && db_wantsmeta(pinfo->meta, metaSongAlbum))
|
||||
/* asal */
|
||||
size += (8 + strlen(valarray[5]));
|
||||
size += (8 + (int) strlen(valarray[5]));
|
||||
if(ISSTR(valarray[4]) && db_wantsmeta(pinfo->meta, metaSongArtist))
|
||||
/* asar */
|
||||
size += (8 + strlen(valarray[4]));
|
||||
size += (8 + (int) strlen(valarray[4]));
|
||||
if(valarray[23] && atoi(valarray[23]) && db_wantsmeta(pinfo->meta, metaSongBPM))
|
||||
/* asbt */
|
||||
size += 10;
|
||||
@ -1266,16 +1266,16 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
|
||||
}
|
||||
if(ISSTR(valarray[7]) && db_wantsmeta(pinfo->meta, metaSongComment))
|
||||
/* ascm */
|
||||
size += (8 + strlen(valarray[7]));
|
||||
size += (8 + (int) strlen(valarray[7]));
|
||||
if(valarray[24] && atoi(valarray[24]) && db_wantsmeta(pinfo->meta,metaSongCompilation))
|
||||
/* asco */
|
||||
size += 9;
|
||||
if(ISSTR(valarray[9]) && db_wantsmeta(pinfo->meta, metaSongComposer))
|
||||
/* ascp */
|
||||
size += (8 + strlen(valarray[9]));
|
||||
size += (8 + (int) strlen(valarray[9]));
|
||||
if(ISSTR(valarray[12]) && db_wantsmeta(pinfo->meta, metaSongGrouping))
|
||||
/* agrp */
|
||||
size += (8 + strlen(valarray[12]));
|
||||
size += (8 + (int) strlen(valarray[12]));
|
||||
if(valarray[30] && atoi(valarray[30]) && db_wantsmeta(pinfo->meta, metaSongDateAdded))
|
||||
/* asda */
|
||||
size += 12;
|
||||
@ -1290,7 +1290,7 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
|
||||
/* asdn */
|
||||
if(ISSTR(valarray[6]) && db_wantsmeta(pinfo->meta, metaSongGenre))
|
||||
/* asgn */
|
||||
size += (8 + strlen(valarray[6]));
|
||||
size += (8 + (int) strlen(valarray[6]));
|
||||
if(db_wantsmeta(pinfo->meta,metaItemId))
|
||||
/* miid */
|
||||
size += 12;
|
||||
@ -1299,7 +1299,7 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
|
||||
if(transcode) {
|
||||
size += 11; /* 'wav' */
|
||||
} else {
|
||||
size += (8 + strlen(valarray[8]));
|
||||
size += (8 + (int) strlen(valarray[8]));
|
||||
}
|
||||
}
|
||||
if(ISSTR(valarray[29]) && db_wantsmeta(pinfo->meta,metaSongDescription)) {
|
||||
@ -1307,12 +1307,12 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
|
||||
if(transcode) {
|
||||
size += 22; /* 'wav audio file' */
|
||||
} else {
|
||||
size += (8 + strlen(valarray[29]));
|
||||
size += (8 + (int) strlen(valarray[29]));
|
||||
}
|
||||
}
|
||||
if(ISSTR(valarray[3]) && db_wantsmeta(pinfo->meta,metaItemName))
|
||||
/* minm */
|
||||
size += (8 + strlen(valarray[3]));
|
||||
size += (8 + (int) strlen(valarray[3]));
|
||||
if(valarray[34] && atoi(valarray[34]) && db_wantsmeta(pinfo->meta,metaSongDisabled))
|
||||
/* asdb */
|
||||
size += 9;
|
||||
|
112
src/dispatch.c
112
src/dispatch.c
@ -27,10 +27,15 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "db-generic.h"
|
||||
#include "configfile.h"
|
||||
@ -40,9 +45,11 @@
|
||||
#include "ssc.h"
|
||||
#include "dynamic-art.h"
|
||||
#include "restart.h"
|
||||
#include "strtok_r.h"
|
||||
#include "daapd.h"
|
||||
#include "query.h"
|
||||
|
||||
|
||||
/* Forwards */
|
||||
static void dispatch_server_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
||||
static void dispatch_login(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
||||
@ -166,20 +173,30 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
||||
}
|
||||
|
||||
/* Start dispatching */
|
||||
if(!strcasecmp(pqi->uri_sections[0],"server-info"))
|
||||
return dispatch_server_info(pwsc,pqi);
|
||||
if(!strcasecmp(pqi->uri_sections[0],"server-info")) {
|
||||
dispatch_server_info(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!strcasecmp(pqi->uri_sections[0],"content-codes"))
|
||||
return dispatch_content_codes(pwsc,pqi);
|
||||
if(!strcasecmp(pqi->uri_sections[0],"content-codes")) {
|
||||
dispatch_content_codes(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!strcasecmp(pqi->uri_sections[0],"login"))
|
||||
return dispatch_login(pwsc,pqi);
|
||||
if(!strcasecmp(pqi->uri_sections[0],"login")) {
|
||||
dispatch_login(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!strcasecmp(pqi->uri_sections[0],"update"))
|
||||
return dispatch_update(pwsc,pqi);
|
||||
if(!strcasecmp(pqi->uri_sections[0],"update")) {
|
||||
dispatch_update(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!strcasecmp(pqi->uri_sections[0],"logout"))
|
||||
return dispatch_logout(pwsc,pqi);
|
||||
if(!strcasecmp(pqi->uri_sections[0],"logout")) {
|
||||
dispatch_logout(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* /databases/id/items
|
||||
@ -190,16 +207,21 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
||||
*/
|
||||
if(!strcasecmp(pqi->uri_sections[0],"databases")) {
|
||||
if(pqi->uri_count == 1) {
|
||||
return dispatch_dbinfo(pwsc,pqi);
|
||||
dispatch_dbinfo(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
pqi->db_id=atoi(pqi->uri_sections[1]);
|
||||
if(pqi->uri_count == 3) {
|
||||
if(!strcasecmp(pqi->uri_sections[2],"items"))
|
||||
if(!strcasecmp(pqi->uri_sections[2],"items")) {
|
||||
/* /databases/id/items */
|
||||
return dispatch_items(pwsc,pqi);
|
||||
if(!strcasecmp(pqi->uri_sections[2],"containers"))
|
||||
dispatch_items(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
if(!strcasecmp(pqi->uri_sections[2],"containers")) {
|
||||
/* /databases/id/containers */
|
||||
return dispatch_playlists(pwsc,pqi);
|
||||
dispatch_playlists(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
|
||||
pwsc->close=1;
|
||||
free(pqi);
|
||||
@ -207,24 +229,35 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
||||
return;
|
||||
}
|
||||
if(pqi->uri_count == 4) {
|
||||
if(!strcasecmp(pqi->uri_sections[2],"browse"))
|
||||
if(!strcasecmp(pqi->uri_sections[2],"browse")) {
|
||||
/* /databases/id/browse/something */
|
||||
return dispatch_browse(pwsc,pqi);
|
||||
if(!strcasecmp(pqi->uri_sections[2],"items"))
|
||||
dispatch_browse(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
if(!strcasecmp(pqi->uri_sections[2],"items")) {
|
||||
/* /databases/id/items/id.mp3 */
|
||||
return dispatch_stream(pwsc,pqi);
|
||||
dispatch_stream(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
||||
(!strcasecmp(pqi->uri_sections[3],"add")))
|
||||
/* /databases/id/containers/add */
|
||||
return dispatch_addplaylist(pwsc,pqi);
|
||||
(!strcasecmp(pqi->uri_sections[3],"add"))) {
|
||||
/* /databases/id/containers/add */
|
||||
dispatch_addplaylist(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
||||
(!strcasecmp(pqi->uri_sections[3],"del")))
|
||||
/* /databases/id/containers/del */
|
||||
return dispatch_deleteplaylist(pwsc,pqi);
|
||||
(!strcasecmp(pqi->uri_sections[3],"del"))) {
|
||||
/* /databases/id/containers/del */
|
||||
dispatch_deleteplaylist(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
||||
(!strcasecmp(pqi->uri_sections[3],"edit")))
|
||||
(!strcasecmp(pqi->uri_sections[3],"edit"))) {
|
||||
/* /databases/id/contaienrs/edit */
|
||||
return dispatch_editplaylist(pwsc,pqi);
|
||||
dispatch_editplaylist(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
|
||||
pwsc->close=1;
|
||||
free(pqi);
|
||||
ws_returnerror(pwsc,404,"Page not found");
|
||||
@ -234,13 +267,15 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
||||
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
||||
(!strcasecmp(pqi->uri_sections[4],"items"))) {
|
||||
pqi->playlist_id=atoi(pqi->uri_sections[3]);
|
||||
return dispatch_playlistitems(pwsc,pqi);
|
||||
dispatch_playlistitems(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
||||
(!strcasecmp(pqi->uri_sections[4],"del"))) {
|
||||
/* /databases/id/containers/id/del */
|
||||
pqi->playlist_id=atoi(pqi->uri_sections[3]);
|
||||
return dispatch_deleteplaylistitems(pwsc,pqi);
|
||||
dispatch_deleteplaylistitems(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(pqi->uri_count == 6) {
|
||||
@ -248,7 +283,8 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
||||
(!strcasecmp(pqi->uri_sections[4],"items")) &&
|
||||
(!strcasecmp(pqi->uri_sections[5],"add"))) {
|
||||
pqi->playlist_id=atoi(pqi->uri_sections[3]);
|
||||
return dispatch_addplaylistitems(pwsc,pqi);
|
||||
dispatch_addplaylistitems(pwsc,pqi);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -355,7 +391,7 @@ int dispatch_output_xml_write(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, unsigned char
|
||||
|
||||
while(current < (block + len)) {
|
||||
block_done=1;
|
||||
len_left=(block+len) - current;
|
||||
len_left=(int)((block+len) - current);
|
||||
if(len_left < 8) {
|
||||
DPRINTF(E_FATAL,L_DAAP,"Badly formatted dmap block - frag size: %d",len_left);
|
||||
}
|
||||
@ -564,7 +600,7 @@ char *dispatch_xml_encode(char *original, int len) {
|
||||
if(len) {
|
||||
truelen=len;
|
||||
} else {
|
||||
truelen=strlen(original);
|
||||
truelen=(int) strlen(original);
|
||||
}
|
||||
|
||||
destsize = 6*truelen+1;
|
||||
@ -1306,7 +1342,7 @@ void dispatch_dbinfo(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
int namelen;
|
||||
int count;
|
||||
|
||||
namelen=strlen(config.servername);
|
||||
namelen=(int) strlen(config.servername);
|
||||
|
||||
current += db_dmap_add_container(current,"avdb",105 + namelen);
|
||||
current += db_dmap_add_int(current,"mstt",200); /* 12 */
|
||||
@ -1363,7 +1399,7 @@ void dispatch_content_codes(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
dicurrent=taglist;
|
||||
len=0;
|
||||
while(dicurrent->type) {
|
||||
len += (8 + 12 + 10 + 8 + strlen(dicurrent->description));
|
||||
len += (8 + 12 + 10 + 8 + (int) strlen(dicurrent->description));
|
||||
dicurrent++;
|
||||
}
|
||||
|
||||
@ -1376,7 +1412,7 @@ void dispatch_content_codes(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
dicurrent=taglist;
|
||||
while(dicurrent->type) {
|
||||
current=mdcl;
|
||||
len = 12 + 10 + 8 + strlen(dicurrent->description);
|
||||
len = 12 + 10 + 8 + (int) strlen(dicurrent->description);
|
||||
current += db_dmap_add_container(current,"mdcl",len);
|
||||
current += db_dmap_add_string(current,"mcnm",dicurrent->tag); /* 12 */
|
||||
current += db_dmap_add_string(current,"mcna",dicurrent->description); /* 8 + descr */
|
||||
@ -1396,7 +1432,7 @@ void dispatch_server_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
int mpro = 2 << 16;
|
||||
int apro = 3 << 16;
|
||||
|
||||
int actual_length=130 + strlen(config.servername);
|
||||
int actual_length=130 + (int) strlen(config.servername);
|
||||
|
||||
if(actual_length > sizeof(server_info)) {
|
||||
DPRINTF(E_FATAL,L_DAAP,"Server name too long.\n");
|
||||
@ -1446,7 +1482,7 @@ void dispatch_error(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *container, char *
|
||||
unsigned char *block, *current;
|
||||
int len;
|
||||
|
||||
len = 12 + 8 + 8 + strlen(error);
|
||||
len = 12 + 8 + 8 + (int) strlen(error);
|
||||
block = (unsigned char *)malloc(len);
|
||||
|
||||
if(!block)
|
||||
|
@ -20,13 +20,19 @@
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@ -48,11 +54,11 @@ int fcopyblock(FILE *fromfp, int tofd, size_t size);
|
||||
This size is everything after the APIC text in this frame.
|
||||
*/
|
||||
/* APIC tag is made up from
|
||||
APIC (4 bytes)
|
||||
xxxx (4 bytes - Image size: raw + 16)
|
||||
\0\0\0 (3 bytes)
|
||||
image/jpeg (10 bytes)
|
||||
\0\0\0 (3 bytes)
|
||||
APIC (4 bytes)
|
||||
xxxx (4 bytes - Image size: raw + 16)
|
||||
\0\0\0 (3 bytes)
|
||||
image/jpeg (10 bytes)
|
||||
\0\0\0 (3 bytes)
|
||||
Image-data
|
||||
*/
|
||||
#define id3v3_image_size(x) x + 14
|
||||
@ -61,11 +67,11 @@ int fcopyblock(FILE *fromfp, int tofd, size_t size);
|
||||
/* This size is everything after the PIC in this frame
|
||||
*/
|
||||
/* PIC tag is made up of
|
||||
PIC (3 bytes)
|
||||
xxx (3 bytes - Image size: raw + 6)
|
||||
\0 (1 byte)
|
||||
JPG (3 bytes)
|
||||
\0\0 (2 bytes)
|
||||
PIC (3 bytes)
|
||||
xxx (3 bytes - Image size: raw + 6)
|
||||
\0 (1 byte)
|
||||
JPG (3 bytes)
|
||||
\0\0 (2 bytes)
|
||||
Image-data
|
||||
*/
|
||||
|
||||
@ -90,7 +96,7 @@ int da_get_image_fd(char *filename) {
|
||||
strcpy(path_end+1,config.artfilename);
|
||||
fd = open(buffer,O_RDONLY);
|
||||
if(fd != -1)
|
||||
DPRINTF(E_INF,L_ART,"Found image file %s (fd %d)\n",buffer,fd);
|
||||
DPRINTF(E_INF,L_ART,"Found image file %s (fd %d)\n",buffer,fd);
|
||||
|
||||
return fd;
|
||||
}
|
||||
@ -105,20 +111,20 @@ int da_get_image_fd(char *filename) {
|
||||
int *da_get_current_tag_info(int file_fd) {
|
||||
unsigned char buffer[10];
|
||||
int *tag_info;
|
||||
|
||||
|
||||
tag_info = (int *) calloc(2,sizeof(int));
|
||||
|
||||
|
||||
r_read(file_fd,buffer,10);
|
||||
if (strncmp((char*)buffer,"ID3", 3) == 0 ) {
|
||||
tag_info[0] = buffer[3];
|
||||
tag_info[1] = ( buffer[6] << 21 ) + ( buffer[7] << 14 ) + ( buffer[8] << 7 ) + buffer[9];
|
||||
return tag_info;
|
||||
tag_info[0] = buffer[3];
|
||||
tag_info[1] = ( buffer[6] << 21 ) + ( buffer[7] << 14 ) + ( buffer[8] << 7 ) + buffer[9];
|
||||
return tag_info;
|
||||
} else {
|
||||
/* By default, we attach an id3v2.3 tag */
|
||||
lseek(file_fd,0,SEEK_SET);
|
||||
tag_info[0] = 2;
|
||||
tag_info[1] = 0;
|
||||
return tag_info;
|
||||
/* By default, we attach an id3v2.3 tag */
|
||||
lseek(file_fd,0,SEEK_SET);
|
||||
tag_info[0] = 2;
|
||||
tag_info[1] = 0;
|
||||
return tag_info;
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,14 +149,14 @@ int da_attach_image(int img_fd, int out_fd, int mp3_fd, int offset)
|
||||
|
||||
DPRINTF(E_INF,L_ART,"Image appears to be %ld bytes\n",img_size);
|
||||
if(img_size < 1) {
|
||||
r_close(img_fd);
|
||||
return 0;
|
||||
r_close(img_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (offset > (img_size + 24) ) {
|
||||
lseek(mp3_fd,(offset - img_size - 24),SEEK_SET);
|
||||
r_close(img_fd);
|
||||
return 0;
|
||||
lseek(mp3_fd,(offset - img_size - 24),SEEK_SET);
|
||||
r_close(img_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tag_info = da_get_current_tag_info(mp3_fd);
|
||||
@ -159,35 +165,35 @@ int da_attach_image(int img_fd, int out_fd, int mp3_fd, int offset)
|
||||
DPRINTF(E_INF,L_ART,"Current tag size is %d bytes\n",tag_size);
|
||||
|
||||
if (tag_info[0] == 3) {
|
||||
r_write(out_fd,"ID3\x03\0\0",6);
|
||||
tag_size += id3v3_tag_size(img_size);
|
||||
r_write(out_fd,"ID3\x03\0\0",6);
|
||||
tag_size += id3v3_tag_size(img_size);
|
||||
} else {
|
||||
r_write(out_fd,"ID3\x02\0\0",6);
|
||||
tag_size += id3v2_tag_size(img_size);
|
||||
r_write(out_fd,"ID3\x02\0\0",6);
|
||||
tag_size += id3v2_tag_size(img_size);
|
||||
}
|
||||
|
||||
buffer[3] = tag_size & 0x7F;
|
||||
buffer[2] = ( tag_size & 0x3F80 ) >> 7;
|
||||
buffer[1] = ( tag_size & 0x1FC000 ) >> 14;
|
||||
buffer[0] = ( tag_size & 0xFE00000 ) >> 21;
|
||||
|
||||
|
||||
r_write(out_fd,buffer,4);
|
||||
|
||||
|
||||
if (tag_info[0] == 3) {
|
||||
r_write(out_fd,"APIC\0",5);
|
||||
img_size = id3v3_image_size(img_size);
|
||||
r_write(out_fd,"APIC\0",5);
|
||||
img_size = id3v3_image_size(img_size);
|
||||
} else {
|
||||
r_write(out_fd,"PIC",3);
|
||||
img_size = id3v2_image_size(img_size);
|
||||
r_write(out_fd,"PIC",3);
|
||||
img_size = id3v2_image_size(img_size);
|
||||
}
|
||||
buffer[0] = ( img_size & 0xFF0000 ) >> 16;
|
||||
buffer[1] = ( img_size & 0xFF00 ) >> 8;
|
||||
buffer[2] = ( img_size & 0xFF );
|
||||
buffer[0] = ( (int) img_size & 0xFF0000 ) >> 16;
|
||||
buffer[1] = ( (int) img_size & 0xFF00 ) >> 8;
|
||||
buffer[2] = ( (int) img_size & 0xFF );
|
||||
r_write(out_fd,buffer,3);
|
||||
if (tag_info[0] == 3) {
|
||||
r_write(out_fd,"\0\0\0image/jpeg\0\0\0",16);
|
||||
r_write(out_fd,"\0\0\0image/jpeg\0\0\0",16);
|
||||
} else {
|
||||
r_write(out_fd,"\0JPG\x00\0",6);
|
||||
r_write(out_fd,"\0JPG\x00\0",6);
|
||||
}
|
||||
lseek(img_fd,0,SEEK_SET);
|
||||
copyfile(img_fd,out_fd);
|
||||
@ -226,41 +232,41 @@ off_t da_aac_rewrite_stco_atom(off_t extra_size, int out_fd, FILE *aac_fp,
|
||||
/* Drill down to the 'stco' atom which contains offsets to chunks in
|
||||
the 'mdat' section. These offsets need to be readjusted. */
|
||||
atom_offset = scan_aac_drilltoatom(aac_fp, "moov:trak:mdia:minf:stbl:stco",
|
||||
&atom_length);
|
||||
&atom_length);
|
||||
if (atom_offset != -1) {
|
||||
/* Skip flags */
|
||||
fseek(aac_fp, 4, SEEK_CUR);
|
||||
/* Skip flags */
|
||||
fseek(aac_fp, 4, SEEK_CUR);
|
||||
|
||||
old_pos = last_pos;
|
||||
cur_pos = ftell(aac_fp);
|
||||
old_pos = last_pos;
|
||||
cur_pos = ftell(aac_fp);
|
||||
|
||||
/* Copy from last point to this point. */
|
||||
fseek(aac_fp, old_pos, SEEK_SET);
|
||||
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
|
||||
/* Copy from last point to this point. */
|
||||
fseek(aac_fp, old_pos, SEEK_SET);
|
||||
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
|
||||
|
||||
/* Read number of entries */
|
||||
fread(buffer, 1, 4, aac_fp);
|
||||
r_write(out_fd, buffer, 4);
|
||||
/* Read number of entries */
|
||||
fread(buffer, 1, 4, aac_fp);
|
||||
r_write(out_fd, buffer, 4);
|
||||
|
||||
num_entries = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
|
||||
num_entries = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
|
||||
|
||||
DPRINTF(E_DBG, L_ART,"Readjusting %d 'stco' table offsets.\n", num_entries);
|
||||
/* PENDING: Error check on num_entries? */
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
fread(buffer, 1, 4, aac_fp);
|
||||
offset_entry = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
|
||||
/* Adjust chunk offset. */
|
||||
offset_entry += extra_size;
|
||||
buffer[3] = offset_entry & 0xFF;
|
||||
buffer[2] = (offset_entry >> 8) & 0xFF;
|
||||
buffer[1] = (offset_entry >> 16) & 0xFF;
|
||||
buffer[0] = (offset_entry >> 24) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
offset_entry = 0;
|
||||
}
|
||||
return ftell(aac_fp);
|
||||
DPRINTF(E_DBG, L_ART,"Readjusting %d 'stco' table offsets.\n", num_entries);
|
||||
/* PENDING: Error check on num_entries? */
|
||||
for (i = 0; i < (int)num_entries; i++) {
|
||||
fread(buffer, 1, 4, aac_fp);
|
||||
offset_entry = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
|
||||
/* Adjust chunk offset. */
|
||||
offset_entry += extra_size;
|
||||
buffer[3] = offset_entry & 0xFF;
|
||||
buffer[2] = (offset_entry >> 8) & 0xFF;
|
||||
buffer[1] = (offset_entry >> 16) & 0xFF;
|
||||
buffer[0] = (offset_entry >> 24) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
offset_entry = 0;
|
||||
}
|
||||
return ftell(aac_fp);
|
||||
} else {
|
||||
DPRINTF(E_LOG, L_ART,"No 'stco' atom found.\n");
|
||||
DPRINTF(E_LOG, L_ART,"No 'stco' atom found.\n");
|
||||
}
|
||||
return last_pos;
|
||||
}
|
||||
@ -285,17 +291,17 @@ off_t da_aac_insert_covr_atom(off_t extra_size, int out_fd, FILE *aac_fp,
|
||||
/* Figure out image file type since this needs to be encoded in the atom. */
|
||||
cp = strrchr(config.artfilename, '.');
|
||||
if (cp) {
|
||||
if (!strcasecmp(cp, ".jpeg") || !strcasecmp(cp, ".jpg")) {
|
||||
img_type_flag = 0x0d;
|
||||
}
|
||||
else if (!strcasecmp(cp, ".png")) {
|
||||
img_type_flag = 0x0e;
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_ART, "Image type '%s' not supported.\n", cp);
|
||||
return 0;
|
||||
}
|
||||
if (!strcasecmp(cp, ".jpeg") || !strcasecmp(cp, ".jpg")) {
|
||||
img_type_flag = 0x0d;
|
||||
}
|
||||
else if (!strcasecmp(cp, ".png")) {
|
||||
img_type_flag = 0x0e;
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_ART, "Image type '%s' not supported.\n", cp);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_LOG, L_ART, "No file extension for image file.\n");
|
||||
DPRINTF(E_LOG, L_ART, "No file extension for image file.\n");
|
||||
}
|
||||
|
||||
aac_fd = fileno(aac_fp);
|
||||
@ -305,119 +311,119 @@ off_t da_aac_insert_covr_atom(off_t extra_size, int out_fd, FILE *aac_fp,
|
||||
|
||||
atom_offset = scan_aac_findatom(aac_fp, file_size, "moov", &atom_length);
|
||||
if (atom_offset != -1) {
|
||||
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "udta", &atom_length);
|
||||
if (atom_offset != -1) {
|
||||
old_pos = last_pos;
|
||||
cur_pos = ftell(aac_fp) - 8;
|
||||
DPRINTF(E_INF,L_ART,"Found udta atom at %ld.\n", cur_pos);
|
||||
fseek(aac_fp, old_pos, SEEK_SET);
|
||||
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
|
||||
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "udta", &atom_length);
|
||||
if (atom_offset != -1) {
|
||||
old_pos = last_pos;
|
||||
cur_pos = ftell(aac_fp) - 8;
|
||||
DPRINTF(E_INF,L_ART,"Found udta atom at %ld.\n", cur_pos);
|
||||
fseek(aac_fp, old_pos, SEEK_SET);
|
||||
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
|
||||
|
||||
/* Write out new length */
|
||||
atom_length += extra_size;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
/* Write out new length */
|
||||
atom_length += extra_size;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
|
||||
cur_pos += 4;
|
||||
fseek(aac_fp, 8, SEEK_CUR);
|
||||
cur_pos += 4;
|
||||
fseek(aac_fp, 8, SEEK_CUR);
|
||||
|
||||
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "meta", &atom_length);
|
||||
if (atom_offset != -1) {
|
||||
old_pos = cur_pos;
|
||||
cur_pos = ftell(aac_fp) - 8;
|
||||
DPRINTF(E_INF,L_ART,"Found meta atom at %ld.\n", cur_pos);
|
||||
fseek(aac_fp, old_pos, SEEK_SET);
|
||||
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
|
||||
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "meta", &atom_length);
|
||||
if (atom_offset != -1) {
|
||||
old_pos = cur_pos;
|
||||
cur_pos = ftell(aac_fp) - 8;
|
||||
DPRINTF(E_INF,L_ART,"Found meta atom at %ld.\n", cur_pos);
|
||||
fseek(aac_fp, old_pos, SEEK_SET);
|
||||
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
|
||||
|
||||
/* Write out new length */
|
||||
atom_length += extra_size;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
/* Write out new length */
|
||||
atom_length += extra_size;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
|
||||
cur_pos += 4;
|
||||
fseek(aac_fp, 12, SEEK_CUR); /* "meta" atom hack. */
|
||||
cur_pos += 4;
|
||||
fseek(aac_fp, 12, SEEK_CUR); /* "meta" atom hack. */
|
||||
|
||||
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "ilst", &atom_length);
|
||||
if (atom_offset != -1) {
|
||||
old_pos = cur_pos;
|
||||
cur_pos = ftell(aac_fp) - 8;
|
||||
DPRINTF(E_INF,L_ART,"Found ilst atom at %ld.\n", cur_pos);
|
||||
fseek(aac_fp, old_pos, SEEK_SET);
|
||||
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
|
||||
atom_offset = scan_aac_findatom(aac_fp, atom_length - 8, "ilst", &atom_length);
|
||||
if (atom_offset != -1) {
|
||||
old_pos = cur_pos;
|
||||
cur_pos = ftell(aac_fp) - 8;
|
||||
DPRINTF(E_INF,L_ART,"Found ilst atom at %ld.\n", cur_pos);
|
||||
fseek(aac_fp, old_pos, SEEK_SET);
|
||||
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
|
||||
|
||||
old_pos = cur_pos + 4;
|
||||
cur_pos += atom_length;
|
||||
old_pos = cur_pos + 4;
|
||||
cur_pos += atom_length;
|
||||
|
||||
/* Write out new length */
|
||||
atom_length += extra_size;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
/* Write out new length */
|
||||
atom_length += extra_size;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
|
||||
/* Copy all 'ilst' children (all the MP4 'tags'). We will append
|
||||
at the end. */
|
||||
fseek(aac_fp, old_pos, SEEK_SET);
|
||||
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
|
||||
cur_pos = ftell(aac_fp);
|
||||
/* Copy all 'ilst' children (all the MP4 'tags'). We will append
|
||||
at the end. */
|
||||
fseek(aac_fp, old_pos, SEEK_SET);
|
||||
fcopyblock(aac_fp, out_fd, cur_pos - old_pos);
|
||||
cur_pos = ftell(aac_fp);
|
||||
|
||||
/* Write out 'covr' atom */
|
||||
atom_length = extra_size;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
/* Write out 'covr' atom */
|
||||
atom_length = extra_size;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
|
||||
r_write(out_fd, "covr", 4);
|
||||
r_write(out_fd, "covr", 4);
|
||||
|
||||
/* Write out 'data' atom */
|
||||
atom_length = extra_size - 8;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
/* Write out 'data' atom */
|
||||
atom_length = extra_size - 8;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
|
||||
r_write(out_fd, "data", 4);
|
||||
r_write(out_fd, "data", 4);
|
||||
|
||||
/* Write out 'data' flags */
|
||||
buffer[3] = img_type_flag;
|
||||
buffer[2] = 0;
|
||||
buffer[1] = 0;
|
||||
buffer[0] = 0;
|
||||
r_write(out_fd, buffer, 4);
|
||||
/* Write out 'data' flags */
|
||||
buffer[3] = img_type_flag;
|
||||
buffer[2] = 0;
|
||||
buffer[1] = 0;
|
||||
buffer[0] = 0;
|
||||
r_write(out_fd, buffer, 4);
|
||||
|
||||
/* Reserved? Zero in any case. */
|
||||
buffer[3] = 0;
|
||||
buffer[2] = 0;
|
||||
buffer[1] = 0;
|
||||
buffer[0] = 0;
|
||||
/* Reserved? Zero in any case. */
|
||||
buffer[3] = 0;
|
||||
buffer[2] = 0;
|
||||
buffer[1] = 0;
|
||||
buffer[0] = 0;
|
||||
|
||||
r_write(out_fd, buffer, 4);
|
||||
r_write(out_fd, buffer, 4);
|
||||
|
||||
/* Now ready for the image stream. Copy it over. */
|
||||
lseek(img_fd,0,SEEK_SET);
|
||||
copyfile(img_fd,out_fd);
|
||||
last_pos = cur_pos;
|
||||
} else {
|
||||
DPRINTF(E_LOG, L_ART,"No 'ilst' atom found.\n");
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_ART, "No 'meta' atom found.\n");
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_ART, "No 'udta' atom found.\n");
|
||||
}
|
||||
/* Now ready for the image stream. Copy it over. */
|
||||
lseek(img_fd,0,SEEK_SET);
|
||||
copyfile(img_fd,out_fd);
|
||||
last_pos = cur_pos;
|
||||
} else {
|
||||
DPRINTF(E_LOG, L_ART,"No 'ilst' atom found.\n");
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_ART, "No 'meta' atom found.\n");
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_ART, "No 'udta' atom found.\n");
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_ART, "No 'moov' atom found.\n");
|
||||
DPRINTF(E_LOG,L_ART, "No 'moov' atom found.\n");
|
||||
}
|
||||
|
||||
/* Seek to position right after 'udta' atom. Let main() stream out the
|
||||
@ -456,8 +462,8 @@ off_t da_aac_attach_image(int img_fd, int out_fd, int aac_fd, int offset)
|
||||
/* PENDING: We can be stricter here by checking the shortest header between
|
||||
PNG and JPG and using that length. */
|
||||
if (img_size < 1) {
|
||||
r_close(img_fd);
|
||||
return 0;
|
||||
r_close(img_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Include extra bytes for 'covr' atom length (4) and type (4) and its
|
||||
@ -471,21 +477,21 @@ off_t da_aac_attach_image(int img_fd, int out_fd, int aac_fd, int offset)
|
||||
aac_fp = fdopen(dup(aac_fd), "r");
|
||||
|
||||
stco_atom_pos = scan_aac_drilltoatom(aac_fp,
|
||||
"moov:trak:mdia:minf:stbl:stco",
|
||||
&atom_length);
|
||||
"moov:trak:mdia:minf:stbl:stco",
|
||||
&atom_length);
|
||||
ilst_atom_pos = scan_aac_drilltoatom(aac_fp, "moov:udta:meta:ilst",
|
||||
&atom_length);
|
||||
&atom_length);
|
||||
last_pos = scan_aac_drilltoatom(aac_fp, "mdat", &atom_length);
|
||||
|
||||
if (last_pos != -1) {
|
||||
if (offset >= last_pos) {
|
||||
/* Offset is in the actual music data so don't bother processing
|
||||
meta data. */
|
||||
return 0;
|
||||
}
|
||||
if (offset >= last_pos) {
|
||||
/* Offset is in the actual music data so don't bother processing
|
||||
meta data. */
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_ART, "No 'mdat' atom.\n");
|
||||
return 0;
|
||||
DPRINTF(E_LOG,L_ART, "No 'mdat' atom.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rewind(aac_fp);
|
||||
@ -493,32 +499,32 @@ off_t da_aac_attach_image(int img_fd, int out_fd, int aac_fd, int offset)
|
||||
/* Re-adjust length of 'moov' atom. */
|
||||
last_pos = scan_aac_findatom(aac_fp, file_size, "moov", &atom_length);
|
||||
if (last_pos != -1) {
|
||||
/* Copy everything from up to this atom */
|
||||
rewind(aac_fp);
|
||||
fcopyblock(aac_fp, out_fd, last_pos);
|
||||
/* Copy everything from up to this atom */
|
||||
rewind(aac_fp);
|
||||
fcopyblock(aac_fp, out_fd, last_pos);
|
||||
|
||||
/* Write out new length. */
|
||||
atom_length += extra_size;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
/* Write out new length. */
|
||||
atom_length += extra_size;
|
||||
buffer[3] = atom_length & 0xFF;
|
||||
buffer[2] = ( atom_length >> 8 ) & 0xFF;
|
||||
buffer[1] = ( atom_length >> 16 ) & 0xFF;
|
||||
buffer[0] = ( atom_length >> 24 ) & 0xFF;
|
||||
r_write(out_fd, buffer, 4);
|
||||
|
||||
last_pos += 4;
|
||||
last_pos += 4;
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_ART, "Could not find 'moov' atom.\n");
|
||||
return 0;
|
||||
DPRINTF(E_LOG,L_ART, "Could not find 'moov' atom.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stco_atom_pos < ilst_atom_pos) {
|
||||
last_pos = da_aac_rewrite_stco_atom(extra_size, out_fd, aac_fp, last_pos);
|
||||
last_pos = da_aac_insert_covr_atom(extra_size, out_fd, aac_fp, last_pos,
|
||||
file_size, img_fd);
|
||||
last_pos = da_aac_rewrite_stco_atom(extra_size, out_fd, aac_fp, last_pos);
|
||||
last_pos = da_aac_insert_covr_atom(extra_size, out_fd, aac_fp, last_pos,
|
||||
file_size, img_fd);
|
||||
} else {
|
||||
last_pos = da_aac_insert_covr_atom(extra_size, out_fd, aac_fp, last_pos,
|
||||
file_size, img_fd);
|
||||
last_pos = da_aac_rewrite_stco_atom(extra_size, out_fd, aac_fp, last_pos);
|
||||
last_pos = da_aac_insert_covr_atom(extra_size, out_fd, aac_fp, last_pos,
|
||||
file_size, img_fd);
|
||||
last_pos = da_aac_rewrite_stco_atom(extra_size, out_fd, aac_fp, last_pos);
|
||||
}
|
||||
|
||||
/* Seek to position right after last atom. Let main() stream out the rest. */
|
||||
@ -537,20 +543,20 @@ int copyblock(int fromfd, int tofd, size_t size) {
|
||||
int blocksize = BLKSIZE;
|
||||
int bytesleft;
|
||||
|
||||
while (totalbytes < size) {
|
||||
bytesleft = size - totalbytes;
|
||||
if (bytesleft < BLKSIZE) {
|
||||
blocksize = bytesleft;
|
||||
} else {
|
||||
blocksize = BLKSIZE;
|
||||
}
|
||||
if ((bytesread = r_read(fromfd, buf, blocksize)) < 0)
|
||||
return -1;
|
||||
if (bytesread == 0)
|
||||
return totalbytes;
|
||||
if (r_write(tofd, buf, bytesread) < 0)
|
||||
return -1;
|
||||
totalbytes += bytesread;
|
||||
while (totalbytes < (int) size) {
|
||||
bytesleft = (int) (size - totalbytes);
|
||||
if (bytesleft < BLKSIZE) {
|
||||
blocksize = bytesleft;
|
||||
} else {
|
||||
blocksize = BLKSIZE;
|
||||
}
|
||||
if ((bytesread = r_read(fromfd, buf, blocksize)) < 0)
|
||||
return -1;
|
||||
if (bytesread == 0)
|
||||
return totalbytes;
|
||||
if (r_write(tofd, buf, bytesread) < 0)
|
||||
return -1;
|
||||
totalbytes += bytesread;
|
||||
}
|
||||
return totalbytes;
|
||||
}
|
||||
@ -562,23 +568,23 @@ int fcopyblock(FILE *fromfp, int tofd, size_t size) {
|
||||
int blocksize = BLKSIZE;
|
||||
int bytesleft;
|
||||
|
||||
while (totalbytes < size) {
|
||||
bytesleft = size - totalbytes;
|
||||
if (bytesleft < BLKSIZE) {
|
||||
blocksize = bytesleft;
|
||||
} else {
|
||||
blocksize = BLKSIZE;
|
||||
}
|
||||
if ((bytesread = fread(buf, 1, blocksize, fromfp)) < blocksize) {
|
||||
if (ferror(fromfp))
|
||||
return -1;
|
||||
}
|
||||
if (r_write(tofd, buf, bytesread) < 0)
|
||||
return -1;
|
||||
while (totalbytes < (int) size) {
|
||||
bytesleft = (int)(size - totalbytes);
|
||||
if (bytesleft < BLKSIZE) {
|
||||
blocksize = bytesleft;
|
||||
} else {
|
||||
blocksize = BLKSIZE;
|
||||
}
|
||||
if ((bytesread = (int) fread(buf, 1, blocksize, fromfp)) < blocksize) {
|
||||
if (ferror(fromfp))
|
||||
return -1;
|
||||
}
|
||||
if (r_write(tofd, buf, bytesread) < 0)
|
||||
return -1;
|
||||
|
||||
if (feof(fromfp))
|
||||
return 0;
|
||||
totalbytes += bytesread;
|
||||
if (feof(fromfp))
|
||||
return 0;
|
||||
totalbytes += bytesread;
|
||||
}
|
||||
return totalbytes;
|
||||
}
|
||||
|
302
src/err.c
302
src/err.c
@ -39,18 +39,11 @@
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
|
||||
/* don't want to redefine malloc -- if doing memory debugging,
|
||||
* this is the only file that *shouldn't* be redefining malloc and
|
||||
* friends. Hence the define.
|
||||
*/
|
||||
#define __IN_ERR__
|
||||
#include "err.h"
|
||||
#include "os.h"
|
||||
|
||||
|
||||
int err_debuglevel=0; /**< current debuglevel, set from command line with -d */
|
||||
static int err_debuglevel=0; /**< current debuglevel, set from command line with -d */
|
||||
static int err_logdestination=LOGDEST_STDERR; /**< current log destination */
|
||||
static FILE *err_file=NULL; /**< if logging to file, the handle of that file */
|
||||
static pthread_mutex_t err_mutex=PTHREAD_MUTEX_INITIALIZER; /**< for serializing log messages */
|
||||
@ -62,33 +55,16 @@ static char *err_categorylist[] = {
|
||||
"playlist","art","daap","main","rend","xml","parse",NULL
|
||||
};
|
||||
|
||||
#ifdef DEBUG_MEMORY
|
||||
/**
|
||||
* Nodes for a linked list of in-use memory. Any malloc/strdup/etc
|
||||
* calls get a new node of this type added to the #err_leak list.
|
||||
*/
|
||||
typedef struct tag_err_leak {
|
||||
void *ptr;
|
||||
char *file;
|
||||
int line;
|
||||
int size;
|
||||
struct tag_err_leak *next;
|
||||
} ERR_LEAK;
|
||||
|
||||
/** head of linked list of in-use memory */
|
||||
ERR_LEAK err_leak = { NULL, NULL, 0, 0, NULL };
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Forwards
|
||||
*/
|
||||
|
||||
static int err_lock_mutex(void);
|
||||
static int err_unlock_mutex(void);
|
||||
static int _err_lock(void);
|
||||
static int _err_unlock(void);
|
||||
|
||||
/**
|
||||
* Write a printf-style formatted message to the log destination.
|
||||
* This can be stderr, syslog, or a logfile, as determined by
|
||||
* This can be stderr, syslog/eventviewer, or a logfile, as determined by
|
||||
* err_setdest(). Note that this function should not be directly
|
||||
* used, rather it should be used via the #DPRINTF macro.
|
||||
*
|
||||
@ -105,81 +81,92 @@ void err_log(int level, unsigned int cat, char *fmt, ...)
|
||||
time_t tt_now;
|
||||
|
||||
if(level) {
|
||||
if(level > err_debuglevel)
|
||||
return;
|
||||
if(level > err_debuglevel)
|
||||
return;
|
||||
|
||||
if(!(cat & err_debugmask))
|
||||
return;
|
||||
if(!(cat & err_debugmask))
|
||||
return;
|
||||
} /* we'll *always* process a log level 0 */
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
err_lock_mutex(); /* atomic file writes */
|
||||
_err_lock(); /* atomic file writes */
|
||||
|
||||
if((!level) && (err_logdestination != LOGDEST_STDERR)) {
|
||||
fprintf(stderr,"%s",errbuf);
|
||||
fprintf(stderr,"Aborting\n");
|
||||
fflush(stderr); /* shouldn't have to do this? */
|
||||
fprintf(stderr,"%s",errbuf);
|
||||
fprintf(stderr,"Aborting\n");
|
||||
fflush(stderr); /* shouldn't have to do this? */
|
||||
}
|
||||
|
||||
switch(err_logdestination) {
|
||||
case LOGDEST_LOGFILE:
|
||||
tt_now=time(NULL);
|
||||
localtime_r(&tt_now,&tm_now);
|
||||
strftime(timebuf,sizeof(timebuf),"%Y-%m-%d %T",&tm_now);
|
||||
fprintf(err_file,"%s: %s",timebuf,errbuf);
|
||||
if(!level) fprintf(err_file,"%s: Aborting\n",timebuf);
|
||||
fflush(err_file);
|
||||
break;
|
||||
tt_now=time(NULL);
|
||||
localtime_r(&tt_now,&tm_now);
|
||||
strftime(timebuf,sizeof(timebuf),"%Y-%m-%d %T",&tm_now);
|
||||
fprintf(err_file,"%s: %s",timebuf,errbuf);
|
||||
if(!level) fprintf(err_file,"%s: Aborting\n",timebuf);
|
||||
fflush(err_file);
|
||||
break;
|
||||
case LOGDEST_STDERR:
|
||||
fprintf(stderr, "%s",errbuf);
|
||||
if(!level) fprintf(stderr,"Aborting\n");
|
||||
if(!level) fprintf(stderr,"Aborting\n");
|
||||
break;
|
||||
case LOGDEST_SYSLOG:
|
||||
syslog(LOG_NOTICE, "%s", errbuf);
|
||||
if(!level) syslog(LOG_INFO, "Aborting\n");
|
||||
os_syslog(level,errbuf);
|
||||
if(!level) os_syslog(0, "Fatal error... Aborting\n");
|
||||
break;
|
||||
}
|
||||
|
||||
err_unlock_mutex();
|
||||
_err_unlock();
|
||||
|
||||
if(!level) {
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_FAILURE); /* this should go to an OS-specific exit routine */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* simple get/set interface to debuglevel to avoid global
|
||||
*/
|
||||
void err_setlevel(int level) {
|
||||
err_debuglevel = level;
|
||||
}
|
||||
|
||||
int err_getlevel(void) {
|
||||
return err_debuglevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the log destination. (stderr, syslog, or logfile)
|
||||
*
|
||||
* \param app appname (used only for syslog destination)
|
||||
* \param destination where to log to \ref log_dests "as defined in err.h"
|
||||
*/
|
||||
void err_setdest(char *app, int destination) {
|
||||
void err_setdest(char *cvalue, int destination) {
|
||||
if(err_logdestination == destination)
|
||||
return;
|
||||
return;
|
||||
|
||||
switch(err_logdestination) {
|
||||
case LOGDEST_SYSLOG:
|
||||
closelog();
|
||||
break;
|
||||
os_closesyslog();
|
||||
break;
|
||||
case LOGDEST_LOGFILE:
|
||||
fclose(err_file);
|
||||
break;
|
||||
fclose(err_file);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(destination) {
|
||||
case LOGDEST_LOGFILE:
|
||||
err_file=fopen(app,"a");
|
||||
if(err_file==NULL) {
|
||||
fprintf(stderr,"Error opening %s: %s\n",app,strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
err_file=fopen(cvalue,"a");
|
||||
if(err_file==NULL) {
|
||||
fprintf(stderr,"Error opening %s: %s\n",cvalue,strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case LOGDEST_SYSLOG:
|
||||
openlog(app,LOG_PID,LOG_DAEMON);
|
||||
break;
|
||||
os_opensyslog(); // (app,LOG_PID,LOG_DAEMON);
|
||||
break;
|
||||
}
|
||||
|
||||
err_logdestination=destination;
|
||||
@ -200,26 +187,26 @@ extern int err_setdebugmask(char *list) {
|
||||
str=list;
|
||||
|
||||
while(1) {
|
||||
token=strtok_r(str,",",&last);
|
||||
str=NULL;
|
||||
token=strtok_r(str,",",&last);
|
||||
str=NULL;
|
||||
|
||||
if(token) {
|
||||
rack=1;
|
||||
index=0;
|
||||
while((err_categorylist[index]) &&
|
||||
(strcasecmp(err_categorylist[index],token))) {
|
||||
rack <<= 1;
|
||||
index++;
|
||||
}
|
||||
if(token) {
|
||||
rack=1;
|
||||
index=0;
|
||||
while((err_categorylist[index]) &&
|
||||
(strcasecmp(err_categorylist[index],token))) {
|
||||
rack <<= 1;
|
||||
index++;
|
||||
}
|
||||
|
||||
if(!err_categorylist[index]) {
|
||||
DPRINTF(E_LOG,L_MISC,"Unknown module: %s\n",token);
|
||||
return 1;
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_MISC,"Adding module %s to debug list (0x%08x)\n",token,rack);
|
||||
err_debugmask |= rack;
|
||||
}
|
||||
} else break; /* !token */
|
||||
if(!err_categorylist[index]) {
|
||||
DPRINTF(E_LOG,L_MISC,"Unknown module: %s\n",token);
|
||||
return 1;
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_MISC,"Adding module %s to debug list (0x%08x)\n",token,rack);
|
||||
err_debugmask |= rack;
|
||||
}
|
||||
} else break; /* !token */
|
||||
}
|
||||
|
||||
DPRINTF(E_INF,L_MISC,"Debug mask is 0x%08x\n",err_debugmask);
|
||||
@ -234,12 +221,12 @@ extern int err_setdebugmask(char *list) {
|
||||
*
|
||||
* \returns 0 on success, otherwise -1 with errno set
|
||||
*/
|
||||
int err_lock_mutex(void) {
|
||||
int _err_lock(void) {
|
||||
int err;
|
||||
|
||||
if((err=pthread_mutex_lock(&err_mutex))) {
|
||||
errno=err;
|
||||
return -1;
|
||||
errno=err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -250,155 +237,14 @@ int err_lock_mutex(void) {
|
||||
*
|
||||
* \returns 0 on success, otherwise -1 with errno set
|
||||
*/
|
||||
int err_unlock_mutex(void) {
|
||||
int _err_unlock(void) {
|
||||
int err;
|
||||
|
||||
if((err=pthread_mutex_unlock(&err_mutex))) {
|
||||
errno=err;
|
||||
return -1;
|
||||
errno=err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEMORY
|
||||
|
||||
/**
|
||||
* Let the leak detector know about a chunk of memory
|
||||
* that needs to be freed, but came from an external library.
|
||||
* Example: gdbm functions. Note that this should only
|
||||
* be called via the #MEMNOTIFY macro.
|
||||
*
|
||||
* \param file filled in from the #MEMNOTIFY macro with __FILE__
|
||||
* \param line filled in from the #MEMNOTIFY macro with __LINE__
|
||||
* \param ptr ptr to block of memory which must be freed
|
||||
*/
|
||||
void err_notify(char *file, int line, void *ptr) {
|
||||
ERR_LEAK *pnew;
|
||||
|
||||
if(!ptr)
|
||||
return;
|
||||
|
||||
pnew=(ERR_LEAK*)malloc(sizeof(ERR_LEAK));
|
||||
if(!pnew)
|
||||
DPRINTF(E_FATAL,L_MISC,"Error: cannot allocate leak struct\n");
|
||||
|
||||
if(err_lock_mutex())
|
||||
DPRINTF(E_FATAL,L_MISC,"Error: cannot lock error mutex\n");
|
||||
|
||||
pnew->file=file;
|
||||
pnew->line=line;
|
||||
pnew->size=0;
|
||||
pnew->ptr=ptr;
|
||||
|
||||
pnew->next=err_leak.next;
|
||||
err_leak.next=pnew;
|
||||
|
||||
err_unlock_mutex();
|
||||
}
|
||||
|
||||
/**
|
||||
* malloc wrapper for leak checking. This never gets
|
||||
* called directly, only via malloc.
|
||||
*
|
||||
* \param file filled in via macro with __FILE__
|
||||
* \param line filled in via macro with __LINE__
|
||||
* \param size size of block to allocate
|
||||
*/
|
||||
void *err_malloc(char *file, int line, size_t size) {
|
||||
ERR_LEAK *pnew;
|
||||
|
||||
pnew=(ERR_LEAK*)malloc(sizeof(ERR_LEAK));
|
||||
if(!pnew)
|
||||
DPRINTF(E_FATAL,L_MISC,"Error: cannot allocate leak struct\n");
|
||||
|
||||
if(err_lock_mutex())
|
||||
DPRINTF(E_FATAL,L_MISC,"Error: cannot lock error mutex\n");
|
||||
|
||||
pnew->file=file;
|
||||
pnew->line=line;
|
||||
pnew->size=size;
|
||||
pnew->ptr=malloc(size);
|
||||
|
||||
pnew->next=err_leak.next;
|
||||
err_leak.next=pnew;
|
||||
|
||||
err_unlock_mutex();
|
||||
|
||||
return pnew->ptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Memory check wrapper for strdup. This should not
|
||||
* be called directly
|
||||
*
|
||||
* \param file filled in via macro with __FILE__
|
||||
* \param line filled in via macro with __LINE__
|
||||
* \param str str to strdup
|
||||
*/
|
||||
char *err_strdup(char *file, int line, const char *str) {
|
||||
void *pnew;
|
||||
|
||||
pnew=err_malloc(file,line,strlen(str) + 1);
|
||||
if(!pnew)
|
||||
DPRINTF(E_FATAL,L_MISC,"Cannot malloc enough space for strdup\n");
|
||||
|
||||
memcpy(pnew,str,strlen(str)+1);
|
||||
return pnew;
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory checking wrapper for free. This should not be
|
||||
* called direclty.
|
||||
*
|
||||
* \param file filled in by macro with __FILE__
|
||||
* \param line filled in by macro with __LINE__
|
||||
* \param ptr block of memory to free
|
||||
*/
|
||||
void err_free(char *file, int line, void *ptr) {
|
||||
ERR_LEAK *current,*last;
|
||||
|
||||
if(err_lock_mutex())
|
||||
DPRINTF(E_FATAL,L_MISC,"Error: cannot lock error mutex\n");
|
||||
|
||||
last=&err_leak;
|
||||
current=last->next;
|
||||
|
||||
while((current) && (current->ptr != ptr)) {
|
||||
last=current;
|
||||
current=current->next;
|
||||
}
|
||||
|
||||
if(!current) {
|
||||
DPRINTF(E_FATAL,L_MISC,"Attempt to free unallocated memory: %s, %d\n",file,line);
|
||||
} else {
|
||||
free(current->ptr);
|
||||
last->next=current->next;
|
||||
free(current);
|
||||
}
|
||||
|
||||
err_unlock_mutex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the list of in-use memory. This walks the linked
|
||||
* list created by the malloc and strdup wrappers, and dumps
|
||||
* them to stdout.
|
||||
*/
|
||||
void err_leakcheck(void) {
|
||||
ERR_LEAK *current;
|
||||
|
||||
if(err_lock_mutex())
|
||||
DPRINTF(E_FATAL,L_MISC,"Error: cannot lock error mutex\n");
|
||||
|
||||
current=err_leak.next;
|
||||
while(current) {
|
||||
printf("%s: %d - %d bytes at %p\n",current->file, current->line, current->size,
|
||||
current->ptr);
|
||||
current=current->next;
|
||||
}
|
||||
|
||||
err_unlock_mutex();
|
||||
}
|
||||
#endif
|
||||
|
35
src/err.h
35
src/err.h
@ -30,7 +30,7 @@
|
||||
|
||||
/** @anchor log_dests */
|
||||
#define LOGDEST_STDERR 0 /**< Log to stderr */
|
||||
#define LOGDEST_SYSLOG 1 /**< Log to syslog */
|
||||
#define LOGDEST_SYSLOG 1 /**< Log to syslog/eventviewer */
|
||||
#define LOGDEST_LOGFILE 2 /**< Log to logfile */
|
||||
|
||||
/** @anchor log_levels */
|
||||
@ -63,40 +63,15 @@
|
||||
# define FALSE 0
|
||||
#endif
|
||||
|
||||
extern int err_debuglevel;
|
||||
|
||||
extern void err_log(int level, unsigned int cat, char *fmt, ...);
|
||||
extern void err_setdest(char *app, int destination);
|
||||
extern void err_setdest(char *cvalue, int destination);
|
||||
extern void err_setlevel(int level);
|
||||
extern int err_getlevel(void);
|
||||
extern int err_setdebugmask(char *list);
|
||||
/**
|
||||
* Print a debugging or log message
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
# define DPRINTF(level, cat, fmt, arg...) \
|
||||
{ err_log(level,cat,"%s, %d: ",__FILE__,__LINE__); err_log(level,cat,fmt,##arg); }
|
||||
#else
|
||||
# define DPRINTF(level, cat, fmt, arg...) \
|
||||
{ err_log(level,cat,fmt,##arg); }
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_MEMORY
|
||||
# ifndef __IN_ERR__
|
||||
# define malloc(x) err_malloc(__FILE__,__LINE__,x)
|
||||
# define strdup(x) err_strdup(__FILE__,__LINE__,x)
|
||||
# define free(x) err_free(__FILE__,__LINE__,x)
|
||||
# endif /* __IN_ERR__ */
|
||||
#define DPRINTF err_log
|
||||
|
||||
# define MEMNOTIFY(x) err_notify(__FILE__,__LINE__,x)
|
||||
|
||||
extern void *err_malloc(char *file, int line, size_t size);
|
||||
extern char *err_strdup(char *file, int line, const char *str);
|
||||
extern void err_free(char *file, int line, void *ptr);
|
||||
extern void err_notify(char *file, int line, void *ptr);
|
||||
extern void err_leakcheck(void);
|
||||
#else
|
||||
/**
|
||||
* Notify the leak checking system of externally allocated memory.
|
||||
*/
|
||||
# define MEMNOTIFY(x)
|
||||
#endif /* DEBUG_MEMORY */
|
||||
#endif /* __ERR_H__ */
|
||||
|
1265
src/getopt.c
Normal file
1265
src/getopt.c
Normal file
File diff suppressed because it is too large
Load Diff
181
src/getopt.h
Normal file
181
src/getopt.h
Normal file
@ -0,0 +1,181 @@
|
||||
/* Declarations for getopt.
|
||||
Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
|
||||
#ifndef __need_getopt
|
||||
# define _GETOPT_H 1
|
||||
#endif
|
||||
|
||||
/* If __GNU_LIBRARY__ is not already defined, either we are being used
|
||||
standalone, or this is the first header included in the source file.
|
||||
If we are being used with glibc, we need to include <features.h>, but
|
||||
that does not exist if we are standalone. So: if __GNU_LIBRARY__ is
|
||||
not defined, include <ctype.h>, which will pull in <features.h> for us
|
||||
if it's from glibc. (Why ctype.h? It's guaranteed to exist and it
|
||||
doesn't flood the namespace with stuff the way some other headers do.) */
|
||||
#if !defined __GNU_LIBRARY__
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns -1, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int opterr;
|
||||
|
||||
/* Set to an option character which was unrecognized. */
|
||||
|
||||
extern int optopt;
|
||||
|
||||
#ifndef __need_getopt
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct option
|
||||
{
|
||||
# if (defined __STDC__ && __STDC__) || defined __cplusplus
|
||||
const char *name;
|
||||
# else
|
||||
char *name;
|
||||
# endif
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
# define no_argument 0
|
||||
# define required_argument 1
|
||||
# define optional_argument 2
|
||||
#endif /* need getopt */
|
||||
|
||||
|
||||
/* Get definitions and prototypes for functions to process the
|
||||
arguments in ARGV (ARGC of them, minus the program name) for
|
||||
options given in OPTS.
|
||||
|
||||
Return the option character from OPTS just read. Return -1 when
|
||||
there are no more options. For unrecognized options, or options
|
||||
missing arguments, `optopt' is set to the option letter, and '?' is
|
||||
returned.
|
||||
|
||||
The OPTS string is a list of characters which are recognized option
|
||||
letters, optionally followed by colons, specifying that that letter
|
||||
takes an argument, to be placed in `optarg'.
|
||||
|
||||
If a letter in OPTS is followed by two colons, its argument is
|
||||
optional. This behavior is specific to the GNU `getopt'.
|
||||
|
||||
The argument `--' causes premature termination of argument
|
||||
scanning, explicitly telling `getopt' that there are no more
|
||||
options.
|
||||
|
||||
If OPTS begins with `--', then non-option arguments are treated as
|
||||
arguments to the option '\0'. This behavior is specific to the GNU
|
||||
`getopt'. */
|
||||
|
||||
#if (defined __STDC__ && __STDC__) || defined __cplusplus
|
||||
# ifdef __GNU_LIBRARY__
|
||||
/* Many other libraries have conflicting prototypes for getopt, with
|
||||
differences in the consts, in stdlib.h. To avoid compilation
|
||||
errors, only prototype getopt for the GNU C library. */
|
||||
extern int getopt (int ___argc, char *const *___argv, const char *__shortopts);
|
||||
# else /* not __GNU_LIBRARY__ */
|
||||
extern int getopt ();
|
||||
# endif /* __GNU_LIBRARY__ */
|
||||
|
||||
# ifndef __need_getopt
|
||||
extern int getopt_long (int ___argc, char *const *___argv,
|
||||
const char *__shortopts,
|
||||
const struct option *__longopts, int *__longind);
|
||||
extern int getopt_long_only (int ___argc, char *const *___argv,
|
||||
const char *__shortopts,
|
||||
const struct option *__longopts, int *__longind);
|
||||
|
||||
/* Internal only. Users should not call this directly. */
|
||||
extern int _getopt_internal (int ___argc, char *const *___argv,
|
||||
const char *__shortopts,
|
||||
const struct option *__longopts, int *__longind,
|
||||
int __long_only);
|
||||
# endif
|
||||
#else /* not __STDC__ */
|
||||
extern int getopt ();
|
||||
# ifndef __need_getopt
|
||||
extern int getopt_long ();
|
||||
extern int getopt_long_only ();
|
||||
|
||||
extern int _getopt_internal ();
|
||||
# endif
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make sure we later can get all the definitions and declarations. */
|
||||
#undef __need_getopt
|
||||
|
||||
#endif /* getopt.h */
|
9932
src/mDNS.c
9932
src/mDNS.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,12 @@
|
||||
Change History (most recent first):
|
||||
|
||||
$Log$
|
||||
Revision 1.4 2006/02/26 08:46:24 rpedde
|
||||
Merged win32-branch
|
||||
|
||||
Revision 1.3.2.1 2006/02/26 08:28:35 rpedde
|
||||
unix fixes from win32 port
|
||||
|
||||
Revision 1.3 2005/07/21 03:40:07 rpedde
|
||||
Crank up mdns debug messages
|
||||
|
||||
@ -78,41 +84,41 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release
|
||||
#define IS_A_PRINTF_STYLE_FUNCTION(F,A)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if MDNS_DEBUGMSGS
|
||||
#define debugf debugf_
|
||||
extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
|
||||
#else // If debug breaks are off, use a preprocessor trick to optimize those calls out of the code
|
||||
#if( defined( __GNUC__ ) )
|
||||
#define debugf( ARGS... ) ((void)0)
|
||||
#elif( defined( __MWERKS__ ) )
|
||||
#define debugf( ... )
|
||||
#else
|
||||
#define debugf 1 ? ((void)0) : (void)
|
||||
#endif
|
||||
#if( defined( __GNUC__ ) )
|
||||
#define debugf( ARGS... ) ((void)0)
|
||||
#elif( defined( __MWERKS__ ) )
|
||||
#define debugf( ... )
|
||||
#else
|
||||
#define debugf 1 ? ((void)0) : (void)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MDNS_DEBUGMSGS > 1
|
||||
#define verbosedebugf verbosedebugf_
|
||||
extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
|
||||
#else
|
||||
#if( defined( __GNUC__ ) )
|
||||
#define verbosedebugf( ARGS... ) ((void)0)
|
||||
#elif( defined( __MWERKS__ ) )
|
||||
#define verbosedebugf( ... )
|
||||
#else
|
||||
#define verbosedebugf 1 ? ((void)0) : (void)
|
||||
#endif
|
||||
#if( defined( __GNUC__ ) )
|
||||
#define verbosedebugf( ARGS... ) ((void)0)
|
||||
#elif( defined( __MWERKS__ ) )
|
||||
#define verbosedebugf( ... )
|
||||
#else
|
||||
#define verbosedebugf 1 ? ((void)0) : (void)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// LogMsg is used even in shipping code, to write truly serious error messages to syslog (or equivalent)
|
||||
extern void LogMsg(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
1282
src/mDNSPosix.c
1282
src/mDNSPosix.c
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,12 @@
|
||||
Change History (most recent first):
|
||||
|
||||
$Log$
|
||||
Revision 1.3 2006/02/26 08:46:24 rpedde
|
||||
Merged win32-branch
|
||||
|
||||
Revision 1.2.4.1 2006/02/26 08:28:35 rpedde
|
||||
unix fixes from win32 port
|
||||
|
||||
Revision 1.2 2005/01/10 01:07:01 rpedde
|
||||
Synchronize mDNS to Apples 58.8 drop
|
||||
|
||||
@ -74,10 +80,10 @@ First checkin
|
||||
extern int gMDNSPlatformPosixVerboseLevel;
|
||||
|
||||
struct mDNS_PlatformSupport_struct
|
||||
{
|
||||
{
|
||||
// No additional data required for Posix at this time
|
||||
long dummy[1]; // Some compilers don't like empty structures
|
||||
};
|
||||
long dummy[1]; // Some compilers don't like empty structures
|
||||
};
|
||||
|
||||
extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
|
||||
// See comment in implementation.
|
||||
|
@ -23,6 +23,12 @@
|
||||
Change History (most recent first):
|
||||
|
||||
$Log$
|
||||
Revision 1.6 2006/02/26 08:46:24 rpedde
|
||||
Merged win32-branch
|
||||
|
||||
Revision 1.5.2.1 2006/02/26 08:28:35 rpedde
|
||||
unix fixes from win32 port
|
||||
|
||||
Revision 1.5 2005/09/23 05:26:52 rpedde
|
||||
commit the iTunes 5 fixes
|
||||
|
||||
@ -161,23 +167,23 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
|
||||
for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
|
||||
ifr = (struct ifreq *) ptr;
|
||||
|
||||
len = GET_SA_LEN(ifr->ifr_addr);
|
||||
len = GET_SA_LEN(ifr->ifr_addr);
|
||||
|
||||
/* This is completely whacked, and I really need to
|
||||
* find out why this is the case, but I need to
|
||||
* release a 0.2.2, and as the next stable won't
|
||||
* have the apple mDNS included, I guess it's a
|
||||
* small price to pay.
|
||||
*/
|
||||
/* This is completely whacked, and I really need to
|
||||
* find out why this is the case, but I need to
|
||||
* release a 0.2.2, and as the next stable won't
|
||||
* have the apple mDNS included, I guess it's a
|
||||
* small price to pay.
|
||||
*/
|
||||
#ifdef FREEBSD
|
||||
ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
|
||||
// ptr += sizeof(*ifr);
|
||||
ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
|
||||
// ptr += sizeof(*ifr);
|
||||
#else
|
||||
|
||||
ptr += sizeof(struct ifreq); /* for next one in buffer */
|
||||
ptr += sizeof(struct ifreq); /* for next one in buffer */
|
||||
#endif
|
||||
|
||||
DPRINTF(E_DBG,L_REND,"intf %d name=%s AF=%d, flags=%08x\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family,ifr->ifr_flags);
|
||||
DPRINTF(E_DBG,L_REND,"intf %d name=%s AF=%d, flags=%08x\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family,ifr->ifr_flags);
|
||||
|
||||
if (ifr->ifr_addr.sa_family != family)
|
||||
continue; /* ignore if not desired address family */
|
||||
@ -267,7 +273,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
|
||||
/* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
|
||||
/* We need to strip that out */
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
|
||||
sinptr6->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
|
||||
sinptr6->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
|
||||
memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
|
||||
}
|
||||
break;
|
||||
@ -364,7 +370,7 @@ recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
|
||||
|
||||
/* include recvfrom_flags2 */
|
||||
#ifndef CMSG_FIRSTHDR
|
||||
#warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
|
||||
#warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
|
||||
*flagsp = 0; /* pass back results */
|
||||
return(n);
|
||||
#else
|
||||
@ -431,15 +437,15 @@ struct in_pktinfo
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
|
||||
cmptr->cmsg_type == IPV6_PKTINFO) {
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
|
||||
struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
|
||||
|
||||
struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
|
||||
|
||||
sin6->sin6_family = AF_INET6;
|
||||
sin6->sin6_len = sizeof(*sin6);
|
||||
sin6->sin6_addr = ip6_info->ipi6_addr;
|
||||
sin6->sin6_flowinfo = 0;
|
||||
sin6->sin6_scope_id = 0;
|
||||
sin6->sin6_port = 0;
|
||||
pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
|
||||
pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
308
src/main.c
308
src/main.c
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file main.c
|
||||
* @file main.c
|
||||
*
|
||||
* Driver for mt-daapd, including the main() function. This
|
||||
* is responsible for kicking off the initial mp3 scan, starting
|
||||
@ -31,21 +31,19 @@
|
||||
* It also contains the daap handling callback for the webserver.
|
||||
* This should almost certainly be somewhere else, and is in
|
||||
* desparate need of refactoring, but somehow continues to be in
|
||||
* this file.
|
||||
*
|
||||
* \todo Refactor daap_handler()
|
||||
* this files.
|
||||
*/
|
||||
|
||||
/** \mainpage mt-daapd
|
||||
* \section about_section About
|
||||
/** @mainpage mt-daapd
|
||||
* @section about_section About
|
||||
*
|
||||
* This is mt-daapd, an attempt to create an iTunes server for
|
||||
* linux and other POSIXish systems. Maybe even Windows with cygwin,
|
||||
* eventually.
|
||||
*
|
||||
* You might check these locations for more info:
|
||||
* - <a href="http://www.mt-daapd.org">Home page</a>
|
||||
* - <a href="http://sf.net/projects/mt-daapd">Project page on SourceForge</a>
|
||||
* - <a href="http://mt-daapd.sf.net">Home page</a>
|
||||
*
|
||||
*/
|
||||
|
||||
@ -55,29 +53,36 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <restart.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include "configfile.h"
|
||||
#include "dispatch.h"
|
||||
#include "err.h"
|
||||
#include "mp3-scanner.h"
|
||||
#include "webserver.h"
|
||||
#include "restart.h"
|
||||
#include "ssc.h"
|
||||
#include "dynamic-art.h"
|
||||
#include "db-generic.h"
|
||||
#include "os.h"
|
||||
|
||||
#ifdef HAVE_GETOPT_H
|
||||
# include "getopt.h"
|
||||
#endif
|
||||
|
||||
#ifndef WITHOUT_MDNS
|
||||
# include "rend.h"
|
||||
@ -94,16 +99,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Where to dump the pidfile */
|
||||
#ifndef PIDFILE
|
||||
#define PIDFILE "/var/run/mt-daapd.pid"
|
||||
#endif
|
||||
|
||||
/** You say po-tay-to, I say po-tat-o */
|
||||
#ifndef SIGCLD
|
||||
# define SIGCLD SIGCHLD
|
||||
#endif
|
||||
|
||||
/** Seconds to sleep before checking for a shutdown or reload */
|
||||
#define MAIN_SLEEP_INTERVAL 2
|
||||
|
||||
@ -120,61 +115,7 @@ CONFIG config; /**< Main configuration structure, as read from configfile */
|
||||
/*
|
||||
* Forwards
|
||||
*/
|
||||
static int daemon_start(void);
|
||||
static void usage(char *program);
|
||||
static void *signal_handler(void *arg);
|
||||
static int start_signal_handler(pthread_t *handler_tid);
|
||||
|
||||
/**
|
||||
* Fork and exit. Stolen pretty much straight from Stevens.
|
||||
*/
|
||||
int daemon_start(void) {
|
||||
int childpid, fd;
|
||||
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
// Fork and exit
|
||||
if ((childpid = fork()) < 0) {
|
||||
fprintf(stderr, "Can't fork!\n");
|
||||
return -1;
|
||||
} else if (childpid > 0)
|
||||
exit(0);
|
||||
|
||||
#ifdef SETPGRP_VOID
|
||||
setpgrp();
|
||||
#else
|
||||
setpgrp(0,0);
|
||||
#endif
|
||||
|
||||
#ifdef TIOCNOTTY
|
||||
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
|
||||
ioctl(fd, TIOCNOTTY, (char *) NULL);
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
if((fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
for (fd = 0; fd < FOPEN_MAX; fd++)
|
||||
close(fd);
|
||||
*/
|
||||
|
||||
errno = 0;
|
||||
|
||||
chdir("/");
|
||||
umask(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print usage information to stdout
|
||||
@ -198,133 +139,6 @@ void usage(char *program) {
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop privs. This allows mt-daapd to run as a non-privileged user.
|
||||
* Hopefully this will limit the damage it could do if exploited
|
||||
* remotely. Note that only the user need be specified. GID
|
||||
* is set to the primary group of the user.
|
||||
*
|
||||
* \param user user to run as (or UID)
|
||||
*/
|
||||
int drop_privs(char *user) {
|
||||
int err;
|
||||
struct passwd *pw=NULL;
|
||||
|
||||
/* drop privs */
|
||||
if(getuid() == (uid_t)0) {
|
||||
if(atoi(user)) {
|
||||
pw=getpwuid((uid_t)atoi(user)); /* doh! */
|
||||
} else {
|
||||
pw=getpwnam(config.runas);
|
||||
}
|
||||
|
||||
if(pw) {
|
||||
if(initgroups(user,pw->pw_gid) != 0 ||
|
||||
setgid(pw->pw_gid) != 0 ||
|
||||
setuid(pw->pw_uid) != 0) {
|
||||
err=errno;
|
||||
fprintf(stderr,"Couldn't change to %s, gid=%d, uid=%d\n",
|
||||
user,pw->pw_gid, pw->pw_uid);
|
||||
errno=err;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
err=errno;
|
||||
fprintf(stderr,"Couldn't lookup user %s\n",user);
|
||||
errno=err;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for signals and flag the main process. This is
|
||||
* a thread handler for the signal processing thread. It
|
||||
* does absolutely nothing except wait for signals. The rest
|
||||
* of the threads are running with signals blocked, so this thread
|
||||
* is guaranteed to catch all the signals. It sets flags in
|
||||
* the config structure that the main thread looks for. Specifically,
|
||||
* the stop flag (from an INT signal), and the reload flag (from HUP).
|
||||
* \param arg NULL, but required of a thread procedure
|
||||
*/
|
||||
void *signal_handler(void *arg) {
|
||||
sigset_t intmask;
|
||||
int sig;
|
||||
int status;
|
||||
|
||||
config.stop=0;
|
||||
config.reload=0;
|
||||
config.pid=getpid();
|
||||
|
||||
DPRINTF(E_WARN,L_MAIN,"Signal handler started\n");
|
||||
|
||||
while(!config.stop) {
|
||||
if((sigemptyset(&intmask) == -1) ||
|
||||
(sigaddset(&intmask, SIGCLD) == -1) ||
|
||||
(sigaddset(&intmask, SIGINT) == -1) ||
|
||||
(sigaddset(&intmask, SIGHUP) == -1) ||
|
||||
(sigwait(&intmask, &sig) == -1)) {
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error waiting for signals. Aborting\n");
|
||||
} else {
|
||||
/* process the signal */
|
||||
switch(sig) {
|
||||
case SIGCLD:
|
||||
DPRINTF(E_LOG,L_MAIN,"Got CLD signal. Reaping\n");
|
||||
while (wait3(&status, WNOHANG, NULL) > 0) {
|
||||
}
|
||||
break;
|
||||
case SIGINT:
|
||||
DPRINTF(E_LOG,L_MAIN,"Got INT signal. Notifying daap server.\n");
|
||||
config.stop=1;
|
||||
return NULL;
|
||||
break;
|
||||
case SIGHUP:
|
||||
DPRINTF(E_LOG,L_MAIN,"Got HUP signal. Notifying daap server.\n");
|
||||
config.reload=1;
|
||||
break;
|
||||
default:
|
||||
DPRINTF(E_LOG,L_MAIN,"What am I doing here?\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Block signals, then start the signal handler. The
|
||||
* signal handler started by spawning a new thread on
|
||||
* signal_handler().
|
||||
*
|
||||
* \returns 0 on success, -1 on failure with errno set
|
||||
*/
|
||||
int start_signal_handler(pthread_t *handler_tid) {
|
||||
int error;
|
||||
sigset_t set;
|
||||
|
||||
if((sigemptyset(&set) == -1) ||
|
||||
(sigaddset(&set,SIGINT) == -1) ||
|
||||
(sigaddset(&set,SIGHUP) == -1) ||
|
||||
(sigaddset(&set,SIGCLD) == -1) ||
|
||||
(sigprocmask(SIG_BLOCK, &set, NULL) == -1)) {
|
||||
DPRINTF(E_LOG,L_MAIN,"Error setting signal set\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((error=pthread_create(handler_tid, NULL, signal_handler, NULL))) {
|
||||
errno=error;
|
||||
DPRINTF(E_LOG,L_MAIN,"Error creating signal_handler thread\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we'll not detach this... let's join it */
|
||||
//pthread_detach(handler_tid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kick off the daap server and wait for events.
|
||||
*
|
||||
@ -346,7 +160,6 @@ int start_signal_handler(pthread_t *handler_tid) {
|
||||
int main(int argc, char *argv[]) {
|
||||
int option;
|
||||
char *configfile=DEFAULT_CONFIGFILE;
|
||||
char *pidfile=PIDFILE;
|
||||
WSCONFIG ws_config;
|
||||
int foreground=0;
|
||||
int reload=0;
|
||||
@ -356,20 +169,17 @@ int main(int argc, char *argv[]) {
|
||||
int old_song_count, song_count;
|
||||
int force_non_root=0;
|
||||
int skip_initial=0;
|
||||
pthread_t signal_tid;
|
||||
|
||||
int pid_fd;
|
||||
FILE *pid_fp=NULL;
|
||||
int err;
|
||||
char *perr;
|
||||
|
||||
config.use_mdns=1;
|
||||
err_debuglevel=1;
|
||||
err_setlevel(1);
|
||||
|
||||
while((option=getopt(argc,argv,"D:d:c:P:mfrys")) != -1) {
|
||||
while((option=getopt(argc,argv,"D:d:c:P:mfrysiu")) != -1) {
|
||||
switch(option) {
|
||||
case 'd':
|
||||
err_debuglevel=atoi(optarg);
|
||||
err_setlevel(atoi(optarg));
|
||||
break;
|
||||
case 'D':
|
||||
if(err_setdebugmask(optarg)) {
|
||||
@ -389,10 +199,11 @@ int main(int argc, char *argv[]) {
|
||||
config.use_mdns=0;
|
||||
break;
|
||||
|
||||
#ifndef WIN32
|
||||
case 'P':
|
||||
pidfile=optarg;
|
||||
os_set_pidfile(optarg);
|
||||
break;
|
||||
|
||||
#endif
|
||||
case 'r':
|
||||
reload=1;
|
||||
break;
|
||||
@ -405,6 +216,18 @@ int main(int argc, char *argv[]) {
|
||||
force_non_root=1;
|
||||
break;
|
||||
|
||||
#ifdef WIN32
|
||||
case 'i':
|
||||
os_register();
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
os_unregister();
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
@ -420,7 +243,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
/* read the configfile, if specified, otherwise
|
||||
* try defaults */
|
||||
config.stats.start_time=start_time=time(NULL);
|
||||
config.stats.start_time=start_time=(int)time(NULL);
|
||||
config.stop=0;
|
||||
|
||||
if(config_read(configfile)) {
|
||||
@ -428,7 +251,7 @@ int main(int argc, char *argv[]) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
DPRINTF(E_LOG,L_MAIN,"Starting with debuglevel %d\n",err_debuglevel);
|
||||
DPRINTF(E_LOG,L_MAIN,"Starting with debuglevel %d\n",err_getlevel());
|
||||
|
||||
if(!foreground) {
|
||||
if(config.logfile) {
|
||||
@ -447,48 +270,14 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* open the pidfile, so it can be written once we detach */
|
||||
if((!foreground) && (!force_non_root)) {
|
||||
if(-1 == (pid_fd = open(pidfile,O_CREAT | O_WRONLY | O_TRUNC, 0644)))
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error opening pidfile (%s): %s\n",pidfile,strerror(errno));
|
||||
|
||||
if(0 == (pid_fp = fdopen(pid_fd, "w")))
|
||||
DPRINTF(E_FATAL,L_MAIN,"fdopen: %s\n",strerror(errno));
|
||||
|
||||
/* just to be on the safe side... */
|
||||
config.pid=0;
|
||||
|
||||
daemon_start();
|
||||
}
|
||||
|
||||
// Drop privs here
|
||||
if(drop_privs(config.runas)) {
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error in drop_privs: %s\n",strerror(errno));
|
||||
}
|
||||
|
||||
/* block signals and set up the signal handling thread */
|
||||
DPRINTF(E_LOG,L_MAIN,"Starting signal handler\n");
|
||||
if(start_signal_handler(&signal_tid)) {
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error starting signal handler %s\n",strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
if(pid_fp) {
|
||||
/* wait to for config.pid to be set by the signal handler */
|
||||
while(!config.pid) {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
fprintf(pid_fp,"%d\n",config.pid);
|
||||
fclose(pid_fp);
|
||||
if(!os_init(foreground)) {
|
||||
DPRINTF(E_LOG,L_MAIN,"Could not initialize server\n");
|
||||
os_deinit();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* this will require that the db be readable by the runas user */
|
||||
if(config.dbtype) {
|
||||
err=db_open(&perr,config.dbtype,config.dbparms);
|
||||
} else {
|
||||
err=db_open(&perr,NULL,config.dbdir);
|
||||
}
|
||||
err=db_open(&perr,config.dbtype,config.dbparms);
|
||||
|
||||
if(err)
|
||||
DPRINTF(E_FATAL,L_MAIN|L_DB,"Error in db_open: %s\n",perr);
|
||||
@ -535,7 +324,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
#endif
|
||||
|
||||
end_time=time(NULL);
|
||||
end_time=(int) time(NULL);
|
||||
|
||||
db_get_song_count(NULL,&song_count);
|
||||
DPRINTF(E_LOG,L_MAIN,"Scanned %d songs in %d seconds\n",song_count,
|
||||
@ -553,7 +342,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if(config.reload) {
|
||||
old_song_count = song_count;
|
||||
start_time=time(NULL);
|
||||
start_time=(int) time(NULL);
|
||||
|
||||
DPRINTF(E_LOG,L_MAIN|L_DB|L_SCAN,"Rescanning database\n");
|
||||
if(scan_init(config.mp3dir)) {
|
||||
@ -581,11 +370,6 @@ int main(int argc, char *argv[]) {
|
||||
#endif
|
||||
|
||||
|
||||
DPRINTF(E_LOG,L_MAIN,"Stopping signal handler\n");
|
||||
if(!pthread_kill(signal_tid,SIGINT)) {
|
||||
pthread_join(signal_tid,NULL);
|
||||
}
|
||||
|
||||
/* Got to find a cleaner way to stop the web server.
|
||||
* Closing the fd of the socking accepting doesn't necessarily
|
||||
* cause the accept to fail on some libcs.
|
||||
@ -599,15 +383,11 @@ int main(int argc, char *argv[]) {
|
||||
DPRINTF(E_LOG,L_MAIN|L_DB,"Closing database\n");
|
||||
db_deinit();
|
||||
|
||||
#ifdef DEBUG_MEMORY
|
||||
fprintf(stderr,"Leaked memory:\n");
|
||||
err_leakcheck();
|
||||
#endif
|
||||
|
||||
DPRINTF(E_LOG,L_MAIN,"Done!\n");
|
||||
|
||||
err_setdest(NULL,LOGDEST_STDERR);
|
||||
|
||||
os_deinit();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#define _POSIX_PTHREAD_SEMANTICS
|
||||
@ -36,19 +36,21 @@
|
||||
#include <fcntl.h>
|
||||
#include <id3tag.h>
|
||||
#include <limits.h>
|
||||
#include <restart.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <netinet/in.h> /* htons and friends */
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h> /* why here? For osx 10.2, of course! */
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "daapd.h"
|
||||
#include "db-generic.h"
|
||||
#include "err.h"
|
||||
#include "mp3-scanner.h"
|
||||
#include "restart.h"
|
||||
#include "ssc.h"
|
||||
|
||||
#ifndef HAVE_STRCASESTR
|
||||
@ -136,7 +138,7 @@ static TAGHANDLER taghandlers[] = {
|
||||
{ "wma", scan_get_wmainfo, "wma", "wma", "WMA audio file" },
|
||||
{ "url", scan_get_urlinfo, "pls", NULL, "Playlist URL" },
|
||||
{ "pls", scan_get_urlinfo, "pls", NULL, "Playlist URL" },
|
||||
{ "m4v", scan_get_mp4info, "m4v", "mp4v", "MPEG-4 video file" },
|
||||
{ "m4v", scan_get_mp4info, "m4v", "mp4v", "MPEG-4 video file" },
|
||||
#ifdef OGGVORBIS
|
||||
{ "ogg", scan_get_ogginfo, "ogg", "ogg", "Ogg Vorbis audio file" },
|
||||
#endif
|
||||
@ -345,7 +347,7 @@ int scan_path(char *path) {
|
||||
} else if (((ext = strrchr(pde->d_name, '.')) != NULL) &&
|
||||
(strcasestr(config.extensions, ext))) {
|
||||
/* only scan if it's been changed, or empty db */
|
||||
modified_time=sb.st_mtime;
|
||||
modified_time=(int) sb.st_mtime;
|
||||
pmp3=db_fetch_path(NULL,mp3_path,0);
|
||||
|
||||
if((!pmp3) || (pmp3->db_timestamp < modified_time) ||
|
||||
@ -411,9 +413,9 @@ int scan_static_playlist(char *path) {
|
||||
}
|
||||
|
||||
if(pm3u) {
|
||||
DPRINTF(E_DBG,L_SCAN,"Playlist needs updated\n");
|
||||
/* welcome to texas, y'all */
|
||||
db_delete_playlist(NULL,pm3u->id);
|
||||
DPRINTF(E_DBG,L_SCAN,"Playlist needs updated\n");
|
||||
/* welcome to texas, y'all */
|
||||
db_delete_playlist(NULL,pm3u->id);
|
||||
}
|
||||
|
||||
fd=open(path,O_RDONLY);
|
||||
@ -423,7 +425,7 @@ int scan_static_playlist(char *path) {
|
||||
DPRINTF(E_LOG,L_SCAN,"Error adding m3u %s: %s\n",path,perr);
|
||||
free(perr);
|
||||
db_dispose_playlist(pm3u);
|
||||
close(fd);
|
||||
close(fd);
|
||||
return FALSE;
|
||||
}
|
||||
/* now get the *real* base_path */
|
||||
@ -483,13 +485,15 @@ int scan_static_playlist(char *path) {
|
||||
void scan_music_file(char *path, struct dirent *pde,
|
||||
struct stat *psb, int is_compdir) {
|
||||
MP3FILE mp3file;
|
||||
char tmp_path[PATH_MAX];
|
||||
char mp3_path[PATH_MAX];
|
||||
char *current=NULL;
|
||||
char *type;
|
||||
TAGHANDLER *ptaghandler;
|
||||
char fdescr[50];
|
||||
|
||||
snprintf(mp3_path,sizeof(mp3_path),"%s/%s",path,pde->d_name);
|
||||
snprintf(tmp_path,sizeof(mp3_path),"%s/%s",path,pde->d_name);
|
||||
realpath(tmp_path,mp3_path);
|
||||
|
||||
/* we found an mp3 file */
|
||||
DPRINTF(E_INF,L_SCAN,"Found music file: %s\n",pde->d_name);
|
||||
@ -537,10 +541,10 @@ void scan_music_file(char *path, struct dirent *pde,
|
||||
My thinking is to use time created, but what is that? Best
|
||||
guess would be earliest of st_mtime and st_ctime...
|
||||
*/
|
||||
mp3file.time_added=psb->st_mtime;
|
||||
mp3file.time_added=(int) psb->st_mtime;
|
||||
if(psb->st_ctime < mp3file.time_added)
|
||||
mp3file.time_added=psb->st_ctime;
|
||||
mp3file.time_modified=psb->st_mtime;
|
||||
mp3file.time_added=(int) psb->st_ctime;
|
||||
mp3file.time_modified=(int) psb->st_mtime;
|
||||
|
||||
DPRINTF(E_DBG,L_SCAN," Date Added: %d\n",mp3file.time_added);
|
||||
|
||||
@ -648,9 +652,9 @@ void make_composite_tags(MP3FILE *song) {
|
||||
|
||||
if(!song->artist && (song->orchestra || song->conductor)) {
|
||||
if(song->orchestra)
|
||||
len += strlen(song->orchestra);
|
||||
len += (int) strlen(song->orchestra);
|
||||
if(song->conductor)
|
||||
len += strlen(song->conductor);
|
||||
len += (int) strlen(song->conductor);
|
||||
|
||||
len += 3;
|
||||
|
||||
|
@ -64,9 +64,9 @@ typedef struct tag_mp3file {
|
||||
int got_id3;
|
||||
unsigned int id;
|
||||
|
||||
char *description; /* long file type */
|
||||
char *description; /* long file type */
|
||||
char *codectype; /* song.codectype */
|
||||
int item_kind; /* song or movie */
|
||||
int item_kind; /* song or movie */
|
||||
int data_kind; /* dmap.datakind (asdk) */
|
||||
int force_update;
|
||||
int sample_count;
|
||||
|
379
src/os-unix.c
Normal file
379
src/os-unix.c
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
* $Id$
|
||||
* Abstracts os interface
|
||||
*
|
||||
* Copyright (c) 2006 Ron Pedde (rpedde@users.sourceforge.net)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef HAVE_SYS_WAIT
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "err.h"
|
||||
#include "daapd.h"
|
||||
#include "os-unix.h"
|
||||
|
||||
/** You say po-tay-to, I say po-tat-o */
|
||||
#ifndef SIGCLD
|
||||
# define SIGCLD SIGCHLD
|
||||
#endif
|
||||
|
||||
/** Where to dump the pidfile */
|
||||
#ifndef PIDFILE
|
||||
#define PIDFILE "/var/run/mt-daapd.pid"
|
||||
#endif
|
||||
|
||||
/* Forwards */
|
||||
static int _os_daemon_start(void);
|
||||
static void *_os_signal_handler(void *arg);
|
||||
static int _os_start_signal_handler(pthread_t *handler_tid);
|
||||
static volatile int _os_signal_pid;
|
||||
|
||||
/* Globals */
|
||||
pthread_t _os_signal_tid;
|
||||
char *_os_pidfile = PIDFILE;
|
||||
|
||||
/**
|
||||
* this initializes the platform... sets up signal handlers, forks to the
|
||||
* background, etc
|
||||
*
|
||||
* @param foreground whether to run in fg or fork to bg
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
int os_init(int foreground) {
|
||||
int pid_fd;
|
||||
FILE *pid_fp=NULL;
|
||||
|
||||
/* open the pidfile, so it can be written once we detach */
|
||||
if(!foreground) {
|
||||
if(-1 == (pid_fd = open(_os_pidfile,O_CREAT | O_WRONLY | O_TRUNC, 0644))) {
|
||||
DPRINTF(E_LOG,L_MAIN,"Error opening pidfile (%s): %s\n",
|
||||
_os_pidfile,strerror(errno));
|
||||
} else {
|
||||
if(0 == (pid_fp = fdopen(pid_fd, "w")))
|
||||
DPRINTF(E_LOG,L_MAIN,"fdopen: %s\n",strerror(errno));
|
||||
}
|
||||
/* just to be on the safe side... */
|
||||
_os_signal_pid=0;
|
||||
_os_daemon_start();
|
||||
}
|
||||
|
||||
// Drop privs here
|
||||
if(os_drop_privs(config.runas)) {
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error in drop_privs: %s\n",strerror(errno));
|
||||
}
|
||||
|
||||
/* block signals and set up the signal handling thread */
|
||||
DPRINTF(E_LOG,L_MAIN,"Starting signal handler\n");
|
||||
if(_os_start_signal_handler(&_os_signal_tid)) {
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error starting signal handler %s\n",strerror(errno));
|
||||
}
|
||||
|
||||
if(pid_fp) {
|
||||
/* wait to for config.pid to be set by the signal handler */
|
||||
while(!_os_signal_pid) {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
fprintf(pid_fp,"%d\n",_os_signal_pid);
|
||||
fclose(pid_fp);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* do any deinitialization necessary for the platform
|
||||
*/
|
||||
void os_deinit(void) {
|
||||
DPRINTF(E_LOG,L_MAIN,"Stopping signal handler\n");
|
||||
if(!pthread_kill(_os_signal_tid,SIGINT)) {
|
||||
pthread_join(_os_signal_tid,NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* start syslogging
|
||||
*
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
int os_opensyslog(void) {
|
||||
openlog(PACKAGE,LOG_PID,LOG_DAEMON);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* stop syslogging
|
||||
*
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
int os_closesyslog(void) {
|
||||
closelog();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* log a syslog message
|
||||
*
|
||||
* @param level log level (1-9: 1=fatal, 9=debug)
|
||||
* @param msg message to log to the syslog
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
int os_syslog(int level, char *msg) {
|
||||
int priority;
|
||||
|
||||
switch(level) {
|
||||
case 0:
|
||||
case 1:
|
||||
priority = LOG_ALERT;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
priority = LOG_NOTICE;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
priority = LOG_INFO;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
default:
|
||||
priority = LOG_DEBUG;
|
||||
break;
|
||||
}
|
||||
|
||||
syslog(priority,"%s",msg);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fork and exit. Stolen pretty much straight from Stevens.
|
||||
*
|
||||
* @returns 0 on success, -1 with errno set on error
|
||||
*/
|
||||
int _os_daemon_start(void) {
|
||||
int childpid, fd;
|
||||
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
// Fork and exit
|
||||
if ((childpid = fork()) < 0) {
|
||||
fprintf(stderr, "Can't fork!\n");
|
||||
return -1;
|
||||
} else if (childpid > 0)
|
||||
exit(0);
|
||||
|
||||
#ifdef SETPGRP_VOID
|
||||
setpgrp();
|
||||
#else
|
||||
setpgrp(0,0);
|
||||
#endif
|
||||
|
||||
#ifdef TIOCNOTTY
|
||||
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
|
||||
ioctl(fd, TIOCNOTTY, (char *) NULL);
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
if((fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
for (fd = 0; fd < FOPEN_MAX; fd++)
|
||||
close(fd);
|
||||
*/
|
||||
|
||||
errno = 0;
|
||||
|
||||
chdir("/");
|
||||
umask(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Drop privs. This allows mt-daapd to run as a non-privileged user.
|
||||
* Hopefully this will limit the damage it could do if exploited
|
||||
* remotely. Note that only the user need be specified. GID
|
||||
* is set to the primary group of the user.
|
||||
*
|
||||
* \param user user to run as (or UID)
|
||||
*/
|
||||
int os_drop_privs(char *user) {
|
||||
int err;
|
||||
struct passwd *pw=NULL;
|
||||
|
||||
/* drop privs */
|
||||
if(getuid() == (uid_t)0) {
|
||||
if(atoi(user)) {
|
||||
pw=getpwuid((uid_t)atoi(user)); /* doh! */
|
||||
} else {
|
||||
pw=getpwnam(config.runas);
|
||||
}
|
||||
|
||||
if(pw) {
|
||||
if(initgroups(user,pw->pw_gid) != 0 ||
|
||||
setgid(pw->pw_gid) != 0 ||
|
||||
setuid(pw->pw_uid) != 0) {
|
||||
err=errno;
|
||||
fprintf(stderr,"Couldn't change to %s, gid=%d, uid=%d\n",
|
||||
user,pw->pw_gid, pw->pw_uid);
|
||||
errno=err;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
err=errno;
|
||||
fprintf(stderr,"Couldn't lookup user %s\n",user);
|
||||
errno=err;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for signals and flag the main process. This is
|
||||
* a thread handler for the signal processing thread. It
|
||||
* does absolutely nothing except wait for signals. The rest
|
||||
* of the threads are running with signals blocked, so this thread
|
||||
* is guaranteed to catch all the signals. It sets flags in
|
||||
* the config structure that the main thread looks for. Specifically,
|
||||
* the stop flag (from an INT signal), and the reload flag (from HUP).
|
||||
* \param arg NULL, but required of a thread procedure
|
||||
*/
|
||||
void *_os_signal_handler(void *arg) {
|
||||
sigset_t intmask;
|
||||
int sig;
|
||||
int status;
|
||||
|
||||
config.stop=0;
|
||||
config.reload=0;
|
||||
_os_signal_pid=getpid();
|
||||
|
||||
DPRINTF(E_WARN,L_MAIN,"Signal handler started\n");
|
||||
|
||||
while(!config.stop) {
|
||||
if((sigemptyset(&intmask) == -1) ||
|
||||
(sigaddset(&intmask, SIGCLD) == -1) ||
|
||||
(sigaddset(&intmask, SIGINT) == -1) ||
|
||||
(sigaddset(&intmask, SIGHUP) == -1) ||
|
||||
(sigwait(&intmask, &sig) == -1)) {
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error waiting for signals. Aborting\n");
|
||||
} else {
|
||||
/* process the signal */
|
||||
switch(sig) {
|
||||
case SIGCLD:
|
||||
DPRINTF(E_LOG,L_MAIN,"Got CLD signal. Reaping\n");
|
||||
while (wait3(&status, WNOHANG, NULL) > 0) {
|
||||
}
|
||||
break;
|
||||
case SIGINT:
|
||||
DPRINTF(E_LOG,L_MAIN,"Got INT signal. Notifying daap server.\n");
|
||||
config.stop=1;
|
||||
return NULL;
|
||||
break;
|
||||
case SIGHUP:
|
||||
DPRINTF(E_LOG,L_MAIN,"Got HUP signal. Notifying daap server.\n");
|
||||
config.reload=1;
|
||||
break;
|
||||
default:
|
||||
DPRINTF(E_LOG,L_MAIN,"What am I doing here?\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Block signals, then start the signal handler. The
|
||||
* signal handler started by spawning a new thread on
|
||||
* signal_handler().
|
||||
*
|
||||
* \returns 0 on success, -1 on failure with errno set
|
||||
*/
|
||||
int _os_start_signal_handler(pthread_t *handler_tid) {
|
||||
int error;
|
||||
sigset_t set;
|
||||
|
||||
if((sigemptyset(&set) == -1) ||
|
||||
(sigaddset(&set,SIGINT) == -1) ||
|
||||
(sigaddset(&set,SIGHUP) == -1) ||
|
||||
(sigaddset(&set,SIGCLD) == -1) ||
|
||||
(sigprocmask(SIG_BLOCK, &set, NULL) == -1)) {
|
||||
DPRINTF(E_LOG,L_MAIN,"Error setting signal set\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((error=pthread_create(handler_tid, NULL, _os_signal_handler, NULL))) {
|
||||
errno=error;
|
||||
DPRINTF(E_LOG,L_MAIN,"Error creating signal_handler thread\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we'll not detach this... let's join it */
|
||||
//pthread_detach(handler_tid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the pidfile to a non-default value
|
||||
*
|
||||
* @param file file to use as pidfile
|
||||
*/
|
||||
void os_set_pidfile(char *file) {
|
||||
_os_pidfile = file;
|
||||
}
|
||||
|
15
src/os-unix.h
Normal file
15
src/os-unix.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* $Id$
|
||||
* Copyright (C) 2006 Ron Pedde (rpedde@users.sourceforge.net)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _OS_UNIX_H_
|
||||
#define _OS_UNIX_H_
|
||||
|
||||
/* unix-specific functions */
|
||||
extern int os_drop_privs(char *user);
|
||||
void os_set_pidfile(char *file);
|
||||
|
||||
#endif
|
||||
|
645
src/os-win32.c
Normal file
645
src/os-win32.c
Normal file
@ -0,0 +1,645 @@
|
||||
/* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "daapd.h"
|
||||
#include "win32.h"
|
||||
#include "err.h"
|
||||
#include "os-win32.h"
|
||||
#include "w32-eventlog.h"
|
||||
#include "w32-service.h"
|
||||
|
||||
/* Globals */
|
||||
static WSADATA w32_wsadata;
|
||||
static os_serviceflag = 0;
|
||||
static pthread_t os_service_tid;
|
||||
static os_initialized=0;
|
||||
static pthread_mutex_t os_mutex=PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* Forwards */
|
||||
static void _os_socket_startup(void);
|
||||
static void _os_socket_shutdown(void);
|
||||
static int _os_sock_to_fd(SOCKET sock);
|
||||
static void _os_lock(void);
|
||||
static void _os_unlock(void);
|
||||
static BOOL WINAPI _os_cancelhandler(DWORD dwCtrlType);
|
||||
|
||||
extern int gettimeout(struct timeval end,struct timeval *timeoutp);
|
||||
|
||||
#define OSFI_OPEN 1
|
||||
#define OSFI_SHUTDOWN 2
|
||||
|
||||
#define NOTSOCK (fd < MAXDESC)
|
||||
#define REALSOCK (file_info[fd - MAXDESC].sock)
|
||||
#define SOCKSTATE (file_info[fd - MAXDESC].state)
|
||||
|
||||
#define MAXBACKLOG 5
|
||||
|
||||
typedef struct tag_osfileinfo {
|
||||
SOCKET sock;
|
||||
int state;
|
||||
} OSFILEINFO;
|
||||
|
||||
/* Globals */
|
||||
OSFILEINFO file_info[MAXDESC];
|
||||
char os_config_file[_MAX_PATH];
|
||||
|
||||
/* "official" os interface functions */
|
||||
|
||||
/**
|
||||
* initialize the os-specific stuff. this would include
|
||||
* backgrounding (or starting as service), setting up
|
||||
* signal handlers (or ctrl-c handlers), etc
|
||||
*
|
||||
* @param background whether or not to start in background (service)
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
int os_init(int foreground) {
|
||||
int err;
|
||||
|
||||
_os_socket_startup();
|
||||
|
||||
if(!os_initialized) {
|
||||
_os_lock();
|
||||
if(!os_initialized) {
|
||||
memset((void*)&file_info,0,sizeof(file_info));
|
||||
}
|
||||
os_initialized=1;
|
||||
_os_unlock();
|
||||
}
|
||||
|
||||
if(!foreground) {
|
||||
/* startup as service */
|
||||
os_serviceflag = 1;
|
||||
if((err=pthread_create(&os_service_tid,NULL,service_startup,NULL))) {
|
||||
DPRINTF(E_LOG,L_MISC,"Could not spawn thread: %s\n",strerror(err));
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
/* let's set a ctrl-c handler! */
|
||||
SetConsoleCtrlHandler(_os_cancelhandler,TRUE);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown the system-specific stuff started in os_init.
|
||||
*/
|
||||
void os_deinit(void) {
|
||||
_os_socket_shutdown();
|
||||
if(os_serviceflag) {
|
||||
/* then we need to stop the service */
|
||||
SetConsoleCtrlHandler(_os_cancelhandler,FALSE);
|
||||
service_shutdown(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* open the syslog (eventlog)
|
||||
*/
|
||||
int os_opensyslog(void) {
|
||||
return elog_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* close the syslog (eventlog)
|
||||
*/
|
||||
int os_closesyslog(void) {
|
||||
return elog_deinit();
|
||||
}
|
||||
|
||||
/**
|
||||
* write a message to the syslog
|
||||
*
|
||||
* @param level what level of message (1-10)
|
||||
* @param msg message to write
|
||||
* @return TRUE on success, FALSE otherwise
|
||||
*/
|
||||
int os_syslog(int level, char *msg) {
|
||||
return elog_message(level, msg);
|
||||
}
|
||||
|
||||
|
||||
int os_register(void) {
|
||||
service_register();
|
||||
elog_register();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int os_unregister(void) {
|
||||
service_unregister();
|
||||
elog_unregister();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI _os_cancelhandler(DWORD dwCtrlType) {
|
||||
DPRINTF(E_LOG,L_MISC,"Shutting down with a console event\n");
|
||||
config.stop = 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
int _os_sock_to_fd(SOCKET sock) {
|
||||
int fd;
|
||||
|
||||
if(sock == INVALID_SOCKET)
|
||||
return -1;
|
||||
|
||||
DPRINTF(E_SPAM,L_MISC,"Converting socket to fd\n");
|
||||
|
||||
/* I was doing strange osfhandle stuff here, but it seemed
|
||||
* to be leaking file handles, and I don't really know what
|
||||
* it was doing. Thanks, Microsoft. Anyway, since I'm handling
|
||||
* reads, writes, opens and closes, I might just as well hand out
|
||||
* FAKE fds and swap them out to SOCKETS when I need to. No
|
||||
* more fd leaks. Problem solved.
|
||||
*/
|
||||
/*
|
||||
fd=_open_osfhandle(sock,O_RDWR|O_BINARY);
|
||||
// fd=_open_osfhandle(sock,0);
|
||||
if(fd > 0) {
|
||||
file_info[fd].flags = OSFI_SOCKET | OSFI_OPEN;
|
||||
file_info[fd].sock=sock;
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_MISC,"Could not fd for socket osfhandle\n");
|
||||
}
|
||||
*/
|
||||
_os_lock();
|
||||
fd=0;
|
||||
while((fd < MAXDESC) && (file_info[fd].state)) {
|
||||
fd++;
|
||||
}
|
||||
|
||||
if(fd == MAXDESC) {
|
||||
_os_unlock();
|
||||
DPRINTF(E_FATAL,L_MISC,"Out of pseudo file handles. See ya\n");
|
||||
}
|
||||
|
||||
DPRINTF(E_SPAM,L_MISC,"Returning fd %d\n",fd + MAXDESC);
|
||||
file_info[fd].sock = sock;
|
||||
file_info[fd].state = OSFI_OPEN;
|
||||
_os_unlock();
|
||||
return fd + MAXDESC;
|
||||
}
|
||||
|
||||
int os_acceptsocket(int fd, char *hostn, int hostnsize) {
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
struct sockaddr_in netclient;
|
||||
SOCKET retval;
|
||||
|
||||
DPRINTF(E_SPAM,L_MISC,"Accepting socket %d -- %d\n",fd,REALSOCK);
|
||||
|
||||
if(NOTSOCK || (SOCKSTATE != OSFI_OPEN)) {
|
||||
DPRINTF(E_LOG,L_MISC,"Bad socket passed to accept\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (((retval =
|
||||
accept(REALSOCK,(struct sockaddr *)(&netclient), &len)) == SOCKET_ERROR) &&
|
||||
(WSAGetLastError() == WSAEINTR));
|
||||
|
||||
if ((retval == INVALID_SOCKET) || (hostn == NULL) || (hostnsize <= 0)) {
|
||||
DPRINTF(E_LOG,L_MISC,"Error accepting...\n");
|
||||
return _os_sock_to_fd(retval);
|
||||
}
|
||||
|
||||
strncpy(hostn,inet_ntoa(netclient.sin_addr),hostnsize);
|
||||
return _os_sock_to_fd(retval);
|
||||
}
|
||||
|
||||
int os_waitfdtimed(int fd, struct timeval end) {
|
||||
fd_set readset;
|
||||
int retval;
|
||||
struct timeval timeout;
|
||||
SOCKET sock;
|
||||
|
||||
DPRINTF(E_SPAM,L_MISC,"Timed wait on fd %d\n");
|
||||
if(NOTSOCK || (SOCKSTATE != OSFI_OPEN))
|
||||
return -1;
|
||||
|
||||
sock = REALSOCK;
|
||||
|
||||
/*
|
||||
if ((fd < 0) || (fd >= FD_SETSIZE)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
FD_ZERO(&readset);
|
||||
FD_SET(sock, &readset);
|
||||
if (gettimeout(end, &timeout) == -1)
|
||||
return -1;
|
||||
while (((retval = select(1, &readset, NULL, NULL, NULL)) == SOCKET_ERROR)
|
||||
&& (WSAGetLastError() == WSAEINTR)) {
|
||||
if (gettimeout(end, &timeout) == -1)
|
||||
return -1;
|
||||
FD_ZERO(&readset);
|
||||
FD_SET(fd, &readset);
|
||||
}
|
||||
if (retval == 0) {
|
||||
errno = ETIME;
|
||||
return -1;
|
||||
}
|
||||
if (retval == -1)
|
||||
return -1;
|
||||
DPRINTF(E_SPAM,L_MISC,"Timed wait successful\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* from the gnu c library */
|
||||
char *os_strsep(char **stringp, const char *delim) {
|
||||
char *begin, *end;
|
||||
|
||||
begin = *stringp;
|
||||
if (begin == NULL)
|
||||
return NULL;
|
||||
|
||||
/* A frequent case is when the delimiter string contains only one
|
||||
character. Here we don't need to call the expensive `strpbrk'
|
||||
function and instead work using `strchr'. */
|
||||
if (delim[0] == '\0' || delim[1] == '\0') {
|
||||
char ch = delim[0];
|
||||
|
||||
if (ch == '\0') {
|
||||
end = NULL;
|
||||
} else {
|
||||
if (*begin == ch)
|
||||
end = begin;
|
||||
else if (*begin == '\0')
|
||||
end = NULL;
|
||||
else
|
||||
end = strchr (begin + 1, ch);
|
||||
}
|
||||
} else {
|
||||
/* Find the end of the token. */
|
||||
end = strpbrk (begin, delim);
|
||||
}
|
||||
|
||||
if (end) {
|
||||
/* Terminate the token and set *STRINGP past NUL character. */
|
||||
*end++ = '\0';
|
||||
*stringp = end;
|
||||
} else {
|
||||
/* No more delimiters; this is the last token. */
|
||||
*stringp = NULL;
|
||||
}
|
||||
return begin;
|
||||
}
|
||||
|
||||
int os_opensocket(unsigned short port) {
|
||||
int error;
|
||||
struct sockaddr_in server;
|
||||
SOCKET sock;
|
||||
int true = 1;
|
||||
int fd;
|
||||
|
||||
DPRINTF(E_SPAM,L_MISC,"Opening socket\n");
|
||||
/* make sure the file_info struct is initialized */
|
||||
if(!os_initialized) {
|
||||
_os_lock();
|
||||
if(!os_initialized) {
|
||||
memset((void*)&file_info,0,sizeof(file_info));
|
||||
os_initialized=1;
|
||||
}
|
||||
_os_unlock();
|
||||
}
|
||||
|
||||
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
return -1;
|
||||
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&true,
|
||||
sizeof(true)) == SOCKET_ERROR) {
|
||||
error = WSAGetLastError();
|
||||
while ((closesocket(sock) == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR));
|
||||
errno = EINVAL; /* windows errnos suck */
|
||||
return -1;
|
||||
}
|
||||
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
server.sin_port = htons((short)port);
|
||||
if ((bind(sock, (struct sockaddr *)&server, sizeof(server)) == -1) ||
|
||||
(listen(sock, MAXBACKLOG) == -1)) {
|
||||
error = errno;
|
||||
while ((closesocket(sock) == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR));
|
||||
errno = EINVAL; /* should be addrinuse or somethign */
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd=_os_sock_to_fd(sock);
|
||||
DPRINTF(E_SPAM,L_MISC,"created socket %d\n",fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int os_write(int fd, void *buffer, unsigned int count) {
|
||||
int retval;
|
||||
|
||||
if(NOTSOCK) {
|
||||
retval = _write(fd,buffer,count);
|
||||
} else {
|
||||
if(SOCKSTATE != OSFI_OPEN) {
|
||||
DPRINTF(E_LOG,L_MISC,"Write to socket with status: %d\n",
|
||||
file_info[fd-MAXDESC].state);
|
||||
return -1;
|
||||
}
|
||||
retval=send(REALSOCK,buffer,count,0);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int os_read(int fd,void *buffer,unsigned int count) {
|
||||
int retval;
|
||||
|
||||
DPRINTF(E_SPAM,L_MISC,"Reading %d bytes from %d\n",count,fd);
|
||||
if(NOTSOCK) {
|
||||
retval = _read(fd,buffer,count);
|
||||
} else {
|
||||
if(SOCKSTATE != OSFI_OPEN) {
|
||||
DPRINTF(E_LOG,L_MISC,"Read to socket with status: %d\n",
|
||||
file_info[fd-MAXDESC].state);
|
||||
return -1;
|
||||
}
|
||||
retval=recv(REALSOCK,buffer,count,0);
|
||||
DPRINTF(E_SPAM,L_MISC,"Actually returning %d\n",retval);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int os_shutdown(int fd, int how) {
|
||||
if(NOTSOCK || (SOCKSTATE != OSFI_OPEN))
|
||||
return -1;
|
||||
|
||||
SOCKSTATE = OSFI_SHUTDOWN;
|
||||
shutdown(REALSOCK,how);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: mode */
|
||||
int os_open(const char *filename, int oflag) {
|
||||
int fd;
|
||||
|
||||
fd = _open(filename, oflag | O_BINARY);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int os_close(int fd) {
|
||||
if(NOTSOCK) {
|
||||
_close(fd);
|
||||
} else { /* socket */
|
||||
if(SOCKSTATE == OSFI_OPEN) {
|
||||
os_shutdown(fd,SHUT_RDWR);
|
||||
}
|
||||
if(SOCKSTATE == OSFI_SHUTDOWN) {
|
||||
closesocket(REALSOCK);
|
||||
SOCKSTATE = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get uid of current user. this is really stubbed, as it's only used
|
||||
* as a check during startup (it fails normally if you run non-root, as it means
|
||||
* that it can't drop privs, can't write pidfile, etc)
|
||||
*/
|
||||
int os_getuid(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* this is now pretty close to a true realpath implementation
|
||||
*/
|
||||
char *os_realpath(const char *pathname, char *resolved_path) {
|
||||
char *ptr;
|
||||
|
||||
if(!_fullpath(resolved_path,pathname,PATH_MAX)) {
|
||||
DPRINTF(E_FATAL,L_MISC,"Could not realpath %s\n",pathname);
|
||||
}
|
||||
|
||||
ptr = resolved_path;
|
||||
while(*ptr) {
|
||||
*ptr = tolower(*ptr);
|
||||
if(*ptr == '/')
|
||||
*ptr = '\\';
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return &resolved_path[0];
|
||||
}
|
||||
|
||||
|
||||
int os_gettimeofday (struct timeval *tv, struct timezone* tz) {
|
||||
union {
|
||||
long long ns100; /*time since 1 Jan 1601 in 100ns units */
|
||||
FILETIME ft;
|
||||
} now;
|
||||
|
||||
GetSystemTimeAsFileTime (&now.ft);
|
||||
tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL);
|
||||
tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL);
|
||||
|
||||
if(tz) {
|
||||
tz->tz_minuteswest = _timezone;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* initialize winsock
|
||||
*/
|
||||
void _os_socket_startup(void) {
|
||||
WORD minver;
|
||||
int err;
|
||||
|
||||
minver = MAKEWORD( 2, 2 );
|
||||
|
||||
err = WSAStartup( minver, &w32_wsadata );
|
||||
if ( err != 0 ) {
|
||||
DPRINTF(E_FATAL,L_MISC,"Could not initialize winsock\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* deinitialize winsock
|
||||
*/
|
||||
void _os_socket_shutdown(void) {
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
/* COMPAT FUNCTIONS */
|
||||
time_t timegm(struct tm *tm) {
|
||||
time_t ret;
|
||||
char *tz;
|
||||
char buffer[255];
|
||||
|
||||
tz = getenv("TZ");
|
||||
_putenv("TZ=UTC0");
|
||||
_tzset();
|
||||
ret = mktime(tm);
|
||||
|
||||
if(tz)
|
||||
sprintf(buffer,"TZ=%s",tz);
|
||||
else
|
||||
strcpy(buffer,"TZ=");
|
||||
_putenv(buffer);
|
||||
_tzset();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* opendir/closedir/readdir emulation taken from emacs. Thanks. :) */
|
||||
DIR *os_opendir(char *filename) {
|
||||
DIR *dirp;
|
||||
|
||||
/* Opening is done by FindFirstFile. However, a read is inherent to
|
||||
this operation, so we defer the open until read time. */
|
||||
|
||||
if (!(dirp = (DIR *) malloc (sizeof (DIR))))
|
||||
return NULL;
|
||||
|
||||
dirp->dir_find_handle = INVALID_HANDLE_VALUE;
|
||||
dirp->dd_fd = 0;
|
||||
dirp->dd_loc = 0;
|
||||
dirp->dd_size = 0;
|
||||
|
||||
strncpy (dirp->dir_pathname, filename,_MAX_PATH);
|
||||
dirp->dir_pathname[_MAX_PATH] = '\0';
|
||||
|
||||
return dirp;
|
||||
}
|
||||
|
||||
void os_closedir(DIR *dirp) {
|
||||
/* If we have a find-handle open, close it. */
|
||||
if (dirp->dir_find_handle != INVALID_HANDLE_VALUE) {
|
||||
FindClose(dirp->dir_find_handle);
|
||||
}
|
||||
free((char *) dirp);
|
||||
}
|
||||
|
||||
|
||||
int os_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
|
||||
if (dirp->dir_find_handle == INVALID_HANDLE_VALUE) {
|
||||
/* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
|
||||
char filename[MAXNAMLEN + 3];
|
||||
int ln;
|
||||
|
||||
strcpy (filename, dirp->dir_pathname);
|
||||
ln = (int) strlen (filename) - 1;
|
||||
if(filename[ln] != '\\')
|
||||
strcat (filename, "\\");
|
||||
strcat (filename, "*");
|
||||
|
||||
dirp->dir_find_handle = FindFirstFile (filename, &dirp->dir_find_data);
|
||||
|
||||
if (dirp->dir_find_handle == INVALID_HANDLE_VALUE) {
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (!FindNextFile (dirp->dir_find_handle, &dirp->dir_find_data)) {
|
||||
*result = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emacs never uses this value, so don't bother making it match
|
||||
value returned by stat(). */
|
||||
entry->d_ino = 1;
|
||||
|
||||
entry->d_namlen = (int) strlen (dirp->dir_find_data.cFileName);
|
||||
entry->d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
|
||||
entry->d_namlen - entry->d_namlen % 4;
|
||||
strcpy (entry->d_name, dirp->dir_find_data.cFileName);
|
||||
|
||||
/*
|
||||
if (dir_is_fat)
|
||||
_strlwr (dir_static.d_name);
|
||||
else if (!NILP (Vw32_downcase_file_names)) {
|
||||
register char *p;
|
||||
for (p = dir_static.d_name; *p; p++)
|
||||
if (*p >= 'a' && *p <= 'z')
|
||||
break;
|
||||
if (!*p)
|
||||
_strlwr (dir_static.d_name);
|
||||
}
|
||||
*/
|
||||
*result = entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* can't be worse then strerror */
|
||||
char *os_strerror (int error_no) {
|
||||
static char buf[500];
|
||||
|
||||
if (error_no == 0)
|
||||
error_no = GetLastError ();
|
||||
|
||||
buf[0] = '\0';
|
||||
if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
|
||||
error_no,
|
||||
0, /* choose most suitable language */
|
||||
buf, sizeof (buf), NULL))
|
||||
sprintf (buf, "w32 error %u", error_no);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the default config path. there might be an argument to be made
|
||||
* for using the install path as determined by registry, but might
|
||||
* just be easiest to grab the directory the executable is running from
|
||||
*
|
||||
* @returns path to config file (from static buffer)
|
||||
*/
|
||||
char *os_configpath(void) {
|
||||
char drive[_MAX_DRIVE];
|
||||
char dir[_MAX_DIR];
|
||||
char working_dir[_MAX_PATH];
|
||||
|
||||
GetModuleFileName(NULL,os_config_file,MAX_PATH);
|
||||
_splitpath(os_config_file,drive,dir,NULL,NULL);
|
||||
_makepath(os_config_file,drive,dir,"mt-daapd","conf");
|
||||
_makepath(working_dir,drive,dir,NULL,NULL);
|
||||
|
||||
if(_chdir(working_dir) == -1) {
|
||||
DPRINTF(E_LOG,L_MISC,"Could not chdir to %s... using c:\\\n",working_dir);
|
||||
if(_chdir("c:\\") == -1) {
|
||||
DPRINTF(E_FATAL,L_MISC,"Could not chdir to c:\\... aborting\n");
|
||||
}
|
||||
}
|
||||
DPRINTF(E_DBG,L_MISC,"Using config file %s\n",os_config_file);
|
||||
return os_config_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock the mutex. This is used for initialization stuff, among
|
||||
* other things (?)
|
||||
*/
|
||||
void _os_lock(void) {
|
||||
int err;
|
||||
|
||||
if((err=pthread_mutex_lock(&os_mutex))) {
|
||||
DPRINTF(E_FATAL,L_MISC,"Cannot lock mutex\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock the os mutex
|
||||
*/
|
||||
void _os_unlock(void) {
|
||||
int err;
|
||||
|
||||
if((err=pthread_mutex_unlock(&os_mutex))) {
|
||||
DPRINTF(E_FATAL,L_MISC,"Cannot unlock mutex\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
66
src/os-win32.h
Normal file
66
src/os-win32.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* os glue stuff, for functions that vary too greatly between
|
||||
* win32 and unix
|
||||
*/
|
||||
|
||||
#ifndef _OS_WIN32_H_
|
||||
#define _OS_WIN32_H_
|
||||
|
||||
#include "stdlib.h"
|
||||
|
||||
#define MAXNAMLEN 255
|
||||
#define DIRBLKSIZ 512
|
||||
|
||||
|
||||
struct timezone {
|
||||
int tz_minuteswest;
|
||||
int tz_dsttime;
|
||||
};
|
||||
|
||||
struct dirent { /* data from readdir() */
|
||||
|
||||
long d_ino; /* inode number of entry */
|
||||
unsigned short d_reclen; /* length of this record */
|
||||
unsigned short d_namlen; /* length of string in d_name */
|
||||
char d_name[MAXNAMLEN+1]; /* name of file */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int dd_fd; /* file descriptor */
|
||||
int dd_loc; /* offset in block */
|
||||
int dd_size; /* amount of valid data */
|
||||
char dd_buf[DIRBLKSIZ]; /* directory block */
|
||||
HANDLE dir_find_handle;
|
||||
char dir_pathname[_MAX_PATH+1];
|
||||
WIN32_FIND_DATA dir_find_data;
|
||||
} DIR;
|
||||
|
||||
/* win32-specific functions -- set up service, etc */
|
||||
extern int os_register(void);
|
||||
extern int os_unregister(void);
|
||||
extern char *os_configpath(void);
|
||||
|
||||
/* replacements for socket functions */
|
||||
extern int os_opensocket(unsigned short port);
|
||||
extern int os_acceptsocket(int fd, char *hostn, int hostnsize);
|
||||
extern int os_shutdown(int fd, int how);
|
||||
extern int os_waitfdtimed(int fd, struct timeval end);
|
||||
extern int os_close(int fd);
|
||||
extern int os_open(const char *filename, int oflag);
|
||||
extern int os_read(int fd,void *buffer,unsigned int count);
|
||||
extern int os_write(int fd, void *buffer, unsigned int count);
|
||||
extern int os_getuid(void);
|
||||
|
||||
/* missing win32 functions */
|
||||
extern char *os_strsep(char **stringp, const char *delim);
|
||||
extern char *os_realpath(const char *pathname, char *resolved_path);
|
||||
extern int os_gettimeofday (struct timeval *tv, struct timezone* tz);
|
||||
extern int os_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
|
||||
extern void os_closedir(DIR *dirp);
|
||||
extern DIR *os_opendir(char *filename);
|
||||
extern time_t timegm(struct tm *tm);
|
||||
extern char *os_strerror (int error_no);
|
||||
|
||||
#endif /* _OS_WIN32_H_ */
|
41
src/os.h
Normal file
41
src/os.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* $Id$
|
||||
* Abstract os interface for non-unix platforms
|
||||
*
|
||||
* Copyright (C) 2006 Ron Pedde (rpedde@users.sourceforge.net)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _OS_H_
|
||||
#define _OS_H_
|
||||
|
||||
|
||||
/* backgrounding, signal handling, etc */
|
||||
extern int os_init(int foreground);
|
||||
extern void os_deinit(void);
|
||||
|
||||
/* system native logging functions */
|
||||
extern int os_opensyslog(void);
|
||||
extern int os_closesyslog(void);
|
||||
extern int os_syslog(int level, char *msg);
|
||||
|
||||
#ifdef WIN32
|
||||
# include "os-win32.h"
|
||||
#else
|
||||
# include "os-unix.h"
|
||||
#endif
|
||||
|
||||
#endif
|
650
src/query.c
650
src/query.c
@ -17,66 +17,66 @@ static void query_free(query_node_t* query);
|
||||
static int query_build_clause(query_node_t *query, char **current, int *size);
|
||||
|
||||
static const query_field_t *find_field(const char* name,
|
||||
const query_field_t* fields);
|
||||
const query_field_t* fields);
|
||||
// static int arith_query(query_node_t* query, void* target);
|
||||
// static int string_query(query_node_t* query, void* target);
|
||||
|
||||
static query_node_t *match_specifier(const char* query,
|
||||
const char** cursor,
|
||||
const query_field_t* fields);
|
||||
const char** cursor,
|
||||
const query_field_t* fields);
|
||||
|
||||
static query_node_t *group_match(const char* query,
|
||||
const char** cursor,
|
||||
const query_field_t* fields);
|
||||
const char** cursor,
|
||||
const query_field_t* fields);
|
||||
|
||||
static query_node_t *single_match(const char* query,
|
||||
const char** cursor,
|
||||
const query_field_t* fields);
|
||||
const char** cursor,
|
||||
const query_field_t* fields);
|
||||
|
||||
static int get_field_name(const char** pcursor,
|
||||
const char* query,
|
||||
char* name,
|
||||
int len);
|
||||
const char* query,
|
||||
char* name,
|
||||
int len);
|
||||
|
||||
static query_node_t *match_number(const query_field_t* field,
|
||||
char not, char opcode,
|
||||
const char** pcursor,
|
||||
const char* query);
|
||||
char not, char opcode,
|
||||
const char** pcursor,
|
||||
const char* query);
|
||||
|
||||
static query_node_t *match_string(const query_field_t* field,
|
||||
char not, char opcode,
|
||||
const char** pcursor,
|
||||
const char* query);
|
||||
char not, char opcode,
|
||||
const char** pcursor,
|
||||
const char* query);
|
||||
|
||||
char *query_unescape(const char* query);
|
||||
|
||||
|
||||
static query_field_t song_fields[] = {
|
||||
{ qft_string, "dmap.itemname", "title" },
|
||||
{ qft_i32, "dmap.itemid", "id" },
|
||||
{ qft_string, "daap.songalbum", "album" },
|
||||
{ qft_string, "daap.songartist", "artist" },
|
||||
{ qft_i32, "daap.songbitrate", "bitrate" },
|
||||
{ qft_string, "daap.songcomment", "comment" },
|
||||
{ qft_i32, "daap.songcompilation", "compilation" },
|
||||
{ qft_string, "daap.songcomposer", "composer" },
|
||||
{ qft_i32, "daap.songdatakind", "data_kind" },
|
||||
{ qft_string, "daap.songdataurl", "url" },
|
||||
{ qft_i32, "daap.songdateadded", "time_added" },
|
||||
{ qft_i32, "daap.songdatemodified","time_modified" },
|
||||
{ qft_string, "daap.songdescription", "description" },
|
||||
{ qft_i32, "daap.songdisccount", "total_discs" },
|
||||
{ qft_i32, "daap.songdiscnumber", "disc" },
|
||||
{ qft_string, "daap.songformat", "type" },
|
||||
{ qft_string, "daap.songgenre", "genre" },
|
||||
{ qft_i32, "daap.songsamplerate", "samplerate" },
|
||||
{ qft_i32, "daap.songsize", "file_size" },
|
||||
// { qft_i32_const, "daap.songstarttime", 0 },
|
||||
{ qft_i32, "daap.songstoptime", "song_length" },
|
||||
{ qft_i32, "daap.songtime", "song_length" },
|
||||
{ qft_i32, "daap.songtrackcount", "total_tracks" },
|
||||
{ qft_i32, "daap.songtracknumber", "track" },
|
||||
{ qft_i32, "daap.songyear", "year" },
|
||||
static query_field_t song_fields[] = {
|
||||
{ qft_string, "dmap.itemname", "title" },
|
||||
{ qft_i32, "dmap.itemid", "id" },
|
||||
{ qft_string, "daap.songalbum", "album" },
|
||||
{ qft_string, "daap.songartist", "artist" },
|
||||
{ qft_i32, "daap.songbitrate", "bitrate" },
|
||||
{ qft_string, "daap.songcomment", "comment" },
|
||||
{ qft_i32, "daap.songcompilation", "compilation" },
|
||||
{ qft_string, "daap.songcomposer", "composer" },
|
||||
{ qft_i32, "daap.songdatakind", "data_kind" },
|
||||
{ qft_string, "daap.songdataurl", "url" },
|
||||
{ qft_i32, "daap.songdateadded", "time_added" },
|
||||
{ qft_i32, "daap.songdatemodified","time_modified" },
|
||||
{ qft_string, "daap.songdescription", "description" },
|
||||
{ qft_i32, "daap.songdisccount", "total_discs" },
|
||||
{ qft_i32, "daap.songdiscnumber", "disc" },
|
||||
{ qft_string, "daap.songformat", "type" },
|
||||
{ qft_string, "daap.songgenre", "genre" },
|
||||
{ qft_i32, "daap.songsamplerate", "samplerate" },
|
||||
{ qft_i32, "daap.songsize", "file_size" },
|
||||
// { qft_i32_const, "daap.songstarttime", 0 },
|
||||
{ qft_i32, "daap.songstoptime", "song_length" },
|
||||
{ qft_i32, "daap.songtime", "song_length" },
|
||||
{ qft_i32, "daap.songtrackcount", "total_tracks" },
|
||||
{ qft_i32, "daap.songtracknumber", "track" },
|
||||
{ qft_i32, "daap.songyear", "year" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
@ -87,22 +87,22 @@ char *query_sql_escape(char *term) {
|
||||
|
||||
src=term;
|
||||
while(*src) {
|
||||
new_size++;
|
||||
if(*src == '\'')
|
||||
new_size++;
|
||||
src++;
|
||||
new_size++;
|
||||
if(*src == '\'')
|
||||
new_size++;
|
||||
src++;
|
||||
}
|
||||
|
||||
src=term;
|
||||
pnew=(char*)malloc(new_size+1);
|
||||
if(!pnew)
|
||||
return pnew;
|
||||
return pnew;
|
||||
|
||||
dst=pnew;
|
||||
while(*src) {
|
||||
if(*src == '\'')
|
||||
*dst++='\'';
|
||||
*dst++=*src++;
|
||||
if(*src == '\'')
|
||||
*dst++='\'';
|
||||
*dst++=*src++;
|
||||
}
|
||||
|
||||
*dst='\0';
|
||||
@ -118,130 +118,130 @@ char *query_build_sql(char *query) {
|
||||
DPRINTF(E_DBG,L_QRY,"Building query for %s\n",query);
|
||||
pquery=query_build(query);
|
||||
if(pquery) {
|
||||
if(!query_build_clause(pquery,&sqlptr,&size)) {
|
||||
query_free(pquery);
|
||||
DPRINTF(E_DBG,L_QRY,"Built query: %s\n",sql);
|
||||
return strdup(sql);
|
||||
}
|
||||
DPRINTF(E_DBG,L_QRY,"Error converting query to SQL\n");
|
||||
query_free(pquery);
|
||||
if(!query_build_clause(pquery,&sqlptr,&size)) {
|
||||
query_free(pquery);
|
||||
DPRINTF(E_DBG,L_QRY,"Built query: %s\n",sql);
|
||||
return strdup(sql);
|
||||
}
|
||||
DPRINTF(E_DBG,L_QRY,"Error converting query to SQL\n");
|
||||
query_free(pquery);
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_QRY,"Error building query\n");
|
||||
DPRINTF(E_DBG,L_QRY,"Error building query\n");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
query_node_t* query_build(const char* query) {
|
||||
query_node_t* left = 0;
|
||||
char* raw = (char*)query; //query_unescape(query);
|
||||
const char* cursor = raw;
|
||||
query_node_t* right = 0;
|
||||
query_type_t join;
|
||||
query_node_t* left = 0;
|
||||
char* raw = (char*)query; //query_unescape(query);
|
||||
const char* cursor = raw;
|
||||
query_node_t* right = 0;
|
||||
query_type_t join;
|
||||
|
||||
if(0 == (left = match_specifier(query, &cursor, song_fields)))
|
||||
goto error;
|
||||
goto error;
|
||||
|
||||
while(*cursor)
|
||||
{
|
||||
query_node_t* con;
|
||||
query_node_t* con;
|
||||
|
||||
switch(*cursor)
|
||||
{
|
||||
case '+':
|
||||
case ' ': join = qot_and; break;
|
||||
case ',': join = qot_or; break;
|
||||
default:
|
||||
DPRINTF(E_LOG,L_QRY, "Illegal character '%c' (0%o) at index %d: %s\n",
|
||||
*cursor, *cursor, cursor - raw, raw);
|
||||
goto error;
|
||||
}
|
||||
switch(*cursor)
|
||||
{
|
||||
case '+':
|
||||
case ' ': join = qot_and; break;
|
||||
case ',': join = qot_or; break;
|
||||
default:
|
||||
DPRINTF(E_LOG,L_QRY, "Illegal character '%c' (0%o) at index %d: %s\n",
|
||||
*cursor, *cursor, cursor - raw, raw);
|
||||
goto error;
|
||||
}
|
||||
|
||||
cursor++;
|
||||
cursor++;
|
||||
|
||||
if(0 == (right = match_specifier(raw, &cursor, song_fields)))
|
||||
goto error;
|
||||
if(0 == (right = match_specifier(raw, &cursor, song_fields)))
|
||||
goto error;
|
||||
|
||||
con = (query_node_t*) calloc(1, sizeof(*con));
|
||||
con->type = join;
|
||||
con->left.node = left;
|
||||
con->right.node = right;
|
||||
con = (query_node_t*) calloc(1, sizeof(*con));
|
||||
con->type = join;
|
||||
con->left.node = left;
|
||||
con->right.node = right;
|
||||
|
||||
left = con;
|
||||
left = con;
|
||||
}
|
||||
|
||||
if(query != raw)
|
||||
free(raw);
|
||||
free(raw);
|
||||
|
||||
return left;
|
||||
|
||||
error:
|
||||
if(left != 0)
|
||||
query_free(left);
|
||||
query_free(left);
|
||||
if(raw != query)
|
||||
free(raw);
|
||||
free(raw);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static query_node_t* match_specifier(const char* query,
|
||||
const char** cursor,
|
||||
const query_field_t* fields) {
|
||||
static query_node_t* match_specifier(const char* query,
|
||||
const char** cursor,
|
||||
const query_field_t* fields) {
|
||||
switch(**cursor) {
|
||||
case '\'':
|
||||
return single_match(query, cursor, fields);
|
||||
case '(':
|
||||
return group_match(query, cursor, fields);
|
||||
case '\'':
|
||||
return single_match(query, cursor, fields);
|
||||
case '(':
|
||||
return group_match(query, cursor, fields);
|
||||
}
|
||||
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal character '%c' (0%o) at index %d: %s\n",
|
||||
**cursor, **cursor, *cursor - query, query);
|
||||
**cursor, **cursor, *cursor - query, query);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static query_node_t* group_match(const char* query,
|
||||
const char** pcursor,
|
||||
const query_field_t* fields)
|
||||
static query_node_t* group_match(const char* query,
|
||||
const char** pcursor,
|
||||
const query_field_t* fields)
|
||||
{
|
||||
query_node_t* left = 0;
|
||||
query_node_t* right = 0;
|
||||
query_node_t* join = 0;
|
||||
query_type_t opcode;
|
||||
const char* cursor = *pcursor;
|
||||
query_node_t* left = 0;
|
||||
query_node_t* right = 0;
|
||||
query_node_t* join = 0;
|
||||
query_type_t opcode;
|
||||
const char* cursor = *pcursor;
|
||||
|
||||
/* skip the opening ')' */
|
||||
++cursor;
|
||||
|
||||
if(0 == (left = single_match(query, &cursor, fields)))
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
switch(*cursor)
|
||||
{
|
||||
case '+':
|
||||
case ' ':
|
||||
opcode = qot_and;
|
||||
break;
|
||||
opcode = qot_and;
|
||||
break;
|
||||
|
||||
case ',':
|
||||
opcode = qot_or;
|
||||
break;
|
||||
opcode = qot_or;
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal character '%c' (0%o) at index %d: %s\n",
|
||||
*cursor, *cursor, cursor - query, query);
|
||||
goto error;
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal character '%c' (0%o) at index %d: %s\n",
|
||||
*cursor, *cursor, cursor - query, query);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(0 == (right = single_match(query, &cursor, fields)))
|
||||
goto error;
|
||||
goto error;
|
||||
|
||||
if(*cursor != ')')
|
||||
{
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal character '%c' (0%o) at index %d: %s\n",
|
||||
*cursor, *cursor, cursor - query, query);
|
||||
goto error;
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal character '%c' (0%o) at index %d: %s\n",
|
||||
*cursor, *cursor, cursor - query, query);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
*pcursor = cursor + 1;
|
||||
|
||||
join = (query_node_t*) calloc(1, sizeof(*join));
|
||||
@ -253,100 +253,100 @@ static query_node_t* group_match(const char* query,
|
||||
|
||||
error:
|
||||
if(0 != left)
|
||||
query_free(left);
|
||||
query_free(left);
|
||||
if(0 != right)
|
||||
query_free(right);
|
||||
query_free(right);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static query_node_t* single_match(const char* query,
|
||||
const char** pcursor,
|
||||
const query_field_t* fields)
|
||||
static query_node_t* single_match(const char* query,
|
||||
const char** pcursor,
|
||||
const query_field_t* fields)
|
||||
{
|
||||
char fname[64];
|
||||
const query_field_t* field;
|
||||
char not = 0;
|
||||
char op = 0;
|
||||
query_node_t* node = 0;
|
||||
char fname[64];
|
||||
const query_field_t* field;
|
||||
char not = 0;
|
||||
char op = 0;
|
||||
query_node_t* node = 0;
|
||||
|
||||
/* skip opening ' */
|
||||
(*pcursor)++;
|
||||
|
||||
/* collect the field name */
|
||||
if(!get_field_name(pcursor, query, fname, sizeof(fname)))
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
if(**pcursor == '!')
|
||||
{
|
||||
not = '!';
|
||||
++(*pcursor);
|
||||
not = '!';
|
||||
++(*pcursor);
|
||||
}
|
||||
|
||||
if(strchr(":+- ", **pcursor))
|
||||
{
|
||||
op = **pcursor;
|
||||
++(*pcursor);
|
||||
op = **pcursor;
|
||||
++(*pcursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal Operator: %c (0%o) at index %d: %s\n",
|
||||
**pcursor, **pcursor, *pcursor - query, query);
|
||||
return NULL;
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal Operator: %c (0%o) at index %d: %s\n",
|
||||
**pcursor, **pcursor, *pcursor - query, query);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(0 == (field = find_field(fname, fields)))
|
||||
{
|
||||
DPRINTF(E_LOG,L_QRY,"Unknown field: %s\n", fname);
|
||||
return NULL;
|
||||
DPRINTF(E_LOG,L_QRY,"Unknown field: %s\n", fname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch(field->type)
|
||||
{
|
||||
case qft_i32:
|
||||
case qft_i64:
|
||||
node = match_number(field, not, op, pcursor, query);
|
||||
break;
|
||||
node = match_number(field, not, op, pcursor, query);
|
||||
break;
|
||||
|
||||
case qft_string:
|
||||
node = match_string(field, not, op, pcursor, query);
|
||||
break;
|
||||
node = match_string(field, not, op, pcursor, query);
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(E_LOG,L_QRY,"Invalid field type: %d\n", field->type);
|
||||
break;
|
||||
DPRINTF(E_LOG,L_QRY,"Invalid field type: %d\n", field->type);
|
||||
break;
|
||||
}
|
||||
|
||||
if(**pcursor != '\'')
|
||||
{
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal Character: %c (0%o) index %d: %s\n",
|
||||
**pcursor, **pcursor, *pcursor - query, query);
|
||||
query_free(node);
|
||||
node = 0;
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal Character: %c (0%o) index %d: %s\n",
|
||||
**pcursor, **pcursor, *pcursor - query, query);
|
||||
query_free(node);
|
||||
node = 0;
|
||||
}
|
||||
else
|
||||
++(*pcursor);
|
||||
++(*pcursor);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static int get_field_name(const char** pcursor,
|
||||
const char* query,
|
||||
char* name,
|
||||
int len) {
|
||||
const char* cursor = *pcursor;
|
||||
const char* query,
|
||||
char* name,
|
||||
int len) {
|
||||
const char* cursor = *pcursor;
|
||||
|
||||
if(!isalpha(*cursor))
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
while(isalpha(*cursor) || *cursor == '.') {
|
||||
if(--len <= 0) {
|
||||
DPRINTF(E_LOG,L_QRY,"token length exceeded at offset %d: %s\n",
|
||||
cursor - query, query);
|
||||
return 0;
|
||||
}
|
||||
if(--len <= 0) {
|
||||
DPRINTF(E_LOG,L_QRY,"token length exceeded at offset %d: %s\n",
|
||||
cursor - query, query);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*name++ = *cursor++;
|
||||
*name++ = *cursor++;
|
||||
}
|
||||
|
||||
*pcursor = cursor;
|
||||
@ -356,25 +356,25 @@ static int get_field_name(const char** pcursor,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static query_node_t* match_number(const query_field_t* field,
|
||||
char not, char opcode,
|
||||
const char** pcursor,
|
||||
const char* query)
|
||||
static query_node_t* match_number(const query_field_t* field,
|
||||
char not, char opcode,
|
||||
const char** pcursor,
|
||||
const char* query)
|
||||
{
|
||||
query_node_t* node = (query_node_t*) calloc(1, sizeof(*node));
|
||||
query_node_t* node = (query_node_t*) calloc(1, sizeof(*node));
|
||||
|
||||
switch(opcode)
|
||||
{
|
||||
case ':':
|
||||
node->type = not ? qot_ne : qot_eq;
|
||||
break;
|
||||
node->type = not ? qot_ne : qot_eq;
|
||||
break;
|
||||
case '+':
|
||||
case ' ':
|
||||
node->type = not ? qot_le : qot_gt;
|
||||
break;
|
||||
node->type = not ? qot_le : qot_gt;
|
||||
break;
|
||||
case '-':
|
||||
node->type = not ? qot_ge : qot_lt;
|
||||
break;
|
||||
node->type = not ? qot_ge : qot_lt;
|
||||
break;
|
||||
}
|
||||
|
||||
node->left.field = field;
|
||||
@ -382,77 +382,77 @@ static query_node_t* match_number(const query_field_t* field,
|
||||
switch(field->type)
|
||||
{
|
||||
case qft_i32:
|
||||
node->right.i32 = strtol(*pcursor, (char**) pcursor, 10);
|
||||
break;
|
||||
node->right.i32 = strtol(*pcursor, (char**) pcursor, 10);
|
||||
break;
|
||||
case qft_i64:
|
||||
node->right.i64 = strtoll(*pcursor, (char**) pcursor, 10);
|
||||
break;
|
||||
node->right.i64 = strtoll(*pcursor, (char**) pcursor, 10);
|
||||
break;
|
||||
default:
|
||||
DPRINTF(E_LOG,L_QRY,"Bad field type -- invalid query\n");
|
||||
break;
|
||||
DPRINTF(E_LOG,L_QRY,"Bad field type -- invalid query\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if(**pcursor != '\'')
|
||||
{
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal char in number '%c' (0%o) at index %d: %s\n",
|
||||
**pcursor, **pcursor, *pcursor - query, query);
|
||||
free(node);
|
||||
return 0;
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal char in number '%c' (0%o) at index %d: %s\n",
|
||||
**pcursor, **pcursor, *pcursor - query, query);
|
||||
free(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static query_node_t* match_string(const query_field_t* field,
|
||||
char not, char opcode,
|
||||
const char** pcursor,
|
||||
const char* query)
|
||||
static query_node_t* match_string(const query_field_t* field,
|
||||
char not, char opcode,
|
||||
const char** pcursor,
|
||||
const char* query)
|
||||
{
|
||||
char match[256];
|
||||
char* dst = match;
|
||||
int left = sizeof(match);
|
||||
const char* cursor = *pcursor;
|
||||
query_type_t op = qot_is;
|
||||
query_node_t* node;
|
||||
char match[256];
|
||||
char* dst = match;
|
||||
int left = sizeof(match);
|
||||
const char* cursor = *pcursor;
|
||||
query_type_t op = qot_is;
|
||||
query_node_t* node;
|
||||
|
||||
if(opcode != ':') {
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal operation on string: %c at index %d: %s\n",
|
||||
opcode, cursor - query - 1);
|
||||
return NULL;
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal operation on string: %c at index %d: %s\n",
|
||||
opcode, cursor - query - 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(*cursor == '*') {
|
||||
op = qot_ends;
|
||||
cursor++;
|
||||
op = qot_ends;
|
||||
cursor++;
|
||||
}
|
||||
|
||||
while(*cursor && *cursor != '\'') {
|
||||
if(--left == 0) {
|
||||
DPRINTF(E_LOG,L_QRY,"string too long at index %d: %s\n",
|
||||
cursor - query, query);
|
||||
return NULL;
|
||||
}
|
||||
if(--left == 0) {
|
||||
DPRINTF(E_LOG,L_QRY,"string too long at index %d: %s\n",
|
||||
cursor - query, query);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(*cursor == '\\') {
|
||||
switch(*++cursor) {
|
||||
case '*':
|
||||
case '\'':
|
||||
case '\\':
|
||||
*dst++ = *cursor++;
|
||||
break;
|
||||
default:
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal escape: %c (0%o) at index %d: %s\n",
|
||||
*cursor, *cursor, cursor - query, query);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
*dst++ = *cursor++;
|
||||
}
|
||||
if(*cursor == '\\') {
|
||||
switch(*++cursor) {
|
||||
case '*':
|
||||
case '\'':
|
||||
case '\\':
|
||||
*dst++ = *cursor++;
|
||||
break;
|
||||
default:
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal escape: %c (0%o) at index %d: %s\n",
|
||||
*cursor, *cursor, cursor - query, query);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
*dst++ = *cursor++;
|
||||
}
|
||||
}
|
||||
|
||||
if(dst[-1] == '*') {
|
||||
op = (op == qot_is) ? qot_begins : qot_contains;
|
||||
dst--;
|
||||
op = (op == qot_is) ? qot_begins : qot_contains;
|
||||
dst--;
|
||||
}
|
||||
|
||||
*dst = 0;
|
||||
@ -471,57 +471,57 @@ static query_node_t* match_string(const query_field_t* field,
|
||||
void query_free(query_node_t* query) {
|
||||
if(0 != query)
|
||||
{
|
||||
switch(query->type)
|
||||
{
|
||||
// conjunction
|
||||
case qot_and:
|
||||
case qot_or:
|
||||
query_free(query->left.node);
|
||||
query_free(query->right.node);
|
||||
break;
|
||||
switch(query->type)
|
||||
{
|
||||
// conjunction
|
||||
case qot_and:
|
||||
case qot_or:
|
||||
query_free(query->left.node);
|
||||
query_free(query->right.node);
|
||||
break;
|
||||
|
||||
// negation
|
||||
case qot_not:
|
||||
query_free(query->left.node);
|
||||
break;
|
||||
// negation
|
||||
case qot_not:
|
||||
query_free(query->left.node);
|
||||
break;
|
||||
|
||||
// arithmetic
|
||||
case qot_eq:
|
||||
case qot_ne:
|
||||
case qot_le:
|
||||
case qot_lt:
|
||||
case qot_ge:
|
||||
case qot_gt:
|
||||
break;
|
||||
// arithmetic
|
||||
case qot_eq:
|
||||
case qot_ne:
|
||||
case qot_le:
|
||||
case qot_lt:
|
||||
case qot_ge:
|
||||
case qot_gt:
|
||||
break;
|
||||
|
||||
// string
|
||||
case qot_is:
|
||||
case qot_begins:
|
||||
case qot_ends:
|
||||
case qot_contains:
|
||||
free(query->right.str);
|
||||
break;
|
||||
// string
|
||||
case qot_is:
|
||||
case qot_begins:
|
||||
case qot_ends:
|
||||
case qot_contains:
|
||||
free(query->right.str);
|
||||
break;
|
||||
|
||||
// constants
|
||||
case qot_const:
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal query type: %d\n", query->type);
|
||||
break;
|
||||
}
|
||||
// constants
|
||||
case qot_const:
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal query type: %d\n", query->type);
|
||||
break;
|
||||
}
|
||||
|
||||
free(query);
|
||||
free(query);
|
||||
}
|
||||
}
|
||||
|
||||
static const query_field_t* find_field(const char* name, const query_field_t* fields) {
|
||||
while(fields->name && strcasecmp(fields->name, name))
|
||||
fields++;
|
||||
fields++;
|
||||
|
||||
if(fields->name == 0) {
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal query field: %s\n", name);
|
||||
return NULL;
|
||||
DPRINTF(E_LOG,L_QRY,"Illegal query field: %s\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fields;
|
||||
@ -536,8 +536,8 @@ int query_add_string(char **current, int *size, char *fmt, ...) {
|
||||
va_end(ap);
|
||||
|
||||
if(write_size > *size) {
|
||||
*size=0;
|
||||
return 0;
|
||||
*size=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*size = *size - write_size;
|
||||
@ -546,72 +546,72 @@ int query_add_string(char **current, int *size, char *fmt, ...) {
|
||||
|
||||
int query_build_clause(query_node_t *query, char **current, int *size) {
|
||||
char* labels[] = {
|
||||
"NOP",
|
||||
"AND",
|
||||
"OR",
|
||||
"NOT",
|
||||
"=",
|
||||
"<>",
|
||||
"<=",
|
||||
"<",
|
||||
">=",
|
||||
">",
|
||||
"=",
|
||||
" (%s LIKE '%s%%') ",
|
||||
" (%s LIKE '%%%s') ",
|
||||
" (%s LIKE '%%%s%%') ",
|
||||
"constant"
|
||||
"NOP",
|
||||
"AND",
|
||||
"OR",
|
||||
"NOT",
|
||||
"=",
|
||||
"<>",
|
||||
"<=",
|
||||
"<",
|
||||
">=",
|
||||
">",
|
||||
"=",
|
||||
" (%s LIKE '%s%%') ",
|
||||
" (%s LIKE '%%%s') ",
|
||||
" (%s LIKE '%%%s%%') ",
|
||||
"constant"
|
||||
};
|
||||
|
||||
switch(query->type) {
|
||||
case qot_and:
|
||||
case qot_or:
|
||||
if(*size) (*current) += query_add_string(current,size," (");
|
||||
if(query_build_clause(query->left.node,current,size)) return 1;
|
||||
if(*size) (*current) += query_add_string(current,size," %s ", labels[query->type]);
|
||||
if(query_build_clause(query->right.node,current,size)) return 1;
|
||||
if(*size) (*current) += query_add_string(current,size,") ");
|
||||
break;
|
||||
if(*size) (*current) += query_add_string(current,size," (");
|
||||
if(query_build_clause(query->left.node,current,size)) return 1;
|
||||
if(*size) (*current) += query_add_string(current,size," %s ", labels[query->type]);
|
||||
if(query_build_clause(query->right.node,current,size)) return 1;
|
||||
if(*size) (*current) += query_add_string(current,size,") ");
|
||||
break;
|
||||
|
||||
case qot_not:
|
||||
if(*size) (*current) += query_add_string(current,size," (NOT ");
|
||||
if(query_build_clause(query->left.node,current,size)) return 1;
|
||||
if(*size) (*current) += query_add_string(current,size,") ");
|
||||
break;
|
||||
|
||||
if(*size) (*current) += query_add_string(current,size," (NOT ");
|
||||
if(query_build_clause(query->left.node,current,size)) return 1;
|
||||
if(*size) (*current) += query_add_string(current,size,") ");
|
||||
break;
|
||||
|
||||
case qot_eq:
|
||||
case qot_ne:
|
||||
case qot_le:
|
||||
case qot_lt:
|
||||
case qot_ge:
|
||||
case qot_gt:
|
||||
if(*size) (*current) += query_add_string(current,size," (%s %s ",
|
||||
query->left.field->fieldname,
|
||||
labels[query->type]);
|
||||
if(query->left.field->type == qft_i32) {
|
||||
if(*size) (*current) += query_add_string(current,size," %d) ",query->right.i32);
|
||||
} else {
|
||||
if(*size) (*current) += query_add_string(current,size," %ll) ",query->right.i64);
|
||||
}
|
||||
break;
|
||||
if(*size) (*current) += query_add_string(current,size," (%s %s ",
|
||||
query->left.field->fieldname,
|
||||
labels[query->type]);
|
||||
if(query->left.field->type == qft_i32) {
|
||||
if(*size) (*current) += query_add_string(current,size," %d) ",query->right.i32);
|
||||
} else {
|
||||
if(*size) (*current) += query_add_string(current,size," %ll) ",query->right.i64);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case qot_is:
|
||||
if(*size)(*current) += query_add_string(current,size," (%s='%s') ",
|
||||
query->left.field->fieldname,
|
||||
query->right.str);
|
||||
break;
|
||||
if(*size)(*current) += query_add_string(current,size," (%s='%s') ",
|
||||
query->left.field->fieldname,
|
||||
query->right.str);
|
||||
break;
|
||||
case qot_begins:
|
||||
case qot_ends:
|
||||
case qot_contains:
|
||||
if(*size)(*current) += query_add_string(current,size,labels[query->type],
|
||||
query->left.field->fieldname,
|
||||
query->right.str);
|
||||
break;
|
||||
if(*size)(*current) += query_add_string(current,size,labels[query->type],
|
||||
query->left.field->fieldname,
|
||||
query->right.str);
|
||||
break;
|
||||
case qot_const: /* Not sure what this would be for */
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -619,36 +619,36 @@ int query_build_clause(query_node_t *query, char **current, int *size) {
|
||||
|
||||
char* query_unescape(const char* src) {
|
||||
|
||||
char* copy = malloc(strlen(src) + 1);
|
||||
char* dst = copy;
|
||||
char* copy = malloc(strlen(src) + 1);
|
||||
char* dst = copy;
|
||||
|
||||
while(*src)
|
||||
{
|
||||
if(*src == '%')
|
||||
{
|
||||
int val = 0;
|
||||
if(*src == '%')
|
||||
{
|
||||
int val = 0;
|
||||
|
||||
if(*++src)
|
||||
{
|
||||
if(isdigit(*src))
|
||||
val = val * 16 + *src - '0';
|
||||
else
|
||||
val = val * 16 + tolower(*src) - 'a' + 10;
|
||||
}
|
||||
if(*++src)
|
||||
{
|
||||
if(isdigit(*src))
|
||||
val = val * 16 + *src - '0';
|
||||
else
|
||||
val = val * 16 + tolower(*src) - 'a' + 10;
|
||||
}
|
||||
|
||||
if(*++src)
|
||||
{
|
||||
if(isdigit(*src))
|
||||
val = val * 16 + *src - '0';
|
||||
else
|
||||
val = val * 16 + tolower(*src) - 'a' + 10;
|
||||
}
|
||||
if(*++src)
|
||||
{
|
||||
if(isdigit(*src))
|
||||
val = val * 16 + *src - '0';
|
||||
else
|
||||
val = val * 16 + tolower(*src) - 'a' + 10;
|
||||
}
|
||||
|
||||
src++;
|
||||
*dst++ = val;
|
||||
}
|
||||
else
|
||||
*dst++ = *src++;
|
||||
src++;
|
||||
*dst++ = val;
|
||||
}
|
||||
else
|
||||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
*dst++ = 0;
|
||||
|
22
src/query.h
22
src/query.h
@ -41,25 +41,25 @@ typedef struct query_field_ query_field_t;
|
||||
struct query_field_
|
||||
{
|
||||
query_type_t type;
|
||||
const char* name;
|
||||
const char* name;
|
||||
const char* fieldname;
|
||||
};
|
||||
|
||||
typedef struct query_node_ query_node_t;
|
||||
struct query_node_
|
||||
{
|
||||
query_type_t type;
|
||||
query_type_t type;
|
||||
union {
|
||||
query_node_t* node;
|
||||
const query_field_t* field;
|
||||
int constant;
|
||||
} left;
|
||||
query_node_t* node;
|
||||
const query_field_t* field;
|
||||
int constant;
|
||||
} left;
|
||||
union {
|
||||
query_node_t* node;
|
||||
int i32;
|
||||
long long i64;
|
||||
char* str;
|
||||
} right;
|
||||
query_node_t* node;
|
||||
int i32;
|
||||
long long i64;
|
||||
char* str;
|
||||
} right;
|
||||
};
|
||||
|
||||
extern char *query_build_sql(char *query);
|
||||
|
1249
src/redblack.c
1249
src/redblack.c
File diff suppressed because it is too large
Load Diff
@ -39,10 +39,10 @@
|
||||
* compiled in, RB_CMP only needs to take two arguments. If your
|
||||
* content type is not a pointer, define INLINE to get direct access.
|
||||
*/
|
||||
#define rbdata_t void
|
||||
#define RB_CMP(s, t, e) (*rbinfo->rb_cmp)(s, t, e)
|
||||
#define rbdata_t void
|
||||
#define RB_CMP(s, t, e) (*rbinfo->rb_cmp)(s, t, e)
|
||||
#undef RB_INLINE
|
||||
#define RB_ENTRY(name) rb##name
|
||||
#define RB_ENTRY(name) rb##name
|
||||
#endif /* RB_CUSTOMIZE */
|
||||
|
||||
#ifndef RB_STATIC
|
||||
@ -50,16 +50,16 @@
|
||||
#endif
|
||||
|
||||
/* Modes for rblookup */
|
||||
#define RB_NONE -1 /* None of those below */
|
||||
#define RB_LUEQUAL 0 /* Only exact match */
|
||||
#define RB_LUGTEQ 1 /* Exact match or greater */
|
||||
#define RB_LULTEQ 2 /* Exact match or less */
|
||||
#define RB_LULESS 3 /* Less than key (not equal to) */
|
||||
#define RB_LUGREAT 4 /* Greater than key (not equal to) */
|
||||
#define RB_LUNEXT 5 /* Next key after current */
|
||||
#define RB_LUPREV 6 /* Prev key before current */
|
||||
#define RB_LUFIRST 7 /* First key in index */
|
||||
#define RB_LULAST 8 /* Last key in index */
|
||||
#define RB_NONE -1 /* None of those below */
|
||||
#define RB_LUEQUAL 0 /* Only exact match */
|
||||
#define RB_LUGTEQ 1 /* Exact match or greater */
|
||||
#define RB_LULTEQ 2 /* Exact match or less */
|
||||
#define RB_LULESS 3 /* Less than key (not equal to) */
|
||||
#define RB_LUGREAT 4 /* Greater than key (not equal to) */
|
||||
#define RB_LUNEXT 5 /* Next key after current */
|
||||
#define RB_LUPREV 6 /* Prev key before current */
|
||||
#define RB_LUFIRST 7 /* First key in index */
|
||||
#define RB_LULAST 8 /* Last key in index */
|
||||
|
||||
/* For rbwalk - pinched from search.h */
|
||||
typedef enum
|
||||
@ -80,18 +80,18 @@ const struct RB_ENTRY(node) *nextp;
|
||||
|
||||
struct RB_ENTRY(tree) {
|
||||
#ifndef RB_CUSTOMIZE
|
||||
/* comparison routine */
|
||||
/* comparison routine */
|
||||
int (*rb_cmp)(const void *, const void *, const void *);
|
||||
/* config data to be passed to rb_cmp */
|
||||
/* config data to be passed to rb_cmp */
|
||||
const void *rb_config;
|
||||
/* root of tree */
|
||||
/* root of tree */
|
||||
#endif /* RB_CUSTOMIZE */
|
||||
struct RB_ENTRY(node) *rb_root;
|
||||
};
|
||||
|
||||
#ifndef RB_CUSTOMIZE
|
||||
RB_STATIC struct RB_ENTRY(tree) *rbinit(int (*)(const void *, const void *, const void *),
|
||||
const void *);
|
||||
const void *);
|
||||
#else
|
||||
RB_STATIC struct RB_ENTRY(tree) *RB_ENTRY(init)(void);
|
||||
#endif /* RB_CUSTOMIZE */
|
||||
@ -118,8 +118,8 @@ RB_STATIC void RB_ENTRY(destroy)(struct RB_ENTRY(tree) *);
|
||||
|
||||
#ifndef no_walk
|
||||
RB_STATIC void RB_ENTRY(walk)(const struct RB_ENTRY(tree) *,
|
||||
void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *),
|
||||
void *);
|
||||
void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *),
|
||||
void *);
|
||||
#endif
|
||||
|
||||
#ifndef no_readlist
|
||||
@ -138,6 +138,12 @@ RB_STATIC void RB_ENTRY(closelist)(RBLIST *);
|
||||
/*
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.4 2006/02/26 08:46:24 rpedde
|
||||
* Merged win32-branch
|
||||
*
|
||||
* Revision 1.3.2.1 2006/02/26 08:28:35 rpedde
|
||||
* unix fixes from win32 port
|
||||
*
|
||||
* Revision 1.3 2005/05/21 05:56:09 rpedde
|
||||
* for quick translation from itunes song id to mt-daapd song id
|
||||
*
|
||||
|
123
src/rend-howl.c
123
src/rend-howl.c
@ -33,6 +33,7 @@
|
||||
#include <pthread.h>
|
||||
|
||||
#include "err.h"
|
||||
#include "os-unix.h"
|
||||
#include "rend-unix.h"
|
||||
|
||||
pthread_t rend_tid;
|
||||
@ -48,14 +49,14 @@ void rend_callback(void);
|
||||
* Callback function for mDNS stuff
|
||||
*/
|
||||
static sw_result rend_howl_reply(sw_discovery discovery,
|
||||
sw_discovery_publish_status status,
|
||||
sw_discovery_oid oid,
|
||||
sw_opaque extra) {
|
||||
sw_discovery_publish_status status,
|
||||
sw_discovery_oid oid,
|
||||
sw_opaque extra) {
|
||||
static sw_string status_text[] = {
|
||||
"started",
|
||||
"stopped",
|
||||
"name collision",
|
||||
"invalid"
|
||||
"started",
|
||||
"stopped",
|
||||
"name collision",
|
||||
"invalid"
|
||||
};
|
||||
|
||||
DPRINTF(E_DBG,L_REND,"Publish reply: %s\n",status_text[status]);
|
||||
@ -75,20 +76,20 @@ int rend_private_init(char *user) {
|
||||
signal(SIGHUP, SIG_IGN); // SIGHUP might happen from a request to reload the daap server
|
||||
|
||||
if(sw_discovery_init(&rend_handle) != SW_OKAY) {
|
||||
DPRINTF(E_WARN,L_REND,"Error initializing howl\n");
|
||||
errno=EINVAL;
|
||||
return -1;
|
||||
DPRINTF(E_WARN,L_REND,"Error initializing howl\n");
|
||||
errno=EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(drop_privs(user))
|
||||
return -1;
|
||||
if(os_drop_privs(user))
|
||||
return -1;
|
||||
|
||||
DPRINTF(E_DBG,L_REND,"Starting polling thread\n");
|
||||
|
||||
if(pthread_create(&rend_tid,NULL,rend_pipe_monitor,NULL)) {
|
||||
DPRINTF(E_FATAL,L_REND,"Could not start thread. Terminating\n");
|
||||
/* should kill parent, too */
|
||||
exit(EXIT_FAILURE);
|
||||
DPRINTF(E_FATAL,L_REND,"Could not start thread. Terminating\n");
|
||||
/* should kill parent, too */
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_REND,"Entering runloop\n");
|
||||
@ -109,21 +110,21 @@ void *rend_pipe_monitor(void* arg) {
|
||||
int result;
|
||||
|
||||
while(1) {
|
||||
DPRINTF(E_DBG,L_REND,"Waiting for data\n");
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(rend_pipe_to[RD_SIDE],&rset);
|
||||
DPRINTF(E_DBG,L_REND,"Waiting for data\n");
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(rend_pipe_to[RD_SIDE],&rset);
|
||||
|
||||
/* sit in a select spin until there is data on the to fd */
|
||||
while(((result=select(rend_pipe_to[RD_SIDE] + 1,&rset,NULL,NULL,NULL)) != -1) &&
|
||||
errno != EINTR) {
|
||||
if(FD_ISSET(rend_pipe_to[RD_SIDE],&rset)) {
|
||||
DPRINTF(E_DBG,L_REND,"Received a message from daap server\n");
|
||||
rend_callback();
|
||||
}
|
||||
}
|
||||
/* sit in a select spin until there is data on the to fd */
|
||||
while(((result=select(rend_pipe_to[RD_SIDE] + 1,&rset,NULL,NULL,NULL)) != -1) &&
|
||||
errno != EINTR) {
|
||||
if(FD_ISSET(rend_pipe_to[RD_SIDE],&rset)) {
|
||||
DPRINTF(E_DBG,L_REND,"Received a message from daap server\n");
|
||||
rend_callback();
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_REND,"Select error!\n");
|
||||
/* should really bail here */
|
||||
DPRINTF(E_DBG,L_REND,"Select error!\n");
|
||||
/* should really bail here */
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,46 +143,46 @@ void rend_callback(void) {
|
||||
/* here, we've seen the message, now we have to process it */
|
||||
|
||||
if(rend_read_message(&msg) != sizeof(msg)) {
|
||||
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
switch(msg.cmd) {
|
||||
case REND_MSG_TYPE_REGISTER:
|
||||
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.type,msg.name,msg.port);
|
||||
if((result=sw_discovery_publish(rend_handle,
|
||||
0, /* interface handle */
|
||||
msg.name,
|
||||
msg.type,
|
||||
NULL, /* domain */
|
||||
NULL, /* host */
|
||||
msg.port,
|
||||
"\011txtvers=1\034Database ID=beddab1edeadbea7", /* text record */
|
||||
39, /* text record length */
|
||||
rend_howl_reply,
|
||||
NULL,
|
||||
&rend_oid)) != SW_OKAY) {
|
||||
DPRINTF(E_WARN,L_REND,"Error registering name\n");
|
||||
rend_send_response(-1);
|
||||
} else {
|
||||
rend_send_response(0); /* success */
|
||||
}
|
||||
break;
|
||||
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.type,msg.name,msg.port);
|
||||
if((result=sw_discovery_publish(rend_handle,
|
||||
0, /* interface handle */
|
||||
msg.name,
|
||||
msg.type,
|
||||
NULL, /* domain */
|
||||
NULL, /* host */
|
||||
msg.port,
|
||||
"\011txtvers=1\034Database ID=beddab1edeadbea7", /* text record */
|
||||
39, /* text record length */
|
||||
rend_howl_reply,
|
||||
NULL,
|
||||
&rend_oid)) != SW_OKAY) {
|
||||
DPRINTF(E_WARN,L_REND,"Error registering name\n");
|
||||
rend_send_response(-1);
|
||||
} else {
|
||||
rend_send_response(0); /* success */
|
||||
}
|
||||
break;
|
||||
case REND_MSG_TYPE_UNREGISTER:
|
||||
DPRINTF(E_WARN,L_REND,"Unsupported function: UNREGISTER\n");
|
||||
rend_send_response(-1); /* error */
|
||||
break;
|
||||
DPRINTF(E_WARN,L_REND,"Unsupported function: UNREGISTER\n");
|
||||
rend_send_response(-1); /* error */
|
||||
break;
|
||||
case REND_MSG_TYPE_STOP:
|
||||
DPRINTF(E_DBG,L_REND,"Stopping mDNS\n");
|
||||
rend_send_response(0);
|
||||
//sw_rendezvous_stop_publish(rend_handle);
|
||||
sw_discovery_fina(rend_handle);
|
||||
break;
|
||||
DPRINTF(E_DBG,L_REND,"Stopping mDNS\n");
|
||||
rend_send_response(0);
|
||||
//sw_rendezvous_stop_publish(rend_handle);
|
||||
sw_discovery_fina(rend_handle);
|
||||
break;
|
||||
case REND_MSG_TYPE_STATUS:
|
||||
DPRINTF(E_DBG,L_REND,"Status inquiry -- returning 0\n");
|
||||
rend_send_response(0); /* success */
|
||||
break;
|
||||
DPRINTF(E_DBG,L_REND,"Status inquiry -- returning 0\n");
|
||||
rend_send_response(0); /* success */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
123
src/rend-osx.c
123
src/rend-osx.c
@ -35,6 +35,7 @@
|
||||
|
||||
#include "daapd.h"
|
||||
#include "err.h"
|
||||
#include "os-unix.h"
|
||||
#include "rend-unix.h"
|
||||
|
||||
CFRunLoopRef rend_runloop;
|
||||
@ -75,19 +76,19 @@ static int rend_addtorunloop(dns_service_discovery_ref client) {
|
||||
mach_port_t port=DNSServiceDiscoveryMachPort(client);
|
||||
|
||||
if(!port)
|
||||
return -1;
|
||||
return -1;
|
||||
else {
|
||||
CFMachPortContext context = { 0, 0, NULL, NULL, NULL };
|
||||
Boolean shouldFreeInfo;
|
||||
CFMachPortRef cfMachPort=CFMachPortCreateWithPort(kCFAllocatorDefault,
|
||||
port, rend_handler,
|
||||
&context, &shouldFreeInfo);
|
||||
CFMachPortContext context = { 0, 0, NULL, NULL, NULL };
|
||||
Boolean shouldFreeInfo;
|
||||
CFMachPortRef cfMachPort=CFMachPortCreateWithPort(kCFAllocatorDefault,
|
||||
port, rend_handler,
|
||||
&context, &shouldFreeInfo);
|
||||
|
||||
CFRunLoopSourceRef rls=CFMachPortCreateRunLoopSource(NULL,cfMachPort,0);
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(),
|
||||
rls,kCFRunLoopDefaultMode);
|
||||
CFRelease(rls);
|
||||
return 0;
|
||||
CFRunLoopSourceRef rls=CFMachPortCreateRunLoopSource(NULL,cfMachPort,0);
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(),
|
||||
rls,kCFRunLoopDefaultMode);
|
||||
CFRelease(rls);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,14 +98,14 @@ static int rend_addtorunloop(dns_service_discovery_ref client) {
|
||||
static void rend_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context) {
|
||||
switch(errorCode) {
|
||||
case kDNSServiceDiscoveryNoError:
|
||||
DPRINTF(E_DBG,L_REND,"Registered successfully\n");
|
||||
break;
|
||||
DPRINTF(E_DBG,L_REND,"Registered successfully\n");
|
||||
break;
|
||||
case kDNSServiceDiscoveryNameConflict:
|
||||
DPRINTF(E_WARN,L_REND,"Error - name in use\n");
|
||||
break;
|
||||
DPRINTF(E_WARN,L_REND,"Error - name in use\n");
|
||||
break;
|
||||
default:
|
||||
DPRINTF(E_WARN,L_REND,"Error %d\n",errorCode);
|
||||
break;
|
||||
DPRINTF(E_WARN,L_REND,"Error %d\n",errorCode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,23 +118,23 @@ void *rend_pipe_monitor(void* arg) {
|
||||
|
||||
|
||||
while(1) {
|
||||
DPRINTF(E_DBG,L_REND,"Waiting for data\n");
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(rend_pipe_to[RD_SIDE],&rset);
|
||||
DPRINTF(E_DBG,L_REND,"Waiting for data\n");
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(rend_pipe_to[RD_SIDE],&rset);
|
||||
|
||||
/* sit in a select spin until there is data on the to fd */
|
||||
while(((result=select(rend_pipe_to[RD_SIDE] + 1,&rset,NULL,NULL,NULL)) != -1) &&
|
||||
errno != EINTR) {
|
||||
if(FD_ISSET(rend_pipe_to[RD_SIDE],&rset)) {
|
||||
DPRINTF(E_DBG,L_REND,"Received a message from daap server\n");
|
||||
CFRunLoopSourceSignal(rend_rls);
|
||||
CFRunLoopWakeUp(rend_runloop);
|
||||
sleep(1); /* force a reschedule, hopefully */
|
||||
}
|
||||
}
|
||||
/* sit in a select spin until there is data on the to fd */
|
||||
while(((result=select(rend_pipe_to[RD_SIDE] + 1,&rset,NULL,NULL,NULL)) != -1) &&
|
||||
errno != EINTR) {
|
||||
if(FD_ISSET(rend_pipe_to[RD_SIDE],&rset)) {
|
||||
DPRINTF(E_DBG,L_REND,"Received a message from daap server\n");
|
||||
CFRunLoopSourceSignal(rend_rls);
|
||||
CFRunLoopWakeUp(rend_runloop);
|
||||
sleep(1); /* force a reschedule, hopefully */
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_REND,"Select error!\n");
|
||||
/* should really bail here */
|
||||
DPRINTF(E_DBG,L_REND,"Select error!\n");
|
||||
/* should really bail here */
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,38 +164,38 @@ void rend_callback(void *info) {
|
||||
|
||||
/* here, we've seen the message, now we have to process it */
|
||||
if(rend_read_message(&msg) != sizeof(msg)) {
|
||||
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
switch(msg.cmd) {
|
||||
case REND_MSG_TYPE_REGISTER:
|
||||
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.type,msg.name,msg.port);
|
||||
usPort=msg.port;
|
||||
dns_ref=DNSServiceRegistrationCreate(msg.name,msg.type,"",usPort,
|
||||
"txtvers=1\001Database ID=bedabb1edeadbea7",rend_reply,nil);
|
||||
if(rend_addtorunloop(dns_ref)) {
|
||||
DPRINTF(E_WARN,L_REND,"Add to runloop failed\n");
|
||||
rend_send_response(-1);
|
||||
} else {
|
||||
rend_send_response(0); /* success */
|
||||
}
|
||||
break;
|
||||
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.type,msg.name,msg.port);
|
||||
usPort=msg.port;
|
||||
dns_ref=DNSServiceRegistrationCreate(msg.name,msg.type,"",usPort,
|
||||
"txtvers=1\001Database ID=bedabb1edeadbea7",rend_reply,nil);
|
||||
if(rend_addtorunloop(dns_ref)) {
|
||||
DPRINTF(E_WARN,L_REND,"Add to runloop failed\n");
|
||||
rend_send_response(-1);
|
||||
} else {
|
||||
rend_send_response(0); /* success */
|
||||
}
|
||||
break;
|
||||
case REND_MSG_TYPE_UNREGISTER:
|
||||
DPRINTF(E_WARN,L_REND,"Unsupported function: UNREGISTER\n");
|
||||
rend_send_response(-1); /* error */
|
||||
break;
|
||||
DPRINTF(E_WARN,L_REND,"Unsupported function: UNREGISTER\n");
|
||||
rend_send_response(-1); /* error */
|
||||
break;
|
||||
case REND_MSG_TYPE_STOP:
|
||||
DPRINTF(E_DBG,L_REND,"Stopping mDNS\n");
|
||||
rend_send_response(0);
|
||||
rend_stoprunloop();
|
||||
break;
|
||||
DPRINTF(E_DBG,L_REND,"Stopping mDNS\n");
|
||||
rend_send_response(0);
|
||||
rend_stoprunloop();
|
||||
break;
|
||||
case REND_MSG_TYPE_STATUS:
|
||||
DPRINTF(E_DBG,L_REND,"Status inquiry -- returning 0\n");
|
||||
rend_send_response(0); /* success */
|
||||
break;
|
||||
DPRINTF(E_DBG,L_REND,"Status inquiry -- returning 0\n");
|
||||
rend_send_response(0); /* success */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,8 +207,8 @@ void rend_callback(void *info) {
|
||||
int rend_private_init(char *user) {
|
||||
CFRunLoopSourceContext context;
|
||||
|
||||
if(drop_privs(user)) /* shouldn't be running as root anyway */
|
||||
return -1;
|
||||
if(os_drop_privs(user)) /* shouldn't be running as root anyway */
|
||||
return -1;
|
||||
|
||||
/* need a sigint handler */
|
||||
DPRINTF(E_DBG,L_REND,"Starting rendezvous services\n");
|
||||
@ -222,9 +223,9 @@ int rend_private_init(char *user) {
|
||||
DPRINTF(E_DBG,L_REND,"Starting polling thread\n");
|
||||
|
||||
if(pthread_create(&rend_tid,NULL,rend_pipe_monitor,NULL)) {
|
||||
DPRINTF(E_FATAL,L_REND,"Could not start thread. Terminating\n");
|
||||
/* should kill parent, too */
|
||||
exit(EXIT_FAILURE);
|
||||
DPRINTF(E_FATAL,L_REND,"Could not start thread. Terminating\n");
|
||||
/* should kill parent, too */
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_REND,"Starting runloop\n");
|
||||
|
286
src/rend-posix.c
286
src/rend-posix.c
@ -89,6 +89,15 @@
|
||||
Change History (most recent first):
|
||||
|
||||
$Log$
|
||||
Revision 1.28 2006/02/26 08:46:24 rpedde
|
||||
Merged win32-branch
|
||||
|
||||
Revision 1.27.2.2 2006/02/26 08:28:35 rpedde
|
||||
unix fixes from win32 port
|
||||
|
||||
Revision 1.27.2.1 2006/02/23 03:19:40 rpedde
|
||||
First pass at win32 port.
|
||||
|
||||
Revision 1.27 2006/02/20 03:36:57 rpedde
|
||||
Annoying fprintf
|
||||
|
||||
@ -188,11 +197,11 @@
|
||||
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h> // For printf()
|
||||
#include <stdlib.h> // For exit() etc.
|
||||
#include <string.h> // For strlen() etc.
|
||||
#include <unistd.h> // For select()
|
||||
#include <errno.h> // For errno, EINTR
|
||||
#include <stdio.h> // For printf()
|
||||
#include <stdlib.h> // For exit() etc.
|
||||
#include <string.h> // For strlen() etc.
|
||||
#include <unistd.h> // For select()
|
||||
#include <errno.h> // For errno, EINTR
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
@ -201,6 +210,7 @@
|
||||
#define __IN_ERR__
|
||||
#include "daapd.h"
|
||||
#include "err.h"
|
||||
#include "os-unix.h"
|
||||
#include "rend.h"
|
||||
#include "rend-unix.h"
|
||||
|
||||
@ -211,12 +221,12 @@
|
||||
typedef struct PosixNetworkInterface PosixNetworkInterface;
|
||||
|
||||
struct PosixNetworkInterface {
|
||||
NetworkInterfaceInfo coreIntf;
|
||||
const char * intfName;
|
||||
PosixNetworkInterface * aliasIntf;
|
||||
int index;
|
||||
int multicastSocket;
|
||||
int multicastSocketv6;
|
||||
NetworkInterfaceInfo coreIntf;
|
||||
const char * intfName;
|
||||
PosixNetworkInterface * aliasIntf;
|
||||
int index;
|
||||
int multicastSocket;
|
||||
int multicastSocketv6;
|
||||
};
|
||||
|
||||
|
||||
@ -291,52 +301,52 @@ static void RegistrationCallback(mDNS *const m, ServiceRecordSet *const thisRegi
|
||||
switch (status) {
|
||||
|
||||
case mStatus_NoError:
|
||||
DPRINTF(E_DBG,L_REND,"Callback: Name Registered\n");
|
||||
// Do nothing; our name was successfully registered. We may
|
||||
// get more call backs in the future.
|
||||
break;
|
||||
DPRINTF(E_DBG,L_REND,"Callback: Name Registered\n");
|
||||
// Do nothing; our name was successfully registered. We may
|
||||
// get more call backs in the future.
|
||||
break;
|
||||
|
||||
case mStatus_NameConflict:
|
||||
DPRINTF(E_WARN,L_REND,"Callback: Name Conflict\n");
|
||||
DPRINTF(E_WARN,L_REND,"Callback: Name Conflict\n");
|
||||
|
||||
// In the event of a conflict, this sample RegistrationCallback
|
||||
// just calls mDNS_RenameAndReregisterService to automatically
|
||||
// pick a new unique name for the service. For a device such as a
|
||||
// printer, this may be appropriate. For a device with a user
|
||||
// interface, and a screen, and a keyboard, the appropriate response
|
||||
// may be to prompt the user and ask them to choose a new name for
|
||||
// the service.
|
||||
//
|
||||
// Also, what do we do if mDNS_RenameAndReregisterService returns an
|
||||
// error. Right now I have no place to send that error to.
|
||||
// In the event of a conflict, this sample RegistrationCallback
|
||||
// just calls mDNS_RenameAndReregisterService to automatically
|
||||
// pick a new unique name for the service. For a device such as a
|
||||
// printer, this may be appropriate. For a device with a user
|
||||
// interface, and a screen, and a keyboard, the appropriate response
|
||||
// may be to prompt the user and ask them to choose a new name for
|
||||
// the service.
|
||||
//
|
||||
// Also, what do we do if mDNS_RenameAndReregisterService returns an
|
||||
// error. Right now I have no place to send that error to.
|
||||
|
||||
status = mDNS_RenameAndReregisterService(m, thisRegistration, mDNSNULL);
|
||||
assert(status == mStatus_NoError);
|
||||
break;
|
||||
status = mDNS_RenameAndReregisterService(m, thisRegistration, mDNSNULL);
|
||||
assert(status == mStatus_NoError);
|
||||
break;
|
||||
|
||||
case mStatus_MemFree:
|
||||
DPRINTF(E_WARN,L_REND,"Callback: Memory Free\n");
|
||||
DPRINTF(E_WARN,L_REND,"Callback: Memory Free\n");
|
||||
|
||||
// When debugging is enabled, make sure that thisRegistration
|
||||
// is not on our gServiceList.
|
||||
// When debugging is enabled, make sure that thisRegistration
|
||||
// is not on our gServiceList.
|
||||
|
||||
#if defined(DEBUG)
|
||||
{
|
||||
PosixService *cursor;
|
||||
{
|
||||
PosixService *cursor;
|
||||
|
||||
cursor = gServiceList;
|
||||
while (cursor != NULL) {
|
||||
assert(&cursor->coreServ != thisRegistration);
|
||||
cursor = cursor->next;
|
||||
}
|
||||
}
|
||||
cursor = gServiceList;
|
||||
while (cursor != NULL) {
|
||||
assert(&cursor->coreServ != thisRegistration);
|
||||
cursor = cursor->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
free(thisRegistration);
|
||||
break;
|
||||
free(thisRegistration);
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(E_WARN,L_REND,"Callback: Unknown Status %d\n",status);
|
||||
break;
|
||||
DPRINTF(E_WARN,L_REND,"Callback: Unknown Status %d\n",status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,11 +354,11 @@ static int gServiceID = 0;
|
||||
|
||||
static mStatus RegisterOneService(const char * richTextHostName,
|
||||
const char * serviceType,
|
||||
const char * serviceDomain,
|
||||
const char * serviceDomain,
|
||||
const mDNSu8 text[],
|
||||
mDNSu16 textLen,
|
||||
long portNumber,
|
||||
mDNSInterfaceID id)
|
||||
mDNSInterfaceID id)
|
||||
{
|
||||
mStatus status;
|
||||
PosixService * thisServ;
|
||||
@ -370,13 +380,13 @@ static mStatus RegisterOneService(const char * richTextHostName,
|
||||
port.b[0] = (portNumber >> 8) & 0x0FF;
|
||||
port.b[1] = (portNumber >> 0) & 0x0FF;;
|
||||
status = mDNS_RegisterService(&mDNSStorage, &thisServ->coreServ,
|
||||
&name, &type, &domain,
|
||||
NULL,
|
||||
port,
|
||||
text, textLen,
|
||||
NULL, 0,
|
||||
id,
|
||||
RegistrationCallback, thisServ);
|
||||
&name, &type, &domain,
|
||||
NULL,
|
||||
port,
|
||||
text, textLen,
|
||||
NULL, 0,
|
||||
id,
|
||||
RegistrationCallback, thisServ);
|
||||
}
|
||||
if (status == mStatus_NoError) {
|
||||
thisServ->serviceID = gServiceID;
|
||||
@ -385,13 +395,13 @@ static mStatus RegisterOneService(const char * richTextHostName,
|
||||
thisServ->next = gServiceList;
|
||||
gServiceList = thisServ;
|
||||
|
||||
DPRINTF(E_DBG,L_REND,
|
||||
"Registered service %d, name '%s', type '%s', domain '%s', port %ld\n",
|
||||
thisServ->serviceID,
|
||||
richTextHostName,
|
||||
serviceType,
|
||||
serviceDomain,
|
||||
portNumber);
|
||||
DPRINTF(E_DBG,L_REND,
|
||||
"Registered service %d, name '%s', type '%s', domain '%s', port %ld\n",
|
||||
thisServ->serviceID,
|
||||
richTextHostName,
|
||||
serviceType,
|
||||
serviceDomain,
|
||||
portNumber);
|
||||
} else {
|
||||
if (thisServ != NULL) {
|
||||
free(thisServ);
|
||||
@ -413,8 +423,8 @@ static void DeregisterOurServices(void)
|
||||
|
||||
mDNS_DeregisterService(&mDNSStorage, &thisServ->coreServ);
|
||||
|
||||
DPRINTF(E_DBG,L_REND,"Deregistered service %d\n",
|
||||
thisServ->serviceID);
|
||||
DPRINTF(E_DBG,L_REND,"Deregistered service %d\n",
|
||||
thisServ->serviceID);
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,22 +432,22 @@ mDNSInterfaceID rend_get_interface_id(char *iface) {
|
||||
PosixNetworkInterface *pni;
|
||||
|
||||
if(!iface)
|
||||
return mDNSInterface_Any;
|
||||
return mDNSInterface_Any;
|
||||
|
||||
if(!strlen(iface))
|
||||
return mDNSInterface_Any;
|
||||
return mDNSInterface_Any;
|
||||
|
||||
DPRINTF(E_LOG,L_REND,"Searching for interface %s\n",iface);
|
||||
|
||||
pni=(PosixNetworkInterface*)mDNSStorage.HostInterfaces;
|
||||
while(pni) {
|
||||
DPRINTF(E_INF,L_REND,"Found interface %s, index %d\n",pni->intfName,
|
||||
pni->index);
|
||||
if(strcasecmp(pni->intfName,iface) == 0) {
|
||||
DPRINTF(E_INF,L_REND,"Found interface id: %d\n",pni->coreIntf.InterfaceID);
|
||||
return pni->coreIntf.InterfaceID;
|
||||
}
|
||||
pni=(PosixNetworkInterface*)(pni->coreIntf.next);
|
||||
DPRINTF(E_INF,L_REND,"Found interface %s, index %d\n",pni->intfName,
|
||||
pni->index);
|
||||
if(strcasecmp(pni->intfName,iface) == 0) {
|
||||
DPRINTF(E_INF,L_REND,"Found interface id: %d\n",pni->coreIntf.InterfaceID);
|
||||
return pni->coreIntf.InterfaceID;
|
||||
}
|
||||
pni=(PosixNetworkInterface*)(pni->coreIntf.next);
|
||||
}
|
||||
|
||||
DPRINTF(E_INF,L_REND,"Could not find interface.\n");
|
||||
@ -460,33 +470,33 @@ void rend_callback(void) {
|
||||
/* here, we've seen the message, now we have to process it */
|
||||
|
||||
if((result=rend_read_message(&msg)) != sizeof(msg)) {
|
||||
err=errno;
|
||||
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
|
||||
gStopNow=mDNStrue;
|
||||
return;
|
||||
err=errno;
|
||||
DPRINTF(E_FATAL,L_REND,"Rendezvous socket closed (daap server crashed?) Aborting.\n");
|
||||
gStopNow=mDNStrue;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(msg.cmd) {
|
||||
case REND_MSG_TYPE_REGISTER:
|
||||
id=rend_get_interface_id(msg.interface);
|
||||
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.name,msg.type,msg.port);
|
||||
RegisterOneService(msg.name,msg.type,"local.","\011txtvers=1\034Database ID=beddab1edeadbea7",39,
|
||||
msg.port,id);
|
||||
rend_send_response(0); /* success */
|
||||
break;
|
||||
id=rend_get_interface_id(msg.iface);
|
||||
DPRINTF(E_DBG,L_REND,"Registering %s.%s (%d)\n",msg.name,msg.type,msg.port);
|
||||
RegisterOneService(msg.name,msg.type,"local.","\011txtvers=1\034Database ID=beddab1edeadbea7",39,
|
||||
msg.port,id);
|
||||
rend_send_response(0); /* success */
|
||||
break;
|
||||
case REND_MSG_TYPE_UNREGISTER:
|
||||
rend_send_response(1); /* error */
|
||||
break;
|
||||
rend_send_response(1); /* error */
|
||||
break;
|
||||
case REND_MSG_TYPE_STOP:
|
||||
DPRINTF(E_INF,L_REND,"Stopping mDNS\n");
|
||||
gStopNow = mDNStrue;
|
||||
rend_send_response(0);
|
||||
break;
|
||||
DPRINTF(E_INF,L_REND,"Stopping mDNS\n");
|
||||
gStopNow = mDNStrue;
|
||||
rend_send_response(0);
|
||||
break;
|
||||
case REND_MSG_TYPE_STATUS:
|
||||
rend_send_response(1);
|
||||
break;
|
||||
rend_send_response(1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -497,63 +507,63 @@ int rend_private_init(char *user) {
|
||||
mDNSBool result;
|
||||
|
||||
status = mDNS_Init(&mDNSStorage, &PlatformStorage,
|
||||
mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
|
||||
mDNS_Init_AdvertiseLocalAddresses,
|
||||
mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
|
||||
mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
|
||||
mDNS_Init_AdvertiseLocalAddresses,
|
||||
mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
|
||||
|
||||
if (status != mStatus_NoError) {
|
||||
DPRINTF(E_FATAL,L_REND,"mDNS Error %d\n",status);
|
||||
return(-1);
|
||||
DPRINTF(E_FATAL,L_REND,"mDNS Error %d\n",status);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(drop_privs(user))
|
||||
return -1;
|
||||
if(os_drop_privs(user))
|
||||
return -1;
|
||||
|
||||
signal(SIGINT, HandleSigInt); // SIGINT is what you get for a Ctrl-C
|
||||
signal(SIGQUIT, HandleSigQuit); // SIGQUIT is what you get for a Ctrl-\ (indeed)
|
||||
signal(SIGHUP, SIG_IGN); // SIGHUP might happen from a request to reload the daap server
|
||||
|
||||
while (!gStopNow) {
|
||||
int nfds = 1;
|
||||
fd_set readfds;
|
||||
struct timeval timeout;
|
||||
int result;
|
||||
|
||||
// 1. Set up the fd_set as usual here.
|
||||
// This example client has no file descriptors of its own,
|
||||
// but a real application would call FD_SET to add them to the set here
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(rend_pipe_to[RD_SIDE],&readfds);
|
||||
|
||||
// 2. Set up the timeout.
|
||||
// This example client has no other work it needs to be doing,
|
||||
// so we set an effectively infinite timeout
|
||||
timeout.tv_sec = 0x3FFFFFFF;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
// 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
|
||||
mDNSPosixGetFDSet(&mDNSStorage, &nfds, &readfds, &timeout);
|
||||
|
||||
// 4. Call select as normal
|
||||
DPRINTF(E_DBG,L_REND,"select(%d, %d.%06d)\n", nfds,
|
||||
timeout.tv_sec, timeout.tv_usec);
|
||||
|
||||
result = select(nfds, &readfds, NULL, NULL, &timeout);
|
||||
|
||||
if (result < 0) {
|
||||
if (errno != EINTR) gStopNow = mDNStrue;
|
||||
DPRINTF(E_WARN,L_REND,"select() returned %d errno %d\n", result, errno);
|
||||
} else {
|
||||
// 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
|
||||
mDNSPosixProcessFDSet(&mDNSStorage, &readfds);
|
||||
|
||||
// 6. This example client has no other work it needs to be doing,
|
||||
// but a real client would do its work here
|
||||
// ... (do work) ...
|
||||
if(FD_ISSET(rend_pipe_to[RD_SIDE],&readfds)) {
|
||||
rend_callback();
|
||||
}
|
||||
}
|
||||
int nfds = 1;
|
||||
fd_set readfds;
|
||||
struct timeval timeout;
|
||||
int result;
|
||||
|
||||
// 1. Set up the fd_set as usual here.
|
||||
// This example client has no file descriptors of its own,
|
||||
// but a real application would call FD_SET to add them to the set here
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(rend_pipe_to[RD_SIDE],&readfds);
|
||||
|
||||
// 2. Set up the timeout.
|
||||
// This example client has no other work it needs to be doing,
|
||||
// so we set an effectively infinite timeout
|
||||
timeout.tv_sec = 0x3FFFFFFF;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
// 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
|
||||
mDNSPosixGetFDSet(&mDNSStorage, &nfds, &readfds, &timeout);
|
||||
|
||||
// 4. Call select as normal
|
||||
DPRINTF(E_DBG,L_REND,"select(%d, %d.%06d)\n", nfds,
|
||||
timeout.tv_sec, timeout.tv_usec);
|
||||
|
||||
result = select(nfds, &readfds, NULL, NULL, &timeout);
|
||||
|
||||
if (result < 0) {
|
||||
if (errno != EINTR) gStopNow = mDNStrue;
|
||||
DPRINTF(E_WARN,L_REND,"select() returned %d errno %d\n", result, errno);
|
||||
} else {
|
||||
// 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
|
||||
mDNSPosixProcessFDSet(&mDNSStorage, &readfds);
|
||||
|
||||
// 6. This example client has no other work it needs to be doing,
|
||||
// but a real client would do its work here
|
||||
// ... (do work) ...
|
||||
if(FD_ISSET(rend_pipe_to[RD_SIDE],&readfds)) {
|
||||
rend_callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_REND,"Exiting\n");
|
||||
@ -567,7 +577,7 @@ int rend_private_init(char *user) {
|
||||
result = 2;
|
||||
}
|
||||
DPRINTF(E_DBG,L_REND, "Finished with status %ld, result %d\n",
|
||||
status, result);
|
||||
status, result);
|
||||
|
||||
exit(result);
|
||||
}
|
||||
|
@ -54,31 +54,31 @@ int rend_init(char *user) {
|
||||
int fd;
|
||||
|
||||
if(pipe((int*)&rend_pipe_to) == -1)
|
||||
return -1;
|
||||
return -1;
|
||||
|
||||
if(pipe((int*)&rend_pipe_from) == -1) {
|
||||
err=errno;
|
||||
close(rend_pipe_to[RD_SIDE]);
|
||||
close(rend_pipe_to[WR_SIDE]);
|
||||
errno=err;
|
||||
return -1;
|
||||
err=errno;
|
||||
close(rend_pipe_to[RD_SIDE]);
|
||||
close(rend_pipe_to[WR_SIDE]);
|
||||
errno=err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rend_pid=fork();
|
||||
if(rend_pid==-1) {
|
||||
err=errno;
|
||||
close(rend_pipe_to[RD_SIDE]);
|
||||
close(rend_pipe_to[WR_SIDE]);
|
||||
close(rend_pipe_from[RD_SIDE]);
|
||||
close(rend_pipe_from[WR_SIDE]);
|
||||
errno=err;
|
||||
return -1;
|
||||
err=errno;
|
||||
close(rend_pipe_to[RD_SIDE]);
|
||||
close(rend_pipe_to[WR_SIDE]);
|
||||
close(rend_pipe_from[RD_SIDE]);
|
||||
close(rend_pipe_from[WR_SIDE]);
|
||||
errno=err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(rend_pid) { /* parent */
|
||||
close(rend_pipe_to[RD_SIDE]);
|
||||
close(rend_pipe_from[WR_SIDE]);
|
||||
return 0;
|
||||
close(rend_pipe_to[RD_SIDE]);
|
||||
close(rend_pipe_from[WR_SIDE]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* child */
|
||||
@ -100,17 +100,17 @@ int rend_init(char *user) {
|
||||
|
||||
#ifdef TIOCNOTTY
|
||||
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
|
||||
ioctl(fd, TIOCNOTTY, (char *) NULL);
|
||||
close(fd);
|
||||
ioctl(fd, TIOCNOTTY, (char *) NULL);
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
if((fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
// dup2(fd, STDERR_FILENO);
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
// dup2(fd, STDERR_FILENO);
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
@ -159,20 +159,20 @@ int rend_stop(void) {
|
||||
*
|
||||
* register a rendezvous name
|
||||
*/
|
||||
int rend_register(char *name, char *type, int port, char *interface) {
|
||||
int rend_register(char *name, char *type, int port, char *iface) {
|
||||
REND_MESSAGE msg;
|
||||
|
||||
if((strlen(name)+1 > MAX_NAME_LEN) || (strlen(type)+1 > MAX_NAME_LEN)) {
|
||||
DPRINTF(E_FATAL,L_REND,"Registration failed: name or type too long\n");
|
||||
return -1;
|
||||
DPRINTF(E_FATAL,L_REND,"Registration failed: name or type too long\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset((void*)&msg,0x00,sizeof(msg)); /* shut valgrind up */
|
||||
msg.cmd=REND_MSG_TYPE_REGISTER;
|
||||
strncpy(msg.name,name,MAX_NAME_LEN-1);
|
||||
strncpy(msg.type,type,MAX_NAME_LEN-1);
|
||||
if(interface)
|
||||
strncpy(msg.interface,interface,MAX_IFACE_NAME_LEN-1);
|
||||
if(iface)
|
||||
strncpy(msg.iface,iface,MAX_IFACE_NAME_LEN-1);
|
||||
|
||||
msg.port=port;
|
||||
|
||||
@ -197,10 +197,10 @@ int rend_send_message(REND_MESSAGE *pmsg) {
|
||||
int retval;
|
||||
|
||||
if(r_write(rend_pipe_to[WR_SIDE],pmsg,sizeof(REND_MESSAGE)) == -1)
|
||||
return -1;
|
||||
return -1;
|
||||
|
||||
if((retval=r_read(rend_pipe_from[RD_SIDE],&retval,sizeof(int)) == -1))
|
||||
return -1;
|
||||
return -1;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ typedef struct tag_rend_message {
|
||||
int port;
|
||||
char name[MAX_NAME_LEN];
|
||||
char type[MAX_NAME_LEN];
|
||||
char interface[MAX_IFACE_NAME_LEN];
|
||||
char iface[MAX_IFACE_NAME_LEN];
|
||||
} REND_MESSAGE;
|
||||
|
||||
#define REND_MSG_TYPE_REGISTER 0
|
||||
|
187
src/rend-win32.c
Normal file
187
src/rend-win32.c
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* This is an implementation of rendezvous using the Bonjour (tm)
|
||||
* for windows dns_sd.h implementation
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "dns_sd.h"
|
||||
#include "err.h"
|
||||
|
||||
/* Globals */
|
||||
pthread_t rend_tid;
|
||||
static volatile int rend_stop_flag = 0;
|
||||
static volatile int rend_timeout = 10; /* select timeout */
|
||||
static DNSServiceRef rend_client = NULL;
|
||||
static DNSServiceRef rend_client2 = NULL;
|
||||
static volatile int rend_count=0;
|
||||
|
||||
/* Forwards */
|
||||
void *rend_mainthread(void *arg);
|
||||
void DNSSD_API rend_reg_reply(DNSServiceRef client, const DNSServiceFlags flags,
|
||||
DNSServiceErrorType errorCode, const char *name,
|
||||
const char *regtype, const char *domain, void *context);
|
||||
|
||||
/* Typedefs */
|
||||
typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
|
||||
|
||||
|
||||
/**
|
||||
* initialize the rendezvous interface.
|
||||
*
|
||||
* @param user user to drop privs to (ignored)
|
||||
* @returns 0 on success, -1 with errno set otherwise
|
||||
*/
|
||||
int rend_init(char *user) {
|
||||
/* we'll throw off a handler thread when we register a name */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* main bonjourvous thread
|
||||
*
|
||||
* @param arg unused
|
||||
*/
|
||||
void *rend_mainthread(void *arg) {
|
||||
/* this is pretty much right out of the old mdns stuff */
|
||||
int dns_sd_fd = rend_client ? DNSServiceRefSockFD(rend_client) : -1;
|
||||
int dns_sd_fd2 = rend_client2 ? DNSServiceRefSockFD(rend_client2) : -1;
|
||||
int nfds = dns_sd_fd + 1;
|
||||
fd_set readfds;
|
||||
struct timeval tv;
|
||||
int result;
|
||||
DNSServiceErrorType err = kDNSServiceErr_NoError;
|
||||
|
||||
if (dns_sd_fd2 > dns_sd_fd) nfds = dns_sd_fd2 + 1;
|
||||
|
||||
while (!rend_stop_flag) {
|
||||
FD_ZERO(&readfds);
|
||||
|
||||
if (rend_client) FD_SET(dns_sd_fd, &readfds);
|
||||
if (rend_client2) FD_SET(dns_sd_fd2, &readfds);
|
||||
|
||||
tv.tv_sec = rend_timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
|
||||
if (result > 0) {
|
||||
if (rend_client && FD_ISSET(dns_sd_fd, &readfds)) {
|
||||
err = DNSServiceProcessResult(rend_client);
|
||||
} else if (rend_client2 && FD_ISSET(dns_sd_fd2, &readfds)) {
|
||||
err = DNSServiceProcessResult(rend_client2);
|
||||
}
|
||||
if (err) {
|
||||
DPRINTF(E_LOG,L_REND,"DNSServiceProcessResult returned %d\n", err);
|
||||
rend_stop_flag = 1;
|
||||
}
|
||||
} else if (result == 0) {
|
||||
DPRINTF(E_DBG,L_REND,"rendezvous: tick!\n");
|
||||
|
||||
// myTimerCallBack();
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_REND,"select() returned %d errno %d %s\n", result, errno, strerror(errno));
|
||||
if (errno != EINTR) rend_stop_flag = 1;
|
||||
}
|
||||
}
|
||||
if(rend_client) DNSServiceRefDeallocate(rend_client);
|
||||
if(rend_client2) DNSServiceRefDeallocate(rend_client2);
|
||||
|
||||
rend_client = NULL;
|
||||
rend_client2 = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* check to see if rendezvous is running.
|
||||
*
|
||||
* @returns TRUE if running, FALSE otherwise
|
||||
*/
|
||||
int rend_running(void) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* stop rendezvous if it is running. There should really be a way
|
||||
* to start it, would't one think?
|
||||
*
|
||||
* @returns TRUE if stopped, FALSE otherwise
|
||||
*/
|
||||
int rend_stop(void) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* register a rendezvous name
|
||||
*
|
||||
* @param name long name to register (mt-daapd)
|
||||
* @param type type to register (_daap._tcp)
|
||||
* @param port port to register (3689)
|
||||
* @param iface interface to register with (ignored)
|
||||
* @returns TRUE if registered, FALSE otherwise
|
||||
*/
|
||||
int rend_register(char *name, char *type, int port, char *iface) {
|
||||
int err;
|
||||
uint16_t port_netorder = htons((unsigned short)port);
|
||||
|
||||
DPRINTF(E_INF,L_REND,"Registering %s as type (%s) on port %d\n",
|
||||
name, type, port);
|
||||
|
||||
DNSServiceRegister(&rend_client,0,kDNSServiceInterfaceIndexAny,name,type,"local",NULL,
|
||||
htons((unsigned short)port),0,NULL,rend_reg_reply, NULL);
|
||||
|
||||
/* throw off a new thread work this */
|
||||
if(!rend_count) {
|
||||
if((err=pthread_create(&rend_tid,NULL,rend_mainthread,NULL))) {
|
||||
DPRINTF(E_LOG,L_REND,"Could not spawn thread: %s\n",strerror(err));
|
||||
errno=err;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rend_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DNSSD_API rend_reg_reply(DNSServiceRef client, const DNSServiceFlags flags,
|
||||
DNSServiceErrorType errorCode, const char *name,
|
||||
const char *regtype, const char *domain, void *context)
|
||||
{
|
||||
DPRINTF(E_INF,L_REND,"Got a reply for %s.%s%s: ", name, regtype, domain);
|
||||
switch (errorCode) {
|
||||
case kDNSServiceErr_NoError:
|
||||
DPRINTF(E_INF,L_REND,"Name now registered and active\n");
|
||||
break;
|
||||
case kDNSServiceErr_NameConflict:
|
||||
DPRINTF(E_FATAL,L_REND,"Rendezvous name in use, aborting...\n");
|
||||
break;
|
||||
default:
|
||||
DPRINTF(E_FATAL,L_REND,"Error %d\n", errorCode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* unregister a name
|
||||
*
|
||||
* unimplemented
|
||||
*/
|
||||
int rend_unregister(char *name, char *type, int port) {
|
||||
return -1;
|
||||
}
|
@ -25,7 +25,7 @@
|
||||
extern int rend_init(char *user);
|
||||
extern int rend_running(void);
|
||||
extern int rend_stop(void);
|
||||
extern int rend_register(char *name, char *type, int port, char *interface);
|
||||
extern int rend_register(char *name, char *type, int port, char *iface);
|
||||
extern int rend_unregister(char *name, char *type, int port);
|
||||
|
||||
#endif /* _REND_H_ */
|
||||
|
199
src/restart.c
199
src/restart.c
@ -32,40 +32,52 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include "err.h"
|
||||
#include "restart.h"
|
||||
|
||||
#define BLKSIZE PIPE_BUF
|
||||
#define MILLION 1000000L
|
||||
#define D_MILLION 1000000.0
|
||||
|
||||
/* Private functions */
|
||||
|
||||
static int gettimeout(struct timeval end,
|
||||
struct timeval *timeoutp) {
|
||||
int gettimeout(struct timeval end,
|
||||
struct timeval *timeoutp) {
|
||||
gettimeofday(timeoutp, NULL);
|
||||
timeoutp->tv_sec = end.tv_sec - timeoutp->tv_sec;
|
||||
timeoutp->tv_usec = end.tv_usec - timeoutp->tv_usec;
|
||||
if (timeoutp->tv_usec >= MILLION) {
|
||||
timeoutp->tv_sec++;
|
||||
timeoutp->tv_usec -= MILLION;
|
||||
timeoutp->tv_sec++;
|
||||
timeoutp->tv_usec -= MILLION;
|
||||
}
|
||||
if (timeoutp->tv_usec < 0) {
|
||||
timeoutp->tv_sec--;
|
||||
timeoutp->tv_usec += MILLION;
|
||||
timeoutp->tv_sec--;
|
||||
timeoutp->tv_usec += MILLION;
|
||||
}
|
||||
if ((timeoutp->tv_sec < 0) ||
|
||||
((timeoutp->tv_sec == 0) && (timeoutp->tv_usec == 0))) {
|
||||
errno = ETIME;
|
||||
return -1;
|
||||
((timeoutp->tv_sec == 0) && (timeoutp->tv_usec == 0))) {
|
||||
errno = ETIME;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -103,28 +115,9 @@ int r_open2(const char *path, int oflag) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
int r_open3(const char *path, int oflag, mode_t mode) {
|
||||
int retval;
|
||||
while (retval = open(path, oflag, mode), retval == -1 && errno == EINTR) ;
|
||||
return retval;
|
||||
}
|
||||
|
||||
ssize_t r_read(int fd, void *buf, size_t size) {
|
||||
ssize_t retval;
|
||||
while (((retval = read(fd, buf, size)) == -1) && (errno==EINTR)) {};
|
||||
return retval;
|
||||
}
|
||||
|
||||
pid_t r_wait(int *stat_loc) {
|
||||
pid_t retval;
|
||||
while (((retval = wait(stat_loc)) == -1) && (errno == EINTR)) ;
|
||||
return retval;
|
||||
}
|
||||
|
||||
pid_t r_waitpid(pid_t pid, int *stat_loc, int options) {
|
||||
pid_t retval;
|
||||
while (((retval = waitpid(pid, stat_loc, options)) == -1) &&
|
||||
(errno == EINTR)) ;
|
||||
while (((retval = read(fd, buf, (int)size)) == -1) && (errno==EINTR)) {};
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -135,16 +128,16 @@ ssize_t r_write(int fd, void *buf, size_t size) {
|
||||
size_t totalbytes;
|
||||
|
||||
for (bufp = buf, bytestowrite = size, totalbytes = 0;
|
||||
bytestowrite > 0;
|
||||
bufp += byteswritten, bytestowrite -= byteswritten) {
|
||||
byteswritten = write(fd, bufp, bytestowrite);
|
||||
if ((byteswritten) == -1 && (errno != EINTR))
|
||||
return -1;
|
||||
if (byteswritten == -1)
|
||||
byteswritten = 0;
|
||||
totalbytes += byteswritten;
|
||||
bytestowrite > 0;
|
||||
bufp += byteswritten, bytestowrite -= byteswritten) {
|
||||
byteswritten = write(fd, bufp, bytestowrite);
|
||||
if ((byteswritten) == -1 && (errno != EINTR))
|
||||
return -1;
|
||||
if (byteswritten == -1)
|
||||
byteswritten = 0;
|
||||
totalbytes += byteswritten;
|
||||
}
|
||||
return totalbytes;
|
||||
return (ssize_t) totalbytes;
|
||||
}
|
||||
|
||||
/* Utility functions */
|
||||
@ -156,8 +149,8 @@ struct timeval add2currenttime(double seconds) {
|
||||
newtime.tv_sec += (int)seconds;
|
||||
newtime.tv_usec += (int)((seconds - (int)seconds)*D_MILLION + 0.5);
|
||||
if (newtime.tv_usec >= MILLION) {
|
||||
newtime.tv_sec++;
|
||||
newtime.tv_usec -= MILLION;
|
||||
newtime.tv_sec++;
|
||||
newtime.tv_usec -= MILLION;
|
||||
}
|
||||
return newtime;
|
||||
}
|
||||
@ -167,7 +160,7 @@ int copyfile(int fromfd, int tofd) {
|
||||
int totalbytes = 0;
|
||||
|
||||
while ((bytesread = readwrite(fromfd, tofd)) > 0)
|
||||
totalbytes += bytesread;
|
||||
totalbytes += bytesread;
|
||||
return totalbytes;
|
||||
}
|
||||
|
||||
@ -178,22 +171,22 @@ ssize_t readblock(int fd, void *buf, size_t size) {
|
||||
size_t totalbytes;
|
||||
|
||||
for (bufp = buf, bytestoread = size, totalbytes = 0;
|
||||
bytestoread > 0;
|
||||
bufp += bytesread, bytestoread -= bytesread) {
|
||||
bytesread = read(fd, bufp, bytestoread);
|
||||
if ((bytesread == 0) && (totalbytes == 0))
|
||||
return 0;
|
||||
if (bytesread == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ((bytesread) == -1 && (errno != EINTR))
|
||||
return -1;
|
||||
if (bytesread == -1)
|
||||
bytesread = 0;
|
||||
totalbytes += bytesread;
|
||||
bytestoread > 0;
|
||||
bufp += bytesread, bytestoread -= bytesread) {
|
||||
bytesread = read(fd, bufp, bytestoread);
|
||||
if ((bytesread == 0) && (totalbytes == 0))
|
||||
return 0;
|
||||
if (bytesread == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ((bytesread) == -1 && (errno != EINTR))
|
||||
return -1;
|
||||
if (bytesread == -1)
|
||||
bytesread = 0;
|
||||
totalbytes += bytesread;
|
||||
}
|
||||
return totalbytes;
|
||||
return (ssize_t) totalbytes;
|
||||
}
|
||||
|
||||
int readline(int fd, char *buf, int nbytes) {
|
||||
@ -201,20 +194,20 @@ int readline(int fd, char *buf, int nbytes) {
|
||||
int returnval;
|
||||
|
||||
while (numread < nbytes - 1) {
|
||||
returnval = read(fd, buf + numread, 1);
|
||||
if ((returnval == -1) && (errno == EINTR))
|
||||
continue;
|
||||
if ((returnval == 0) && (numread == 0))
|
||||
return 0;
|
||||
if (returnval == 0)
|
||||
break;
|
||||
if (returnval == -1)
|
||||
return -1;
|
||||
numread++;
|
||||
if (buf[numread-1] == '\n') {
|
||||
buf[numread] = '\0';
|
||||
return numread;
|
||||
}
|
||||
returnval = read(fd, buf + numread, 1);
|
||||
if ((returnval == -1) && (errno == EINTR))
|
||||
continue;
|
||||
if ((returnval == 0) && (numread == 0))
|
||||
return 0;
|
||||
if (returnval == 0)
|
||||
break;
|
||||
if (returnval == -1)
|
||||
return -1;
|
||||
numread++;
|
||||
if (buf[numread-1] == '\n') {
|
||||
buf[numread] = '\0';
|
||||
return numread;
|
||||
}
|
||||
}
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -225,20 +218,20 @@ int readlinetimed(int fd, char *buf, int nbytes, double seconds) {
|
||||
int returnval;
|
||||
|
||||
while (numread < nbytes - 1) {
|
||||
returnval = (int)readtimed(fd, buf + numread, 1, seconds);
|
||||
if ((returnval == -1) && (errno == EINTR))
|
||||
continue;
|
||||
if ((returnval == 0) && (numread == 0))
|
||||
return 0;
|
||||
if (returnval == 0)
|
||||
break;
|
||||
if (returnval == -1)
|
||||
return -1;
|
||||
numread++;
|
||||
if (buf[numread-1] == '\n') {
|
||||
buf[numread] = '\0';
|
||||
return numread;
|
||||
}
|
||||
returnval = (int)readtimed(fd, buf + numread, 1, seconds);
|
||||
if ((returnval == -1) && (errno == EINTR))
|
||||
continue;
|
||||
if ((returnval == 0) && (numread == 0))
|
||||
return 0;
|
||||
if (returnval == 0)
|
||||
break;
|
||||
if (returnval == -1)
|
||||
return -1;
|
||||
numread++;
|
||||
if (buf[numread-1] == '\n') {
|
||||
buf[numread] = '\0';
|
||||
return numread;
|
||||
}
|
||||
}
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@ -249,7 +242,7 @@ ssize_t readtimed(int fd, void *buf, size_t nbyte, double seconds) {
|
||||
|
||||
timedone = add2currenttime(seconds);
|
||||
if (waitfdtimed(fd, timedone) == -1)
|
||||
return (ssize_t)(-1);
|
||||
return (ssize_t)(-1);
|
||||
return r_read(fd, buf, nbyte);
|
||||
}
|
||||
|
||||
@ -258,11 +251,11 @@ int readwrite(int fromfd, int tofd) {
|
||||
int bytesread;
|
||||
|
||||
if ((bytesread = r_read(fromfd, buf, BLKSIZE)) < 0)
|
||||
return -1;
|
||||
return -1;
|
||||
if (bytesread == 0)
|
||||
return 0;
|
||||
return 0;
|
||||
if (r_write(tofd, buf, bytesread) < 0)
|
||||
return -1;
|
||||
return -1;
|
||||
return bytesread;
|
||||
}
|
||||
|
||||
@ -271,35 +264,37 @@ int readwriteblock(int fromfd, int tofd, char *buf, int size) {
|
||||
|
||||
bytesread = readblock(fromfd, buf, size);
|
||||
if (bytesread != size) /* can only be 0 or -1 */
|
||||
return bytesread;
|
||||
return bytesread;
|
||||
return r_write(tofd, buf, size);
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
int waitfdtimed(int fd, struct timeval end) {
|
||||
fd_set readset;
|
||||
int retval;
|
||||
struct timeval timeout;
|
||||
|
||||
if ((fd < 0) || (fd >= FD_SETSIZE)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
FD_ZERO(&readset);
|
||||
FD_SET(fd, &readset);
|
||||
if (gettimeout(end, &timeout) == -1)
|
||||
return -1;
|
||||
return -1;
|
||||
while (((retval = select(fd+1, &readset, NULL, NULL, &timeout)) == -1)
|
||||
&& (errno == EINTR)) {
|
||||
if (gettimeout(end, &timeout) == -1)
|
||||
return -1;
|
||||
FD_ZERO(&readset);
|
||||
FD_SET(fd, &readset);
|
||||
if (gettimeout(end, &timeout) == -1)
|
||||
return -1;
|
||||
FD_ZERO(&readset);
|
||||
FD_SET(fd, &readset);
|
||||
}
|
||||
if (retval == 0) {
|
||||
errno = ETIME;
|
||||
return -1;
|
||||
errno = ETIME;
|
||||
return -1;
|
||||
}
|
||||
if (retval == -1)
|
||||
return -1;
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -32,9 +32,20 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef ETIME
|
||||
@ -47,10 +58,7 @@ int r_fdprintf(int fd, char *fmt, ...);
|
||||
int r_close(int fildes);
|
||||
int r_dup2(int fildes, int fildes2);
|
||||
int r_open2(const char *path, int oflag);
|
||||
int r_open3(const char *path, int oflag, mode_t mode);
|
||||
ssize_t r_read(int fd, void *buf, size_t size);
|
||||
pid_t r_wait(int *stat_loc);
|
||||
pid_t r_waitpid(pid_t pid, int *stat_loc, int options);
|
||||
ssize_t r_write(int fd, void *buf, size_t size);
|
||||
ssize_t readblock(int fd, void *buf, size_t size);
|
||||
int readline(int fd, char *buf, int nbytes);
|
||||
|
247
src/rxml.c
247
src/rxml.c
@ -2,6 +2,9 @@
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
@ -72,42 +75,42 @@ int rxml_decode_string(char *string) {
|
||||
src=dst=string;
|
||||
|
||||
while(*src) {
|
||||
if((*src) == '&') {
|
||||
len = strlen(src);
|
||||
if((len > 3) && (strncmp(src,">",4) == 0)) {
|
||||
*dst++ = '>';
|
||||
src += 4;
|
||||
} else if((len > 3) && (strncmp(src,"<",4) == 0)) {
|
||||
*dst++ = '<';
|
||||
src += 4;
|
||||
} else if((len > 4) && (strncmp(src,"&",5) == 0)) {
|
||||
*dst++ = '&';
|
||||
src += 5;
|
||||
} else if((len > 5) && (strncmp(src,""",6) == 0)) {
|
||||
*dst++ = '"';
|
||||
src += 6;
|
||||
} else if((len > 5) && (strncmp(src,"'",6) == 0)) {
|
||||
*dst ++ = '\'';
|
||||
src += 6;
|
||||
} else {
|
||||
/* &#xx; */
|
||||
if(!sscanf((char*)&src[2],"%d;",&cval))
|
||||
return FALSE;
|
||||
if((*src) == '&') {
|
||||
len = (int)strlen(src);
|
||||
if((len > 3) && (strncmp(src,">",4) == 0)) {
|
||||
*dst++ = '>';
|
||||
src += 4;
|
||||
} else if((len > 3) && (strncmp(src,"<",4) == 0)) {
|
||||
*dst++ = '<';
|
||||
src += 4;
|
||||
} else if((len > 4) && (strncmp(src,"&",5) == 0)) {
|
||||
*dst++ = '&';
|
||||
src += 5;
|
||||
} else if((len > 5) && (strncmp(src,""",6) == 0)) {
|
||||
*dst++ = '"';
|
||||
src += 6;
|
||||
} else if((len > 5) && (strncmp(src,"'",6) == 0)) {
|
||||
*dst ++ = '\'';
|
||||
src += 6;
|
||||
} else {
|
||||
/* &#xx; */
|
||||
if(!sscanf((char*)&src[2],"%d;",&cval))
|
||||
return FALSE;
|
||||
|
||||
*dst++ = cval;
|
||||
if(src[3] == ';') {
|
||||
src += 4;
|
||||
} else if(src[4] == ';') {
|
||||
src += 5;
|
||||
} else if(src[5] == ';') {
|
||||
src += 6;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*dst++=*src++;
|
||||
}
|
||||
*dst++ = cval;
|
||||
if(src[3] == ';') {
|
||||
src += 4;
|
||||
} else if(src[4] == ';') {
|
||||
src += 5;
|
||||
} else if(src[5] == ';') {
|
||||
src += 6;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*dst++=*src++;
|
||||
}
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
@ -123,13 +126,13 @@ int rxml_decode_string(char *string) {
|
||||
* @param udata opaque data structure to pass to the callback
|
||||
*/
|
||||
int rxml_open(RXMLHANDLE *vp, char *file,
|
||||
RXML_EVTHANDLER handler, void *udata) {
|
||||
RXML_EVTHANDLER handler, void *udata) {
|
||||
RXML *pnew;
|
||||
|
||||
pnew=(RXML*)malloc(sizeof(RXML));
|
||||
if(!pnew) {
|
||||
*vp = NULL;
|
||||
return FALSE;
|
||||
*vp = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memset(pnew,0x0,sizeof(RXML));
|
||||
@ -142,10 +145,10 @@ int rxml_open(RXMLHANDLE *vp, char *file,
|
||||
pnew->line = 0;
|
||||
|
||||
if(!pnew->fhandle)
|
||||
RXML_ERROR(pnew,E_RXML_OPEN);
|
||||
RXML_ERROR(pnew,E_RXML_OPEN);
|
||||
|
||||
if(pnew->handler)
|
||||
pnew->handler(RXML_EVT_OPEN, pnew->udata, pnew->fname);
|
||||
pnew->handler(RXML_EVT_OPEN, pnew->udata, pnew->fname);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -177,31 +180,31 @@ char *rxml_errorstring(RXMLHANDLE vp) {
|
||||
char *estring=NULL;
|
||||
|
||||
if(!ph) {
|
||||
return "Malloc error";
|
||||
return "Malloc error";
|
||||
}
|
||||
|
||||
if(ph->estring) free(ph->estring);
|
||||
|
||||
len = strlen(rxml_estrings[ph->ecode]) + 16;
|
||||
len = (int)strlen(rxml_estrings[ph->ecode]) + 16;
|
||||
if((ph->ecode & 0x80)) {
|
||||
estring=strerror(ph->stdio_errno);
|
||||
len += strlen(estring);
|
||||
estring=strerror(ph->stdio_errno);
|
||||
len += (int)strlen(estring);
|
||||
}
|
||||
|
||||
ph->estring=(char*)malloc(len);
|
||||
if(!ph->estring)
|
||||
return "Double-fault malloc error";
|
||||
return "Double-fault malloc error";
|
||||
|
||||
|
||||
if((ph->ecode & 0x80)) {
|
||||
snprintf(ph->estring,len,"%s%s",rxml_estrings[ph->ecode],estring);
|
||||
snprintf(ph->estring,len,"%s%s",rxml_estrings[ph->ecode],estring);
|
||||
} else {
|
||||
if(strncmp(rxml_estrings[ph->ecode],"Parse",5)==0) {
|
||||
snprintf(ph->estring, len, "%s (Line:%d)",
|
||||
rxml_estrings[ph->ecode], ph->line);
|
||||
} else {
|
||||
snprintf(ph->estring,len, "%s", rxml_estrings[ph->ecode]);
|
||||
}
|
||||
if(strncmp(rxml_estrings[ph->ecode],"Parse",5)==0) {
|
||||
snprintf(ph->estring, len, "%s (Line:%d)",
|
||||
rxml_estrings[ph->ecode], ph->line);
|
||||
} else {
|
||||
snprintf(ph->estring,len, "%s", rxml_estrings[ph->ecode]);
|
||||
}
|
||||
}
|
||||
|
||||
return ph->estring;
|
||||
@ -234,94 +237,94 @@ int rxml_parse(RXMLHANDLE vp) {
|
||||
|
||||
/* walk through and read row by row */
|
||||
while(fgets(linebuffer,sizeof(linebuffer),ph->fhandle) != NULL) {
|
||||
ph->line++;
|
||||
offset=0;
|
||||
size=strlen(linebuffer);
|
||||
in_text=0;
|
||||
text_offset=0;
|
||||
while(offset < size) {
|
||||
switch(linebuffer[offset]) {
|
||||
case '<':
|
||||
if(in_tag)
|
||||
RXML_ERROR(ph, E_RXML_NEST);
|
||||
ph->line++;
|
||||
offset=0;
|
||||
size=(int)strlen(linebuffer);
|
||||
in_text=0;
|
||||
text_offset=0;
|
||||
while(offset < size) {
|
||||
switch(linebuffer[offset]) {
|
||||
case '<':
|
||||
if(in_tag)
|
||||
RXML_ERROR(ph, E_RXML_NEST);
|
||||
|
||||
in_tag=TRUE;
|
||||
tag_start=offset+1;
|
||||
tag_end=FALSE;
|
||||
if(linebuffer[tag_start] == '/') {
|
||||
tag_end = TRUE;
|
||||
offset++;
|
||||
tag_start++;
|
||||
}
|
||||
in_tag=TRUE;
|
||||
tag_start=offset+1;
|
||||
tag_end=FALSE;
|
||||
if(linebuffer[tag_start] == '/') {
|
||||
tag_end = TRUE;
|
||||
offset++;
|
||||
tag_start++;
|
||||
}
|
||||
|
||||
offset++;
|
||||
offset++;
|
||||
|
||||
in_text=0;
|
||||
break;
|
||||
in_text=0;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
if(!in_tag)
|
||||
RXML_ERROR(ph, E_RXML_CLOSE);
|
||||
case '>':
|
||||
if(!in_tag)
|
||||
RXML_ERROR(ph, E_RXML_CLOSE);
|
||||
|
||||
in_tag=FALSE;
|
||||
if((offset - tag_start) > RXML_MAX_TAG)
|
||||
RXML_ERROR(ph, E_RXML_TAGSIZE);
|
||||
in_tag=FALSE;
|
||||
if((offset - tag_start) > RXML_MAX_TAG)
|
||||
RXML_ERROR(ph, E_RXML_TAGSIZE);
|
||||
|
||||
strncpy(tagbuffer,&linebuffer[tag_start],offset-tag_start);
|
||||
tagbuffer[offset-tag_start] = '\0';
|
||||
strncpy(tagbuffer,&linebuffer[tag_start],offset-tag_start);
|
||||
tagbuffer[offset-tag_start] = '\0';
|
||||
|
||||
if(tag_end) {
|
||||
/* send the text before the tag end */
|
||||
if((ph->handler) && (strlen(textbuffer))) {
|
||||
if(!rxml_decode_string(textbuffer))
|
||||
RXML_ERROR(ph,E_RXML_ENTITY);
|
||||
if(tag_end) {
|
||||
/* send the text before the tag end */
|
||||
if((ph->handler) && (strlen(textbuffer))) {
|
||||
if(!rxml_decode_string(textbuffer))
|
||||
RXML_ERROR(ph,E_RXML_ENTITY);
|
||||
|
||||
ph->handler(RXML_EVT_TEXT,ph->udata,textbuffer);
|
||||
}
|
||||
}
|
||||
ph->handler(RXML_EVT_TEXT,ph->udata,textbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
in_text=1;
|
||||
text_offset=0;
|
||||
textbuffer[0] = '\0';
|
||||
in_text=1;
|
||||
text_offset=0;
|
||||
textbuffer[0] = '\0';
|
||||
|
||||
single_tag=0;
|
||||
if(tagbuffer[strlen(tagbuffer)-1] == '/') {
|
||||
tagbuffer[strlen(tagbuffer)-1] = '\0';
|
||||
single_tag=1;
|
||||
}
|
||||
single_tag=0;
|
||||
if(tagbuffer[strlen(tagbuffer)-1] == '/') {
|
||||
tagbuffer[strlen(tagbuffer)-1] = '\0';
|
||||
single_tag=1;
|
||||
}
|
||||
|
||||
if(ph->handler)
|
||||
ph->handler(tag_end ? RXML_EVT_END : RXML_EVT_BEGIN,
|
||||
ph->udata,tagbuffer);
|
||||
if(ph->handler)
|
||||
ph->handler(tag_end ? RXML_EVT_END : RXML_EVT_BEGIN,
|
||||
ph->udata,tagbuffer);
|
||||
|
||||
/* send a follow-up end on a <tag/> - style tag */
|
||||
if((single_tag) && (ph->handler))
|
||||
ph->handler(RXML_EVT_END,ph->udata,tagbuffer);
|
||||
/* send a follow-up end on a <tag/> - style tag */
|
||||
if((single_tag) && (ph->handler))
|
||||
ph->handler(RXML_EVT_END,ph->udata,tagbuffer);
|
||||
|
||||
offset++;
|
||||
break;
|
||||
offset++;
|
||||
break;
|
||||
|
||||
default:
|
||||
if((in_text) && (text_offset < (sizeof(textbuffer)-1))) {
|
||||
/* get rid of EOL */
|
||||
if((linebuffer[offset] != '\r') &&
|
||||
(linebuffer[offset] != '\n')) {
|
||||
textbuffer[text_offset] = linebuffer[offset];
|
||||
text_offset++;
|
||||
textbuffer[text_offset] = '\x0';
|
||||
}
|
||||
} else if (in_text) {
|
||||
/* should warn of an overflow */
|
||||
}
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
if((in_text) && (text_offset < (sizeof(textbuffer)-1))) {
|
||||
/* get rid of EOL */
|
||||
if((linebuffer[offset] != '\r') &&
|
||||
(linebuffer[offset] != '\n')) {
|
||||
textbuffer[text_offset] = linebuffer[offset];
|
||||
text_offset++;
|
||||
textbuffer[text_offset] = '\x0';
|
||||
}
|
||||
} else if (in_text) {
|
||||
/* should warn of an overflow */
|
||||
}
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ph->stdio_errno=errno;
|
||||
if(ferror(ph->fhandle))
|
||||
RXML_ERROR(ph,E_RXML_READ);
|
||||
RXML_ERROR(ph,E_RXML_READ);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ typedef void* RXMLHANDLE;
|
||||
typedef void(*RXML_EVTHANDLER)(int,void*,char*);
|
||||
|
||||
extern int rxml_open(RXMLHANDLE *handle, char *file,
|
||||
RXML_EVTHANDLER handler, void* udata);
|
||||
RXML_EVTHANDLER handler, void* udata);
|
||||
extern int rxml_close(RXMLHANDLE handle);
|
||||
extern char *rxml_errorstring(RXMLHANDLE handle);
|
||||
extern int rxml_parse(RXMLHANDLE handle);
|
||||
|
344
src/scan-aac.c
344
src/scan-aac.c
@ -26,7 +26,9 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "err.h"
|
||||
#include "mp3-scanner.h"
|
||||
@ -63,7 +65,7 @@ time_t scan_aac_mac_to_unix_time(int t) {
|
||||
* @returns offset of the atom, or -1 if unsuccessful
|
||||
*/
|
||||
off_t scan_aac_drilltoatom(FILE *aac_fp,char *atom_path,
|
||||
unsigned int *atom_length) {
|
||||
unsigned int *atom_length) {
|
||||
long atom_offset;
|
||||
off_t file_size;
|
||||
char *cur_p, *end_p;
|
||||
@ -75,40 +77,40 @@ off_t scan_aac_drilltoatom(FILE *aac_fp,char *atom_path,
|
||||
|
||||
end_p = atom_path;
|
||||
while (*end_p != '\0') {
|
||||
end_p++;
|
||||
end_p++;
|
||||
}
|
||||
atom_name[4] = '\0';
|
||||
cur_p = atom_path;
|
||||
|
||||
while (cur_p != NULL) {
|
||||
if ((end_p - cur_p) < 4) {
|
||||
return -1;
|
||||
}
|
||||
strncpy(atom_name, cur_p, 4);
|
||||
atom_offset = scan_aac_findatom(aac_fp, file_size,
|
||||
atom_name, atom_length);
|
||||
if (atom_offset == -1) {
|
||||
return -1;
|
||||
}
|
||||
DPRINTF(E_SPAM,L_SCAN,"Found %s atom at off %ld.\n",
|
||||
atom_name, ftell(aac_fp) - 8);
|
||||
if ((end_p - cur_p) < 4) {
|
||||
return -1;
|
||||
}
|
||||
strncpy(atom_name, cur_p, 4);
|
||||
atom_offset = scan_aac_findatom(aac_fp, file_size,
|
||||
atom_name, atom_length);
|
||||
if (atom_offset == -1) {
|
||||
return -1;
|
||||
}
|
||||
DPRINTF(E_SPAM,L_SCAN,"Found %s atom at off %ld.\n",
|
||||
atom_name, ftell(aac_fp) - 8);
|
||||
|
||||
cur_p = strchr(cur_p, ':');
|
||||
if (cur_p != NULL) {
|
||||
cur_p++;
|
||||
cur_p = strchr(cur_p, ':');
|
||||
if (cur_p != NULL) {
|
||||
cur_p++;
|
||||
|
||||
/* FIXME
|
||||
* Hack to deal with atoms that have extra data in addition
|
||||
* to having child atoms. This should be dealt in a better fashion
|
||||
* than this (table with skip offsets or a real mp4 parser.) */
|
||||
if (!strcmp(atom_name, "meta")) {
|
||||
fseek(aac_fp, 4, SEEK_CUR);
|
||||
} else if (!strcmp(atom_name, "stsd")) {
|
||||
fseek(aac_fp, 8, SEEK_CUR);
|
||||
} else if (!strcmp(atom_name, "mp4a")) {
|
||||
fseek(aac_fp, 28, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
/* FIXME
|
||||
* Hack to deal with atoms that have extra data in addition
|
||||
* to having child atoms. This should be dealt in a better fashion
|
||||
* than this (table with skip offsets or a real mp4 parser.) */
|
||||
if (!strcmp(atom_name, "meta")) {
|
||||
fseek(aac_fp, 4, SEEK_CUR);
|
||||
} else if (!strcmp(atom_name, "stsd")) {
|
||||
fseek(aac_fp, 8, SEEK_CUR);
|
||||
} else if (!strcmp(atom_name, "mp4a")) {
|
||||
fseek(aac_fp, 28, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ftell(aac_fp) - 8;
|
||||
@ -123,30 +125,30 @@ off_t scan_aac_drilltoatom(FILE *aac_fp,char *atom_path,
|
||||
* @param atom_size this will hold the size of the atom found
|
||||
*/
|
||||
long scan_aac_findatom(FILE *fin, long max_offset,
|
||||
char *which_atom, unsigned int *atom_size) {
|
||||
char *which_atom, unsigned int *atom_size) {
|
||||
long current_offset=0;
|
||||
int size;
|
||||
char atom[4];
|
||||
|
||||
while(current_offset < max_offset) {
|
||||
if(fread((void*)&size,1,sizeof(int),fin) != sizeof(int))
|
||||
return -1;
|
||||
if(fread((void*)&size,1,sizeof(int),fin) != sizeof(int))
|
||||
return -1;
|
||||
|
||||
size=ntohl(size);
|
||||
size=ntohl(size);
|
||||
|
||||
if(size <= 7) /* something not right */
|
||||
return -1;
|
||||
if(size <= 7) /* something not right */
|
||||
return -1;
|
||||
|
||||
if(fread(atom,1,4,fin) != 4)
|
||||
return -1;
|
||||
if(fread(atom,1,4,fin) != 4)
|
||||
return -1;
|
||||
|
||||
if(strncasecmp(atom,which_atom,4) == 0) {
|
||||
*atom_size=size;
|
||||
return current_offset;
|
||||
}
|
||||
if(strncasecmp(atom,which_atom,4) == 0) {
|
||||
*atom_size=size;
|
||||
return current_offset;
|
||||
}
|
||||
|
||||
fseek(fin,size-8,SEEK_CUR);
|
||||
current_offset+=size;
|
||||
fseek(fin,size-8,SEEK_CUR);
|
||||
current_offset+=size;
|
||||
}
|
||||
|
||||
return -1;
|
||||
@ -181,8 +183,8 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) {
|
||||
|
||||
|
||||
if(!(fin=fopen(filename,"rb"))) {
|
||||
DPRINTF(E_INF,L_SCAN,"Cannot open file %s for reading\n",filename);
|
||||
return FALSE;
|
||||
DPRINTF(E_INF,L_SCAN,"Cannot open file %s for reading\n",filename);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fseek(fin,0,SEEK_END);
|
||||
@ -192,86 +194,86 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) {
|
||||
|
||||
atom_offset=scan_aac_drilltoatom(fin, "moov:udta:meta:ilst", &atom_length);
|
||||
if(atom_offset != -1) {
|
||||
/* found the tag section - need to walk through now */
|
||||
/* found the tag section - need to walk through now */
|
||||
|
||||
while(current_offset < atom_length) {
|
||||
if(fread((void*)¤t_size,1,sizeof(int),fin) != sizeof(int))
|
||||
break;
|
||||
|
||||
current_size=ntohl(current_size);
|
||||
|
||||
if(current_size <= 7) /* something not right */
|
||||
break;
|
||||
while(current_offset < (long)atom_length) {
|
||||
if(fread((void*)¤t_size,1,sizeof(int),fin) != sizeof(int))
|
||||
break;
|
||||
|
||||
current_size=ntohl(current_size);
|
||||
|
||||
if(current_size <= 7) /* something not right */
|
||||
break;
|
||||
|
||||
if(fread(current_atom,1,4,fin) != 4)
|
||||
break;
|
||||
|
||||
len=current_size-7; /* for ill-formed too-short tags */
|
||||
if(len < 22)
|
||||
len=22;
|
||||
if(fread(current_atom,1,4,fin) != 4)
|
||||
break;
|
||||
|
||||
len=current_size-7; /* for ill-formed too-short tags */
|
||||
if(len < 22)
|
||||
len=22;
|
||||
|
||||
current_data=(char*)malloc(len); /* extra byte */
|
||||
memset(current_data,0x00,len);
|
||||
current_data=(char*)malloc(len); /* extra byte */
|
||||
memset(current_data,0x00,len);
|
||||
|
||||
if(fread(current_data,1,current_size-8,fin) != current_size-8)
|
||||
break;
|
||||
if(fread(current_data,1,current_size-8,fin) != current_size-8)
|
||||
break;
|
||||
|
||||
if(!memcmp(current_atom,"\xA9" "nam",4)) { /* Song name */
|
||||
pmp3->title=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "ART",4)) {
|
||||
pmp3->artist=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "alb",4)) {
|
||||
pmp3->album=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "cmt",4)) {
|
||||
pmp3->comment=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "wrt",4)) {
|
||||
pmp3->composer=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "grp",4)) {
|
||||
pmp3->grouping=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "gen",4)) {
|
||||
/* can this be a winamp genre??? */
|
||||
pmp3->genre=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"tmpo",4)) {
|
||||
us_data=*((unsigned short *)¤t_data[16]);
|
||||
us_data=ntohs(us_data);
|
||||
pmp3->bpm=us_data;
|
||||
} else if(!memcmp(current_atom,"trkn",4)) {
|
||||
us_data=*((unsigned short *)¤t_data[18]);
|
||||
us_data=ntohs(us_data);
|
||||
if(!memcmp(current_atom,"\xA9" "nam",4)) { /* Song name */
|
||||
pmp3->title=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "ART",4)) {
|
||||
pmp3->artist=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "alb",4)) {
|
||||
pmp3->album=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "cmt",4)) {
|
||||
pmp3->comment=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "wrt",4)) {
|
||||
pmp3->composer=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "grp",4)) {
|
||||
pmp3->grouping=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"\xA9" "gen",4)) {
|
||||
/* can this be a winamp genre??? */
|
||||
pmp3->genre=strdup((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"tmpo",4)) {
|
||||
us_data=*((unsigned short *)¤t_data[16]);
|
||||
us_data=ntohs(us_data);
|
||||
pmp3->bpm=us_data;
|
||||
} else if(!memcmp(current_atom,"trkn",4)) {
|
||||
us_data=*((unsigned short *)¤t_data[18]);
|
||||
us_data=ntohs(us_data);
|
||||
|
||||
pmp3->track=us_data;
|
||||
pmp3->track=us_data;
|
||||
|
||||
us_data=*((unsigned short *)¤t_data[20]);
|
||||
us_data=ntohs(us_data);
|
||||
us_data=*((unsigned short *)¤t_data[20]);
|
||||
us_data=ntohs(us_data);
|
||||
|
||||
pmp3->total_tracks=us_data;
|
||||
} else if(!memcmp(current_atom,"disk",4)) {
|
||||
us_data=*((unsigned short *)¤t_data[18]);
|
||||
us_data=ntohs(us_data);
|
||||
pmp3->total_tracks=us_data;
|
||||
} else if(!memcmp(current_atom,"disk",4)) {
|
||||
us_data=*((unsigned short *)¤t_data[18]);
|
||||
us_data=ntohs(us_data);
|
||||
|
||||
pmp3->disc=us_data;
|
||||
pmp3->disc=us_data;
|
||||
|
||||
us_data=*((unsigned short *)¤t_data[20]);
|
||||
us_data=ntohs(us_data);
|
||||
us_data=*((unsigned short *)¤t_data[20]);
|
||||
us_data=ntohs(us_data);
|
||||
|
||||
pmp3->total_discs=us_data;
|
||||
} else if(!memcmp(current_atom,"\xA9" "day",4)) {
|
||||
pmp3->year=atoi((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"gnre",4)) {
|
||||
genre=(int)(*((char*)¤t_data[17]));
|
||||
genre--;
|
||||
|
||||
if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN))
|
||||
genre=WINAMP_GENRE_UNKNOWN;
|
||||
pmp3->total_discs=us_data;
|
||||
} else if(!memcmp(current_atom,"\xA9" "day",4)) {
|
||||
pmp3->year=atoi((char*)¤t_data[16]);
|
||||
} else if(!memcmp(current_atom,"gnre",4)) {
|
||||
genre=(int)(*((char*)¤t_data[17]));
|
||||
genre--;
|
||||
|
||||
if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN))
|
||||
genre=WINAMP_GENRE_UNKNOWN;
|
||||
|
||||
pmp3->genre=strdup(scan_winamp_genre[genre]);
|
||||
} else if (!memcmp(current_atom, "cpil", 4)) {
|
||||
pmp3->compilation = current_data[16];
|
||||
}
|
||||
pmp3->genre=strdup(scan_winamp_genre[genre]);
|
||||
} else if (!memcmp(current_atom, "cpil", 4)) {
|
||||
pmp3->compilation = current_data[16];
|
||||
}
|
||||
|
||||
free(current_data);
|
||||
current_offset+=current_size;
|
||||
}
|
||||
free(current_data);
|
||||
current_offset+=current_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* got the tag info, now let's get bitrate, etc */
|
||||
@ -280,97 +282,97 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) {
|
||||
fseek(fin, 4, SEEK_CUR);
|
||||
fread((void *)&time, sizeof(int), 1, fin);
|
||||
time = ntohl(time);
|
||||
pmp3->time_added = scan_aac_mac_to_unix_time(time);
|
||||
pmp3->time_added = (int)scan_aac_mac_to_unix_time(time);
|
||||
|
||||
fread((void *)&time, sizeof(int), 1, fin);
|
||||
time = ntohl(time);
|
||||
pmp3->time_modified = scan_aac_mac_to_unix_time(time);
|
||||
fread((void*)&sample_size,1,sizeof(int),fin);
|
||||
fread((void*)&samples,1,sizeof(int),fin);
|
||||
pmp3->time_modified = (int)scan_aac_mac_to_unix_time(time);
|
||||
fread((void*)&sample_size,1,sizeof(int),fin);
|
||||
fread((void*)&samples,1,sizeof(int),fin);
|
||||
|
||||
sample_size=ntohl(sample_size);
|
||||
samples=ntohl(samples);
|
||||
sample_size=ntohl(sample_size);
|
||||
samples=ntohl(samples);
|
||||
|
||||
/* avoid overflowing on large sample_sizes (90000) */
|
||||
ms=1000;
|
||||
while((ms > 9) && (!(sample_size % 10))) {
|
||||
sample_size /= 10;
|
||||
ms /= 10;
|
||||
}
|
||||
/* avoid overflowing on large sample_sizes (90000) */
|
||||
ms=1000;
|
||||
while((ms > 9) && (!(sample_size % 10))) {
|
||||
sample_size /= 10;
|
||||
ms /= 10;
|
||||
}
|
||||
|
||||
/* DWB: use ms time instead of sec */
|
||||
pmp3->song_length=(int)((samples * ms) / sample_size);
|
||||
DPRINTF(E_DBG,L_SCAN,"Song length: %d seconds\n",
|
||||
pmp3->song_length / 1000);
|
||||
/* DWB: use ms time instead of sec */
|
||||
pmp3->song_length=(int)((samples * ms) / sample_size);
|
||||
DPRINTF(E_DBG,L_SCAN,"Song length: %d seconds\n",
|
||||
pmp3->song_length / 1000);
|
||||
}
|
||||
|
||||
pmp3->bitrate = 0;
|
||||
|
||||
/* see if it is aac or alac */
|
||||
atom_offset = scan_aac_drilltoatom(fin,
|
||||
"moov:trak:mdia:minf:stbl:stsd:alac",
|
||||
&atom_length);
|
||||
"moov:trak:mdia:minf:stbl:stsd:alac",
|
||||
&atom_length);
|
||||
|
||||
if(atom_offset != -1) {
|
||||
/* should we still pull samplerate, etc from the this atom? */
|
||||
if(pmp3->codectype) {
|
||||
free(pmp3->codectype);
|
||||
}
|
||||
pmp3->codectype=strdup("alac");
|
||||
/* should we still pull samplerate, etc from the this atom? */
|
||||
if(pmp3->codectype) {
|
||||
free(pmp3->codectype);
|
||||
}
|
||||
pmp3->codectype=strdup("alac");
|
||||
}
|
||||
|
||||
/* Get the sample rate from the 'mp4a' atom (timescale). This is also
|
||||
found in the 'mdhd' atom which is a bit closer but we need to
|
||||
navigate to the 'mp4a' atom anyways to get to the 'esds' atom. */
|
||||
atom_offset=scan_aac_drilltoatom(fin,
|
||||
"moov:trak:mdia:minf:stbl:stsd:mp4a",
|
||||
&atom_length);
|
||||
"moov:trak:mdia:minf:stbl:stsd:mp4a",
|
||||
&atom_length);
|
||||
if (atom_offset != -1) {
|
||||
fseek(fin, atom_offset + 32, SEEK_SET);
|
||||
fseek(fin, atom_offset + 32, SEEK_SET);
|
||||
|
||||
/* Timescale here seems to be 2 bytes here (the 2 bytes before it are
|
||||
* "reserved") though the timescale in the 'mdhd' atom is 4. Not sure
|
||||
* how this is dealt with when sample rate goes higher than 64K. */
|
||||
fread(buffer, sizeof(unsigned char), 2, fin);
|
||||
/* Timescale here seems to be 2 bytes here (the 2 bytes before it are
|
||||
* "reserved") though the timescale in the 'mdhd' atom is 4. Not sure
|
||||
* how this is dealt with when sample rate goes higher than 64K. */
|
||||
fread(buffer, sizeof(unsigned char), 2, fin);
|
||||
|
||||
pmp3->samplerate = (buffer[0] << 8) | (buffer[1]);
|
||||
pmp3->samplerate = (buffer[0] << 8) | (buffer[1]);
|
||||
|
||||
/* Seek to end of atom. */
|
||||
fseek(fin, 2, SEEK_CUR);
|
||||
/* Seek to end of atom. */
|
||||
fseek(fin, 2, SEEK_CUR);
|
||||
|
||||
/* Get the bit rate from the 'esds' atom. We are already positioned
|
||||
in the parent atom so just scan ahead. */
|
||||
atom_offset = scan_aac_findatom(fin,
|
||||
atom_length-(ftell(fin)-atom_offset),
|
||||
"esds", &atom_length);
|
||||
/* Get the bit rate from the 'esds' atom. We are already positioned
|
||||
in the parent atom so just scan ahead. */
|
||||
atom_offset = scan_aac_findatom(fin,
|
||||
atom_length-(ftell(fin)-atom_offset),
|
||||
"esds", &atom_length);
|
||||
|
||||
if (atom_offset != -1) {
|
||||
/* Roku Soundbridge seems to believe anything above 320K is
|
||||
* an ALAC encoded m4a. We'll lie on their behalf.
|
||||
*/
|
||||
fseek(fin, atom_offset + 22, SEEK_CUR);
|
||||
fread((void *)&bit_rate, sizeof(unsigned int), 1, fin);
|
||||
pmp3->bitrate = ntohl(bit_rate) / 1000;
|
||||
DPRINTF(E_DBG,L_SCAN,"esds bitrate: %d\n",pmp3->bitrate);
|
||||
if (atom_offset != -1) {
|
||||
/* Roku Soundbridge seems to believe anything above 320K is
|
||||
* an ALAC encoded m4a. We'll lie on their behalf.
|
||||
*/
|
||||
fseek(fin, atom_offset + 22, SEEK_CUR);
|
||||
fread((void *)&bit_rate, sizeof(unsigned int), 1, fin);
|
||||
pmp3->bitrate = ntohl(bit_rate) / 1000;
|
||||
DPRINTF(E_DBG,L_SCAN,"esds bitrate: %d\n",pmp3->bitrate);
|
||||
|
||||
if(pmp3->bitrate > 320) {
|
||||
pmp3->bitrate = 320;
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_SCAN, "Couldn't find 'esds' atom for bit rate.\n");
|
||||
}
|
||||
if(pmp3->bitrate > 320) {
|
||||
pmp3->bitrate = 320;
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_SCAN, "Couldn't find 'esds' atom for bit rate.\n");
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_SCAN, "Couldn't find 'mp4a' atom for sample rate.\n");
|
||||
DPRINTF(E_DBG,L_SCAN, "Couldn't find 'mp4a' atom for sample rate.\n");
|
||||
}
|
||||
|
||||
/* Fallback if we can't find the info in the atoms. */
|
||||
if (pmp3->bitrate == 0) {
|
||||
/* calculate bitrate from song length... Kinda cheesy */
|
||||
DPRINTF(E_DBG,L_SCAN, "Guesstimating bit rate.\n");
|
||||
atom_offset=scan_aac_drilltoatom(fin,"mdat",&atom_length);
|
||||
if ((atom_offset != -1) && (pmp3->song_length)) {
|
||||
pmp3->bitrate = atom_length / ((pmp3->song_length / 1000) * 128);
|
||||
}
|
||||
/* calculate bitrate from song length... Kinda cheesy */
|
||||
DPRINTF(E_DBG,L_SCAN, "Guesstimating bit rate.\n");
|
||||
atom_offset=scan_aac_drilltoatom(fin,"mdat",&atom_length);
|
||||
if ((atom_offset != -1) && (pmp3->song_length)) {
|
||||
pmp3->bitrate = atom_length / ((pmp3->song_length / 1000) * 128);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fin);
|
||||
|
174
src/scan-flac.c
174
src/scan-flac.c
@ -49,12 +49,12 @@
|
||||
#include <FLAC/metadata.h>
|
||||
|
||||
|
||||
#define GET_VORBIS_COMMENT(comment, name, len) (char*) \
|
||||
#define GET_VORBIS_COMMENT(comment, name, len) (char*) \
|
||||
(((strncasecmp(name, (char*)(comment).entry, strlen(name)) == 0) && \
|
||||
((comment).entry[strlen(name)] == '=')) ? \
|
||||
((*(len) = (comment).length - (strlen(name) + 1)), \
|
||||
(&((comment).entry[strlen(name) + 1]))) : \
|
||||
NULL)
|
||||
((comment).entry[strlen(name)] == '=')) ? \
|
||||
((*(len) = (comment).length - (strlen(name) + 1)), \
|
||||
(&((comment).entry[strlen(name) + 1]))) : \
|
||||
NULL)
|
||||
|
||||
/**
|
||||
* scan a flac file for metainfo.
|
||||
@ -77,8 +77,8 @@ int scan_get_flacinfo(char *filename, MP3FILE *pmp3) {
|
||||
|
||||
/* get file length */
|
||||
if (!(f = fopen(filename, "rb"))) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n", filename);
|
||||
return FALSE;
|
||||
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n", filename);
|
||||
return FALSE;
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
pmp3->file_size = ftell(f);
|
||||
@ -87,103 +87,103 @@ int scan_get_flacinfo(char *filename, MP3FILE *pmp3) {
|
||||
|
||||
chain = FLAC__metadata_chain_new();
|
||||
if (! chain) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Cannot allocate FLAC metadata chain\n");
|
||||
DPRINTF(E_WARN,L_SCAN,"Cannot allocate FLAC metadata chain\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (! FLAC__metadata_chain_read(chain, filename)) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Cannot read FLAC metadata from %s\n", filename);
|
||||
FLAC__metadata_chain_delete(chain);
|
||||
return FALSE;
|
||||
DPRINTF(E_WARN,L_SCAN,"Cannot read FLAC metadata from %s\n", filename);
|
||||
FLAC__metadata_chain_delete(chain);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
iterator = FLAC__metadata_iterator_new();
|
||||
if (! iterator) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Cannot allocate FLAC metadata iterator\n");
|
||||
FLAC__metadata_chain_delete(chain);
|
||||
return FALSE;
|
||||
DPRINTF(E_WARN,L_SCAN,"Cannot allocate FLAC metadata iterator\n");
|
||||
FLAC__metadata_chain_delete(chain);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FLAC__metadata_iterator_init(iterator, chain);
|
||||
do {
|
||||
block = FLAC__metadata_iterator_get_block(iterator);
|
||||
block = FLAC__metadata_iterator_get_block(iterator);
|
||||
|
||||
if (block->type == FLAC__METADATA_TYPE_STREAMINFO) {
|
||||
sec = (unsigned int)(block->data.stream_info.total_samples /
|
||||
block->data.stream_info.sample_rate);
|
||||
ms = (unsigned int)(((block->data.stream_info.total_samples %
|
||||
block->data.stream_info.sample_rate) * 1000) /
|
||||
block->data.stream_info.sample_rate);
|
||||
if ((sec == 0) && (ms == 0))
|
||||
break; /* Info is crap, escape div-by-zero. */
|
||||
pmp3->song_length = (sec * 1000) + ms;
|
||||
pmp3->bitrate = (pmp3->file_size) / (((sec * 1000) + ms) / 8);
|
||||
pmp3->samplerate = block->data.stream_info.sample_rate;
|
||||
if (block->type == FLAC__METADATA_TYPE_STREAMINFO) {
|
||||
sec = (unsigned int)(block->data.stream_info.total_samples /
|
||||
block->data.stream_info.sample_rate);
|
||||
ms = (unsigned int)(((block->data.stream_info.total_samples %
|
||||
block->data.stream_info.sample_rate) * 1000) /
|
||||
block->data.stream_info.sample_rate);
|
||||
if ((sec == 0) && (ms == 0))
|
||||
break; /* Info is crap, escape div-by-zero. */
|
||||
pmp3->song_length = (sec * 1000) + ms;
|
||||
pmp3->bitrate = (pmp3->file_size) / (((sec * 1000) + ms) / 8);
|
||||
pmp3->samplerate = block->data.stream_info.sample_rate;
|
||||
|
||||
found |= 1;
|
||||
if(found == 3)
|
||||
break;
|
||||
}
|
||||
found |= 1;
|
||||
if(found == 3)
|
||||
break;
|
||||
}
|
||||
|
||||
if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
|
||||
for (i = 0; i < block->data.vorbis_comment.num_comments; i++) {
|
||||
if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"ARTIST", &len))) {
|
||||
if ((pmp3->artist = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->artist, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"TITLE", &len))) {
|
||||
if ((pmp3->title = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->title, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"ALBUM", &len))) {
|
||||
if ((pmp3->album = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->album, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"GENRE", &len))) {
|
||||
if ((pmp3->genre = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->genre, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"COMPOSER", &len))) {
|
||||
if ((pmp3->composer = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->composer, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"COMMENT", &len))) {
|
||||
if ((pmp3->comment = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->comment, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"TRACKNUMBER", &len))) {
|
||||
tmp = *(val + len);
|
||||
*(val + len) = '\0';
|
||||
pmp3->track = atoi(val);
|
||||
*(val + len) = tmp;
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"DISCNUMBER", &len))) {
|
||||
tmp = *(val + len);
|
||||
*(val + len) = '\0';
|
||||
pmp3->disc = atoi(val);
|
||||
*(val + len) = tmp;
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"YEAR", &len))) {
|
||||
tmp = *(val + len);
|
||||
*(val + len) = '\0';
|
||||
pmp3->year = atoi(val);
|
||||
*(val + len) = tmp;
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"DATE", &len))) {
|
||||
tmp = *(val + len);
|
||||
*(val + len) = '\0';
|
||||
pmp3->year = atoi(val);
|
||||
*(val + len) = tmp;
|
||||
}
|
||||
}
|
||||
found |= 2;
|
||||
if(found == 3)
|
||||
break;
|
||||
}
|
||||
if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
|
||||
for (i = 0; i < block->data.vorbis_comment.num_comments; i++) {
|
||||
if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"ARTIST", &len))) {
|
||||
if ((pmp3->artist = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->artist, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"TITLE", &len))) {
|
||||
if ((pmp3->title = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->title, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"ALBUM", &len))) {
|
||||
if ((pmp3->album = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->album, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"GENRE", &len))) {
|
||||
if ((pmp3->genre = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->genre, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"COMPOSER", &len))) {
|
||||
if ((pmp3->composer = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->composer, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"COMMENT", &len))) {
|
||||
if ((pmp3->comment = calloc(len + 1, 1)) != NULL)
|
||||
strncpy(pmp3->comment, val, len);
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"TRACKNUMBER", &len))) {
|
||||
tmp = *(val + len);
|
||||
*(val + len) = '\0';
|
||||
pmp3->track = atoi(val);
|
||||
*(val + len) = tmp;
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"DISCNUMBER", &len))) {
|
||||
tmp = *(val + len);
|
||||
*(val + len) = '\0';
|
||||
pmp3->disc = atoi(val);
|
||||
*(val + len) = tmp;
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"YEAR", &len))) {
|
||||
tmp = *(val + len);
|
||||
*(val + len) = '\0';
|
||||
pmp3->year = atoi(val);
|
||||
*(val + len) = tmp;
|
||||
} else if ((val = GET_VORBIS_COMMENT(block->data.vorbis_comment.comments[i],
|
||||
"DATE", &len))) {
|
||||
tmp = *(val + len);
|
||||
*(val + len) = '\0';
|
||||
pmp3->year = atoi(val);
|
||||
*(val + len) = tmp;
|
||||
}
|
||||
}
|
||||
found |= 2;
|
||||
if(found == 3)
|
||||
break;
|
||||
}
|
||||
} while (FLAC__metadata_iterator_next(iterator));
|
||||
|
||||
if (!found) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Cannot find FLAC metadata in %s\n", filename);
|
||||
DPRINTF(E_WARN,L_SCAN,"Cannot find FLAC metadata in %s\n", filename);
|
||||
}
|
||||
|
||||
FLAC__metadata_iterator_delete(iterator);
|
||||
|
@ -35,6 +35,12 @@
|
||||
#include "err.h"
|
||||
#include "mp3-scanner.h"
|
||||
|
||||
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
|
||||
# define _PACKED __attribute((packed))
|
||||
#else
|
||||
# define _PACKED
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Struct to keep info about the information gleaned from
|
||||
* the mp3 frame header.
|
||||
@ -59,13 +65,15 @@ typedef struct tag_scan_frameinfo {
|
||||
int is_valid;
|
||||
} SCAN_FRAMEINFO;
|
||||
|
||||
|
||||
/* This should take take of win32 and gcc, any others? */
|
||||
#pragma pack(1)
|
||||
typedef struct tag_scan_id3header {
|
||||
unsigned char id[3];
|
||||
unsigned char version[2];
|
||||
unsigned char flags;
|
||||
unsigned char size[4];
|
||||
} __attribute((packed)) SCAN_ID3HEADER;
|
||||
} _PACKED SCAN_ID3HEADER;
|
||||
#pragma pack()
|
||||
|
||||
/*
|
||||
* Globals
|
||||
@ -342,7 +350,6 @@ int scan_mp3_get_mp3tags(char *file, MP3FILE *pmp3) {
|
||||
} else {
|
||||
utf8_text=(char *)id3_ucs4_utf8duplicate(native_text);
|
||||
}
|
||||
MEMNOTIFY(utf8_text);
|
||||
|
||||
if(!strcmp(pid3frame->id,"TIT2")) { /* Title */
|
||||
used=1;
|
||||
@ -462,7 +469,6 @@ int scan_mp3_get_mp3tags(char *file, MP3FILE *pmp3) {
|
||||
utf8_text=(char*)id3_ucs4_utf8duplicate(native_text);
|
||||
if(utf8_text) {
|
||||
pmp3->comment=utf8_text;
|
||||
MEMNOTIFY(pmp3->comment);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -26,7 +26,9 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "err.h"
|
||||
#include "mp3-scanner.h"
|
||||
@ -84,7 +86,7 @@ int scan_get_mp4info(char *filename, MP3FILE *pmp3) {
|
||||
if(atom_offset != -1) {
|
||||
/* found the tag section - need to walk through now */
|
||||
|
||||
while(current_offset < atom_length) {
|
||||
while(current_offset < (long) atom_length) {
|
||||
if(fread((void*)¤t_size,1,sizeof(int),fin) != sizeof(int))
|
||||
break;
|
||||
|
||||
@ -170,11 +172,11 @@ int scan_get_mp4info(char *filename, MP3FILE *pmp3) {
|
||||
fseek(fin, 4, SEEK_CUR);
|
||||
fread((void *)&time, sizeof(int), 1, fin);
|
||||
time = ntohl(time);
|
||||
pmp3->time_added = scan_aac_mac_to_unix_time(time);
|
||||
pmp3->time_added = (int) scan_aac_mac_to_unix_time(time);
|
||||
|
||||
fread((void *)&time, sizeof(int), 1, fin);
|
||||
time = ntohl(time);
|
||||
pmp3->time_modified = scan_aac_mac_to_unix_time(time);
|
||||
pmp3->time_modified = (int) scan_aac_mac_to_unix_time(time);
|
||||
fread((void*)&sample_size,1,sizeof(int),fin);
|
||||
fread((void*)&samples,1,sizeof(int),fin);
|
||||
|
||||
|
@ -33,61 +33,61 @@ int scan_get_ogginfo(char *filename, MP3FILE *pmp3) {
|
||||
f = fopen(filename, "rb");
|
||||
if (f == NULL) {
|
||||
DPRINTF(E_FATAL, L_SCAN,
|
||||
"Error opening input file \"%s\": %s\n", filename,
|
||||
strerror(errno));
|
||||
"Error opening input file \"%s\": %s\n", filename,
|
||||
strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!fseek(f,0,SEEK_END)) {
|
||||
pmp3->file_size=ftell(f);
|
||||
fseek(f,0,SEEK_SET);
|
||||
pmp3->file_size=ftell(f);
|
||||
fseek(f,0,SEEK_SET);
|
||||
}
|
||||
|
||||
if (ov_open(f, &vf, NULL, 0) != 0) {
|
||||
fclose(f);
|
||||
fclose(f);
|
||||
DPRINTF(E_FATAL, L_SCAN,
|
||||
"Error opening Vorbis stream in \"%s\"\n", filename);
|
||||
"Error opening Vorbis stream in \"%s\"\n", filename);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
vi=ov_info(&vf,-1);
|
||||
if(vi) {
|
||||
DPRINTF(E_DBG,L_SCAN," Bitrates: %d %d %d\n",vi->bitrate_upper,
|
||||
vi->bitrate_nominal,vi->bitrate_lower);
|
||||
if(vi->bitrate_nominal) {
|
||||
pmp3->bitrate=vi->bitrate_nominal / 1000;
|
||||
} else if(vi->bitrate_upper) {
|
||||
pmp3->bitrate=vi->bitrate_upper / 1000;
|
||||
} else if(vi->bitrate_lower) {
|
||||
pmp3->bitrate=vi->bitrate_lower / 1000;
|
||||
}
|
||||
DPRINTF(E_DBG,L_SCAN," Bitrates: %d %d %d\n",vi->bitrate_upper,
|
||||
vi->bitrate_nominal,vi->bitrate_lower);
|
||||
if(vi->bitrate_nominal) {
|
||||
pmp3->bitrate=vi->bitrate_nominal / 1000;
|
||||
} else if(vi->bitrate_upper) {
|
||||
pmp3->bitrate=vi->bitrate_upper / 1000;
|
||||
} else if(vi->bitrate_lower) {
|
||||
pmp3->bitrate=vi->bitrate_lower / 1000;
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_SCAN," Bitrates: %d",pmp3->bitrate);
|
||||
pmp3->samplerate=vi->rate;
|
||||
DPRINTF(E_DBG,L_SCAN," Bitrates: %d",pmp3->bitrate);
|
||||
pmp3->samplerate=vi->rate;
|
||||
}
|
||||
|
||||
pmp3->song_length=ov_time_total(&vf,-1) * 1000;
|
||||
|
||||
comment = ov_comment(&vf, -1);
|
||||
if (comment != NULL) {
|
||||
if ((val = vorbis_comment_query(comment, "artist", 0)) != NULL)
|
||||
pmp3->artist = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "title", 0)) != NULL)
|
||||
pmp3->title = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "album", 0)) != NULL)
|
||||
pmp3->album = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "genre", 0)) != NULL)
|
||||
pmp3->genre = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "composer", 0)) != NULL)
|
||||
pmp3->composer = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "comment", 0)) != NULL)
|
||||
pmp3->comment = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "tracknumber", 0)) != NULL)
|
||||
pmp3->track = atoi(val);
|
||||
if ((val = vorbis_comment_query(comment, "discnumber", 0)) != NULL)
|
||||
pmp3->disc = atoi(val);
|
||||
if ((val = vorbis_comment_query(comment, "year", 0)) != NULL)
|
||||
pmp3->year = atoi(val);
|
||||
if ((val = vorbis_comment_query(comment, "artist", 0)) != NULL)
|
||||
pmp3->artist = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "title", 0)) != NULL)
|
||||
pmp3->title = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "album", 0)) != NULL)
|
||||
pmp3->album = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "genre", 0)) != NULL)
|
||||
pmp3->genre = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "composer", 0)) != NULL)
|
||||
pmp3->composer = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "comment", 0)) != NULL)
|
||||
pmp3->comment = strdup(val);
|
||||
if ((val = vorbis_comment_query(comment, "tracknumber", 0)) != NULL)
|
||||
pmp3->track = atoi(val);
|
||||
if ((val = vorbis_comment_query(comment, "discnumber", 0)) != NULL)
|
||||
pmp3->disc = atoi(val);
|
||||
if ((val = vorbis_comment_query(comment, "year", 0)) != NULL)
|
||||
pmp3->year = atoi(val);
|
||||
}
|
||||
ov_clear(&vf);
|
||||
/*fclose(f);*/
|
||||
|
@ -47,31 +47,31 @@ int scan_get_urlinfo(char *filename, MP3FILE *pmp3) {
|
||||
DPRINTF(E_DBG,L_SCAN,"Getting URL file info\n");
|
||||
|
||||
if(!(infile=fopen(filename,"rb"))) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n",filename);
|
||||
return FALSE;
|
||||
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n",filename);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fgets(linebuffer,sizeof(linebuffer),infile);
|
||||
while((linebuffer[strlen(linebuffer)-1] == '\n') ||
|
||||
(linebuffer[strlen(linebuffer)-1] == '\r')) {
|
||||
linebuffer[strlen(linebuffer)-1] = '\0';
|
||||
(linebuffer[strlen(linebuffer)-1] == '\r')) {
|
||||
linebuffer[strlen(linebuffer)-1] = '\0';
|
||||
}
|
||||
|
||||
head=linebuffer;
|
||||
tail=strchr(head,',');
|
||||
if(!tail) {
|
||||
DPRINTF(E_LOG,L_SCAN,"Badly formatted .url file - must be bitrate,descr,url\n");
|
||||
fclose(infile);
|
||||
return FALSE;
|
||||
DPRINTF(E_LOG,L_SCAN,"Badly formatted .url file - must be bitrate,descr,url\n");
|
||||
fclose(infile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pmp3->bitrate=atoi(head);
|
||||
head=++tail;
|
||||
tail=strchr(head,',');
|
||||
if(!tail) {
|
||||
DPRINTF(E_LOG,L_SCAN,"Badly formatted .url file - must be bitrate,descr,url\n");
|
||||
fclose(infile);
|
||||
return FALSE;
|
||||
DPRINTF(E_LOG,L_SCAN,"Badly formatted .url file - must be bitrate,descr,url\n");
|
||||
fclose(infile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*tail++='\0';
|
||||
|
@ -30,13 +30,13 @@
|
||||
#include "err.h"
|
||||
#include "mp3-scanner.h"
|
||||
|
||||
#define GET_WAV_INT32(p) ((((unsigned long)((p)[3])) << 24) | \
|
||||
(((unsigned long)((p)[2])) << 16) | \
|
||||
(((unsigned long)((p)[1])) << 8) | \
|
||||
(((unsigned long)((p)[0]))))
|
||||
#define GET_WAV_INT32(p) ((((unsigned long)((p)[3])) << 24) | \
|
||||
(((unsigned long)((p)[2])) << 16) | \
|
||||
(((unsigned long)((p)[1])) << 8) | \
|
||||
(((unsigned long)((p)[0]))))
|
||||
|
||||
#define GET_WAV_INT16(p) ((((unsigned long)((p)[1])) << 8) | \
|
||||
(((unsigned long)((p)[0]))))
|
||||
#define GET_WAV_INT16(p) ((((unsigned long)((p)[1])) << 8) | \
|
||||
(((unsigned long)((p)[0]))))
|
||||
|
||||
/**
|
||||
* Get info from the actual wav headers. Since there is no
|
||||
@ -64,8 +64,8 @@ int scan_get_wavinfo(char *filename, MP3FILE *pmp3) {
|
||||
DPRINTF(E_DBG,L_SCAN,"Getting WAV file info\n");
|
||||
|
||||
if(!(infile=fopen(filename,"rb"))) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n",filename);
|
||||
return FALSE;
|
||||
DPRINTF(E_WARN,L_SCAN,"Could not open %s for reading\n",filename);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fseek(infile,0,SEEK_END);
|
||||
@ -75,15 +75,15 @@ int scan_get_wavinfo(char *filename, MP3FILE *pmp3) {
|
||||
rl = fread(hdr, 1, 44, infile);
|
||||
fclose(infile);
|
||||
if (rl != 44) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Could not read wav header from %s\n",filename);
|
||||
DPRINTF(E_WARN,L_SCAN,"Could not read wav header from %s\n",filename);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (strncmp((char*)hdr + 0, "RIFF", 4) ||
|
||||
strncmp((char*)hdr + 8, "WAVE", 4) ||
|
||||
strncmp((char*)hdr + 12, "fmt ", 4) ||
|
||||
strncmp((char*)hdr + 36, "data", 4)) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Invalid wav header in %s\n",filename);
|
||||
strncmp((char*)hdr + 8, "WAVE", 4) ||
|
||||
strncmp((char*)hdr + 12, "fmt ", 4) ||
|
||||
strncmp((char*)hdr + 36, "data", 4)) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Invalid wav header in %s\n",filename);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -96,9 +96,9 @@ int scan_get_wavinfo(char *filename, MP3FILE *pmp3) {
|
||||
data_length = GET_WAV_INT32(hdr + 40);
|
||||
|
||||
if ((format_data_length != 16) ||
|
||||
(compression_code != 1) ||
|
||||
(channel_count < 1)) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Invalid wav header in %s\n",filename);
|
||||
(compression_code != 1) ||
|
||||
(channel_count < 1)) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Invalid wav header in %s\n",filename);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
486
src/scan-wma.c
486
src/scan-wma.c
@ -221,22 +221,28 @@ WMA_GUID wma_guidlist[] = {
|
||||
{ NULL, NULL, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" }
|
||||
};
|
||||
|
||||
#define PACKED __attribute__((packed))
|
||||
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
|
||||
# define _PACKED __attribute((packed))
|
||||
#else
|
||||
# define _PACKED
|
||||
#endif
|
||||
#define MAYBEFREE(x) { free((x)); }
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct tag_wma_header {
|
||||
unsigned char objectid[16];
|
||||
unsigned long long size;
|
||||
unsigned int objects;
|
||||
char reserved1;
|
||||
char reserved2;
|
||||
} PACKED WMA_HEADER;
|
||||
|
||||
|
||||
} _PACKED WMA_HEADER;
|
||||
|
||||
|
||||
typedef struct tag_wma_subheader {
|
||||
unsigned char objectid[16];
|
||||
long long size;
|
||||
} PACKED WMA_SUBHEADER;
|
||||
} _PACKED WMA_SUBHEADER;
|
||||
#pragma pack()
|
||||
|
||||
/*
|
||||
* Forwards
|
||||
@ -256,7 +262,7 @@ int wma_parse_file_properteis(int fd,int size, MP3FILE *pmp3);
|
||||
*/
|
||||
int wma_file_read_short(int fd, unsigned short int *psi) {
|
||||
if(r_read(fd,(void*)psi,sizeof(unsigned short int)) != sizeof(unsigned short int)) {
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*psi = wma_convert_short((unsigned char *)psi);
|
||||
@ -268,7 +274,7 @@ int wma_file_read_short(int fd, unsigned short int *psi) {
|
||||
*/
|
||||
int wma_file_read_int(int fd, unsigned int *pi) {
|
||||
if(r_read(fd,(void*)pi,sizeof(unsigned int)) != sizeof(unsigned int)) {
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pi = wma_convert_int((unsigned char *)pi);
|
||||
@ -280,7 +286,7 @@ int wma_file_read_int(int fd, unsigned int *pi) {
|
||||
*/
|
||||
int wma_file_read_ll(int fd, unsigned long long *pll) {
|
||||
if(r_read(fd,(void*)pll,sizeof(unsigned long long)) != sizeof(unsigned long long)) {
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pll = wma_convert_ll((unsigned char *)pll);
|
||||
@ -296,10 +302,10 @@ int wma_file_read_utf16(int fd, int len, char **utf8) {
|
||||
|
||||
utf16=(unsigned char*)malloc(len);
|
||||
if(!utf16)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
if(r_read(fd,utf16,len) != len)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
out = wma_utf16toutf8(utf16,len);
|
||||
*utf8 = out;
|
||||
@ -311,10 +317,10 @@ int wma_file_read_utf16(int fd, int len, char **utf8) {
|
||||
int wma_file_read_bytes(int fd,int len, unsigned char **data) {
|
||||
*data = (unsigned char *)malloc(len);
|
||||
if(!*data)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
if(r_read(fd,*data,len) != len)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -344,98 +350,98 @@ int wma_parse_extended_content_description(int fd,int size, MP3FILE *pmp3) {
|
||||
DPRINTF(E_DBG,L_SCAN,"Reading extended content description object\n");
|
||||
|
||||
if(!wma_file_read_short(fd, &descriptor_count))
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
|
||||
for(index = 0; index < descriptor_count; index++) {
|
||||
if(!wma_file_read_short(fd,&descriptor_name_len)) return -1;
|
||||
if(!wma_file_read_utf16(fd,descriptor_name_len,&descriptor_name)) return -1;
|
||||
if(!wma_file_read_short(fd,&descriptor_value_type)) {
|
||||
free(descriptor_name);
|
||||
return FALSE;
|
||||
}
|
||||
if(!wma_file_read_short(fd,&descriptor_value_len)) {
|
||||
free(descriptor_name);
|
||||
return FALSE;
|
||||
}
|
||||
if(!wma_file_read_short(fd,&descriptor_name_len)) return -1;
|
||||
if(!wma_file_read_utf16(fd,descriptor_name_len,&descriptor_name)) return -1;
|
||||
if(!wma_file_read_short(fd,&descriptor_value_type)) {
|
||||
free(descriptor_name);
|
||||
return FALSE;
|
||||
}
|
||||
if(!wma_file_read_short(fd,&descriptor_value_len)) {
|
||||
free(descriptor_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_SCAN,"Found descriptor: %s\n", descriptor_name);
|
||||
DPRINTF(E_DBG,L_SCAN,"Found descriptor: %s\n", descriptor_name);
|
||||
|
||||
/* see what kind it is */
|
||||
switch(descriptor_value_type) {
|
||||
case 0x0000: /* string */
|
||||
if(!wma_file_read_utf16(fd,descriptor_value_len,
|
||||
&descriptor_byte_value)) {
|
||||
fail=1;
|
||||
}
|
||||
DPRINTF(E_DBG,L_SCAN,"Type: string, value: %s\n",descriptor_byte_value);
|
||||
break;
|
||||
case 0x0001: /* byte array */
|
||||
if(!wma_file_read_bytes(fd,descriptor_value_len,
|
||||
(unsigned char **)&descriptor_byte_value)){
|
||||
fail=1;
|
||||
}
|
||||
DPRINTF(E_DBG,L_SCAN,"Type: bytes\n");
|
||||
break;
|
||||
case 0x0002: /* bool - dropthru */
|
||||
case 0x0003: /* dword */
|
||||
if(!wma_file_read_int(fd,&descriptor_int_value)) fail=1;
|
||||
DPRINTF(E_DBG,L_SCAN,"Type: int, value: %d\n",descriptor_int_value);
|
||||
break;
|
||||
case 0x0004: /* qword */
|
||||
if(!wma_file_read_ll(fd,&descriptor_ll_value)) fail=1;
|
||||
DPRINTF(E_DBG,L_SCAN,"Type: ll, value: %lld\n",descriptor_ll_value);
|
||||
break;
|
||||
case 0x0005: /* word */
|
||||
if(!wma_file_read_short(fd,&descriptor_short_value)) fail=1;
|
||||
DPRINTF(E_DBG,L_SCAN,"type: short, value %d\n",descriptor_short_value);
|
||||
break;
|
||||
}
|
||||
/* see what kind it is */
|
||||
switch(descriptor_value_type) {
|
||||
case 0x0000: /* string */
|
||||
if(!wma_file_read_utf16(fd,descriptor_value_len,
|
||||
&descriptor_byte_value)) {
|
||||
fail=1;
|
||||
}
|
||||
DPRINTF(E_DBG,L_SCAN,"Type: string, value: %s\n",descriptor_byte_value);
|
||||
break;
|
||||
case 0x0001: /* byte array */
|
||||
if(!wma_file_read_bytes(fd,descriptor_value_len,
|
||||
(unsigned char **)&descriptor_byte_value)){
|
||||
fail=1;
|
||||
}
|
||||
DPRINTF(E_DBG,L_SCAN,"Type: bytes\n");
|
||||
break;
|
||||
case 0x0002: /* bool - dropthru */
|
||||
case 0x0003: /* dword */
|
||||
if(!wma_file_read_int(fd,&descriptor_int_value)) fail=1;
|
||||
DPRINTF(E_DBG,L_SCAN,"Type: int, value: %d\n",descriptor_int_value);
|
||||
break;
|
||||
case 0x0004: /* qword */
|
||||
if(!wma_file_read_ll(fd,&descriptor_ll_value)) fail=1;
|
||||
DPRINTF(E_DBG,L_SCAN,"Type: ll, value: %lld\n",descriptor_ll_value);
|
||||
break;
|
||||
case 0x0005: /* word */
|
||||
if(!wma_file_read_short(fd,&descriptor_short_value)) fail=1;
|
||||
DPRINTF(E_DBG,L_SCAN,"type: short, value %d\n",descriptor_short_value);
|
||||
break;
|
||||
}
|
||||
|
||||
if(fail) {
|
||||
free(descriptor_name);
|
||||
return FALSE;
|
||||
}
|
||||
if(fail) {
|
||||
free(descriptor_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* do stuff with what we found */
|
||||
if(strcasecmp(descriptor_name,"wm/genre")==0) {
|
||||
MAYBEFREE(pmp3->genre);
|
||||
pmp3->genre = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL; /* don't free it! */
|
||||
} else if(strcasecmp(descriptor_name,"wm/albumtitle")==0) {
|
||||
MAYBEFREE(pmp3->album);
|
||||
pmp3->album = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL;
|
||||
} else if(strcasecmp(descriptor_name,"wm/track")==0) {
|
||||
pmp3->track = descriptor_int_value + 1;
|
||||
} else if(strcasecmp(descriptor_name,"wm/tracknumber")==0) {
|
||||
pmp3->track = descriptor_int_value;
|
||||
} else if(strcasecmp(descriptor_name,"wm/year")==0) {
|
||||
pmp3->year = atoi(descriptor_byte_value);
|
||||
} else if(strcasecmp(descriptor_name,"wm/composer")==0) {
|
||||
MAYBEFREE(pmp3->composer);
|
||||
pmp3->composer = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL;
|
||||
} else if(strcasecmp(descriptor_name,"wm/albumartist")==0) {
|
||||
MAYBEFREE(pmp3->artist);
|
||||
pmp3->artist = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL;
|
||||
} else if(strcasecmp(descriptor_name,"wm/contengroupdescription")==0) {
|
||||
MAYBEFREE(pmp3->grouping);
|
||||
pmp3->grouping = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL;
|
||||
} else if(strcasecmp(descriptor_name,"comment")==0) {
|
||||
MAYBEFREE(pmp3->comment);
|
||||
pmp3->comment = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL;
|
||||
}
|
||||
/* do stuff with what we found */
|
||||
if(strcasecmp(descriptor_name,"wm/genre")==0) {
|
||||
MAYBEFREE(pmp3->genre);
|
||||
pmp3->genre = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL; /* don't free it! */
|
||||
} else if(strcasecmp(descriptor_name,"wm/albumtitle")==0) {
|
||||
MAYBEFREE(pmp3->album);
|
||||
pmp3->album = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL;
|
||||
} else if(strcasecmp(descriptor_name,"wm/track")==0) {
|
||||
pmp3->track = descriptor_int_value + 1;
|
||||
} else if(strcasecmp(descriptor_name,"wm/tracknumber")==0) {
|
||||
pmp3->track = descriptor_int_value;
|
||||
} else if(strcasecmp(descriptor_name,"wm/year")==0) {
|
||||
pmp3->year = atoi(descriptor_byte_value);
|
||||
} else if(strcasecmp(descriptor_name,"wm/composer")==0) {
|
||||
MAYBEFREE(pmp3->composer);
|
||||
pmp3->composer = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL;
|
||||
} else if(strcasecmp(descriptor_name,"wm/albumartist")==0) {
|
||||
MAYBEFREE(pmp3->artist);
|
||||
pmp3->artist = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL;
|
||||
} else if(strcasecmp(descriptor_name,"wm/contengroupdescription")==0) {
|
||||
MAYBEFREE(pmp3->grouping);
|
||||
pmp3->grouping = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL;
|
||||
} else if(strcasecmp(descriptor_name,"comment")==0) {
|
||||
MAYBEFREE(pmp3->comment);
|
||||
pmp3->comment = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL;
|
||||
}
|
||||
|
||||
/* cleanup - done with this round */
|
||||
if(descriptor_byte_value) {
|
||||
free(descriptor_byte_value);
|
||||
descriptor_byte_value = NULL;
|
||||
}
|
||||
/* cleanup - done with this round */
|
||||
if(descriptor_byte_value) {
|
||||
free(descriptor_byte_value);
|
||||
descriptor_byte_value = NULL;
|
||||
}
|
||||
|
||||
free(descriptor_name);
|
||||
free(descriptor_name);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -456,47 +462,47 @@ int wma_parse_content_description(int fd,int size, MP3FILE *pmp3) {
|
||||
char *utf8;
|
||||
|
||||
if(size < 10) /* must be at least enough room for the size block */
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
|
||||
for(index=0; index < 5; index++) {
|
||||
if(!wma_file_read_short(fd,&sizes[index]))
|
||||
return FALSE;
|
||||
if(!wma_file_read_short(fd,&sizes[index]))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for(index=0;index<5;index++) {
|
||||
if(sizes[index]) {
|
||||
if(!wma_file_read_utf16(fd,sizes[index],&utf8))
|
||||
return FALSE;
|
||||
if(sizes[index]) {
|
||||
if(!wma_file_read_utf16(fd,sizes[index],&utf8))
|
||||
return FALSE;
|
||||
|
||||
DPRINTF(E_DBG,L_SCAN,"Got item of length %d: %s\n",sizes[index],utf8);
|
||||
|
||||
switch(index) {
|
||||
case 0: /* title */
|
||||
if(pmp3->title)
|
||||
free(pmp3->title);
|
||||
pmp3->title = utf8;
|
||||
break;
|
||||
case 1: /* author */
|
||||
if(pmp3->artist)
|
||||
free(pmp3->artist);
|
||||
pmp3->artist = utf8;
|
||||
break;
|
||||
case 2: /* copyright - dontcare */
|
||||
free(utf8);
|
||||
break;
|
||||
case 3: /* description */
|
||||
if(pmp3->comment)
|
||||
free(pmp3->comment);
|
||||
pmp3->comment = utf8;
|
||||
break;
|
||||
case 4: /* rating - dontcare */
|
||||
free(utf8);
|
||||
break;
|
||||
default: /* can't get here */
|
||||
DPRINTF(E_FATAL,L_SCAN,"This is not my beautiful wife.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
DPRINTF(E_DBG,L_SCAN,"Got item of length %d: %s\n",sizes[index],utf8);
|
||||
|
||||
switch(index) {
|
||||
case 0: /* title */
|
||||
if(pmp3->title)
|
||||
free(pmp3->title);
|
||||
pmp3->title = utf8;
|
||||
break;
|
||||
case 1: /* author */
|
||||
if(pmp3->artist)
|
||||
free(pmp3->artist);
|
||||
pmp3->artist = utf8;
|
||||
break;
|
||||
case 2: /* copyright - dontcare */
|
||||
free(utf8);
|
||||
break;
|
||||
case 3: /* description */
|
||||
if(pmp3->comment)
|
||||
free(pmp3->comment);
|
||||
pmp3->comment = utf8;
|
||||
break;
|
||||
case 4: /* rating - dontcare */
|
||||
free(utf8);
|
||||
break;
|
||||
default: /* can't get here */
|
||||
DPRINTF(E_FATAL,L_SCAN,"This is not my beautiful wife.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -523,19 +529,19 @@ int wma_parse_file_properties(int fd,int size, MP3FILE *pmp3) {
|
||||
lseek(fd,40,SEEK_CUR);
|
||||
|
||||
if(!wma_file_read_ll(fd, &play_duration))
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
|
||||
if(!wma_file_read_ll(fd, &send_duration))
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
|
||||
if(!wma_file_read_ll(fd, &preroll))
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
|
||||
/* I'm not entirely certain what preroll is, but it seems
|
||||
* to make it match up with what windows thinks is the song
|
||||
* length.
|
||||
*/
|
||||
pmp3->song_length = ((int) (play_duration / 10000)) - preroll;
|
||||
pmp3->song_length = ((int)play_duration / 10000) - (int)preroll;
|
||||
|
||||
/* skip flags(4),
|
||||
* min_packet_size (4), max_packet_size(4)
|
||||
@ -543,7 +549,7 @@ int wma_parse_file_properties(int fd,int size, MP3FILE *pmp3) {
|
||||
|
||||
lseek(fd,12,SEEK_CUR);
|
||||
if(!wma_file_read_int(fd,&max_bitrate))
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
|
||||
pmp3->bitrate = max_bitrate/1000;
|
||||
|
||||
@ -573,59 +579,59 @@ char *wma_utf16toutf8(unsigned char *utf16, int len) {
|
||||
int bytes;
|
||||
|
||||
if(!len)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
utf8=(char *)malloc(len*2 + 1);
|
||||
if(!utf8)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
memset(utf8,0x0,len*2 + 1);
|
||||
dst=utf8;
|
||||
|
||||
while((src+2) <= utf16+len) {
|
||||
w1=src[1] << 8 | src[0];
|
||||
src += 2;
|
||||
if((w1 & 0xFC00) == 0xD800) { /* could be surrogate pair */
|
||||
if(src+2 > utf16+len) {
|
||||
DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
|
||||
free(utf8);
|
||||
return NULL;
|
||||
}
|
||||
w2 = src[3] << 8 | src[2];
|
||||
if((w2 & 0xFC00) != 0xDC00) {
|
||||
DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
|
||||
free(utf8);
|
||||
return NULL;
|
||||
}
|
||||
w1=src[1] << 8 | src[0];
|
||||
src += 2;
|
||||
if((w1 & 0xFC00) == 0xD800) { /* could be surrogate pair */
|
||||
if(src+2 > utf16+len) {
|
||||
DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
|
||||
free(utf8);
|
||||
return NULL;
|
||||
}
|
||||
w2 = src[3] << 8 | src[2];
|
||||
if((w2 & 0xFC00) != 0xDC00) {
|
||||
DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
|
||||
free(utf8);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get bottom 10 of each */
|
||||
w1 = w1 & 0x03FF;
|
||||
w1 = w1 << 10;
|
||||
w1 = w1 | (w2 & 0x03FF);
|
||||
/* get bottom 10 of each */
|
||||
w1 = w1 & 0x03FF;
|
||||
w1 = w1 << 10;
|
||||
w1 = w1 | (w2 & 0x03FF);
|
||||
|
||||
/* add back the 0x10000 */
|
||||
w1 += 0x10000;
|
||||
}
|
||||
/* add back the 0x10000 */
|
||||
w1 += 0x10000;
|
||||
}
|
||||
|
||||
/* now encode the original code point in utf-8 */
|
||||
if (w1 < 0x80) {
|
||||
*dst++ = w1;
|
||||
bytes=0;
|
||||
} else if (w1 < 0x800) {
|
||||
*dst++ = 0xC0 | (w1 >> 6);
|
||||
bytes=1;
|
||||
} else if (w1 < 0x10000) {
|
||||
*dst++ = 0xE0 | (w1 >> 12);
|
||||
bytes=2;
|
||||
} else {
|
||||
*dst++ = 0xF0 | (w1 >> 18);
|
||||
bytes=3;
|
||||
}
|
||||
/* now encode the original code point in utf-8 */
|
||||
if (w1 < 0x80) {
|
||||
*dst++ = w1;
|
||||
bytes=0;
|
||||
} else if (w1 < 0x800) {
|
||||
*dst++ = 0xC0 | (w1 >> 6);
|
||||
bytes=1;
|
||||
} else if (w1 < 0x10000) {
|
||||
*dst++ = 0xE0 | (w1 >> 12);
|
||||
bytes=2;
|
||||
} else {
|
||||
*dst++ = 0xF0 | (w1 >> 18);
|
||||
bytes=3;
|
||||
}
|
||||
|
||||
while(bytes) {
|
||||
*dst++ = 0x80 | ((w1 >> (6*bytes)) & 0x3f);
|
||||
bytes--;
|
||||
}
|
||||
while(bytes) {
|
||||
*dst++ = 0x80 | ((w1 >> (6*bytes)) & 0x3f);
|
||||
bytes--;
|
||||
}
|
||||
}
|
||||
|
||||
return utf8;
|
||||
@ -640,11 +646,11 @@ WMA_GUID *wma_find_guid(unsigned char *guid) {
|
||||
WMA_GUID *pguid = wma_guidlist;
|
||||
|
||||
while((pguid->name) && (memcmp(guid,pguid->value,16) != 0)) {
|
||||
pguid++;
|
||||
pguid++;
|
||||
}
|
||||
|
||||
if(!pguid->name)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
return pguid;
|
||||
}
|
||||
@ -656,7 +662,7 @@ WMA_GUID *wma_find_guid(unsigned char *guid) {
|
||||
*/
|
||||
unsigned short wma_convert_short(unsigned char *src) {
|
||||
return src[1] << 8 |
|
||||
src[0];
|
||||
src[0];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -666,9 +672,9 @@ unsigned short wma_convert_short(unsigned char *src) {
|
||||
*/
|
||||
unsigned int wma_convert_int(unsigned char *src) {
|
||||
return src[3] << 24 |
|
||||
src[2] << 16 |
|
||||
src[1] << 8 |
|
||||
src[0];
|
||||
src[2] << 16 |
|
||||
src[1] << 8 |
|
||||
src[0];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -682,14 +688,14 @@ unsigned long long wma_convert_ll(unsigned char *src) {
|
||||
unsigned long long retval;
|
||||
|
||||
tmp_hi = src[7] << 24 |
|
||||
src[6] << 16 |
|
||||
src[5] << 8 |
|
||||
src[4];
|
||||
src[6] << 16 |
|
||||
src[5] << 8 |
|
||||
src[4];
|
||||
|
||||
tmp_lo = src[3] << 24 |
|
||||
src[2] << 16 |
|
||||
src[1] << 8 |
|
||||
src[0];
|
||||
src[2] << 16 |
|
||||
src[1] << 8 |
|
||||
src[0];
|
||||
|
||||
retval = tmp_hi;
|
||||
retval = (retval << 32) | tmp_lo;
|
||||
@ -715,23 +721,23 @@ int scan_get_wmainfo(char *filename, MP3FILE *pmp3) {
|
||||
|
||||
wma_fd = r_open2(filename,O_RDONLY);
|
||||
if(wma_fd == -1) {
|
||||
DPRINTF(E_INF,L_SCAN,"Error opening WMA file (%s): %s\n",filename,
|
||||
strerror(errno));
|
||||
return FALSE;
|
||||
DPRINTF(E_INF,L_SCAN,"Error opening WMA file (%s): %s\n",filename,
|
||||
strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(read(wma_fd,(void*)&hdr,sizeof(hdr)) != sizeof(hdr)) {
|
||||
DPRINTF(E_INF,L_SCAN,"Error reading from %s: %s\n",filename,
|
||||
strerror(errno));
|
||||
r_close(wma_fd);
|
||||
return FALSE;
|
||||
DPRINTF(E_INF,L_SCAN,"Error reading from %s: %s\n",filename,
|
||||
strerror(errno));
|
||||
r_close(wma_fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pguid = wma_find_guid(hdr.objectid);
|
||||
if(!pguid) {
|
||||
DPRINTF(E_INF,L_SCAN,"Could not find header in %s\n",filename);
|
||||
r_close(wma_fd);
|
||||
return FALSE;
|
||||
DPRINTF(E_INF,L_SCAN,"Could not find header in %s\n",filename);
|
||||
r_close(wma_fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hdr.objects=wma_convert_int((unsigned char *)&hdr.objects);
|
||||
@ -747,56 +753,56 @@ int scan_get_wmainfo(char *filename, MP3FILE *pmp3) {
|
||||
* find anything interesting
|
||||
*/
|
||||
|
||||
for(item=0; item < hdr.objects; item++) {
|
||||
if(lseek(wma_fd,offset,SEEK_SET) == (off_t)-1) {
|
||||
DPRINTF(E_INF,L_SCAN,"Error seeking in %s\n",filename);
|
||||
r_close(wma_fd);
|
||||
return FALSE;
|
||||
}
|
||||
for(item=0; item < (int) hdr.objects; item++) {
|
||||
if(lseek(wma_fd,offset,SEEK_SET) == (off_t)-1) {
|
||||
DPRINTF(E_INF,L_SCAN,"Error seeking in %s\n",filename);
|
||||
r_close(wma_fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(r_read(wma_fd,(void*)&subhdr,sizeof(subhdr)) != sizeof(subhdr)) {
|
||||
err=errno;
|
||||
DPRINTF(E_INF,L_SCAN,"Error reading from %s: %s\n",filename,
|
||||
strerror(err));
|
||||
r_close(wma_fd);
|
||||
return FALSE;
|
||||
}
|
||||
if(r_read(wma_fd,(void*)&subhdr,sizeof(subhdr)) != sizeof(subhdr)) {
|
||||
err=errno;
|
||||
DPRINTF(E_INF,L_SCAN,"Error reading from %s: %s\n",filename,
|
||||
strerror(err));
|
||||
r_close(wma_fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
subhdr.size=wma_convert_ll((unsigned char *)&subhdr.size);
|
||||
subhdr.size=wma_convert_ll((unsigned char *)&subhdr.size);
|
||||
|
||||
pguid = wma_find_guid(subhdr.objectid);
|
||||
if(pguid) {
|
||||
DPRINTF(E_DBG,L_SCAN,"Found subheader: %s\n",pguid->name);
|
||||
if(strcmp(pguid->name,"ASF_Content_Description_Object")==0) {
|
||||
res &= wma_parse_content_description(wma_fd,subhdr.size,pmp3);
|
||||
} else if (strcmp(pguid->name,"ASF_Extended_Content_Description_Object")==0) {
|
||||
res &= wma_parse_extended_content_description(wma_fd,subhdr.size,pmp3);
|
||||
} else if (strcmp(pguid->name,"ASF_File_Properties_Object")==0) {
|
||||
res &= wma_parse_file_properties(wma_fd,subhdr.size,pmp3);
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_SCAN,"Unknown subheader: %02hhx%02hhx%02hhx%02hhx-"
|
||||
"%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
|
||||
"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
|
||||
subhdr.objectid[3],subhdr.objectid[2],
|
||||
subhdr.objectid[1],subhdr.objectid[0],
|
||||
subhdr.objectid[5],subhdr.objectid[4],
|
||||
subhdr.objectid[7],subhdr.objectid[6],
|
||||
subhdr.objectid[8],subhdr.objectid[9],
|
||||
subhdr.objectid[10],subhdr.objectid[11],
|
||||
subhdr.objectid[12],subhdr.objectid[13],
|
||||
subhdr.objectid[14],subhdr.objectid[15]);
|
||||
pguid = wma_find_guid(subhdr.objectid);
|
||||
if(pguid) {
|
||||
DPRINTF(E_DBG,L_SCAN,"Found subheader: %s\n",pguid->name);
|
||||
if(strcmp(pguid->name,"ASF_Content_Description_Object")==0) {
|
||||
res &= wma_parse_content_description(wma_fd,(int)subhdr.size,pmp3);
|
||||
} else if (strcmp(pguid->name,"ASF_Extended_Content_Description_Object")==0) {
|
||||
res &= wma_parse_extended_content_description(wma_fd,(int)subhdr.size,pmp3);
|
||||
} else if (strcmp(pguid->name,"ASF_File_Properties_Object")==0) {
|
||||
res &= wma_parse_file_properties(wma_fd,(int)subhdr.size,pmp3);
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_SCAN,"Unknown subheader: %02hhx%02hhx%02hhx%02hhx-"
|
||||
"%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
|
||||
"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
|
||||
subhdr.objectid[3],subhdr.objectid[2],
|
||||
subhdr.objectid[1],subhdr.objectid[0],
|
||||
subhdr.objectid[5],subhdr.objectid[4],
|
||||
subhdr.objectid[7],subhdr.objectid[6],
|
||||
subhdr.objectid[8],subhdr.objectid[9],
|
||||
subhdr.objectid[10],subhdr.objectid[11],
|
||||
subhdr.objectid[12],subhdr.objectid[13],
|
||||
subhdr.objectid[14],subhdr.objectid[15]);
|
||||
|
||||
}
|
||||
offset += subhdr.size;
|
||||
}
|
||||
offset += (long) subhdr.size;
|
||||
}
|
||||
|
||||
|
||||
if(!res) {
|
||||
DPRINTF(E_INF,L_SCAN,"Error reading meta info for file %s\n",
|
||||
filename);
|
||||
DPRINTF(E_INF,L_SCAN,"Error reading meta info for file %s\n",
|
||||
filename);
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_SCAN,"Successfully parsed file\n");
|
||||
DPRINTF(E_DBG,L_SCAN,"Successfully parsed file\n");
|
||||
}
|
||||
|
||||
r_close(wma_fd);
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "mp3-scanner.h"
|
||||
#include "rxml.h"
|
||||
#include "redblack.h"
|
||||
#include "strptime.h"
|
||||
|
||||
/* Forwards */
|
||||
int scan_xml_playlist(char *filename);
|
||||
@ -126,7 +127,7 @@ int scan_xml_datedecode(char *string) {
|
||||
|
||||
strptime(string,"%Y-%m-%dT%H:%M:%SZ",&date_time);
|
||||
seconds = timegm(&date_time);
|
||||
return seconds;
|
||||
return (int)seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,7 +205,7 @@ int scan_xml_translate_path(char *pold, char *pnew) {
|
||||
DPRINTF(E_DBG,L_SCAN,"Trying %s\n",base_path);
|
||||
if(scan_xml_is_file(base_path)) {
|
||||
path_found=1;
|
||||
discard = (current - working_path);
|
||||
discard = (int)(current - working_path);
|
||||
DPRINTF(E_DBG,L_SCAN,"Found it!\n");
|
||||
}
|
||||
*current='\0';
|
||||
|
@ -140,28 +140,28 @@ int main(int argc, char *argv[]) {
|
||||
memset((void*)&mp3,0x00,sizeof(MP3FILE));
|
||||
|
||||
if(strchr(argv[0],'/')) {
|
||||
av0 = strrchr(argv[0],'/')+1;
|
||||
av0 = strrchr(argv[0],'/')+1;
|
||||
} else {
|
||||
av0 = argv[0];
|
||||
av0 = argv[0];
|
||||
}
|
||||
|
||||
while((option = getopt(argc, argv, "d:")) != -1) {
|
||||
switch(option) {
|
||||
case 'd':
|
||||
err_debuglevel = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"Error: unknown option (%c)\n\n",option);
|
||||
usage(-1);
|
||||
}
|
||||
switch(option) {
|
||||
case 'd':
|
||||
err_debuglevel = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"Error: unknown option (%c)\n\n",option);
|
||||
usage(-1);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if(argc == 0) {
|
||||
fprintf(stderr,"Error: Must specifiy file name\n\n");
|
||||
usage(-1);
|
||||
fprintf(stderr,"Error: Must specifiy file name\n\n");
|
||||
usage(-1);
|
||||
}
|
||||
|
||||
printf("Getting info for %s\n",argv[0]);
|
||||
@ -170,15 +170,15 @@ int main(int argc, char *argv[]) {
|
||||
plist=scanner_list;
|
||||
|
||||
while(plist->ext && (strcasecmp(plist->ext,ext) != 0)) {
|
||||
plist++;
|
||||
plist++;
|
||||
}
|
||||
|
||||
if(plist->ext) {
|
||||
fprintf(stderr,"dispatching as single-file metatag parser\n");
|
||||
plist->scanner(argv[0],&mp3);
|
||||
dump_mp3(&mp3);
|
||||
fprintf(stderr,"dispatching as single-file metatag parser\n");
|
||||
plist->scanner(argv[0],&mp3);
|
||||
dump_mp3(&mp3);
|
||||
} else {
|
||||
fprintf(stderr,"unknown file extension: %s\n",ext);
|
||||
exit(-1);
|
||||
fprintf(stderr,"unknown file extension: %s\n",ext);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
@ -10,11 +10,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "strptime.h"
|
||||
|
||||
#include "err.h"
|
||||
|
||||
typedef struct tag_token {
|
||||
@ -385,7 +391,7 @@ int sp_scan(PARSETREE tree) {
|
||||
while(*(tree->current) && strchr(" \t\n\r",*(tree->current)))
|
||||
tree->current++;
|
||||
|
||||
tree->token_pos = tree->current - tree->term;
|
||||
tree->token_pos = (int) (tree->current - tree->term);
|
||||
|
||||
if(!*(tree->current)) {
|
||||
tree->token.token_id = T_EOF;
|
||||
@ -481,7 +487,7 @@ int sp_scan(PARSETREE tree) {
|
||||
}
|
||||
|
||||
found=0;
|
||||
len = tail - tree->current;
|
||||
len = (int) (tail - tree->current);
|
||||
|
||||
if(!tree->in_string) {
|
||||
/* find it in the token list */
|
||||
@ -1189,16 +1195,16 @@ int sp_node_size(SP_NODE *node) {
|
||||
size += 7; /* (xxx AND xxx) */
|
||||
} else {
|
||||
size = 4; /* parens, plus spaces around op */
|
||||
size += strlen(node->left.field);
|
||||
size += (int) strlen(node->left.field);
|
||||
if((node->op & 0x0FFF) > T_LAST) {
|
||||
DPRINTF(E_FATAL,L_PARSE,"Can't determine node size: op %04x\n",
|
||||
node->op);
|
||||
} else {
|
||||
size += strlen(sp_token_descr[node->op & 0x0FFF]);
|
||||
size += (int) strlen(sp_token_descr[node->op & 0x0FFF]);
|
||||
}
|
||||
|
||||
if(node->op_type == SP_OPTYPE_STRING) {
|
||||
size += (2 + strlen(node->right.cvalue));
|
||||
size += (2 + (int) strlen(node->right.cvalue));
|
||||
if(node->op == T_INCLUDES) {
|
||||
size += 2; /* extra %'s */
|
||||
}
|
||||
@ -1319,7 +1325,7 @@ void sp_set_error(PARSETREE tree, int error) {
|
||||
if(tree->error)
|
||||
free(tree->error);
|
||||
|
||||
len = 10 + (tree->token_pos / 10) + 1 + strlen(sp_errorstrings[error]) + 1;
|
||||
len = 10 + (tree->token_pos / 10) + 1 + (int) strlen(sp_errorstrings[error]) + 1;
|
||||
tree->error = (char*)malloc(len);
|
||||
if(!tree->error) {
|
||||
DPRINTF(E_FATAL,L_PARSE,"Malloc error");
|
||||
|
@ -34,9 +34,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <netinet/in.h> /* htons and friends */
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h> /* why here? For osx 10.2, of course! */
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "daapd.h"
|
||||
#include "db-generic.h"
|
||||
|
@ -28,9 +28,9 @@
|
||||
extern int server_side_convert(char *codectype);
|
||||
extern char *server_side_convert_path(char *path);
|
||||
extern FILE *server_side_convert_open(char *path,
|
||||
off_t offset,
|
||||
unsigned long len_ms,
|
||||
char *codectype);
|
||||
off_t offset,
|
||||
unsigned long len_ms,
|
||||
char *codectype);
|
||||
extern void server_side_convert_close(FILE *f);
|
||||
|
||||
#endif /* _SCC_H_ */
|
||||
|
@ -9,8 +9,8 @@
|
||||
* matching */
|
||||
char * strcasestr(char* haystack, char* needle) {
|
||||
int i;
|
||||
int nlength = strlen (needle);
|
||||
int hlength = strlen (haystack);
|
||||
int nlength = (int) strlen (needle);
|
||||
int hlength = (int) strlen (haystack);
|
||||
|
||||
if (nlength > hlength) return NULL;
|
||||
if (hlength <= 0) return NULL;
|
||||
|
373
src/strptime.c
Normal file
373
src/strptime.c
Normal file
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright (c) 1994 Powerdog Industries. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgement:
|
||||
* This product includes software developed by Powerdog Industries.
|
||||
* 4. The name of Powerdog Industries may not be used to endorse or
|
||||
* promote products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRPTIME
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
|
||||
|
||||
|
||||
#ifndef sun
|
||||
struct dtconv {
|
||||
char *abbrev_month_names[12];
|
||||
char *month_names[12];
|
||||
char *abbrev_weekday_names[7];
|
||||
char *weekday_names[7];
|
||||
char *time_format;
|
||||
char *sdate_format;
|
||||
char *dtime_format;
|
||||
char *am_string;
|
||||
char *pm_string;
|
||||
char *ldate_format;
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct dtconv En_US = {
|
||||
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" },
|
||||
{ "January", "February", "March", "April",
|
||||
"May", "June", "July", "August",
|
||||
"September", "October", "November", "December" },
|
||||
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
|
||||
{ "Sunday", "Monday", "Tuesday", "Wednesday",
|
||||
"Thursday", "Friday", "Saturday" },
|
||||
"%H:%M:%S",
|
||||
"%m/%d/%y",
|
||||
"%a %b %e %T %Z %Y",
|
||||
"AM",
|
||||
"PM",
|
||||
"%A, %B, %e, %Y"
|
||||
};
|
||||
|
||||
#ifdef SUNOS4
|
||||
extern int strncasecmp();
|
||||
#endif
|
||||
|
||||
void lowercase_string(char *buffer) {
|
||||
while(*buffer) {
|
||||
*buffer = tolower(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
char *strptime(char *buf, char *fmt, struct tm *tm) {
|
||||
char c,
|
||||
*ptr;
|
||||
int i, j,
|
||||
len;
|
||||
ptr = fmt;
|
||||
while (*ptr != 0) {
|
||||
if (*buf == 0)
|
||||
break;
|
||||
|
||||
c = *ptr++;
|
||||
|
||||
if (c != '%') {
|
||||
if (isspace(c))
|
||||
while (*buf != 0 && isspace(*buf))
|
||||
buf++;
|
||||
else if (c != *buf++)
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
c = *ptr++;
|
||||
switch (c) {
|
||||
case 0:
|
||||
case '%':
|
||||
if (*buf++ != '%')
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
buf = strptime(buf, En_US.ldate_format, tm);
|
||||
if (buf == 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
buf = strptime(buf, "%x %X", tm);
|
||||
if (buf == 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
buf = strptime(buf, "%m/%d/%y", tm);
|
||||
if (buf == 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
buf = strptime(buf, "%H:%M", tm);
|
||||
if (buf == 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
buf = strptime(buf, "%I:%M:%S %p", tm);
|
||||
if (buf == 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
buf = strptime(buf, "%H:%M:%S", tm);
|
||||
if (buf == 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
buf = strptime(buf, En_US.time_format, tm);
|
||||
if (buf == 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
buf = strptime(buf, En_US.sdate_format, tm);
|
||||
if (buf == 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
if (!isdigit(*buf))
|
||||
return 0;
|
||||
|
||||
for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
}
|
||||
if (i > 365)
|
||||
return 0;
|
||||
|
||||
tm->tm_yday = i;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
case 'S':
|
||||
if (*buf == 0 || isspace(*buf))
|
||||
break;
|
||||
|
||||
if (!isdigit(*buf))
|
||||
return 0;
|
||||
|
||||
for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
}
|
||||
if (i > 59)
|
||||
return 0;
|
||||
|
||||
if (c == 'M')
|
||||
tm->tm_min = i;
|
||||
else
|
||||
tm->tm_sec = i;
|
||||
|
||||
if (*buf != 0 && isspace(*buf))
|
||||
while (*ptr != 0 && !isspace(*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'k':
|
||||
case 'l':
|
||||
if (!isdigit(*buf))
|
||||
return 0;
|
||||
|
||||
for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
}
|
||||
if (c == 'H' || c == 'k') {
|
||||
if (i > 23)
|
||||
return 0;
|
||||
} else if (i > 11)
|
||||
return 0;
|
||||
|
||||
tm->tm_hour = i;
|
||||
|
||||
if (*buf != 0 && isspace(*buf))
|
||||
while (*ptr != 0 && !isspace(*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
len = (int) strlen(En_US.am_string);
|
||||
lowercase_string( buf );
|
||||
|
||||
if (strncmp(buf, En_US.am_string, len) == 0) {
|
||||
if (tm->tm_hour > 12)
|
||||
return 0;
|
||||
if (tm->tm_hour == 12)
|
||||
tm->tm_hour = 0;
|
||||
buf += len;
|
||||
break;
|
||||
}
|
||||
|
||||
len = (int) strlen(En_US.pm_string);
|
||||
|
||||
if (strncmp(buf, En_US.pm_string, len) == 0) {
|
||||
if (tm->tm_hour > 12)
|
||||
return 0;
|
||||
if (tm->tm_hour != 12)
|
||||
tm->tm_hour += 12;
|
||||
buf += len;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case 'A':
|
||||
case 'a':
|
||||
for (i = 0; i < asizeof(En_US.weekday_names); i++) {
|
||||
len = (int) strlen(En_US.weekday_names[i]);
|
||||
|
||||
lowercase_string( buf );
|
||||
|
||||
if (strncmp(buf,
|
||||
En_US.weekday_names[i],
|
||||
len) == 0)
|
||||
break;
|
||||
|
||||
len = (int) strlen(En_US.abbrev_weekday_names[i]);
|
||||
if (strncmp(buf,
|
||||
En_US.abbrev_weekday_names[i],
|
||||
len) == 0)
|
||||
break;
|
||||
}
|
||||
if (i == asizeof(En_US.weekday_names))
|
||||
return 0;
|
||||
|
||||
tm->tm_wday = i;
|
||||
buf += len;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'e':
|
||||
if (!isdigit(*buf))
|
||||
return 0;
|
||||
|
||||
for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
}
|
||||
if (i > 31)
|
||||
return 0;
|
||||
|
||||
tm->tm_mday = i;
|
||||
|
||||
if (*buf != 0 && isspace(*buf))
|
||||
while (*ptr != 0 && !isspace(*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
case 'b':
|
||||
case 'h':
|
||||
for (i = 0; i < asizeof(En_US.month_names); i++) {
|
||||
len = (int) strlen(En_US.month_names[i]);
|
||||
|
||||
lowercase_string( buf );
|
||||
if (strncmp(buf, En_US.month_names[i],len) == 0)
|
||||
break;
|
||||
|
||||
len = (int) strlen(En_US.abbrev_month_names[i]);
|
||||
if (strncmp(buf,
|
||||
En_US.abbrev_month_names[i],
|
||||
len) == 0)
|
||||
break;
|
||||
}
|
||||
if (i == asizeof(En_US.month_names))
|
||||
return 0;
|
||||
|
||||
tm->tm_mon = i;
|
||||
buf += len;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
if (!isdigit(*buf))
|
||||
return 0;
|
||||
|
||||
for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<2; j++,buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
}
|
||||
if (i < 1 || i > 12)
|
||||
return 0;
|
||||
|
||||
tm->tm_mon = i - 1;
|
||||
|
||||
if (*buf != 0 && isspace(*buf))
|
||||
while (*ptr != 0 && !isspace(*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
case 'y':
|
||||
if (*buf == 0 || isspace(*buf))
|
||||
break;
|
||||
|
||||
if (!isdigit(*buf))
|
||||
return 0;
|
||||
|
||||
for (j=0,i = 0; *buf != 0 && isdigit(*buf) && j<((c=='Y')?4:2); j++,buf++) {
|
||||
i *= 10;
|
||||
i += *buf - '0';
|
||||
}
|
||||
|
||||
if (c == 'Y')
|
||||
i -= 1900;
|
||||
else if (i < 69) /*c=='y', 00-68 is for 20xx, the rest is for 19xx*/
|
||||
i += 100;
|
||||
|
||||
if (i < 0)
|
||||
return 0;
|
||||
|
||||
tm->tm_year = i;
|
||||
|
||||
if (*buf != 0 && isspace(*buf))
|
||||
while (*ptr != 0 && !isspace(*ptr))
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif /* ndef HAVE_STRPTIME */
|
39
src/strptime.h
Normal file
39
src/strptime.h
Normal file
@ -0,0 +1,39 @@
|
||||
/******************************************************************************
|
||||
**
|
||||
** Copyright (C) 2001 - the shmoo group -
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it, however, you cannot sell it.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
**
|
||||
** You should have received a copy of the license attached to the
|
||||
** use of this software. If not, visit www.shmoo.com/osiris for
|
||||
** details.
|
||||
**
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
**
|
||||
** The Shmoo Group (TSG)
|
||||
**
|
||||
** File: strptime.h
|
||||
** Author: Brian Wotring
|
||||
**
|
||||
** Date: June 22, 2001.
|
||||
** Project: osiris
|
||||
**
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef STRPTIME_H
|
||||
#define STRPTIME_H
|
||||
|
||||
#ifndef HAVE_STRPTIME
|
||||
char * strptime( char *buf, char *fmt, struct tm *tm );
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
12
src/strsep.c
12
src/strsep.c
@ -8,11 +8,11 @@
|
||||
|
||||
#if !HAVE_STRSEP
|
||||
char *strsep(char **stringp, const char *delim) {
|
||||
char *ret = *stringp;
|
||||
if (ret == NULL) return(NULL); /* grrr */
|
||||
if ((*stringp = strpbrk(*stringp, delim)) != NULL) {
|
||||
*((*stringp)++) = '\0';
|
||||
}
|
||||
return(ret);
|
||||
char *ret = *stringp;
|
||||
if (ret == NULL) return(NULL); /* grrr */
|
||||
if ((*stringp = strpbrk(*stringp, delim)) != NULL) {
|
||||
*((*stringp)++) = '\0';
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
#endif /* !HAVE_STRSEP */
|
||||
|
88
src/strtok_r.c
Normal file
88
src/strtok_r.c
Normal file
@ -0,0 +1,88 @@
|
||||
/* Reentrant string tokenizer. Generic version.
|
||||
Copyright (C) 1991,1996-1999,2001,2004 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRTOK_R
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Parse S into tokens separated by characters in DELIM.
|
||||
If S is NULL, the saved pointer in SAVE_PTR is used as
|
||||
the next starting point. For example:
|
||||
char s[] = "-abc-=-def";
|
||||
char *sp;
|
||||
x = strtok_r(s, "-", &sp); // x = "abc", sp = "=-def"
|
||||
x = strtok_r(NULL, "-=", &sp); // x = "def", sp = NULL
|
||||
x = strtok_r(NULL, "=", &sp); // x = NULL
|
||||
// s = "abc\0-def\0"
|
||||
*/
|
||||
char *strtok_r(char *s, const char *delim, char **last)
|
||||
{
|
||||
char *spanp;
|
||||
int c, sc;
|
||||
char *tok;
|
||||
|
||||
if (s == NULL && (s = *last) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
|
||||
*/
|
||||
cont:
|
||||
c = *s++;
|
||||
for (spanp = (char *)delim; (sc = *spanp++) != 0; ) {
|
||||
if (c == sc) {
|
||||
goto cont;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == 0) { /* no non-delimiter characters */
|
||||
*last = NULL;
|
||||
return NULL;
|
||||
}
|
||||
tok = s - 1;
|
||||
|
||||
/*
|
||||
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
|
||||
* Note that delim must have one NUL; we stop if we see that, too.
|
||||
*/
|
||||
for (;;) {
|
||||
c = *s++;
|
||||
spanp = (char *)delim;
|
||||
do {
|
||||
if ((sc = *spanp++) == c) {
|
||||
if (c == 0) {
|
||||
s = NULL;
|
||||
}
|
||||
else {
|
||||
char *w = s - 1;
|
||||
*w = '\0';
|
||||
}
|
||||
*last = s;
|
||||
return tok;
|
||||
}
|
||||
}
|
||||
while (sc != 0);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
#endif
|
49
src/strtok_r.h
Normal file
49
src/strtok_r.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* Split string into tokens
|
||||
Copyright (C) 2004-2005 Free Software Foundation, Inc.
|
||||
Written by Simon Josefsson.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef _STRTOK_R_H
|
||||
#define _STRTOK_R_H
|
||||
|
||||
/* Parse S into tokens separated by characters in DELIM.
|
||||
If S is NULL, the saved pointer in SAVE_PTR is used as
|
||||
the next starting point. For example:
|
||||
char s[] = "-abc-=-def";
|
||||
char *sp;
|
||||
x = strtok_r(s, "-", &sp); // x = "abc", sp = "=-def"
|
||||
x = strtok_r(NULL, "-=", &sp); // x = "def", sp = NULL
|
||||
x = strtok_r(NULL, "=", &sp); // x = NULL
|
||||
// s = "abc\0-def\0"
|
||||
|
||||
This is a variant of strtok() that is multithread-safe.
|
||||
|
||||
For the POSIX documentation for this function, see:
|
||||
http://www.opengroup.org/susv3xsh/strtok.html
|
||||
|
||||
Caveat: It modifies the original string.
|
||||
Caveat: These functions cannot be used on constant strings.
|
||||
Caveat: The identity of the delimiting character is lost.
|
||||
Caveat: It doesn't work with multibyte strings unless all of the delimiter
|
||||
characters are ASCII characters < 0x30.
|
||||
|
||||
See also strsep().
|
||||
*/
|
||||
#ifndef HAVE_STRTOK_R
|
||||
extern char *strtok_r(char *s, const char *delim, char **last);
|
||||
#endif
|
||||
|
||||
#endif /* _STRTOK_R_H */
|
@ -175,12 +175,12 @@ int u_connect(u_port_t port, char *hostn) {
|
||||
if(inet_addr(hostn) == INADDR_NONE) {
|
||||
phe=gethostbyname(hostn);
|
||||
if(phe == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy((char*)&server.sin_addr,(char*)(phe->h_addr_list[0]),
|
||||
sizeof(struct in_addr));
|
||||
sizeof(struct in_addr));
|
||||
} else {
|
||||
server.sin_addr.s_addr=inet_addr(hostn);
|
||||
}
|
||||
|
127
src/w32-eventlog.c
Normal file
127
src/w32-eventlog.c
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* eventlog messages utility functions
|
||||
*
|
||||
* Copyright (C) 2005-2006 Ron Pedde (ron@pedde.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "messages.h"
|
||||
|
||||
static HANDLE elog_handle = NULL;
|
||||
|
||||
/**
|
||||
* register eventlog functions
|
||||
*
|
||||
* @returns TRUE if successful, FALSE otherwise
|
||||
*/
|
||||
int elog_register(void) {
|
||||
HKEY reg_key = NULL;
|
||||
DWORD err = 0;
|
||||
char path[MAX_PATH];
|
||||
DWORD event_types;
|
||||
|
||||
wsprintf(path,"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s", PACKAGE);
|
||||
if((err=RegCreateKey(HKEY_LOCAL_MACHINE, path, ®_key)) != ERROR_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
GetModuleFileName(NULL, path, MAX_PATH );
|
||||
|
||||
err=RegSetValueEx(reg_key, "EventMessageFile",0,REG_EXPAND_SZ,path,(DWORD)strlen(path) + 1);
|
||||
if(err != ERROR_SUCCESS) {
|
||||
RegCloseKey(reg_key);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
event_types = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
|
||||
err=RegSetValueEx(reg_key,"TypesSupported", 0, REG_DWORD, (BYTE*)&event_types, sizeof event_types );
|
||||
if(err != ERROR_SUCCESS) {
|
||||
RegCloseKey(reg_key);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RegCloseKey(reg_key);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME: ENOTIMPL
|
||||
*/
|
||||
int elog_unregister(void) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize the eventlog
|
||||
*
|
||||
* @returns TRUE if successful, FALSE otherwise
|
||||
*/
|
||||
int elog_init(void) {
|
||||
elog_handle=RegisterEventSource(NULL, PACKAGE);
|
||||
if(elog_handle == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* uninitialize the eventlog
|
||||
*
|
||||
* @returns TRUE
|
||||
*/
|
||||
int elog_deinit(void) {
|
||||
DeregisterEventSource(elog_handle);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* log a message to the event viewer
|
||||
*
|
||||
* @param level event level to log: 0=fatal, 3=warn, > info
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
|
||||
int elog_message(int level, char *msg) {
|
||||
WORD message_level = EVENTLOG_INFORMATION_TYPE;
|
||||
int ret;
|
||||
|
||||
if(level == 0)
|
||||
message_level = EVENTLOG_ERROR_TYPE;
|
||||
|
||||
ret = ReportEvent(
|
||||
elog_handle,
|
||||
message_level,
|
||||
0,
|
||||
EVENT_MSG,
|
||||
NULL,
|
||||
1,
|
||||
0,
|
||||
&msg,
|
||||
NULL);
|
||||
|
||||
/* ReportEvent returns non-zero on success */
|
||||
return ret ? TRUE : FALSE;
|
||||
}
|
32
src/w32-eventlog.h
Normal file
32
src/w32-eventlog.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* eventlog messages utility functions
|
||||
*
|
||||
* Copyright (C) 2005 Ron Pedde (ron.pedde@firstmarkcu.org)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _EVENTLOG_H_
|
||||
#define _EVENTLOG_H_
|
||||
|
||||
extern int elog_register(void);
|
||||
extern int elog_unregister(void);
|
||||
extern int elog_init(void);
|
||||
extern int elog_deinit(void);
|
||||
extern int elog_message(int level, char *msg);
|
||||
|
||||
#endif /* _EVENTLOG_H_ */
|
292
src/w32-service.c
Normal file
292
src/w32-service.c
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* simple service management functions
|
||||
*
|
||||
* Copyright (C) 2005 Ron Pedde (ron.pedde@firstmarkcu.org)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "daapd.h"
|
||||
#include "err.h"
|
||||
|
||||
/* Forwards */
|
||||
BOOL service_update_status (DWORD,DWORD,DWORD,DWORD,DWORD);
|
||||
void service_mainfunc(DWORD, LPTSTR *);
|
||||
void service_init(void);
|
||||
void service_handler(DWORD);
|
||||
|
||||
/* Globals */
|
||||
SERVICE_STATUS_HANDLE service_status_handle = NULL;
|
||||
HANDLE service_kill_event = NULL;
|
||||
DWORD service_current_status;
|
||||
|
||||
/**
|
||||
* handle the stop, start, pause requests, etc.
|
||||
*
|
||||
* @param code action the SCM wants us to take
|
||||
*/
|
||||
void service_handler(DWORD code) {
|
||||
switch(code) {
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
break;
|
||||
|
||||
case SERVICE_CONTROL_SHUTDOWN:
|
||||
// fallthrough
|
||||
|
||||
case SERVICE_CONTROL_STOP:
|
||||
service_update_status(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);
|
||||
SetEvent(service_kill_event);
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
service_update_status(service_current_status, NO_ERROR, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* exit the service as gracefully as possible, returning the error
|
||||
* level specified. I think there are some state machine problems
|
||||
* here, but probably nothing fatal -- an unnecessary call to
|
||||
* xfer_shutdown, maybe. That's about it.
|
||||
*
|
||||
* @param errorlevel errorlevel to return
|
||||
*/
|
||||
void service_shutdown(int errorlevel) {
|
||||
DPRINTF(E_INF,L_MISC,"Service about to terminate with error %d\n",errorlevel);
|
||||
|
||||
if(service_current_status != SERVICE_STOPPED) {
|
||||
service_update_status(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);
|
||||
|
||||
config.stop = 1;
|
||||
service_update_status(SERVICE_STOPPED,errorlevel,0,0,3000);
|
||||
}
|
||||
|
||||
if(service_kill_event) {
|
||||
SetEvent(service_kill_event);
|
||||
CloseHandle(service_kill_event);
|
||||
}
|
||||
|
||||
// exit(errorlevel);
|
||||
/* we'll let the main process exit (or hang!) */
|
||||
Sleep(5000);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The main for the service -- starts up the service and
|
||||
* makes it run. This sits in a tight loop until the service
|
||||
* is shutdown. If this function exits, it's because the
|
||||
* service is stopping.
|
||||
*
|
||||
* @param argc argc as passed from SCM
|
||||
* @param argv argv as passed from SCM
|
||||
*/
|
||||
void service_mainfunc(DWORD argc, LPTSTR *argv) {
|
||||
BOOL success;
|
||||
|
||||
service_current_status = SERVICE_STOPPED;
|
||||
service_status_handle = RegisterServiceCtrlHandler(PACKAGE,
|
||||
(LPHANDLER_FUNCTION) service_handler);
|
||||
|
||||
if(!service_status_handle) {
|
||||
service_shutdown(GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
// Next Notify the Service Control Manager of progress
|
||||
success = service_update_status(SERVICE_START_PENDING, NO_ERROR, 0, 1, 5000);
|
||||
if (!success) {
|
||||
service_shutdown(GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
service_kill_event = CreateEvent (0, TRUE, FALSE, 0);
|
||||
if(!service_kill_event) {
|
||||
service_shutdown(GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME
|
||||
// startup errors generate an ERR_FATAL, which exit()s in the
|
||||
// logging code -- fine for console apps, not so good here.
|
||||
// Generates ugly error messages from the service tool.
|
||||
// (terminated unexpectedly).
|
||||
// xfer_startup();
|
||||
|
||||
// The service is now running. Notify the SCM of this fact.
|
||||
service_current_status = SERVICE_RUNNING;
|
||||
success = service_update_status(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);
|
||||
if (!success) {
|
||||
service_shutdown(GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
// Now just wait for our killed service signal, and then exit, which
|
||||
// terminates the service!
|
||||
WaitForSingleObject (service_kill_event, INFINITE);
|
||||
service_shutdown(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* update the scm service status, so it can make pretty
|
||||
* gui stupidness. light wrapper around SetServiceStatus
|
||||
*
|
||||
* If the visual studio editor wasn't so horribly useless
|
||||
* and munge up the indents, I'd split these parameters
|
||||
* into several lines, but Microsoft apparently can't build
|
||||
* an editor that is as good as that made by volunteers.
|
||||
*
|
||||
* Those who do not understand Unix are condemned to reinvent
|
||||
* it, poorly. -- Henry Spencer
|
||||
*
|
||||
* @param dwCurrentState new service state
|
||||
* @param dwWin32ExitCode exit code if state is SERVICE_STOPPED
|
||||
* @param dwServiceSpecificExitCode specified service exit code
|
||||
* @param dwCheckPoint incremented value for long startups
|
||||
* @param dwWaitHint how to before giving up on the service
|
||||
*
|
||||
* @returns result of SetServiceStatus - true on success
|
||||
*/
|
||||
BOOL service_update_status (DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint, DWORD dwWaitHint) {
|
||||
BOOL success;
|
||||
SERVICE_STATUS serviceStatus;
|
||||
|
||||
service_current_status = dwCurrentState;
|
||||
|
||||
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
serviceStatus.dwCurrentState = dwCurrentState;
|
||||
if (dwCurrentState == SERVICE_START_PENDING) {
|
||||
serviceStatus.dwControlsAccepted = 0;
|
||||
} else {
|
||||
serviceStatus.dwControlsAccepted =
|
||||
SERVICE_ACCEPT_STOP |
|
||||
SERVICE_ACCEPT_SHUTDOWN;
|
||||
}
|
||||
|
||||
if (dwServiceSpecificExitCode == 0) {
|
||||
serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
|
||||
} else {
|
||||
serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
|
||||
}
|
||||
|
||||
serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
|
||||
serviceStatus.dwCheckPoint = dwCheckPoint;
|
||||
serviceStatus.dwWaitHint = dwWaitHint;
|
||||
|
||||
success = SetServiceStatus (service_status_handle, &serviceStatus);
|
||||
if (!success) {
|
||||
SetEvent(service_kill_event);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* kick off the application when in service mdoe - suitable for threadprocing
|
||||
*/
|
||||
void *service_startup(void *arg) {
|
||||
SERVICE_TABLE_ENTRY serviceTable[] = {
|
||||
{ PACKAGE, (LPSERVICE_MAIN_FUNCTION) service_mainfunc },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
BOOL success;
|
||||
|
||||
// Register the service with the Service Control Manager
|
||||
// If it were to fail, what would we do, anyway?
|
||||
success = StartServiceCtrlDispatcher(serviceTable);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* install the service
|
||||
*/
|
||||
void service_register(void) {
|
||||
SC_HANDLE scm;
|
||||
SC_HANDLE svc;
|
||||
char path[MAX_PATH];
|
||||
|
||||
GetModuleFileName(NULL, path, MAX_PATH );
|
||||
|
||||
if(!(scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE))) {
|
||||
DPRINTF(E_FATAL,L_MISC,"Cannot open service control manager\n");
|
||||
}
|
||||
|
||||
svc = CreateService(scm,PACKAGE,SERVICENAME,SERVICE_ALL_ACCESS,
|
||||
SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START,SERVICE_ERROR_NORMAL,
|
||||
path,0,0,0,0,0);
|
||||
if(!svc) {
|
||||
DPRINTF(E_FATAL,L_MISC,"Cannot create service: %d\n",GetLastError());
|
||||
}
|
||||
|
||||
CloseServiceHandle(svc);
|
||||
CloseServiceHandle(scm);
|
||||
|
||||
DPRINTF(E_LOG,L_MISC,"Registered service successfully\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* uninstall the service
|
||||
*/
|
||||
void service_unregister(void) {
|
||||
SC_HANDLE scm;
|
||||
SC_HANDLE svc;
|
||||
BOOL res;
|
||||
SERVICE_STATUS status;
|
||||
|
||||
if(!(scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE))) {
|
||||
DPRINTF(E_FATAL,L_MISC,"Cannot open service control manager: %d\n",GetLastError());
|
||||
}
|
||||
|
||||
svc = OpenService(scm,PACKAGE,SERVICE_ALL_ACCESS | DELETE);
|
||||
if(!svc) {
|
||||
DPRINTF(E_FATAL,L_MISC,"Cannot open service: %d (is it installed??)\n",GetLastError());
|
||||
}
|
||||
|
||||
res=QueryServiceStatus(svc,&status);
|
||||
if(!res) {
|
||||
DPRINTF(E_FATAL,L_MISC,"Cannot query service status: %d\n",GetLastError());
|
||||
}
|
||||
|
||||
if(status.dwCurrentState != SERVICE_STOPPED) {
|
||||
DPRINTF(E_LOG,L_MISC,"Stopping service...\n");
|
||||
ControlService(svc,SERVICE_CONTROL_STOP,&status);
|
||||
// we should probably poll for service stoppage...
|
||||
Sleep(2000);
|
||||
}
|
||||
|
||||
DPRINTF(E_LOG,L_MISC,"Deleting service...\n");
|
||||
res = DeleteService(svc);
|
||||
|
||||
if(res) {
|
||||
DPRINTF(E_LOG,L_MISC,"Deleted successfully\n");
|
||||
} else {
|
||||
DPRINTF(E_FATAL,L_MISC,"Error deleting service: %d\n",GetLastError());
|
||||
}
|
||||
|
||||
CloseServiceHandle(svc);
|
||||
CloseServiceHandle(scm);
|
||||
}
|
||||
|
32
src/w32-service.h
Normal file
32
src/w32-service.h
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* simple service management functions
|
||||
*
|
||||
* Copyright (C) 2005 Ron Pedde (ron.pedde@firstmarkcu.org)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _SERVICE_H_
|
||||
#define _SERVICE_H_
|
||||
|
||||
extern void *service_startup(void *);
|
||||
extern void service_shutdown(int);
|
||||
extern void service_register(void);
|
||||
extern void service_unregister(void);
|
||||
|
||||
#endif /* _SERVICE_H_ */
|
@ -61,43 +61,43 @@ unsigned char *read_hdr(FILE *f, size_t *hdr_len)
|
||||
|
||||
hdr = malloc(256);
|
||||
if (hdr == NULL)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
if (fread(hdr, 44, 1, f) != 1)
|
||||
goto fail;
|
||||
goto fail;
|
||||
|
||||
if (strncmp((char*)hdr + 12, "fmt ", 4))
|
||||
goto fail;
|
||||
goto fail;
|
||||
|
||||
format_data_length = GET_WAV_INT32(hdr + 16);
|
||||
|
||||
if ((format_data_length < 16) || (format_data_length > 100))
|
||||
goto fail;
|
||||
goto fail;
|
||||
|
||||
*hdr_len = 44;
|
||||
|
||||
if (format_data_length > 16) {
|
||||
if (fread(hdr + 44, format_data_length - 16, 1, f) != 1)
|
||||
goto fail;
|
||||
*hdr_len += format_data_length - 16;
|
||||
if (fread(hdr + 44, format_data_length - 16, 1, f) != 1)
|
||||
goto fail;
|
||||
*hdr_len += format_data_length - 16;
|
||||
}
|
||||
|
||||
return hdr;
|
||||
|
||||
fail:
|
||||
if (hdr != NULL)
|
||||
free(hdr);
|
||||
free(hdr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t parse_hdr(unsigned char *hdr, size_t hdr_len,
|
||||
unsigned long *chunk_data_length_ret,
|
||||
unsigned long *format_data_length_ret,
|
||||
unsigned long *compression_code_ret,
|
||||
unsigned long *channel_count_ret,
|
||||
unsigned long *sample_rate_ret,
|
||||
unsigned long *sample_bit_length_ret,
|
||||
unsigned long *data_length_ret)
|
||||
unsigned long *chunk_data_length_ret,
|
||||
unsigned long *format_data_length_ret,
|
||||
unsigned long *compression_code_ret,
|
||||
unsigned long *channel_count_ret,
|
||||
unsigned long *sample_rate_ret,
|
||||
unsigned long *sample_bit_length_ret,
|
||||
unsigned long *data_length_ret)
|
||||
{
|
||||
unsigned long chunk_data_length;
|
||||
unsigned long format_data_length;
|
||||
@ -108,14 +108,14 @@ size_t parse_hdr(unsigned char *hdr, size_t hdr_len,
|
||||
unsigned long data_length;
|
||||
|
||||
if (strncmp((char*)hdr + 0, "RIFF", 4) ||
|
||||
strncmp((char*)hdr + 8, "WAVE", 4) ||
|
||||
strncmp((char*)hdr + 12, "fmt ", 4))
|
||||
return 0;
|
||||
strncmp((char*)hdr + 8, "WAVE", 4) ||
|
||||
strncmp((char*)hdr + 12, "fmt ", 4))
|
||||
return 0;
|
||||
|
||||
format_data_length = GET_WAV_INT32(hdr + 16);
|
||||
|
||||
if (strncmp((char*)hdr + 20 + format_data_length, "data", 4))
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
chunk_data_length = GET_WAV_INT32(hdr + 4);
|
||||
compression_code = GET_WAV_INT16(hdr + 20);
|
||||
@ -125,12 +125,12 @@ size_t parse_hdr(unsigned char *hdr, size_t hdr_len,
|
||||
data_length = GET_WAV_INT32(hdr + 20 + format_data_length + 4);
|
||||
|
||||
if ((format_data_length != 16) ||
|
||||
(compression_code != 1) ||
|
||||
(channel_count < 1) ||
|
||||
(sample_rate == 0) ||
|
||||
(sample_rate > 512000) ||
|
||||
(sample_bit_length < 2))
|
||||
return 0;
|
||||
(compression_code != 1) ||
|
||||
(channel_count < 1) ||
|
||||
(sample_rate == 0) ||
|
||||
(sample_rate > 512000) ||
|
||||
(sample_bit_length < 2))
|
||||
return 0;
|
||||
|
||||
*chunk_data_length_ret = chunk_data_length;
|
||||
*format_data_length_ret = format_data_length;
|
||||
@ -144,9 +144,9 @@ size_t parse_hdr(unsigned char *hdr, size_t hdr_len,
|
||||
}
|
||||
|
||||
size_t patch_hdr(unsigned char *hdr, size_t hdr_len,
|
||||
unsigned long sec, unsigned long us,
|
||||
unsigned long samples,
|
||||
size_t *data_length_ret)
|
||||
unsigned long sec, unsigned long us,
|
||||
unsigned long samples,
|
||||
size_t *data_length_ret)
|
||||
{
|
||||
unsigned long chunk_data_length;
|
||||
unsigned long format_data_length;
|
||||
@ -158,45 +158,45 @@ size_t patch_hdr(unsigned char *hdr, size_t hdr_len,
|
||||
unsigned long bytes_per_sample;
|
||||
|
||||
if (parse_hdr(hdr, hdr_len,
|
||||
&chunk_data_length,
|
||||
&format_data_length,
|
||||
&compression_code,
|
||||
&channel_count,
|
||||
&sample_rate,
|
||||
&sample_bit_length,
|
||||
&data_length) != hdr_len)
|
||||
return 0;
|
||||
&chunk_data_length,
|
||||
&format_data_length,
|
||||
&compression_code,
|
||||
&channel_count,
|
||||
&sample_rate,
|
||||
&sample_bit_length,
|
||||
&data_length) != hdr_len)
|
||||
return 0;
|
||||
|
||||
if (hdr_len != (20 + format_data_length + 8))
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
if (format_data_length > 16) {
|
||||
memmove(hdr + 20 + 16, hdr + 20 + format_data_length, 8);
|
||||
hdr[16] = 16;
|
||||
hdr[17] = 0;
|
||||
hdr[18] = 0;
|
||||
hdr[19] = 0;
|
||||
format_data_length = 16;
|
||||
hdr_len = 44;
|
||||
memmove(hdr + 20 + 16, hdr + 20 + format_data_length, 8);
|
||||
hdr[16] = 16;
|
||||
hdr[17] = 0;
|
||||
hdr[18] = 0;
|
||||
hdr[19] = 0;
|
||||
format_data_length = 16;
|
||||
hdr_len = 44;
|
||||
}
|
||||
|
||||
bytes_per_sample = channel_count * ((sample_bit_length + 7) / 8);
|
||||
|
||||
if (samples == 0) {
|
||||
samples = sample_rate * sec;
|
||||
samples += ((sample_rate / 100) * (us / 10)) / 1000;
|
||||
samples = sample_rate * sec;
|
||||
samples += ((sample_rate / 100) * (us / 10)) / 1000;
|
||||
}
|
||||
|
||||
if (samples > 0) {
|
||||
data_length = samples * bytes_per_sample;
|
||||
chunk_data_length = data_length + 36;
|
||||
data_length = samples * bytes_per_sample;
|
||||
chunk_data_length = data_length + 36;
|
||||
} else {
|
||||
chunk_data_length = 0xffffffff;
|
||||
data_length = chunk_data_length - 36;
|
||||
chunk_data_length = 0xffffffff;
|
||||
data_length = chunk_data_length - 36;
|
||||
}
|
||||
|
||||
if (data_length_ret != NULL)
|
||||
*data_length_ret = data_length;
|
||||
*data_length_ret = data_length;
|
||||
|
||||
hdr[4] = chunk_data_length % 0x100;
|
||||
hdr[5] = (chunk_data_length >> 8) % 0x100;
|
||||
@ -216,25 +216,25 @@ static void usage(int exitval);
|
||||
static void usage(int exitval)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s [ options ] [input-file]\n", av0);
|
||||
"Usage: %s [ options ] [input-file]\n", av0);
|
||||
fprintf(stderr,
|
||||
"\n");
|
||||
"\n");
|
||||
fprintf(stderr,
|
||||
"Options:\n");
|
||||
"Options:\n");
|
||||
fprintf(stderr,
|
||||
"-l len | --length=len Length of the sound file in seconds.\n");
|
||||
"-l len | --length=len Length of the sound file in seconds.\n");
|
||||
fprintf(stderr,
|
||||
"-s len | --samples=len Length of the sound file in samples.\n");
|
||||
"-s len | --samples=len Length of the sound file in samples.\n");
|
||||
fprintf(stderr,
|
||||
"-o offset | --offset=offset Number of bytes to discard from the stream.\n");
|
||||
"-o offset | --offset=offset Number of bytes to discard from the stream.\n");
|
||||
fprintf(stderr,
|
||||
"\n");
|
||||
"\n");
|
||||
fprintf(stderr,
|
||||
"--samples and --length are mutually exclusive.\n");
|
||||
"--samples and --length are mutually exclusive.\n");
|
||||
|
||||
#if 1
|
||||
fprintf(stderr,
|
||||
"\n\nLong options are not available on this system.\n");
|
||||
"\n\nLong options are not available on this system.\n");
|
||||
#endif
|
||||
|
||||
exit(exitval);
|
||||
@ -254,127 +254,127 @@ int main(int argc, char **argv)
|
||||
size_t buf_len;
|
||||
|
||||
if (strchr(argv[0], '/'))
|
||||
av0 = strrchr(argv[0], '/') + 1;
|
||||
av0 = strrchr(argv[0], '/') + 1;
|
||||
else
|
||||
av0 = argv[0];
|
||||
av0 = argv[0];
|
||||
|
||||
#if 0
|
||||
while ((c = getopt_long(argc, argv, "+hl:o:s:", longopts, NULL)) != EOF) {
|
||||
#else
|
||||
while ((c = getopt(argc, argv, "hl:o:s:")) != -1) {
|
||||
#endif
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage(0);
|
||||
/*NOTREACHED*/
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
sec = strtoul(optarg, &end, 10);
|
||||
if ((*optarg == '-') || (end == optarg) || ((*end != '\0') && (*end != '.'))) {
|
||||
fprintf(stderr, "%s: Invalid -l argument.\n", av0);
|
||||
exit(-1);
|
||||
} else if (*end == '.') {
|
||||
char tmp[7];
|
||||
int i;
|
||||
|
||||
memset(tmp, '0', sizeof (tmp) - 1);
|
||||
tmp[sizeof (tmp) - 1] = '\0';
|
||||
for (i = 0; (i < (sizeof (tmp) - 1)) && (isdigit(end[i+1])); i++)
|
||||
tmp[i] = end[i+1];
|
||||
us = strtoul(tmp, NULL, 10);
|
||||
} else {
|
||||
us = 0;
|
||||
}
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage(0);
|
||||
/*NOTREACHED*/
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
sec = strtoul(optarg, &end, 10);
|
||||
if ((*optarg == '-') || (end == optarg) || ((*end != '\0') && (*end != '.'))) {
|
||||
fprintf(stderr, "%s: Invalid -l argument.\n", av0);
|
||||
exit(-1);
|
||||
} else if (*end == '.') {
|
||||
char tmp[7];
|
||||
int i;
|
||||
|
||||
memset(tmp, '0', sizeof (tmp) - 1);
|
||||
tmp[sizeof (tmp) - 1] = '\0';
|
||||
for (i = 0; (i < (sizeof (tmp) - 1)) && (isdigit(end[i+1])); i++)
|
||||
tmp[i] = end[i+1];
|
||||
us = strtoul(tmp, NULL, 10);
|
||||
} else {
|
||||
us = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
if ((sec == 0) && (us == 0)) {
|
||||
fprintf(stderr, "%s: Invalid -l argument (zero is not acceptable).\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if ((sec == 0) && (us == 0)) {
|
||||
fprintf(stderr, "%s: Invalid -l argument (zero is not acceptable).\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
*/
|
||||
|
||||
if (samples != 0) {
|
||||
fprintf(stderr, "%s: Parameters -s and -l are mutually exclusive.\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
samples = strtoul(optarg, &end, 10);
|
||||
if ((*optarg == '-') || (end == optarg) || (*end != '\0')) {
|
||||
fprintf(stderr, "%s: Invalid -s argument.\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
if (samples == 0) {
|
||||
fprintf(stderr, "%s: Invalid -s argument (zero is not acceptable).\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
if ((sec != 0) || (us != 0)) {
|
||||
fprintf(stderr, "%s: Parameters -l and -s are mutually exclusive.\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
offset = strtoul(optarg, &end, 10);
|
||||
if ((*optarg == '-') || (end == optarg) || (*end != '\0')) {
|
||||
fprintf(stderr, "%s: Invalid -o argument.\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s: Bad command line option -%c.\n", av0, optopt);
|
||||
usage(-1);
|
||||
}
|
||||
if (samples != 0) {
|
||||
fprintf(stderr, "%s: Parameters -s and -l are mutually exclusive.\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
samples = strtoul(optarg, &end, 10);
|
||||
if ((*optarg == '-') || (end == optarg) || (*end != '\0')) {
|
||||
fprintf(stderr, "%s: Invalid -s argument.\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
if (samples == 0) {
|
||||
fprintf(stderr, "%s: Invalid -s argument (zero is not acceptable).\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
if ((sec != 0) || (us != 0)) {
|
||||
fprintf(stderr, "%s: Parameters -l and -s are mutually exclusive.\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
offset = strtoul(optarg, &end, 10);
|
||||
if ((*optarg == '-') || (end == optarg) || (*end != '\0')) {
|
||||
fprintf(stderr, "%s: Invalid -o argument.\n", av0);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s: Bad command line option -%c.\n", av0, optopt);
|
||||
usage(-1);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc == 0) {
|
||||
f = stdin;
|
||||
f = stdin;
|
||||
} else if (argc == 1) {
|
||||
f = fopen(argv[0], "rb");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "%s: Can't open file %s for reading.\n", av0, argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
f = fopen(argv[0], "rb");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "%s: Can't open file %s for reading.\n", av0, argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "%s: Too many command line arguments.\n", av0);
|
||||
usage(-1);
|
||||
fprintf(stderr, "%s: Too many command line arguments.\n", av0);
|
||||
usage(-1);
|
||||
}
|
||||
|
||||
hdr = read_hdr(f, &hdr_len);
|
||||
if (hdr == NULL) {
|
||||
fprintf(stderr, "%s: Can't read wav header.\n", av0);
|
||||
exit(2);
|
||||
fprintf(stderr, "%s: Can't read wav header.\n", av0);
|
||||
exit(2);
|
||||
}
|
||||
if ((hdr_len = patch_hdr(hdr, hdr_len, sec, us, samples, &data_len)) == 0) {
|
||||
free(hdr);
|
||||
fprintf(stderr, "%s: Can't parse (or patch) wav header.\n", av0);
|
||||
exit(2);
|
||||
free(hdr);
|
||||
fprintf(stderr, "%s: Can't parse (or patch) wav header.\n", av0);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (offset > hdr_len + data_len) {
|
||||
fprintf(stderr, "%s: Offset is beyond EOF.\n", av0);
|
||||
exit(3);
|
||||
fprintf(stderr, "%s: Offset is beyond EOF.\n", av0);
|
||||
exit(3);
|
||||
}
|
||||
|
||||
if ((offset > 0) && (offset < hdr_len)) {
|
||||
memmove(hdr, hdr + offset, hdr_len - offset);
|
||||
hdr_len -= offset;
|
||||
offset = 0;
|
||||
memmove(hdr, hdr + offset, hdr_len - offset);
|
||||
hdr_len -= offset;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (offset > 0) {
|
||||
offset -= hdr_len;
|
||||
offset -= hdr_len;
|
||||
} else {
|
||||
if (fwrite(hdr, hdr_len, 1, stdout) != 1) {
|
||||
fprintf(stderr, "%s: Write failed.\n", av0);
|
||||
exit(4);
|
||||
}
|
||||
if (fwrite(hdr, hdr_len, 1, stdout) != 1) {
|
||||
fprintf(stderr, "%s: Write failed.\n", av0);
|
||||
exit(4);
|
||||
}
|
||||
}
|
||||
|
||||
free(hdr);
|
||||
@ -382,32 +382,32 @@ int main(int argc, char **argv)
|
||||
hdr_len = 0;
|
||||
|
||||
if (offset > 0) {
|
||||
data_len -= offset;
|
||||
while (offset > 0) {
|
||||
buf_len = (offset > sizeof (buf)) ? sizeof (buf) : offset;
|
||||
if (fread(buf, buf_len, 1, f) != 1) {
|
||||
fprintf(stderr, "%s: Read failed.\n", av0);
|
||||
exit(5);
|
||||
}
|
||||
offset -= buf_len;
|
||||
}
|
||||
data_len -= offset;
|
||||
while (offset > 0) {
|
||||
buf_len = (offset > sizeof (buf)) ? sizeof (buf) : offset;
|
||||
if (fread(buf, buf_len, 1, f) != 1) {
|
||||
fprintf(stderr, "%s: Read failed.\n", av0);
|
||||
exit(5);
|
||||
}
|
||||
offset -= buf_len;
|
||||
}
|
||||
}
|
||||
|
||||
while (data_len > 0) {
|
||||
buf_len = (data_len > sizeof (buf)) ? sizeof (buf) : data_len;
|
||||
if (fread(buf, buf_len, 1, f) != 1) {
|
||||
fprintf(stderr, "%s: Read failed.\n", av0);
|
||||
exit(5);
|
||||
}
|
||||
if (fwrite(buf, buf_len, 1, stdout) != 1) {
|
||||
fprintf(stderr, "%s: Write failed.\n", av0);
|
||||
exit(4);
|
||||
}
|
||||
data_len -= buf_len;
|
||||
buf_len = (data_len > sizeof (buf)) ? sizeof (buf) : data_len;
|
||||
if (fread(buf, buf_len, 1, f) != 1) {
|
||||
fprintf(stderr, "%s: Read failed.\n", av0);
|
||||
exit(5);
|
||||
}
|
||||
if (fwrite(buf, buf_len, 1, stdout) != 1) {
|
||||
fprintf(stderr, "%s: Write failed.\n", av0);
|
||||
exit(4);
|
||||
}
|
||||
data_len -= buf_len;
|
||||
}
|
||||
|
||||
if (f != stdout) {
|
||||
fclose(f);
|
||||
fclose(f);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
@ -29,21 +29,27 @@
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <regex.h>
|
||||
#include <restart.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <uici.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#ifndef WIN32
|
||||
# include <sys/param.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include "err.h"
|
||||
#include "restart.h"
|
||||
#include "webserver.h"
|
||||
|
||||
#ifndef WIN32 /* FIXME: the uici stuff should be moved into os-win32 and os-unix
|
||||
* as os_opensocket, os_accept, etc */
|
||||
# include "uici.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Defines
|
||||
*/
|
||||
@ -343,7 +349,7 @@ extern int ws_stop(WSHANDLE ws) {
|
||||
|
||||
DPRINTF(E_DBG,L_WS,"ws_stop: closing the server fd\n");
|
||||
shutdown(pwsp->server_fd,SHUT_RDWR);
|
||||
r_close(pwsp->server_fd); /* this should tick off the listener */
|
||||
r_close(pwsp->server_fd);
|
||||
|
||||
/* wait for the server thread to terminate. SHould be quick! */
|
||||
pthread_join(pwsp->server_tid,&result);
|
||||
@ -434,7 +440,7 @@ void *ws_mainthread(void *arg) {
|
||||
ws_lock_unsafe();
|
||||
pwsc->threadno=pwsp->threadno;
|
||||
pwsp->threadno++;
|
||||
/* we'll hold the unsafe until the dispatch thread is registered */
|
||||
/* we'll hold the unsafe until the dispatch thread is registered */
|
||||
|
||||
/* now, throw off a dispatch thread */
|
||||
if((err=pthread_create(&tid,NULL,ws_dispatcher,(void*)pwsc))) {
|
||||
@ -445,7 +451,7 @@ void *ws_mainthread(void *arg) {
|
||||
ws_add_dispatch_thread(pwsp,pwsc);
|
||||
pthread_detach(tid);
|
||||
}
|
||||
ws_unlock_unsafe();
|
||||
ws_unlock_unsafe();
|
||||
}
|
||||
|
||||
DPRINTF(E_SPAM,L_WS,"Exiting ws_mainthred\n");
|
||||
@ -488,17 +494,17 @@ void ws_close(WS_CONNINFO *pwsc) {
|
||||
|
||||
ws_remove_dispatch_thread(pwsp, pwsc);
|
||||
|
||||
/* Get rid of the local storage */
|
||||
if(pwsc->local_storage) {
|
||||
if(pwsc->storage_callback) {
|
||||
pwsc->storage_callback(pwsc->local_storage);
|
||||
pwsc->local_storage=NULL;
|
||||
pwsc->storage_callback=NULL;
|
||||
}
|
||||
}
|
||||
/* Get rid of the local storage */
|
||||
if(pwsc->local_storage) {
|
||||
if(pwsc->storage_callback) {
|
||||
pwsc->storage_callback(pwsc->local_storage);
|
||||
pwsc->local_storage=NULL;
|
||||
pwsc->storage_callback=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free(pwsc->hostname);
|
||||
memset(pwsc,0x00,sizeof(WS_CONNINFO));
|
||||
memset(pwsc,0x00,sizeof(WS_CONNINFO));
|
||||
free(pwsc);
|
||||
DPRINTF(E_SPAM,L_WS,"Exiting ws_close (thread terminating)\n");
|
||||
pthread_exit(NULL);
|
||||
@ -1033,14 +1039,14 @@ int ws_returnerror(WS_CONNINFO *pwsc,int error, char *description) {
|
||||
* and serves it up
|
||||
*/
|
||||
void ws_defaulthandler(WS_PRIVATE *pwsp, WS_CONNINFO *pwsc) {
|
||||
char path[MAXPATHLEN];
|
||||
char resolved_path[MAXPATHLEN];
|
||||
char path[PATH_MAX];
|
||||
char resolved_path[PATH_MAX];
|
||||
int file_fd;
|
||||
off_t len;
|
||||
|
||||
DPRINTF(E_SPAM,L_WS,"Entering ws_defaulthandler\n");
|
||||
|
||||
snprintf(path,MAXPATHLEN,"%s/%s",pwsp->wsconfig.web_root,pwsc->uri);
|
||||
snprintf(path,PATH_MAX,"%s/%s",pwsp->wsconfig.web_root,pwsc->uri);
|
||||
if(!realpath(path,resolved_path)) {
|
||||
pwsc->error=errno;
|
||||
DPRINTF(E_WARN,L_WS,"Exiting ws_defaulthandler: Cannot resolve %s\n",path);
|
||||
@ -1577,7 +1583,7 @@ WS_CONNINFO *ws_thread_enum_first(WSHANDLE wsh, WSTHREADENUM *vpp) {
|
||||
if(pconlist) {
|
||||
pwsc = pconlist->pwsc;
|
||||
} else {
|
||||
ws_unlock_connlist(pwsp);
|
||||
ws_unlock_connlist(pwsp);
|
||||
}
|
||||
|
||||
return pwsc;
|
||||
|
@ -75,9 +75,9 @@ typedef struct tag_ws_conninfo {
|
||||
extern WSHANDLE ws_start(WSCONFIG *config);
|
||||
extern int ws_stop(WSHANDLE ws);
|
||||
extern int ws_registerhandler(WSHANDLE ws, char *regex,
|
||||
void(*handler)(WS_CONNINFO*),
|
||||
int(*auth)(char *, char *),
|
||||
int addheaders);
|
||||
void(*handler)(WS_CONNINFO*),
|
||||
int(*auth)(char *, char *),
|
||||
int addheaders);
|
||||
|
||||
extern void ws_lock_local_storage(WS_CONNINFO *pwsc);
|
||||
extern void ws_unlock_local_storage(WS_CONNINFO *pwsc);
|
||||
|
79
src/win32.h
Normal file
79
src/win32.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Win32 compatibility stuff
|
||||
*/
|
||||
|
||||
#ifndef _WIN32_H_
|
||||
#define _WIN32_H_
|
||||
|
||||
#include <windows.h>
|
||||
//#include <winsock2.h>
|
||||
#include <io.h>
|
||||
#include <stddef.h>
|
||||
#include <fcntl.h>
|
||||
#include <direct.h>
|
||||
|
||||
#include "os-win32.h"
|
||||
|
||||
#ifndef TRUE
|
||||
# define TRUE 1
|
||||
# define FALSE 0
|
||||
#endif
|
||||
|
||||
/* Funtion fixups */
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#define usleep Sleep
|
||||
#define sleep(a) Sleep((a) * 1000)
|
||||
#define read(a,b,c) os_read((a),(b),(int)(c))
|
||||
#define write(a,b,c) os_write((a),(b),(int)(c))
|
||||
#define strncasecmp strnicmp
|
||||
#define strcasecmp stricmp
|
||||
#define mkdir(a,b) _mkdir((a))
|
||||
#define popen _popen
|
||||
#define pclose _pclose
|
||||
#define strtoll strtol
|
||||
|
||||
#define realpath os_realpath
|
||||
#define close os_close
|
||||
#define strsep os_strsep
|
||||
#define open os_open
|
||||
#define waitfdtimed os_waitfdtimed
|
||||
|
||||
#define readdir_r os_readdir_r
|
||||
#define closedir os_closedir
|
||||
#define opendir os_opendir
|
||||
|
||||
#define getuid os_getuid
|
||||
#define strerror os_strerror
|
||||
|
||||
/* override the uici stuff */
|
||||
#define u_open os_opensocket
|
||||
#define u_accept os_acceptsocket
|
||||
|
||||
/* privately implemented functions: @see os-win32.c */
|
||||
#define gettimeofday os_gettimeofday
|
||||
|
||||
/* Type fixups */
|
||||
#define mode_t int
|
||||
#define ssize_t int
|
||||
#define socklen_t int
|
||||
|
||||
/* Consts */
|
||||
#define PIPE_BUF 256 /* What *should* this be on win32? */
|
||||
#define MAXDESC 512 /* http://msdn.microsoft.com/en-us/library/kdfaxaay.aspx */
|
||||
#define SHUT_RDWR 2
|
||||
#define MAX_NAME_LEN _MAX_PATH
|
||||
#define ETIME 101
|
||||
#define PATH_MAX _MAX_PATH
|
||||
|
||||
#define HOST "unknown-windows-ick"
|
||||
#define SERVICENAME "Multithreaded DAAP Server"
|
||||
|
||||
#define DEFAULT_CONFIGFILE os_configpath()
|
||||
|
||||
extern char *os_configpath(void);
|
||||
|
||||
#endif /* _WIN32_H_ */
|
||||
|
@ -4,6 +4,10 @@
|
||||
* This really isn't xmlrpc. It's xmlrpc-ish. Emphasis on -ish.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
@ -242,7 +246,7 @@ void xml_get_stats(WS_CONNINFO *pwsc) {
|
||||
|
||||
xml_push(pxml,"statistics");
|
||||
|
||||
r_secs=time(NULL)-config.stats.start_time;
|
||||
r_secs=(int)(time(NULL)-config.stats.start_time);
|
||||
|
||||
r_days=r_secs/(3600 * 24);
|
||||
r_secs -= ((3600 * 24) * r_days);
|
||||
@ -300,7 +304,7 @@ char *xml_entity_encode(char *original) {
|
||||
char *s, *d;
|
||||
int destsize;
|
||||
|
||||
destsize = 6*strlen(original)+1;
|
||||
destsize = 6*(int)strlen(original)+1;
|
||||
new=(char *)malloc(destsize);
|
||||
if(!new) return NULL;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user