xfreecd

Audio CD player for X
git clone https://www.brianlane.com/git/xfreecd
Log | Files | Refs | README | LICENSE

cddb.c (21691B)


      1 /* ---------------------------------------------------------------------
      2    basic cddb functions for XfreeCD
      3 
      4    Copyright 1998 by Brian C. Lane
      5    nexus@tatoosh.com
      6    http://www.tatoosh.com/nexus
      7 
      8    This program is free software; you can redistribute it and/or
      9    modify it under the terms of the GNU General Public License
     10    as published by the Free Software Foundation; either version 2
     11    of the License, or (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program; if not, write to the Free Software
     20    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     21 
     22    =============================[ HISTORY ]=============================
     23    06/19/98     Adding write extended data to the database. DONE.
     24                 Switching to using g_malloc, g_free, g_realloc -- they're
     25 		safer than libc and can provide usage stats.
     26 
     27    06/16/98     Need to add support for extended data lines. Split lines
     28                 too of course. This data needs to make it into the
     29 		database, and be able to send it to the server when
     30 		the CD is edited.
     31 
     32 		Revision # support needs to be added to. Read it and
     33 		increment it when the CD is submitted to the server.
     34 		FIXED.
     35 
     36    06/06/98     I need to support split TTITLE lines, and get the
     37                 track # from the TTITLE line instead of assuming they
     38 		just go in order.
     39 		I found my garbage at the end of the file problem. If
     40 		A long file was written then it was shortened it
     41 		wouldn't erase it first, it would just write over
     42 		the top and leave the old stuff hanging off the end.
     43 		So I added an unlink to delete it first.
     44 
     45    05/27/98     Adding creation of the cddb database directories if
     46                 they don't exist (only creates the ones that don't
     47 		exist). Added to write_cddb(). Only creates what it
     48 		needs to. This way it isn't limited to a static list of
     49 		categories. Works.
     50 		Found a bug. CDDB read/write don't handle multiple
     51 		DTITLEs very well.
     52 
     53    05/16/98     Added expansion of ~/ to $HOME enviornmental variable
     54                 Added a local_cddb path in the cdinfo structure to point
     55 		to the local storage location for writing and reading
     56 		cd information.
     57 
     58    05/11/98     Split off reading code to read_cddb_file so it can be
     59                 used to read a specific temporary file after the data
     60 		is downloaded from the server.
     61 
     62    05/09/98     Started this part of the XfreeCD code. 
     63                 Correct operation confirmed for discid using
     64 		Bryan Adams / Waking up the Neighbors id 0xce118c0f
     65 		Writing database entries works well so far, frames,
     66 		length, and discid are correct. Default track and title
     67 		strings are saved ok too.
     68 		find_discid works.
     69 
     70    ---------------------------------------------------------------------
     71    This file includes support for saving and loading local database
     72    information.
     73    --------------------------------------------------------------------- */
     74 #include <stdio.h>
     75 #include <sys/types.h>
     76 #include <unistd.h>
     77 #include <sys/stat.h>
     78 #include <fcntl.h>
     79 #include <string.h>
     80 #include <dirent.h>
     81 #include <stdlib.h>
     82 #include <errno.h>
     83 #include <gtk/gtk.h>
     84 #include "xfreecd.h"
     85 #include "cd_control.h"
     86 #include "cddb.h"
     87 
     88 #undef DEBUG1
     89 #undef DEBUG2
     90 #undef DEBUG3
     91 #undef DEBUG6
     92 #undef DEBUG9
     93 
     94 int
     95 cddb_sum(int n)
     96 {
     97 	char	buf[12],
     98 		*p;
     99 	int	ret = 0;
    100 
    101 	/* For backward compatibility this algorithm must not change */
    102 	sprintf(buf, "%lu", n);
    103 	for (p = buf; *p != '\0'; p++)
    104 		ret += (*p - '0');
    105 
    106 	return (ret);
    107 }
    108 
    109 unsigned long cddb_discid( struct CDINFO *cdinfo )
    110 {
    111   int	i,
    112         t = 0,
    113         n = 0,
    114         tot_trks;
    115 
    116   tot_trks = cdinfo->tochdr.cdth_trk1;
    117 
    118   /* For backward compatibility this algorithm must not change */
    119   for (i = 0; i < tot_trks; i++)
    120     n += cddb_sum((cdinfo->track[i].te.cdte_addr.msf.minute * 60) + cdinfo->track[i].te.cdte_addr.msf.second);
    121   
    122   t = ((cdinfo->leadout.cdte_addr.msf.minute * 60) + cdinfo->leadout.cdte_addr.msf.second) - ((cdinfo->track[0].te.cdte_addr.msf.minute * 60) + cdinfo->track[0].te.cdte_addr.msf.second);
    123   
    124   return ((n % 0xff) << 24 | t << 8 | tot_trks);
    125 }
    126 
    127 
    128 /* -------------------------------------------------------------------------
    129    Write the data from cdinfo structure to the correct file in the selected
    130    category.
    131 
    132    The master database directory is in cdinfo->local_cddb
    133 
    134    How do I check for the same CD with a different ID so I can symlink?
    135 
    136    if over is 0 then check to make sure the file doesn't already exist
    137    if over is 1 then go ahead and overwrite it.
    138 
    139    return -2 if the file already exists.
    140    return -3 if the HOME variable cannot be found
    141    return -4 if we had trouble creating the local cddb directories
    142    ------------------------------------------------------------------------- */
    143 int write_cddb( struct CDINFO *cdinfo, int over )
    144 {
    145   char  fname[1024],
    146         tmp_fname[1024],
    147         tmpstr[255],
    148         idstr[9],
    149         *p;
    150   int   fd,
    151         x,
    152         i;
    153   struct stat   sbuf;
    154 
    155   /* Copy the path to the local datbase to a temporary variable */
    156   strncpy( fname, cdinfo->local_cddb, 1023 );
    157 
    158   /* Convert a leading ~ into the user's HOME directory */
    159   if( fname[0] == '~' )
    160     {
    161       /* Copy the reset of the path/filename to tmp_fname */
    162       strncpy( tmp_fname, &fname[1], 1023 );
    163 
    164       if( ( p = getenv("HOME") ) == NULL )
    165 	{
    166 	  return(-3);
    167 	}
    168       strncpy( fname, p, 1023 );
    169 
    170       /* Make sure there is a slash inbetween */
    171       if( (fname[strlen(fname)-1] != '/') && (tmp_fname[0] != '/') )
    172 	{
    173 	  strcat( fname, "/" );
    174 	}
    175 
    176       strncat( fname, tmp_fname, 1023-strlen( p ) );
    177     }
    178 
    179 #ifdef DEBUG1
    180   g_print("write_cddb( %s )\n", fname );
    181 #endif
    182 
    183   /* 
    184      See if we have the top level directory. If not, try to create it.
    185   */
    186   if( stat( fname, &sbuf ) < 0 )
    187     {
    188       /* If the top level directory doesn't exist, create it */
    189       if( errno == ENOENT )
    190 	{
    191 	  /* Try to make the top level directory, if it fails, quit */
    192 	  if( mkdir( fname, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH | S_IROTH ) < 0 )
    193 	    {
    194 	      return(-4);
    195 	    }
    196 	} else {
    197 	  return(-4);
    198 	}
    199     }
    200 
    201 
    202   /* Make sure we have slashes between the path and category directory */
    203   if( fname[strlen(fname)] != '/' )
    204     strcat( fname, "/" );
    205   strcat( fname, cdinfo->category->str );
    206   if( fname[strlen(fname)] != '/' )
    207     strcat( fname, "/" );
    208 
    209   /*
    210     See if the category directory exists. If not, create it.
    211   */
    212   if( stat( fname, &sbuf ) < 0 )
    213     {
    214       /* If the top level directory doesn't exist, create it */
    215       if( errno == ENOENT )
    216 	{
    217 	  /* Try to make the category directory, if it fails, quit with an error*/
    218 	  if( mkdir( fname, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH | S_IROTH ) < 0 )
    219 	    {
    220 	      return(-4);
    221 	    }
    222 	} else {
    223 	  return(-4);
    224 	}
    225     }
    226 
    227   sprintf( idstr, "%08lx", cdinfo->discid );
    228   strcat( fname, idstr );
    229 
    230   /* Should we check for prior existance? */  
    231   if( !over )
    232     {
    233       if( ( fd = open( fname, O_RDONLY ) ) != -1 )
    234 	{
    235 	  close( fd );
    236 	  return(-2);
    237 	}
    238     }
    239 
    240   /* Make sure it is deleted */
    241   unlink( fname );
    242 
    243   if( ( fd = open( fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ) < 0 )
    244     {
    245       return(-1);
    246     }
    247 
    248   /* Write the cddb entry from the info in the cdinfostructure */
    249   sprintf( tmpstr, "# xmcd CD database file generated by XfreeCD %s\n", VERSION );
    250 
    251   if( write( fd, tmpstr, strlen( tmpstr) ) < 0 )
    252     {
    253       close( fd );
    254       return(-1);
    255     }
    256 
    257   sprintf( tmpstr, "#\n# Track frame offsets:\n" );
    258   if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    259     {
    260       close( fd );
    261       return(-1);
    262     }
    263 
    264   /* Write the frame offset for each track */
    265   for( x = 0; x < cdinfo->tochdr.cdth_trk1; x++ )
    266     {
    267       sprintf( tmpstr, "#\t%ld\n", cdinfo->track[x].frame_offset );
    268       if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    269 	{
    270 	  close( fd );
    271 	  return(-1);
    272 	}
    273     }
    274 
    275   strcpy( tmpstr, "#\n" );
    276   if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    277     {
    278       close( fd );
    279       return(-1);
    280     }
    281 
    282   sprintf( tmpstr, "# Disc length: %d seconds\n#\n", cdinfo->cd_length );
    283   if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    284     {
    285       close( fd );
    286       return(-1);
    287     }
    288  
    289   sprintf( tmpstr, "# Revision: %d\n", cdinfo->revision );
    290   if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    291     {
    292       close( fd );
    293       return(-1);
    294     }
    295 
    296   sprintf( tmpstr, "# Submitted via: XfreeCD %s\n#\n", VERSION );
    297   if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    298     {
    299       close( fd );
    300       return(-1);
    301     } 
    302 
    303   sprintf( tmpstr, "DISCID=%08lx\n", cddb_discid( cdinfo ) );
    304   if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    305     {
    306       close( fd );
    307       return(-1);
    308     } 
    309 
    310   if( (cdinfo->title == NULL) || (cdinfo->title->len == 0) )
    311     {
    312       if( write( fd, "DTITLE=\n", 8 ) < 0 )
    313 	{
    314 	  close( fd );
    315 	  return(-1);
    316 	} 
    317     } else {
    318       /* If the title is too long, split it up into 70 byte chunks */
    319       i = 0;
    320       p = cdinfo->title->str;
    321       while( i < cdinfo->title->len )
    322 	{
    323 	  strcpy( tmpstr, "DTITLE=" );
    324 	  strncat( tmpstr, p, 70 );
    325 	  strcat( tmpstr, "\n" );
    326 
    327 	  if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    328 	    {
    329 	      close( fd );
    330 	      return(-1);
    331 	    } 
    332 	  
    333 	  if( cdinfo->title->len > 70 )
    334 	    {
    335 	      p = p + 70;
    336 	      i += 70;
    337 	    } else { 
    338 	      i = cdinfo->title->len;
    339 	    }
    340 	}
    341     }
    342 
    343   /* Write the titles */
    344   for( x = 0; x < cdinfo->tochdr.cdth_trk1; x++ )
    345     {
    346       if( (cdinfo->name[x] == NULL) || (cdinfo->name[x]->len == 0) )
    347 	{
    348 	  sprintf( tmpstr, "TTITLE%d=\n", x );
    349 	  if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    350 	    {
    351 	      close( fd );
    352 	      return(-1);
    353 	    } 
    354 	} else {
    355 	  
    356 	  /* If the track name is too long, split it up into 70 byte chunks */
    357 	  i = 0;
    358 	  p = cdinfo->name[x]->str;
    359 	  while( i < cdinfo->name[x]->len )
    360 	    {
    361 	      sprintf( tmpstr, "TTITLE%d=", x );
    362 	      strncat( tmpstr, p, 70 );
    363 	      strcat( tmpstr, "\n" );
    364 
    365 	      if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    366 		{
    367 		  close( fd );
    368 		  return(-1);
    369 		} 
    370 
    371 	      if( cdinfo->name[x]->len > 70 )
    372 		{
    373 		  p = p + 70;
    374 		  i += 70;
    375 		} else { 
    376 		  i = cdinfo->name[x]->len;
    377 		}
    378 	    }
    379 	}
    380     }
    381   
    382   /* Check for a null entry first */
    383   if( (cdinfo->extd == NULL) || (cdinfo->extd->len == 0) )
    384     {
    385       if( write( fd, "EXTD=\n", 6 ) < 0 )
    386 	{
    387 	  close( fd );
    388 	  return(-1);
    389 	} 
    390     } else {
    391       /* Write the extended disc data to the file. It it is too long, break it
    392 	 up into 70 byte chuncks
    393       */
    394       i = 0;
    395       p = cdinfo->extd->str;
    396       while( i < cdinfo->extd->len )
    397 	{
    398 	  strcpy( tmpstr, "EXTD=" );
    399 	  strncat( tmpstr, p, 70 );
    400 	  strcat( tmpstr, "\n" );
    401 	  
    402 	  if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    403 	    {
    404 	      close( fd );
    405 	      return(-1);
    406 	    } 
    407 
    408 	  if( cdinfo->extd->len > 70 )
    409 	    {
    410 	      p = p + 70;
    411 	      i += 70;
    412 	    } else { 
    413 	      i = cdinfo->extd->len;
    414 	    }
    415 	}
    416     }
    417 
    418   /* Write the extended title information to the database */
    419   for( x = 0; x < cdinfo->tochdr.cdth_trk1; x++ )
    420     {
    421       if( (cdinfo->extt[x] == NULL) || (cdinfo->extt[x]->len == 0) )
    422 	{
    423 	  sprintf( tmpstr, "EXTT%d=\n", x );
    424 	  if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    425 	    {
    426 	      close( fd );
    427 	      return(-1);
    428 	    } 
    429 	} else {
    430 	  /* If the track name is too long, split it up into 70 byte chunks */
    431 	  i = 0;
    432 	  p = cdinfo->extt[x]->str;
    433 	  while( i < cdinfo->extt[x]->len )
    434 	    {
    435 	      sprintf( tmpstr, "EXTT%d=", x );
    436 	      strncat( tmpstr, p, 70 );
    437 	      strcat( tmpstr, "\n" );
    438 
    439 	      if( write( fd, tmpstr, strlen( tmpstr ) ) < 0 )
    440 		{
    441 		  close( fd );
    442 		  return(-1);
    443 		} 
    444 
    445 	      if( cdinfo->extt[x]->len > 70 )
    446 		{
    447 		  p = p + 70;
    448 		  i += 70;
    449 		} else { 
    450 		  i = cdinfo->extt[x]->len;
    451 		}
    452 	    }
    453 	}
    454     }
    455 
    456   /* XfreeCD doesn't use this at all */
    457   if( write( fd, "PLAYORDER=\n", 11 ) < 0 )
    458     {
    459       close( fd );
    460       return(-1);
    461     } 
    462     
    463   close( fd );
    464 
    465   return(0);
    466 }
    467 
    468 
    469 /* -----------------------------------------------------------------------
    470    Search all sub-directories below CDDB_PATH for the file to read
    471    Fills in the category with the name of the trailing directory that
    472    it is found in.
    473 
    474 
    475    Return 0 on file found
    476    Return -1 on an error
    477    Return -2 on no file found
    478    ----------------------------------------------------------------------- */
    479 int find_discid( char *fname,                /* Path to local database */
    480 		 unsigned long id,           /* discid to search for   */
    481 		 char *path,                 /* Return full path       */
    482 		 GString **category )        /* Return category found  */
    483 {
    484   DIR   *dp;
    485   struct dirent *dirp;
    486   char  idstr[9],
    487         tmp_fname[1024],
    488         *p;
    489   int   fp;
    490 
    491   /* Convert a leading ~ into the user's HOME directory */
    492   if( fname[0] == '~' )
    493     {
    494       /* Copy the reset of the path/filename to tmp_fname */
    495       strncpy( tmp_fname, &fname[1], 1023 );
    496 
    497       if( ( p = (char *) getenv("HOME") ) == NULL )
    498 	{
    499 	  return(-2);
    500 	}
    501       strncpy( fname, p, 1023 );
    502 
    503       /* Make sure there is a slash inbetween the two */
    504       if( (fname[strlen(fname)-1] != '/') && (tmp_fname[0] != '/') )
    505 	{
    506 	  strcat( fname, "/" );
    507 	}
    508 
    509       strncat( fname, tmp_fname, 1023-strlen( p ) );
    510     }
    511 
    512 #ifdef DEBUG1
    513   g_print("find_discid( %s )\n", fname );
    514 #endif
    515 
    516 
    517   sprintf( idstr, "%08lx", id );
    518 
    519   if( ( dp = opendir( fname ) ) == NULL )
    520     return(-1);
    521 
    522   while( ( dirp = readdir( dp ) ) != NULL )
    523     {
    524       if( (strcmp(dirp->d_name,"." )==0) || (strcmp(dirp->d_name, "..")==0) )
    525 	continue;
    526 
    527       strcpy( path, fname );
    528       if( path[strlen(path)] != '/' )
    529 	strcat( path, "/" );
    530       strcat( path, dirp->d_name );
    531       if( path[strlen(path)] != '/' )
    532 	strcat( path, "/" );
    533       strcat( path, idstr );
    534 
    535       /* Copy the directory name as the category name */
    536       if( *category == NULL )
    537 	*category = g_string_new( dirp->d_name );
    538       else
    539 	*category = g_string_assign( *category, dirp->d_name );
    540 
    541 #ifdef DEBUG1
    542       g_print("Checking %s\n", path );
    543 #endif
    544 
    545       /* Does this file exist? */
    546       if( ( fp = open( path, O_RDONLY ) ) != -1 )
    547 	{
    548 	  close( fp );
    549 	  closedir( dp );
    550 	  return(0);
    551 	}
    552     } 
    553 
    554   closedir( dp );
    555 
    556   return(-2);
    557 }
    558 
    559 
    560 /* -----------------------------------------------------------------------
    561    Read the CDDB info from a filename into a cdinfo structure
    562    Allocate all needed string storage using gtk's g_string functions
    563 
    564    return -2  = failed to find HOME enviornmental variable
    565    ----------------------------------------------------------------------- */
    566 int read_cddb_file( char *fname, struct CDINFO *tmpinfo )
    567 {
    568   int   gotid,
    569         i,
    570         x,
    571         f;
    572   FILE  *fp;
    573   char  line[255],
    574         discid[9],
    575         *p;
    576   
    577   if( ( fp = fopen( fname, "r" ) ) == NULL )
    578     {
    579       return(-1);
    580     }
    581 
    582   /* Read the cddb file, placing data into tmpinfo */
    583   if( fgets( line, 255, fp ) == NULL )
    584     {
    585       fclose( fp );
    586       return(-1);
    587     }
    588 
    589   /* Check the file to make sure its a cddb file */
    590   if( strncmp( line, "# xmcd", 6 ) != 0 )
    591     {
    592       fclose( fp );
    593       return(-1);
    594     }
    595 
    596 #ifdef DEBUG1
    597   g_print("%s", line );
    598 #endif
    599 
    600   /* Find the track offsets, abort serarch at the end of comments */
    601   while( ( line[0] == '#' ) && ( strncmp( line, "# Track frame offsets:",22 ) != 0 )  )
    602     {
    603       if( fgets( line, 255, fp ) == NULL )
    604 	{
    605 	  fclose( fp );
    606 	  return(-1);
    607 	}
    608     }
    609 
    610   /* Skip all the reset of the comments up to Revision: */
    611   while( line[0] == '#' && (strncmp( line, "# Revision:", 11)!=0) )
    612     {
    613       if( fgets( line, 255, fp ) == NULL )
    614 	{
    615 	  fclose( fp );
    616 	  return(-1);
    617 	}
    618     }
    619 
    620   /* If we got the Revision line, get the revision # */
    621   if( strncmp( line, "# Revision:", 11)==0 )
    622     {
    623       sscanf( line, "# Revision: %d", &tmpinfo->revision );
    624 
    625       /* Now read the rest of the comments */
    626       while( line[0] == '#' )
    627 	{
    628 	  if( fgets( line, 255, fp ) == NULL )
    629 	    {
    630 	      fclose( fp );
    631 	      return(-1);
    632 	    }
    633 	}
    634     }
    635 
    636   /* Read discid lines */
    637   /*
    638      How should this be handled? check for our id, and discard all others
    639      that may be present?
    640 
    641      DISCID= lines are comma seperated and can be multiple lines
    642   */
    643   gotid = 0;
    644   sprintf( discid, "%08lx", tmpinfo->discid );
    645   while( strncmp( line, "DISCID=", 7 ) == 0 )
    646     {
    647       if( strstr( line, discid ) != NULL )
    648 	gotid = 1;
    649       if( fgets( line, 255, fp ) == NULL )
    650 	{
    651 	  fclose( fp );
    652 	  return(-1);
    653 	}
    654     }
    655 
    656   /* Process multiple DTITLE lines and concatanate them */
    657   i = 0;
    658   f = 0;
    659   while( strncmp( line, "DTITLE", 6 ) == 0 )
    660   {
    661     p = strtok( line, "=\n" );
    662     p = strtok( NULL, "=\n" );
    663 
    664     /* Add the title to the tmpinfo.title string */
    665     if( f == 0 )
    666       {
    667 	tmpinfo->title = g_string_new( p );
    668 	f = 1;
    669       } else {
    670 	tmpinfo->title = g_string_append( tmpinfo->title, p );
    671       }
    672 
    673     /* Keep reading DTITLE no matter what */
    674     if( fgets( line, 255, fp ) == NULL )
    675       {
    676 	fclose( fp );
    677 	return(-1);
    678       }
    679   }
    680 
    681 #ifdef DEBUG1
    682   g_print("title read = %s\n", tmpinfo->title->str );
    683 #endif
    684 
    685   /*
    686      Copy the titles from the TTITLE strings
    687 
    688      This has to:
    689        Get the track # from the TTITLEx
    690        strcat split title lines up to the limit of storage (255)
    691   */
    692   x = -1;
    693   f = 0;
    694   while( strncmp( line, "TTITLE", 6 ) == 0 )
    695   {
    696     /* Get the track # */
    697     p = strtok( &line[6], "=\n" );
    698 
    699     /* Is it a new track? */
    700     if( atoi(p) != x )
    701       {
    702 	/* Yes, reset the length counter and track name */
    703 	i = 0;
    704 	f = 0;
    705 	tmpinfo->name[atoi(p)] = NULL;
    706       }
    707 
    708     /* Get the track number and make sure its not too big. */
    709     if( ( x = atoi( p ) ) < 99 )
    710       {
    711 	/* Get the track name */
    712 	p = strtok( NULL, "=\n" );
    713 
    714 	/* If its blank, then insert default track name */
    715 	if( p == NULL )
    716 	  {
    717 	    tmpinfo->name[x] = NULL;
    718 	  } else {
    719 	    if( f == 0 )
    720 	      {
    721 		tmpinfo->name[x] = g_string_new( p );
    722 		f = 1;
    723 	      } else {
    724 		tmpinfo->name[x] = g_string_append( tmpinfo->name[x], p );
    725 	      }
    726 	  }
    727       }
    728 
    729     /* Read the next line */
    730     if( fgets( line, 255, fp ) == NULL )
    731       {
    732 	fclose( fp );
    733 	return(-1);
    734       }
    735   }
    736 
    737 
    738   /* Process multiple EXTD lines and concatanate them, dynamically
    739      allocating memory at tmpinfo->extd for it
    740    */
    741   i = 0;
    742   f = 0;
    743   tmpinfo->extd = NULL;
    744   while( strncmp( line, "EXTD", 4 ) == 0 )
    745   {
    746     /* Add to the data until the end is reached */
    747     p = strtok( line, "=\n" );
    748     p = strtok( NULL, "=\n" );
    749 
    750     if( p != NULL )
    751       {
    752 	/* Move the pointer and copy the new string */
    753 	if( f == 0 )
    754 	  {
    755 	    tmpinfo->extd = g_string_new( p );
    756 	    f = 1;
    757 	  } else {
    758 	    tmpinfo->extd = g_string_append( tmpinfo->extd, p );
    759 	  }
    760       }
    761 
    762     /* Keep reading lines */
    763     if( fgets( line, 255, fp ) == NULL )
    764       {
    765 	fclose( fp );
    766 	return(-1);
    767       }
    768   }
    769 
    770 
    771   /*
    772      Copy the extended title data from the EXTTx entries
    773 
    774      This has to:
    775        Get the track # from the EXTTx
    776        Allocate storage for it and copy it over, and handle multiple lines
    777        for each track entry.
    778   */
    779   x = -1;
    780   f = 0;
    781   while( strncmp( line, "EXTT", 4 ) == 0 )
    782   {
    783     /* Get the track # */
    784     p = strtok( &line[4], "=\n" );
    785 
    786     /* Is it a new track? */
    787     if( atoi(p) != x )
    788       {
    789 	/* Yes, reset the length counter and track name */
    790 	i = 0;
    791         f = 0;
    792 	tmpinfo->extt[atoi(p)] = NULL;
    793       }
    794 
    795     /* Get the track number, make sure it isn't too big */
    796     if( ( x = atoi( p ) ) < 99 )
    797       {
    798 	/* Get the extended data from the rest of the line*/
    799 	p = strtok( NULL, "=\n" );
    800 
    801 	/* Process multiple EXTT lines and concatanate them, dynamicly
    802 	   allocating memory at tmpinfo->extd for it
    803 	*/
    804 	if( p != NULL )
    805 	  {
    806 	    /* Move the pointer and copy the new string */
    807 	    if( f == 0 )
    808 	      {
    809 		tmpinfo->extt[x] = g_string_new( p );
    810 		f = 1;
    811 	      } else {
    812 		tmpinfo->extt[x] = g_string_append( tmpinfo->extt[x], p );
    813 	      }
    814 	  }
    815       }
    816 
    817     /* Read the next line */
    818     if( fgets( line, 255, fp ) == NULL )
    819       {
    820 	fclose( fp );
    821 	return(-1);
    822       }
    823   }
    824 
    825   fclose( fp );
    826 
    827   return(0);
    828 }
    829 
    830 
    831 /* -----------------------------------------------------------------------
    832    Read a cddb entry for the current CD
    833 
    834    This needs to search through the sub-directories in CDDB_PATH to find
    835    the discid of the current CD.
    836 
    837    We then read the file, filling in the track names, etc.
    838    We should also compare the frame count to make sure it is the
    839    correct CD.
    840 
    841    Returns -1 if there was an error
    842    Returns -2 if it cannot find the file
    843    ----------------------------------------------------------------------- */
    844 int read_cddb( struct CDINFO *cdinfo )
    845 {
    846   int   x;
    847   char  fname[255];
    848   struct CDINFO tmpinfo;
    849 
    850   /* Clean out the structure */
    851   bzero( &tmpinfo, sizeof( struct CDINFO ) );
    852 
    853   tmpinfo.discid = cdinfo->discid;
    854 
    855   /* Find out where this ID lives and fill in fname with full name */
    856   if( find_discid( cdinfo->local_cddb, tmpinfo.discid, fname, &tmpinfo.category ) < 0 )
    857     {
    858       /* Could not find an entry for this */
    859       return(-2);
    860     }
    861 
    862   if( read_cddb_file( fname, &tmpinfo ) == 0 )
    863     {
    864       cdinfo->title = tmpinfo.title;
    865       for( x = 0; x < cdinfo->tochdr.cdth_trk1; x++ )
    866 	{
    867 	  cdinfo->name[x] = tmpinfo.name[x];
    868 	}
    869 
    870       /* Copy the category over too */
    871       cdinfo->category = tmpinfo.category;
    872 
    873       /* Copy the revision # over if it is valid */
    874       if( tmpinfo.revision >= 0 )
    875 	cdinfo->revision = tmpinfo.revision;
    876       else
    877 	cdinfo->revision = 1;
    878 
    879       /* Copy the extd pointer over */
    880       cdinfo->extd = tmpinfo.extd;
    881 
    882       /* Copy all the extended track pointers */
    883       for( x = 0; x < 99; x++ )
    884 	cdinfo->extt[x] = tmpinfo.extt[x];
    885     }
    886 
    887   return(0);
    888 }