$NetBSD: patch-af,v 1.9 2004/09/12 05:08:28 minskim Exp $

--- mserv/mserv.c.orig	2003-08-03 16:57:20.000000000 +0200
+++ mserv/mserv.c	2012-02-07 10:39:02.000000000 +0100
@@ -62,12 +62,17 @@
 #include <sys/ioctl.h>
 #include <time.h>
 
+#ifdef PARSE_OGG_INFO
+#include <vorbis/codec.h>
+#include <vorbis/vorbisfile.h>
+#endif
+
 #include "mserv.h"
 #include "misc.h"
 #include "cmd.h"
 #include "acl.h"
 #include "mp3info.h"
-#include "soundcard.h"
+#include "mservsoundcard.h"
 #include "defconf.h"
 #include "conf.h"
 #include "opt.h"
@@ -79,6 +84,10 @@
 # define MIN(X,Y) (((X) < (Y)) ? (X) : (Y))
 #endif
 
+#ifndef HAVE_STRLCPY
+#define strlcpy strncpy
+#endif
+
 extern char *optarg;
 extern int optind;
 /* extern int getopt(int, char *const *, const char *); */ /* sunos ;( */
@@ -131,7 +140,8 @@
 static void mserv_scandir(void);
 static void mserv_scandir_recurse(const char *pathname);
 static t_track *mserv_loadtrk(const char *filename);
-static t_album *mserv_loadalbum(const char *filename, int onlyifexists);
+static t_album *mserv_loadalbum(const char *filename, int onlyifexists,
+			const char *default_author);
 static int album_insertsort(t_album *album);
 static t_author *mserv_authorlist(void);
 static int author_insertsort(t_author **list, t_author *author);
@@ -224,7 +234,7 @@
   int i;
   struct protoent *protocol;
   struct sockaddr_in sin;
-  int so_int;
+  int so_int, proto;
   int flags;
   char *mserv_root = NULL;
   char *mserv_conf = NULL;
@@ -292,7 +302,7 @@
 	     ps->pw_dir[strlen(ps->pw_dir)-1] == '/' ? "" : "/");
   } else {
     /* copy out of environment */
-    if ((m = malloc(strlen(mserv_root))) == NULL) {
+    if ((m = malloc(strlen(mserv_root)+1)) == NULL) {
       fprintf(stderr, "%s: out of memory\n", progname);
       exit(1);
     }
@@ -305,7 +315,7 @@
     l--;
   mserv_root[l] = '\0';
   if (!mserv_conf) {
-    if ((m = malloc(strlen(mserv_root)+sizeof("/config"))) == NULL) {
+    if ((m = malloc(strlen(mserv_root)+sizeof("/config")+1)) == NULL) {
       fprintf(stderr, "%s: out of memory\n", progname);
       exit(1);
     }
@@ -427,8 +437,13 @@
  
   if (mserv_verbose && mserv_port)
     printf("Port set via command line options to %d\n", mserv_port);
+
   protocol = getprotobyname("IP");
-  mserv_socket = socket(AF_INET, SOCK_STREAM, protocol->p_proto);
+  if (protocol)
+    proto = protocol->p_proto;
+  else
+    proto = IPPROTO_IP;
+  mserv_socket = socket(AF_INET, SOCK_STREAM, proto);
   if (mserv_socket == -1) {
     mserv_log("Socket error '%s'", strerror(errno));
     mserv_closedown(1);
@@ -1624,6 +1639,7 @@
   int i;
   t_album *album;
   int flag = 0;
+  const char *default_author = 0;
 
   /* pathname is "" or "directory/" or "directory/directory/..." */
 
@@ -1686,22 +1702,32 @@
       toomany = 1;
       break;
     }
+
     if (mserv_verbose)
       mserv_log("Track file: %s", fullpath);
     if ((tracks[tnum] = mserv_loadtrk(filename)) == NULL) {
       mserv_log("Unable to add track '%s'", fullpath);
     } else {
+
+      if (default_author == 0)
+        default_author = tracks[tnum]->author;
+      else if (default_author != (const char *)-1 && strcmp(default_author,
+						  tracks[tnum]->author))
+        default_author = (const char *)-1;
+
       tracks[tnum]->id = mserv_nextid_track++;
       tracks[tnum]->n_album = mserv_nextid_album;
       tracks[tnum]->n_track = tnum+1;
       tracks[tnum]->next = mserv_tracks;
       mserv_tracks = tracks[tnum++];
     }
+
     flag = 1; /* there is at least one track in this directory */
   }
   closedir(dir);
   /* load album, but only if there is an album file or flag is set */
-  if ((album = mserv_loadalbum(pathname, flag ? 0 : 1)) == NULL)
+  if ((album = mserv_loadalbum(pathname, flag ? 0 : 1,
+	(default_author == (const char *)-1) ?0 :default_author)) == NULL)
     return;
   qsort(tracks, TRACKSPERALBUM, sizeof(t_track *),
 	mserv_trackcompare_filename);
@@ -1815,7 +1841,7 @@
   }
 }
 
-static t_album *mserv_loadalbum(const char *filename, int onlyifexists)
+static t_album *mserv_loadalbum(const char *filename, int onlyifexists, const char *default_author)
 {
   FILE *fd;
   char fullpath[MAXFNAME];
@@ -1899,8 +1925,13 @@
       return NULL;
     mtime = time(NULL);
   }
-  if (!*author)
-    strcpy(author, "!-Unindexed");
+  if (!*author) {
+    if (default_author)
+      strcpy(author, default_author);
+    else
+      strcpy(author, "!-Unindexed");
+  }
+      
   if (!*name) {
     if (!*filename || !*(filename+1)) {
       strcpy(name, "rootdir");
@@ -2019,11 +2050,13 @@
       alen = strlen(buffer);
       if (buffer[alen-1] != '\n') {
 	mserv_log("Line %d too long in '%s'", line, fullpath_trk);
+	fclose(fd);
 	return NULL;
       }
       buffer[--alen] = '\0';
       if (!(l = strcspn(buffer, "=")) || l >= 64) {
 	mserv_log("Invalid track line %d in '%s'", line, fullpath_trk);
+	fclose(fd);
 	return NULL;
       }
       strncpy(token, buffer, l);
@@ -2059,6 +2092,7 @@
 	}
 	if ((arate = malloc(sizeof(t_rating)+strlen(token)+1)) == NULL) {
 	  mserv_log("Out of memory creating ratings for '%s'", fullpath_trk);
+	  fclose(fd);
 	  return NULL;
 	}
 	memset(arate, 0, sizeof(t_rating));
@@ -2082,15 +2116,18 @@
     }
     if (!*author) {
       mserv_log("No author specified in '%s'", fullpath_trk);
+      fclose(fd);
       return NULL;
     }
     if (!*name) {
       mserv_log("No name specified in '%s'", fullpath_trk);
+      fclose(fd);
       return NULL;
     }
     if (fstat(fileno(fd), &buf) == -1) {
       perror("fstat");
       mserv_log("Unable to stat '%s': %s", filename, strerror(errno));
+      fclose(fd);
       return NULL;
     }
     mtime = buf.st_mtime;
@@ -2098,8 +2135,17 @@
   }
   if (duration == 0 && !*miscinfo) {
     len = strlen(fullpath_file);
+#ifdef PARSE_OGG_INFO
+    if (len > 4 && !stricmp(".mp3", fullpath_file+len-4) ||
+	!stricmp(".ogg", fullpath_file+len-4)) {
+      if (!stricmp(".mp3", fullpath_file+len-4))
+        duration = mserv_mp3info_readlen(fullpath_file, &bitrate, &id3tag);
+      else
+        duration = mserv_ogginfo_readlen(fullpath_file, &bitrate, &id3tag);
+#else
     if (len > 4 && !stricmp(".mp3", fullpath_file+len-4)) {
       duration = mserv_mp3info_readlen(fullpath_file, &bitrate, &id3tag);
+#endif
       if (duration == -1) {
 	mserv_log("Unable to determine details of mp3 '%s': %s",
 		  filename, strerror(errno));
@@ -2719,7 +2765,7 @@
   }
   if (buf.st_mtime == album->mtime)
     return album;
-  if ((newalbum = mserv_loadalbum(album->filename, 1)) == NULL) {
+  if ((newalbum = mserv_loadalbum(album->filename, 1, 0)) == NULL) {
     mserv_log("Unable to re-load '%s'", album->filename);
     return album;
   }
@@ -3430,3 +3476,59 @@
 }
 
 #endif
+
+#ifdef PARSE_OGG_INFO
+int mserv_ogginfo_readlen(const char *fname, int *bitrate_ret,
+			  t_id3tag *id3tag)
+{
+  OggVorbis_File    vf;
+  FILE              *f;
+  ogg_sync_state    sync;
+  vorbis_info	    *vi;
+  vorbis_comment    *vc;
+  char		    **comment;
+  double	    duration;
+
+  if (id3tag)
+    memset(id3tag, 0, sizeof(*id3tag));
+
+  if ((f = fopen(fname, "rb")) == NULL)
+    return -1;
+
+  if (ov_open(f, &vf, NULL, 0) < 0) {
+    fclose(f);
+    return -1;
+  }
+
+  if ( !(vi = ov_info(&vf, -1)) || !(vc = ov_comment(&vf, -1))) {
+    ov_clear(&vf);
+    fclose(f);
+    return -1;
+    }
+
+  if (bitrate_ret)
+    *bitrate_ret = vi->bitrate_nominal/1024;
+
+  for (comment = vc->user_comments ; *comment ; ++comment) {
+    if (strncasecmp(*comment, "title=", 6) == 0) {
+	strlcpy(id3tag->title, *comment + 6, MP3ID3_TITLELEN+1);
+        id3tag->present = 1;
+    }
+    else if (strncasecmp(*comment, "artist=", 7) == 0)
+	strlcpy(id3tag->artist, *comment + 7, MP3ID3_ARTISTLEN+1);
+    else if (strncasecmp(*comment, "album=", 6) == 0)
+	strlcpy(id3tag->album, *comment + 6, MP3ID3_ALBUMLEN+1);
+    else if (strncasecmp(*comment, "date=", 5) == 0)
+	strlcpy(id3tag->year, *comment + 5, MP3ID3_YEARLEN+1);
+    else if (strncasecmp(*comment, "genre=", 6) == 0)
+	strlcpy(id3tag->genre, *comment + 6, 31);
+    /* tracknumber ignored */
+  }
+
+  duration = ov_time_total(&vf, -1);
+  ov_clear(&vf);
+  fclose(f);
+  return (int)duration * 100;
+}
+
+#endif
