* Fix some possible memory leaks.

* Pay attention to the specified port number.
* Add support for multiple media directories, and allow content filtering on the directories.
This commit is contained in:
Justin Maggard 2009-02-03 03:36:59 +00:00
parent 3f454a5762
commit 0324818d86
11 changed files with 281 additions and 137 deletions

View File

@ -222,6 +222,7 @@ find_album_art(const char * path)
}
else
{
sqlite3_free(sql);
sql = sqlite3_mprintf( "INSERT into ALBUM_ART"
" (PATH, EMBEDDED) "
"VALUES"
@ -231,6 +232,7 @@ find_album_art(const char * path)
if( sql_exec(db, sql) == SQLITE_OK )
ret = sqlite3_last_insert_rowid(db);
}
sqlite3_free_table(result);
sqlite3_free(sql);
}
if( album_art )

View File

@ -59,17 +59,34 @@ getifaddr(const char * ifname, char * buf, int len)
int
getsysaddr(char * buf, int len)
{
char hn[256];
struct in_addr *addr;
struct hostent *host;
int i;
int s = socket(PF_INET, SOCK_STREAM, 0);
memset(buf, '\0', len);
gethostname(hn, sizeof(hn));
host = gethostbyname(hn);
if( !host )
return -1;
addr = (struct in_addr*)host->h_addr;
strncpy(buf, inet_ntoa(*addr), len);
for (i=1; i > 0; i++)
{
struct ifreq ifr;
struct sockaddr_in *addr = (struct sockaddr_in *) &ifr.ifr_addr;
ifr.ifr_ifindex = i;
if( ioctl(s, SIOCGIFNAME, &ifr) < 0 )
break;
if(ioctl(s, SIOCGIFADDR, &ifr, sizeof(struct ifreq)) < 0)
{
syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m");
close(s);
return -1;
}
if(strncmp(inet_ntoa(addr->sin_addr), "127.", 4) == 0)
continue;
if(!inet_ntop(AF_INET, &addr->sin_addr, buf, len))
{
syslog(LOG_ERR, "inet_ntop(): %m");
close(s);
return -1;
}
break;
}
close(s);
return 0;
}

View File

@ -139,17 +139,6 @@ set_startup_time(int sysuptime)
}
}
/* structure containing variables used during "main loop"
* that are filled during the init */
struct runtime_vars {
/* LAN IP addresses for SSDP traffic and HTTP */
/* moved to global vars */
/*int n_lan_addr;*/
/*struct lan_addr_s lan_addr[MAX_LAN_ADDR];*/
int port; /* HTTP Port */
int notify_interval; /* seconds between SSDP announces */
};
/* parselanaddr()
* parse address with mask
* ex: 192.168.1.1/24
@ -224,7 +213,7 @@ getfriendlyname(char * buf, int len)
* 7) compute presentation URL
* 8) set signal handlers */
static int
init(int argc, char * * argv, struct runtime_vars * v)
init(int argc, char * * argv)
{
int i;
int pid;
@ -261,7 +250,6 @@ init(int argc, char * * argv, struct runtime_vars * v)
getfriendlyname(friendly_name, FRIENDLYNAME_MAX_LEN);
/*v->n_lan_addr = 0;*/
char ext_ip_addr[INET_ADDRSTRLEN];
if( (getsysaddr(ext_ip_addr, INET_ADDRSTRLEN) < 0) &&
(getifaddr("eth0", ext_ip_addr, INET_ADDRSTRLEN) < 0) &&
@ -272,8 +260,8 @@ init(int argc, char * * argv, struct runtime_vars * v)
}
if( parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 )
n_lan_addr++;
v->port = -1;
v->notify_interval = 30; /* seconds between SSDP announces */
runtime_vars.port = -1;
runtime_vars.notify_interval = 30; /* seconds between SSDP announces */
/* read options file first since
* command line arguments have final say */
@ -290,12 +278,11 @@ init(int argc, char * * argv, struct runtime_vars * v)
switch(ary_options[i].id)
{
case UPNPLISTENING_IP:
if(n_lan_addr < MAX_LAN_ADDR)/* if(v->n_lan_addr < MAX_LAN_ADDR)*/
if(n_lan_addr < MAX_LAN_ADDR)
{
/*if(parselanaddr(&v->lan_addr[v->n_lan_addr],*/
if(parselanaddr(&lan_addr[n_lan_addr],
ary_options[i].value) == 0)
n_lan_addr++; /*v->n_lan_addr++; */
n_lan_addr++;
}
else
{
@ -304,13 +291,13 @@ init(int argc, char * * argv, struct runtime_vars * v)
}
break;
case UPNPPORT:
v->port = atoi(ary_options[i].value);
runtime_vars.port = atoi(ary_options[i].value);
break;
case UPNPPRESENTATIONURL:
presurl = ary_options[i].value;
break;
case UPNPNOTIFY_INTERVAL:
v->notify_interval = atoi(ary_options[i].value);
runtime_vars.notify_interval = atoi(ary_options[i].value);
break;
case UPNPSYSTEM_UPTIME:
if(strcmp(ary_options[i].value, "yes") == 0)
@ -337,8 +324,54 @@ init(int argc, char * * argv, struct runtime_vars * v)
friendly_name[FRIENDLYNAME_MAX_LEN-1] = '\0';
break;
case UPNPMEDIADIR:
strncpy(media_dir, ary_options[i].value, MEDIADIR_MAX_LEN);
media_dir[MEDIADIR_MAX_LEN-1] = '\0';
usleep(1);
enum media_types type = ALL_MEDIA;
char * myval = NULL;
switch( ary_options[i].value[0] )
{
case 'A':
case 'a':
if( ary_options[i].value[0] == 'A' || ary_options[i].value[0] == 'a' )
type = AUDIO_ONLY;
case 'V':
case 'v':
if( ary_options[i].value[0] == 'V' || ary_options[i].value[0] == 'v' )
type = VIDEO_ONLY;
case 'P':
case 'p':
if( ary_options[i].value[0] == 'P' || ary_options[i].value[0] == 'p' )
type = IMAGES_ONLY;
myval = index(ary_options[i].value, '/');
case '/':
usleep(1);
char * path = realpath(myval ? myval:ary_options[i].value, NULL);
if( access(path, F_OK) != 0 )
{
fprintf(stderr, "Media directory not accessible! [%s]\n",
path);
free(path);
break;
}
struct media_dir_s * this_dir = calloc(1, sizeof(struct media_dir_s));
this_dir->path = path;
this_dir->type = type;
if( !media_dirs )
{
media_dirs = this_dir;
}
else
{
struct media_dir_s * all_dirs = media_dirs;
while( all_dirs->next )
all_dirs = all_dirs->next;
all_dirs->next = this_dir;
}
break;
default:
fprintf(stderr, "Media directory entry not understood! [%s]\n",
ary_options[i].value);
break;
}
break;
default:
fprintf(stderr, "Unknown option in file %s\n",
@ -358,7 +391,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
{
case 't':
if(i+1 < argc)
v->notify_interval = atoi(argv[++i]);
runtime_vars.notify_interval = atoi(argv[++i]);
else
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
break;
@ -392,7 +425,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
break;
case 'p':
if(i+1 < argc)
v->port = atoi(argv[++i]);
runtime_vars.port = atoi(argv[++i]);
else
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
break;
@ -417,22 +450,19 @@ init(int argc, char * * argv, struct runtime_vars * v)
int address_already_there = 0;
int j;
i++;
for(j=0; j<n_lan_addr; j++)/* for(j=0; j<v->n_lan_addr; j++)*/
for(j=0; j<n_lan_addr; j++)
{
struct lan_addr_s tmpaddr;
parselanaddr(&tmpaddr, argv[i]);
/*if(0 == strcmp(v->lan_addr[j].str, tmpaddr.str))*/
if(0 == strcmp(lan_addr[j].str, tmpaddr.str))
address_already_there = 1;
}
if(address_already_there)
break;
if(n_lan_addr < MAX_LAN_ADDR) /*if(v->n_lan_addr < MAX_LAN_ADDR)*/
if(n_lan_addr < MAX_LAN_ADDR)
{
/*v->lan_addr[v->n_lan_addr++] = argv[i];*/
/*if(parselanaddr(&v->lan_addr[v->n_lan_addr], argv[i]) == 0)*/
if(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0)
n_lan_addr++; /*v->n_lan_addr++;*/
n_lan_addr++;
}
else
{
@ -450,7 +480,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
fprintf(stderr, "Unknown option: %s\n", argv[i]);
}
}
if( (/*v->*/n_lan_addr==0) || (v->port<=0) )
if( (n_lan_addr==0) || (runtime_vars.port<=0) )
{
fprintf(stderr, "Usage:\n\t"
"%s [-f config_file] [-i ext_ifname] [-o ext_ip]\n"
@ -521,8 +551,6 @@ init(int argc, char * * argv, struct runtime_vars * v)
{
snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
"http://%s/", lan_addr[0].str);
/*"http://%s:%d/", lan_addr[0].str, 80);*/
/*"http://%s:%d/", v->lan_addr[0].str, 80);*/
}
/* set signal handler */
@ -566,19 +594,36 @@ main(int argc, char * * argv)
#endif
struct timeval timeout, timeofday, lasttimeofday = {0, 0};
int max_fd = -1;
struct runtime_vars v;
if(init(argc, argv, &v) != 0)
if(init(argc, argv) != 0)
return 1;
LIST_INIT(&upnphttphead);
if( access(DB_PATH, F_OK) )
{
struct media_dir_s * media_path = media_dirs;
sqlite3_open(DB_PATH, &db);
freopen("/dev/null", "a", stderr);
ScanDirectory(media_dir, NULL);
if( CreateDatabase() != 0 )
{
fprintf(stderr, "Error creating database!\n");
return -1;
}
#if USE_FORK
pid_t newpid = fork();
if( newpid )
goto fork_done;
#endif
while( media_path )
{
ScanDirectory(media_path->path, NULL, media_path->type);
media_path = media_path->next;
}
freopen("/proc/self/fd/2", "a", stderr);
#if USE_FORK
_exit(0);
#endif
}
else
{
@ -588,21 +633,40 @@ main(int argc, char * * argv)
if( sqlite3_get_table(db, "pragma user_version", &result, &rows, 0, 0) == SQLITE_OK )
{
if( atoi(result[1]) != DB_VERSION ) {
struct media_dir_s * media_path = media_dirs;
printf("Database version mismatch; need to recreate...\n");
sqlite3_close(db);
unlink(DB_PATH);
sqlite3_open(DB_PATH, &db);
freopen("/dev/null", "a", stderr);
ScanDirectory(media_dir, NULL);
if( CreateDatabase() != 0 )
{
fprintf(stderr, "Error creating database!\n");
return -1;
}
#if USE_FORK
pid_t newpid = fork();
if( newpid )
goto fork_done;
#endif
while( media_path )
{
ScanDirectory(media_path->path, NULL, media_path->type);
media_path = media_path->next;
}
ScanDirectory(media_dirs->path, NULL, media_dirs->type);
freopen("/proc/self/fd/2", "a", stderr);
#if USE_FORK
_exit(0);
#endif
}
sqlite3_free_table(result);
}
}
#if USE_FORK
fork_done:
#endif
/* open socket for SSDP connections */
/*sudp = OpenAndConfSSDPReceiveSocket(v.n_lan_addr, v.lan_addr);*/
sudp = OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr);
if(sudp < 0)
{
@ -610,13 +674,13 @@ main(int argc, char * * argv)
return 1;
}
/* open socket for HTTP connections. Listen on the 1st LAN address */
shttpl = OpenAndConfHTTPSocket(v.port);
shttpl = OpenAndConfHTTPSocket(runtime_vars.port);
if(shttpl < 0)
{
syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
return 1;
}
syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
syslog(LOG_NOTICE, "HTTP listening on port %d", runtime_vars.port);
/* open socket for sending notifications */
if(OpenAndConfSSDPNotifySockets(snotify) < 0)
@ -636,24 +700,24 @@ main(int argc, char * * argv)
if(gettimeofday(&timeofday, 0) < 0)
{
syslog(LOG_ERR, "gettimeofday(): %m");
timeout.tv_sec = v.notify_interval;
timeout.tv_sec = runtime_vars.notify_interval;
timeout.tv_usec = 0;
}
else
{
/* the comparaison is not very precise but who cares ? */
if(timeofday.tv_sec >= (lasttimeofday.tv_sec + v.notify_interval))
if(timeofday.tv_sec >= (lasttimeofday.tv_sec + runtime_vars.notify_interval))
{
SendSSDPNotifies2(snotify,
(unsigned short)v.port,
(v.notify_interval << 1)+10);
(unsigned short)runtime_vars.port,
(runtime_vars.notify_interval << 1)+10);
memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval));
timeout.tv_sec = v.notify_interval;
timeout.tv_sec = runtime_vars.notify_interval;
timeout.tv_usec = 0;
}
else
{
timeout.tv_sec = lasttimeofday.tv_sec + v.notify_interval
timeout.tv_sec = lasttimeofday.tv_sec + runtime_vars.notify_interval
- timeofday.tv_sec;
if(timeofday.tv_usec > lasttimeofday.tv_usec)
{
@ -724,8 +788,7 @@ main(int argc, char * * argv)
if(sudp >= 0 && FD_ISSET(sudp, &readset))
{
/*syslog(LOG_INFO, "Received UDP Packet");*/
/*ProcessSSDPRequest(sudp, v.lan_addr, v.n_lan_addr,*/
ProcessSSDPRequest(sudp, (unsigned short)v.port);
ProcessSSDPRequest(sudp, (unsigned short)runtime_vars.port);
}
/* process active HTTP connections */
/* LIST_FOREACH macro is not available under linux */
@ -802,7 +865,7 @@ shutdown:
{
syslog(LOG_ERR, "Failed to broadcast good-bye notifications");
}
for(i=0; i<n_lan_addr; i++)/* for(i=0; i<v.n_lan_addr; i++)*/
for(i=0; i<n_lan_addr; i++)
close(snotify[i]);
sqlite3_close(db);

View File

@ -4,6 +4,13 @@ port=5555
# enable UPNP support (default is yes)
enable_upnp=yes
# set this to the directory you want scanned.
# * if have multiple directories, you can have multiple media_dir= lines
# * if you want to restrict a media_dir to a specific content type, you
# can prepend the type, followed by a comma, to the directory:
# + "A" for audio (eg. media_dir=A,/home/jmaggard/Music)
# + "V" for video (eg. media_dir=V,/home/jmaggard/Videos)
# + "P" for images (eg. media_dir=P,/home/jmaggard/Pictures)
media_dir=/opt
# set this if you want to customize the name that shows up on your clients

View File

@ -16,4 +16,22 @@ struct lan_addr_s {
struct in_addr addr, mask; /* ip/mask */
};
struct runtime_vars_s {
int port; /* HTTP Port */
int notify_interval; /* seconds between SSDP announces */
};
enum media_types {
ALL_MEDIA,
AUDIO_ONLY,
VIDEO_ONLY,
IMAGES_ONLY
};
struct media_dir_s {
char * path; /* Base path */
enum media_types type; /* type of files to scan */
struct media_dir_s * next;
};
#endif

150
scanner.c
View File

@ -57,6 +57,26 @@ is_image(const char * file)
return (ends_with(file, ".jpg") || ends_with(file, ".jpeg"));
}
sqlite_int64
get_next_available_id(const char * table, const char * parentID)
{
char * sql;
char **result;
int ret;
sqlite_int64 objectID = 0;
asprintf(&sql, "SELECT OBJECT_ID, max(ID) from %s where PARENT_ID = '%s'", table, parentID);
ret = sql_get_table(db, sql, &result, NULL, NULL);
if( result[2] && (sscanf(rindex(result[2], '$')+1, "%llX", &objectID) == 1) )
{
objectID++;
}
sqlite3_free_table(result);
free(sql);
return objectID;
}
long long int
insert_container(const char * tmpTable, const char * item, const char * rootParent, const char *subParent,
const char *class, const char *artist, const char *genre, const char *album_art)
@ -73,29 +93,13 @@ insert_container(const char * tmpTable, const char * item, const char * rootPare
if( cols )
{
sscanf(result[4], "%X", &parentID);
sqlite3_free_table(result);
sql = sqlite3_mprintf("SELECT OBJECT_ID, max(ID) from OBJECTS where PARENT_ID = '%s$%X'", rootParent, parentID);
ret = sql_get_table(db, sql, &result, 0, &cols);
sqlite3_free(sql);
if( result[2] && (sscanf(rindex(result[2], '$')+1, "%X", &objectID) == 1) )
{
objectID++;
}
asprintf(&sql, "%s$%X", rootParent, parentID);
objectID = get_next_available_id("OBJECTS", sql);
free(sql);
}
else
{
sqlite3_free_table(result);
sql = sqlite3_mprintf("SELECT OBJECT_ID, max(ID) from OBJECTS where PARENT_ID = '%s'", rootParent);
sql_get_table(db, sql, &result, &rows, &cols);
sqlite3_free(sql);
if( result[2] && (sscanf(rindex(result[2], '$')+1, "%X", &parentID) == 1) )
{
parentID++;
}
else
{
parentID = 0;
}
parentID = get_next_available_id("OBJECTS", rootParent);
detailID = GetFolderMetadata(item, artist, genre, album_art);
sql = sqlite3_mprintf( "INSERT into OBJECTS"
" (OBJECT_ID, PARENT_ID, DETAIL_ID, CLASS, NAME) "
@ -301,13 +305,14 @@ insert_directory(const char * name, const char * path, const char * base, const
char * id_buf = NULL;
char * parent_buf = NULL;
char **result;
char *dir = strdup(path);
char *dir = NULL;
if( strcmp(base, BROWSEDIR_ID) != 0 )
asprintf(&refID, "%s%s$%X", BROWSEDIR_ID, parentID, objectID);
if( refID )
{
dir = strdup(path);
dir = dirname(dir);
asprintf(&id_buf, "%s%s$%X", base, parentID, objectID);
asprintf(&parent_buf, "%s%s", base, parentID);
@ -315,19 +320,28 @@ insert_directory(const char * name, const char * path, const char * base, const
{
sql = sqlite3_mprintf("SELECT count(OBJECT_ID) from OBJECTS where OBJECT_ID = '%s'", id_buf);
if( (sql_get_table(db, sql, &result, NULL, NULL) == SQLITE_OK) && atoi(result[1]) )
{
sqlite3_free_table(result);
sqlite3_free(sql);
break;
}
sqlite3_free_table(result);
sqlite3_free(sql);
/* Does not exist. Need to create, and may need to create parents also */
sql = sqlite3_mprintf("SELECT DETAIL_ID from OBJECTS where OBJECT_ID = '%s'", refID);
if( (sql_get_table(db, sql, &result, NULL, NULL) == SQLITE_OK) && atoi(result[1]) )
{
detailID = atoi(result[1]);
}
sqlite3_free_table(result);
sqlite3_free(sql);
sql = sqlite3_mprintf( "INSERT into OBJECTS"
" (OBJECT_ID, PARENT_ID, REF_ID, DETAIL_ID, CLASS, NAME) "
"VALUES"
" ('%s', '%s', %Q, '%lld', '%s', '%q')",
id_buf, parent_buf, refID, detailID, class, rindex(dir, '/')+1);
sql_exec(db, sql);
sqlite3_free(sql);
if( rindex(id_buf, '$') )
*rindex(id_buf, '$') = '\0';
if( rindex(parent_buf, '$') )
@ -336,8 +350,10 @@ insert_directory(const char * name, const char * path, const char * base, const
*rindex(refID, '$') = '\0';
dir = dirname(dir);
}
sqlite3_free(sql);
free(refID);
free(parent_buf);
free(id_buf);
free(dir);
return 1;
}
@ -365,16 +381,12 @@ insert_file(char * name, const char * path, const char * parentID, int object)
unsigned long int detailID = 0;
char base[8];
char * typedir_parentID;
int typedir_objectID;
int typedir_objectID = 0;
char * baseid;
static long unsigned int fileno = 0;
printf("Scanned %lu files...\r", fileno++); fflush(stdout);
sprintf(objectID, "%s%s$%X", BROWSEDIR_ID, parentID, object);
typedir_parentID = strdup(parentID);
sscanf(rindex(typedir_parentID, '$')+1, "%X", &typedir_objectID);
*rindex(typedir_parentID, '$') = '\0';
if( is_image(name) )
{
strcpy(base, IMAGE_DIR_ID);
@ -397,6 +409,15 @@ insert_file(char * name, const char * path, const char * parentID, int object)
if( !detailID )
return -1;
sprintf(objectID, "%s%s$%X", BROWSEDIR_ID, parentID, object);
typedir_parentID = strdup(parentID);
baseid = rindex(typedir_parentID, '$');
if( baseid )
{
sscanf(baseid+1, "%X", &typedir_objectID);
*baseid = '\0';
}
insert_directory(name, path, base, typedir_parentID, typedir_objectID);
sql = sqlite3_mprintf( "INSERT into OBJECTS"
@ -406,6 +427,7 @@ insert_file(char * name, const char * path, const char * parentID, int object)
objectID, BROWSEDIR_ID, parentID, class, detailID, name);
//DEBUG printf("SQL: %s\n", sql);
sql_exec(db, sql);
sqlite3_free(sql);
sql = sqlite3_mprintf( "INSERT into OBJECTS"
" (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
@ -416,12 +438,14 @@ insert_file(char * name, const char * path, const char * parentID, int object)
sql_exec(db, sql);
sqlite3_free(sql);
free(typedir_parentID);
insert_containers(name, path, objectID, class, detailID);
return 0;
}
int
create_database(void)
CreateDatabase(void)
{
int ret, i;
char sql_buf[512];
@ -569,42 +593,52 @@ filter_media(const struct dirent *d)
}
void
ScanDirectory(const char * dir, const char * parent)
ScanDirectory(const char * dir, const char * parent, enum media_types type)
{
struct dirent **namelist;
int n, i;
int n, i, startID = 0;
char parent_id[PATH_MAX];
char full_path[PATH_MAX];
char * name;
#if USE_FORK
pid_t newpid;
#endif
if( !parent )
{
if( create_database() != 0 )
{
fprintf(stderr, "Error creating database!\n");
return;
}
#if USE_FORK
newpid = fork();
if( newpid )
return;
#endif
}
char * name = NULL;
setlocale(LC_COLLATE, "");
if( chdir(dir) != 0 )
return;
printf("\nScanning %s\n", dir);
n = scandir(".", &namelist, filter_media, alphasort);
switch( type )
{
case ALL_MEDIA:
n = scandir(".", &namelist, filter_media, alphasort);
break;
case AUDIO_ONLY:
n = scandir(".", &namelist, filter_audio, alphasort);
break;
case VIDEO_ONLY:
n = scandir(".", &namelist, filter_video, alphasort);
break;
case IMAGES_ONLY:
n = scandir(".", &namelist, filter_images, alphasort);
break;
default:
break;
}
if (n < 0) {
fprintf(stderr, "Error scanning %s [scandir]\n", dir);
return;
}
/* sql = sqlite3_mprintf("SELECT OBJECT_ID, max(ID) from OBJECTS where PARENT_ID = '%s$%X'", rootParent, parentID);
ret = sql_get_table(db, sql, &result, 0, &cols);
if( result[2] && (sscanf(rindex(result[2], '$')+1, "%X", &objectID) == 1) )
{
objectID++;
}
*/
if( !parent )
startID = get_next_available_id("OBJECTS", BROWSEDIR_ID);
for (i=0; i < n; i++) {
name = NULL;
sprintf(full_path, "%s/%s", dir, namelist[i]->d_name);
if( index(namelist[i]->d_name, '&') )
{
@ -612,16 +646,19 @@ ScanDirectory(const char * dir, const char * parent)
}
if( namelist[i]->d_type == DT_DIR )
{
insert_directory(name?name:namelist[i]->d_name, full_path, BROWSEDIR_ID, (parent ? parent:""), i);
sprintf(parent_id, "%s$%X", (parent ? parent:""), i);
ScanDirectory(full_path, parent_id);
insert_directory(name?name:namelist[i]->d_name, full_path, BROWSEDIR_ID, (parent ? parent:""), i+startID);
sprintf(parent_id, "%s$%X", (parent ? parent:""), i+startID);
ScanDirectory(full_path, parent_id, type);
}
else
{
insert_file(name?name:namelist[i]->d_name, full_path, (parent ? parent:""), i);
insert_file(name?name:namelist[i]->d_name, full_path, (parent ? parent:""), i+startID);
}
if( name )
{
free(name);
name = NULL;
}
free(namelist[i]);
}
free(namelist);
@ -632,8 +669,5 @@ ScanDirectory(const char * dir, const char * parent)
else
{
printf("Scanning \"%s\" finished!\n", dir);
#if USE_FORK
_exit(0);
#endif
}
}

View File

@ -15,7 +15,10 @@
#define VIDEO_DIR_ID "2$21"
#define IMAGE_DIR_ID "3$22"
int
CreateDatabase(void);
void
ScanDirectory(const char * dir, const char * parent);
ScanDirectory(const char * dir, const char * parent, enum media_types type);
#endif

View File

@ -26,6 +26,7 @@ int logpackets = 0;
#endif
struct runtime_vars_s runtime_vars;
int runtime_flags = 0;
const char * pidfilename = "/var/run/minidlna.pid";
@ -44,5 +45,5 @@ struct lan_addr_s lan_addr[MAX_LAN_ADDR];
/* UPnP-A/V [DLNA] */
sqlite3 *db;
char media_dir[MEDIADIR_MAX_LEN];
struct media_dir_s * media_dirs = NULL;
char friendly_name[FRIENDLYNAME_MAX_LEN];

View File

@ -47,6 +47,7 @@
/* statup time */
extern time_t startup_time;
extern struct runtime_vars_s runtime_vars;
/* runtime boolean flags */
extern int runtime_flags;
#define LOGPACKETSMASK 0x0001
@ -81,7 +82,7 @@ extern struct lan_addr_s lan_addr[];
/* UPnP-A/V [DLNA] */
extern sqlite3 *db;
#define MEDIADIR_MAX_LEN (256)
extern char media_dir[];
extern struct media_dir_s * media_dirs;
#define FRIENDLYNAME_MAX_LEN (64)
extern char friendly_name[];

View File

@ -1178,6 +1178,9 @@ SendResp_dlnafile(struct upnphttp * h, char * object)
int sendfh;
#if USE_FORK
pid_t newpid = 0;
newpid = fork();
if( newpid )
return;
#endif
memset(header, 0, 1500);
@ -1192,15 +1195,10 @@ SendResp_dlnafile(struct upnphttp * h, char * object)
sqlite3_free_table(result);
return;
}
#if USE_FORK
newpid = fork();
if( newpid )
return;
#endif
path = result[3];
mime = result[4];
dlna = result[5];
printf("Serving DetailID: %s [%s]\n", object, path);
if( h->reqflags & FLAG_XFERSTREAMING )

View File

@ -270,10 +270,10 @@ static int callback(void *args, int argc, char **argv, char **azColName)
}
if( album_art && atoi(album_art) && (!passed_args->filter || strstr(passed_args->filter, "upnp:albumArtURI")) ) {
sprintf(str_buf, "&lt;upnp:albumArtURI %s"
"&gt;http://%s:5555/AlbumArt/%s.jpg&lt;/upnp:albumArtURI&gt;",
"&gt;http://%s:%d/AlbumArt/%s.jpg&lt;/upnp:albumArtURI&gt;",
(!passed_args->filter || strstr(passed_args->filter, "upnp:albumArtURI@dlna:profileID")) ?
"dlna:profileID=\"JPEG_TN\" xmlns:dlna=\"urn:schemas-dlnaorg:metadata-1-0/\"" : "",
lan_addr[0].str, album_art);
lan_addr[0].str, runtime_vars.port, album_art);
strcat(passed_args->resp, str_buf);
}
if( !passed_args->filter || strstr(passed_args->filter, "res") ) {
@ -303,26 +303,26 @@ static int callback(void *args, int argc, char **argv, char **azColName)
strcat(passed_args->resp, str_buf);
}
sprintf(str_buf, "protocolInfo=\"http-get:*:%s:%s\"&gt;"
"http://%s:5555/MediaItems/%s.dat"
"http://%s:%d/MediaItems/%s.dat"
"&lt;/res&gt;",
mime, dlna_buf, lan_addr[0].str, detailID);
mime, dlna_buf, lan_addr[0].str, runtime_vars.port, detailID);
#if 0 //JPEG_RESIZE
if( dlna_pn && (strncmp(dlna_pn, "JPEG_LRG", 8) == 0) ) {
strcat(passed_args->resp, str_buf);
sprintf(str_buf, "&lt;res "
"protocolInfo=\"http-get:*:%s:%s\"&gt;"
"http://%s:5555/Resized/%s"
"http://%s:%d/Resized/%s"
"&lt;/res&gt;",
mime, "DLNA.ORG_PN=JPEG_SM", lan_addr[0].str, id);
mime, "DLNA.ORG_PN=JPEG_SM", lan_addr[0].str, runtime_vars.port, id);
}
#endif
if( tn && atoi(tn) && dlna_pn ) {
strcat(passed_args->resp, str_buf);
strcat(passed_args->resp, "&lt;res ");
sprintf(str_buf, "protocolInfo=\"http-get:*:%s:%s\"&gt;"
"http://%s:5555/Thumbnails/%s.dat"
"http://%s:%d/Thumbnails/%s.dat"
"&lt;/res&gt;",
mime, "DLNA.ORG_PN=JPEG_TN", lan_addr[0].str, detailID);
mime, "DLNA.ORG_PN=JPEG_TN", lan_addr[0].str, runtime_vars.port, detailID);
}
strcat(passed_args->resp, str_buf);
}
@ -369,7 +369,7 @@ static int callback(void *args, int argc, char **argv, char **azColName)
}
if( album_art && atoi(album_art) && (!passed_args->filter || strstr(passed_args->filter, "upnp:albumArtURI")) ) {
sprintf(str_buf, "&lt;upnp:albumArtURI dlna:profileID=\"JPEG_TN\" xmlns:dlna=\"urn:schemas-dlnaorg:metadata-1-0/\""
"&gt;http://%s:5555/AlbumArt/%s.jpg&lt;/upnp:albumArtURI&gt;", lan_addr[0].str, album_art);
"&gt;http://%s:%d/AlbumArt/%s.jpg&lt;/upnp:albumArtURI&gt;", lan_addr[0].str, runtime_vars.port, album_art);
strcat(passed_args->resp, str_buf);
}
sprintf(str_buf, "&lt;/container&gt;");