Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / icedax / toc.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)toc.c    1.57 06/02/19 Copyright 1998-2003 Heiko Eissfeldt */
14 /*
15  * Copyright: GNU Public License 2 applies
16  *
17  *   This program is free software; you can redistribute it and/or modify
18  *   it under the terms of the GNU General Public License as published by
19  *   the Free Software Foundation; either version 2, or (at your option)
20  *   any later version.
21  *
22  *   This program is distributed in the hope that it will be useful,
23  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
24  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  *   GNU General Public License for more details.
26  *
27  *   You should have received a copy of the GNU General Public License
28  *   along with this program; if not, write to the Free Software
29  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30  *
31  * CDDA2WAV (C) Heiko Eissfeldt heiko@hexco.de
32  * CDDB routines (C) Ti Kan and Steve Scherf
33  */
34 #include "config.h"
35 #include <stdio.h>
36 #include <standard.h>
37 #include <stdxlib.h>
38 #include <strdefs.h>
39 #include <utypes.h>
40 #include <intcvt.h>
41 #include <unixstd.h>            /* sleep */
42 #include <ctype.h>
43 #include <errno.h>
44 #include <fctldefs.h>
45 #include <vadefs.h>
46 #include <schily.h>
47 #include <libport.h>
48 #include <sys/ioctl.h>
49
50 #define CD_TEXT
51 #define CD_EXTRA
52 #undef DEBUG_XTRA
53 #undef DEBUG_CDTEXT
54 #undef DEBUG_CDDBP
55
56
57 #include <usal/scsitransp.h>
58
59 #include "mytype.h"
60 #include "byteorder.h"
61 #include "interface.h"
62 #include "icedax.h"
63 #include "global.h"
64 #include "sha.h"
65 #include "base64.h"
66 #include "toc.h"
67 #include "exitcodes.h"
68 #include "ringbuff.h"
69
70 int Get_Mins(unsigned long p_track);
71 int Get_Secs(unsigned long p_track);
72 int Get_Frames(unsigned long p_track);
73 int Get_Flags(unsigned long p_track);
74 int Get_SCMS(unsigned long p_track);
75
76
77 #if     defined USE_REMOTE
78 /* tcp stuff */
79 /* fix OS/2 compilation */
80 #ifdef  __EMX__
81 #define gethostid       nogethostid
82 #endif
83 #include <sys/socket.h>
84 #undef gethostid
85 #include <netinet/in.h>
86 #if     defined(HAVE_NETDB_H) && !defined(HOST_NOT_FOUND) && \
87                                 !defined(_INCL_NETDB_H)
88 #include <netdb.h>
89 #define _INCL_NETDB_H
90 #endif
91 #endif
92
93 int have_CD_text;
94 int have_multisession;
95 int have_CD_extra;
96 int have_CDDB;
97
98 struct iterator;
99
100 static void                     UpdateTrackData(int p_num);
101 static void                     UpdateIndexData(int p_num);
102 static void                     UpdateTimeData(int p_min, int p_sec, int p_frm);
103 static unsigned int     is_multisession(void);
104 static unsigned int     get_end_of_last_audio_track(unsigned mult_off);
105 static int                              cddb_sum(int n);
106 static void                     dump_extra_info(unsigned from);
107 static int                              GetIndexOfSector(unsigned sec, unsigned track);
108 static int                              patch_cd_extra(unsigned track, unsigned long sector);
109 static void                     patch_to_audio(unsigned long p_track);
110 static int                              restrict_tracks_illleadout(void);
111 static void                     Set_MCN(unsigned char *MCN_arg);
112 static void                     Set_ISRC(int track, const unsigned char *ISRC_arg);
113 static void                     InitIterator(struct iterator *iter, unsigned long p_track);
114
115 static unsigned char g_track=0xff, g_index=0xff;        /* current track, index */
116
117 /* Conversion function: from logical block adresses  to minute,second,frame
118  */
119 int lba_2_msf(long lba, int *m, int *s, int *f)
120 {
121 #ifdef  __follow_redbook__
122         if (lba >= -150 && lba < 405000) {      /* lba <= 404849 */
123 #else
124         if (lba >= -150) {
125 #endif
126                 lba += 150;
127         } else if (lba >= -45150 && lba <= -151) {
128                 lba += 450150;
129         } else
130                 return 1;
131
132         *m = lba / 60 / 75;
133         lba -= (*m)*60*75;
134         *s = lba / 75;
135         lba -= (*s)*75;
136         *f = lba;
137
138         return 0;
139 }
140
141 /* print the track currently read */
142 static void UpdateTrackData(int p_num)
143 {
144   if (global.quiet == 0) { 
145     fprintf (stderr, "\ntrack: %.2d, ", p_num); fflush(stderr);
146   }
147   g_track = (unsigned char) p_num;
148 }
149
150
151 /* print the index currently read */
152 static void UpdateIndexData(int p_num)
153 {
154   if (global.quiet == 0) { 
155     fprintf (stderr, "index: %.2d\n", p_num); fflush(stderr);
156   }
157   g_index = (unsigned char) p_num;
158 }
159
160
161 /* print the time of track currently read */
162 static void UpdateTimeData(int p_min, int p_sec, int p_frm)
163 {
164   if (global.quiet == 0) {
165     fprintf (stderr, "time: %.2d:%.2d.%.2d\r", p_min, p_sec, p_frm); 
166     fflush(stderr);
167   }
168 }
169
170 void AnalyzeQchannel(unsigned frame)
171 {
172     subq_chnl *sub_ch;
173
174     if (trackindex_disp != 0) {
175         sub_ch = ReadSubQ(get_scsi_p(), GET_POSITIONDATA,0);
176         /* analyze sub Q-channel data */
177         if (sub_ch->track != g_track ||
178             sub_ch->index != g_index) {
179             UpdateTrackData (sub_ch->track);
180             UpdateIndexData (sub_ch->index);
181         }
182     }
183     frame += 150;
184     UpdateTimeData ((unsigned char) (frame / (60*75)), 
185                     (unsigned char) ((frame % (60*75)) / 75), 
186                     (unsigned char) (frame % 75));
187 }
188
189 unsigned cdtracks = 0;
190
191 int no_disguised_audiotracks(void)
192 {
193         /* we can assume no audio tracks according to toc here. */
194         /* read a data sector from the first data track */
195         unsigned char p[3000];
196         int retval;
197         get_scsi_p()->silent++;
198         retval = 1 == ReadCdRomData(get_scsi_p(), p, Get_StartSector(1), 1);
199         get_scsi_p()->silent--;
200         if (retval == 0) {
201                 int i;
202 fprintf(stderr, "Warning: wrong track types found: patching to audio...\n");
203                 for (i = 0; i < cdtracks; i++)
204                         patch_to_audio(i);
205         }
206         return retval;
207 }
208
209
210 #undef SIM_ILLLEADOUT
211 int ReadToc(void)
212 {
213     int retval = (*doReadToc)( get_scsi_p() );
214 #if     defined SIM_ILLLEADOUT
215     g_toc[cdtracks+1] = 20*75;
216 #endif
217     return retval;
218 }
219
220 static int can_read_illleadout(void);
221
222 static int can_read_illleadout(void)
223 {
224         SCSI *usalp = get_scsi_p();
225
226         UINT4 buffer [CD_FRAMESIZE_RAW/4];
227         if (global.illleadout_cd == 0) return 0;
228
229         usalp->silent++;
230         global.reads_illleadout = 
231             ReadCdRom(usalp, buffer, Get_AudioStartSector(CDROM_LEADOUT), 1);
232         usalp->silent--;
233         return global.reads_illleadout;
234 }
235
236
237 unsigned find_an_off_sector(unsigned lSector, unsigned SectorBurstVal);
238
239 unsigned find_an_off_sector(unsigned lSector, unsigned SectorBurstVal)
240 {
241         long track_of_start = Get_Track(lSector);
242         long track_of_end = Get_Track(lSector + SectorBurstVal -1);
243         long start = Get_AudioStartSector(track_of_start);
244         long end = Get_EndSector(track_of_end);
245
246         if (lSector - start > end - lSector + SectorBurstVal -1)
247                 return start;
248         else
249                 return end;
250 }
251
252 #ifdef CD_TEXT
253 #include "scsi_cmds.h"
254 #endif
255
256
257 int handle_cdtext(void)
258 {
259 #ifdef CD_TEXT
260         if (bufferTOC[0] == 0 && bufferTOC[1] == 0) {
261                 have_CD_text = 0;
262                 return have_CD_text;
263         }
264
265         /* do a quick scan over all pack type indicators */
266         {
267                 int i;
268                 int count_fails = 0;
269                 int len = (bufferTOC[0] << 8) | bufferTOC[1];
270
271                 len = min(len, 2048);
272                 for (i = 0; i < len-4; i += 18) {
273                         if (bufferTOC[4+i] < 0x80 || bufferTOC[4+i] > 0x8f) {
274                                 count_fails++;
275                         }
276                 }
277                 have_CD_text = len > 4 && count_fails < 3;
278         }
279
280 #else
281         have_CD_text = 0;
282 #endif
283         return have_CD_text;
284 }
285
286
287 #ifdef CD_TEXT
288 #include "cd_text.c"
289 #endif
290
291
292 #if defined CDROMMULTISESSION
293 static int tmp_fd;
294 #endif
295
296 #ifdef CD_EXTRA
297 #include "cd_extra.c"
298 #endif
299
300 static unsigned session_start;
301 /*
302    A Cd-Extra is detected, if it is a multisession CD with
303    only audio tracks in the first session and a data track
304    in the last session.
305  */
306 static unsigned is_multisession(void)
307 {
308   unsigned mult_off;
309 #if defined CDROMMULTISESSION
310   /*
311    * FIXME: we would have to do a ioctl (CDROMMULTISESSION)
312    *        for the cdrom device associated with the generic device
313    *        not just AUX_DEVICE
314    */
315   struct cdrom_multisession ms_str;
316
317   if (interface == GENERIC_SCSI)
318     tmp_fd = open (global.aux_name, O_RDONLY);
319   else
320     tmp_fd = global.cooked_fd;
321
322   if (tmp_fd != -1) {
323     int result;
324
325     ms_str.addr_format = CDROM_LBA;
326     result = ioctl(tmp_fd, CDROMMULTISESSION, &ms_str);
327     if (result == -1) {
328       if (global.verbose != 0)
329         perror("multi session ioctl not supported: ");
330     } else {
331 #ifdef DEBUG_XTRA
332   fprintf(stderr, "current ioctl multisession_offset = %u\n", ms_str.addr.lba);
333 #endif
334         if (interface == GENERIC_SCSI)
335                 close (tmp_fd);
336         if (ms_str.addr.lba > 0)
337           return ms_str.addr.lba;
338     }
339   }
340 #endif
341   mult_off = 0;
342   if (LastAudioTrack() + 1 == FirstDataTrack()) {
343           mult_off = Get_StartSector(FirstDataTrack());
344   }
345
346 #ifdef DEBUG_XTRA
347   fprintf(stderr, "current guessed multisession_offset = %u\n", mult_off);
348 #endif
349   return mult_off;
350 }
351
352 #define SESSIONSECTORS (152*75)
353 /*
354    The solution is to read the Table of Contents of the first
355    session only (if the drive permits that) and directly use
356    the start of the leadout. If this is not supported, we subtract
357    a constant of SESSIONSECTORS sectors (found heuristically).
358  */
359 static unsigned get_end_of_last_audio_track(unsigned mult_off)
360 {
361    unsigned retval;
362
363    /* Try to read the first session table of contents.
364       This works for Sony and mmc type drives. */
365    if (ReadLastAudio && (retval = ReadLastAudio(get_scsi_p())) != 0) {
366      return retval;
367    } else {
368      return mult_off - SESSIONSECTORS;
369    }
370 }
371
372 static void dump_cdtext_info(void);
373
374 #if defined CDDB_SUPPORT
375 static void emit_cddb_form(char *fname_baseval);
376 #endif
377
378 #if defined CDINDEX_SUPPORT
379 static void emit_cdindex_form(char *fname_baseval);
380 #endif
381
382
383 typedef struct TOC {    /* structure of table of contents (cdrom) */
384         unsigned char reserved1;
385         unsigned char bFlags;
386         unsigned char bTrack;
387         unsigned char reserved2;
388         unsigned int dwStartSector;
389         int mins;
390         int secs;
391         int frms;
392         unsigned char ISRC[16];
393         int     SCMS;
394 } TOC;
395
396
397 /* Flags contains two fields:
398     bits 7-4 (ADR)
399         : 0 no sub-q-channel information
400         : 1 sub-q-channel contains current position
401         : 2 sub-q-channel contains media catalog number
402         : 3 sub-q-channel contains International Standard
403                                    Recording Code ISRC
404         : other values reserved
405     bits 3-0 (Control) :
406     bit 3 : when set indicates there are 4 audio channels else 2 channels
407     bit 2 : when set indicates this is a data track else an audio track
408     bit 1 : when set indicates digital copy is permitted else prohibited
409     bit 0 : when set indicates pre-emphasis is present else not present
410  */
411
412 #define GETFLAGS(x) ((x)->bFlags)
413 #define GETTRACK(x) ((x)->bTrack)
414 #define GETSTART(x) ((x)->dwStartSector)
415 #define GETMINS(x)  ((x)->mins)
416 #define GETSECS(x)  ((x)->secs)
417 #define GETFRAMES(x) ((x)->frms)
418 #define GETISRC(x)  ((x)->ISRC)
419
420 #define IS__PREEMPHASIZED(p) ( (GETFLAGS(p) & 0x10) != 0)
421 #define IS__INCREMENTAL(p) ( (GETFLAGS(p) & 0x10) != 0)
422 #define IS__COPYRESTRICTED(p) (!(GETFLAGS(p) & 0x20) != 0)
423 #define IS__COPYRIGHTED(p) (!(GETFLAGS(p) & 0x20) != 0)
424 #define IS__DATA(p)        ( (GETFLAGS(p) & 0x40) != 0)
425 #define IS__AUDIO(p)       (!(GETFLAGS(p) & 0x40) != 0)
426 #define IS__QUADRO(p)      ( (GETFLAGS(p) & 0x80) != 0)
427
428 /*
429  * Iterator interface inspired from Java
430  */
431 struct iterator {
432         int index;
433         int startindex;
434         void        (*reset)(struct iterator *this);
435         struct TOC *(*getNextTrack)(struct iterator *this);
436         int         (*hasNextTrack)(struct iterator *this);
437 };
438
439
440
441
442 /* The Table of Contents needs to be corrected if we
443    have a CD-Extra. In this case all audio tracks are
444    followed by a data track (in the second session).
445    Unlike for single session CDs the end of the last audio
446    track cannot be set to the start of the following
447    track, since the lead-out and lead-in would then
448    errenously be part of the audio track. This would
449    lead to read errors when trying to read into the
450    lead-out area.
451    So the length of the last track in case of Cd-Extra
452    has to be fixed.
453  */
454 unsigned FixupTOC(unsigned no_tracks)
455 {
456     unsigned mult_off;
457     unsigned offset = 0;
458     int j = -1;
459     unsigned real_end = 2000000;
460
461     /* get the multisession offset in sectors */
462     mult_off = is_multisession();
463
464     /* if the first track address had been the victim of an underflow,
465      * set it to zero.
466      */
467     if (Get_StartSector(1) > Get_StartSector(LastTrack())) {
468         fprintf(stderr, "Warning: first track has negative start sector! Setting to zero.\n");
469         toc_entry( 1, Get_Flags(1), Get_Tracknumber(1), Get_ISRC(1), 0, 0, 2, 0 );
470     }
471
472 #ifdef DEBUG_XTRA
473     fprintf(stderr, "current multisession_offset = %u\n", mult_off);
474 #endif
475     dump_cdtext_info();
476
477     if (mult_off > 100) { /* the offset has to have a minimum size */
478
479       /* believe the multisession offset :-) */
480       /* adjust end of last audio track to be in the first session */
481       real_end = get_end_of_last_audio_track(mult_off);
482 #ifdef DEBUG_XTRA
483       fprintf(stderr, "current end = %u\n", real_end);
484 #endif
485
486       j = FirstDataTrack();
487       if (LastAudioTrack() + 1 == j) {
488           long sj = Get_StartSector(j);
489           if (sj > (long)real_end) {
490             session_start = mult_off;
491                 have_multisession = sj;
492
493 #ifdef CD_EXTRA
494             offset = Read_CD_Extra_Info(sj);
495
496             if (offset != 0) {
497                 have_CD_extra = sj;
498                 dump_extra_info(offset);
499             }
500 #endif
501           }
502       }
503     }
504     if (global.cddbp) {
505 #if     defined USE_REMOTE
506         if (global.disctitle == NULL) {
507             have_CDDB = !request_titles();
508         }
509 #else
510         fprintf(stderr, "Cannot lookup titles: no cddbp support included!\n");
511 #endif
512     }
513 #if defined CDINDEX_SUPPORT || defined CDDB_SUPPORT
514     if (have_CD_text || have_CD_extra || have_CDDB) {
515             unsigned long       count_audio_tracks = 0;
516             static struct iterator i;
517             if (i.reset == NULL)
518                     InitIterator(&i, 1);
519
520             while (i.hasNextTrack(&i)) {
521                     struct TOC *p = i.getNextTrack(&i);
522                     if (IS__AUDIO(p)) count_audio_tracks++;
523             }
524
525             if (count_audio_tracks > 0 && global.no_cddbfile == 0) {
526 #if defined CDINDEX_SUPPORT
527                     emit_cdindex_form(global.fname_base);
528 #endif
529 #if defined CDDB_SUPPORT
530                     emit_cddb_form(global.fname_base);
531 #endif
532             }
533     }
534 #endif
535     if (have_multisession) {
536         /* set start of track to beginning of lead-out */
537         patch_cd_extra(j, real_end);
538 #if     defined CD_EXTRA && defined DEBUG_XTRA
539         fprintf(stderr, "setting end of session (track %d) to %u\n", j, real_end);
540 #endif
541     }
542     return offset;
543 }
544
545 static int cddb_sum(int n)
546 {
547   int ret;
548
549   for (ret = 0; n > 0; n /= 10) {
550     ret += (n % 10);
551   }
552
553   return ret;
554 }
555
556 void calc_cddb_id(void)
557 {
558   UINT4 i;
559   UINT4 t = 0;
560   UINT4 n = 0;
561
562   for (i = 1; i <= cdtracks; i++) {
563     n += cddb_sum(Get_StartSector(i)/75 + 2);
564   }
565
566   t = Get_StartSector(i)/75 - Get_StartSector(1)/75;
567
568   global.cddb_id = (n % 0xff) << 24 | (t << 8) | cdtracks;
569 }
570
571
572 #undef TESTCDINDEX
573 #ifdef  TESTCDINDEX
574 void TestGenerateId(void)
575 {
576    SHA_INFO       sha;
577    unsigned char  digest[20], *base64;
578    unsigned long  size;
579
580    sha_init(&sha);
581    sha_update(&sha, (unsigned char *)"0123456789", 10);
582    sha_final(digest, &sha);
583
584    base64 = rfc822_binary((char *)digest, 20, &size);
585    if (strncmp((char*) base64, "h6zsF82dzSCnFsws9nQXtxyKcBY-", size))
586    {
587        free(base64);
588
589        fprintf(stderr, "The SHA-1 hash function failed to properly generate the\n");
590        fprintf(stderr, "test key.\n");
591        exit(INTERNAL_ERROR);
592    }
593    free(base64);
594 }
595 #endif
596
597 void calc_cdindex_id()
598 {
599         SHA_INFO        sha;
600         unsigned char   digest[20], *base64;
601         unsigned long   size;
602         unsigned        i;
603         char            temp[9];
604
605 #ifdef  TESTCDINDEX
606         TestGenerateId();
607         g_toc[1].bTrack = 1;
608         cdtracks = 15;
609         g_toc[cdtracks].bTrack = 15;
610         i = 1;
611         g_toc[i++].dwStartSector = 0U;
612         g_toc[i++].dwStartSector = 18641U;
613         g_toc[i++].dwStartSector = 34667U;
614         g_toc[i++].dwStartSector = 56350U;
615         g_toc[i++].dwStartSector = 77006U;
616         g_toc[i++].dwStartSector = 106094U;
617         g_toc[i++].dwStartSector = 125729U;
618         g_toc[i++].dwStartSector = 149785U;
619         g_toc[i++].dwStartSector = 168885U;
620         g_toc[i++].dwStartSector = 185910U;
621         g_toc[i++].dwStartSector = 205829U;
622         g_toc[i++].dwStartSector = 230142U;
623         g_toc[i++].dwStartSector = 246659U;
624         g_toc[i++].dwStartSector = 265614U;
625         g_toc[i++].dwStartSector = 289479U;
626         g_toc[i++].dwStartSector = 325732U;
627 #endif
628         sha_init(&sha);
629         sprintf(temp, "%02X", Get_Tracknumber(1));
630         sha_update(&sha, (unsigned char *)temp, 2);
631         sprintf(temp, "%02X", Get_Tracknumber(cdtracks));
632         sha_update(&sha, (unsigned char *)temp, 2);
633
634         /* the position of the leadout comes first. */
635         sprintf(temp, "%08lX", 150 + Get_StartSector(CDROM_LEADOUT));
636         sha_update(&sha, (unsigned char *)temp, 8);
637
638         /* now 99 tracks follow with their positions. */
639         for (i = 1; i <= cdtracks; i++) {
640                 sprintf(temp, "%08lX", 150+Get_StartSector(i));
641                 sha_update(&sha, (unsigned char *)temp, 8);
642         }
643         for (i++  ; i <= 100; i++) {
644                 sha_update(&sha, (unsigned char *)"00000000", 8);
645         }
646         sha_final(digest, &sha);
647
648         base64 = rfc822_binary((char *)digest, 20, &size);
649         global.cdindex_id = base64;
650 }
651
652
653 #if defined CDDB_SUPPORT
654
655 #ifdef  PROTOTYPES
656 static void escape_and_split(FILE *channel, const char *args, ...)
657 #else
658 /*VARARGS3*/
659 static void escape_and_split(FILE *channel, const char *args, va_dcl va_alist)
660 #endif
661 {
662         va_list marker;
663
664         int prefixlen;
665         int len;
666         char    *q;
667
668 #ifdef  PROTOTYPES
669         va_start(marker, args);
670 #else
671         va_start(marker);
672 #endif
673
674         prefixlen = strlen(args);
675         len = prefixlen;
676         fputs(args, channel);
677
678         q = va_arg(marker, char *);
679         while (*q != '\0') {
680                 while (*q != '\0') {
681                         len += 2;
682                         if (*q == '\\')
683                                 fputs("\\\\", channel);
684                         else if (*q == '\t')
685                                 fputs("\\t", channel);
686                         else if (*q == '\n')
687                                 fputs("\\n", channel);
688                         else {
689                                 fputc(*q, channel);
690                                 len--;
691                         }
692                         if (len > 78) {
693                                 fputc('\n', channel);
694                                 fputs(args, channel);
695                                 len = prefixlen;
696                         }
697                         q++;
698                 }
699                 q = va_arg(marker, char *);
700         }
701         fputc('\n', channel);
702
703         va_end(marker);
704 }
705
706 static void emit_cddb_form(char *fname_baseval)
707 {
708   static struct iterator i;
709   unsigned first_audio;
710   FILE *cddb_form;
711   char fname[200];
712   char *pp;
713
714   if (fname_baseval == NULL || fname_baseval[0] == 0)
715         return;
716
717   if (!strcmp(fname_baseval,"standard_output")) return;
718   InitIterator(&i, 1);
719
720   strncpy(fname, fname_baseval, sizeof(fname) -1);
721   fname[sizeof(fname) -1] = 0;
722   pp = strrchr(fname, '.');
723   if (pp == NULL) {
724     pp = fname + strlen(fname);
725   }
726   strncpy(pp, ".cddb", sizeof(fname) - 1 - (pp - fname));
727
728   cddb_form = fopen(fname, "w");
729   if (cddb_form == NULL) return;
730
731   first_audio = FirstAudioTrack();
732   fprintf( cddb_form, "# xmcd\n#\n");
733   fprintf( cddb_form, "# Track frame offsets:\n#\n");
734
735   while (i.hasNextTrack(&i)) {
736           struct TOC *p = i.getNextTrack(&i);
737           if (GETTRACK(p) == CDROM_LEADOUT) break;
738           fprintf( cddb_form,
739                    "# %lu\n", 150 + Get_AudioStartSector(GETTRACK(p)));
740   }
741
742   fprintf( cddb_form, "#\n# Disc length: %lu seconds\n#\n", 
743            (150 + Get_StartSector(CDROM_LEADOUT)) / 75);
744   fprintf( cddb_form, "# Revision: %u\n", global.cddb_revision );
745   fprintf( cddb_form, "# Submitted via: icedax " VERSION "\n" );
746
747   fprintf( cddb_form, "DISCID=%08lx\n", (unsigned long)global.cddb_id);
748
749   if (global.disctitle == NULL && global.creator == NULL) {
750         fprintf( cddb_form, "DTITLE=\n");
751   } else {
752         if (global.creator == NULL) {
753                 escape_and_split( cddb_form, "DTITLE=", global.disctitle, "");
754         } else if (global.disctitle == NULL) {
755                 escape_and_split( cddb_form, "DTITLE=", global.creator, "");
756         } else {
757                 escape_and_split( cddb_form, "DTITLE=", global.creator, " / ", global.disctitle, "");
758         }
759   }
760   if (global.cddb_year != 0)
761         fprintf( cddb_form, "DYEAR=%4u\n", global.cddb_year);
762   else
763         fprintf( cddb_form, "DYEAR=\n");
764   fprintf( cddb_form, "DGENRE=%s\n", global.cddb_genre);
765
766   i.reset(&i);
767   while (i.hasNextTrack(&i)) {
768           struct TOC *p = i.getNextTrack(&i);
769           int ii;
770
771           ii = GETTRACK(p);
772           if (ii == CDROM_LEADOUT) break;
773
774           if (global.tracktitle[ii] != NULL) {
775                 char prefix[10];
776                 sprintf(prefix, "TTITLE%d=", ii-1);
777                   escape_and_split( cddb_form, prefix, global.tracktitle[ii], "");
778           } else {
779                   fprintf( cddb_form, "TTITLE%d=\n", ii-1);
780           }
781   }
782
783   if (global.copyright_message == NULL) {
784         fprintf( cddb_form, "EXTD=\n");
785   } else {
786         escape_and_split( cddb_form, "EXTD=", "Copyright ", global.copyright_message, "");
787   }
788
789   i.reset(&i);
790   while (i.hasNextTrack(&i)) {
791           struct TOC *p = i.getNextTrack(&i);
792           int ii;
793
794           ii = GETTRACK(p);
795
796           if (ii == CDROM_LEADOUT) break;
797
798           fprintf( cddb_form, "EXTT%d=\n", ii-1);
799   }
800   fprintf( cddb_form, "PLAYORDER=\n");
801   fclose( cddb_form );
802 }
803
804 #if     defined USE_REMOTE
805 #include <pwd.h>
806
807 static int readn(register int fd, register char *ptr, register int nbytes)
808 {
809         int     nread;
810
811         nread = read(fd, ptr, nbytes);
812 #ifdef  DEBUG_CDDBP
813         if (nread > 0) {
814                 fprintf(stderr, "READ :(%d)", nread);
815                 write(2, ptr, nread);
816         }
817 #endif
818         if (nread < 0) {
819            perror("socket read error: ");
820            fprintf(stderr, "fd=%d, ptr=%p, nbytes=%d\n", fd, ptr, nbytes);
821         }
822
823         return nread;
824 }
825
826 static ssize_t writez(int fd, const char *ptr)
827 {
828         size_t nleft, nbytes;
829
830         nleft = nbytes = strlen(ptr);
831
832         while (nleft > 0) {
833                 ssize_t nwritten = write(fd, ptr, nleft);
834                 if (nwritten <= 0) {
835                         return nwritten;        /* return error */
836                 }
837 #ifdef  DEBUG_CDDBP
838                 fprintf(stderr, "WRITE:%s\n", ptr);
839 #endif
840
841                 nleft -= nwritten;
842                 ptr   += nwritten;
843         }
844
845         return nbytes - nleft;
846 }
847
848 #define SOCKBUFF        2048
849   
850 static void filter_nonprintable(char *c, size_t l)
851 {
852         size_t i;
853         for(i = 0; i < l; ++i) {
854                 if(!isprint(c[i]) && !isspace(c[i])) {
855                         c[i] = '_';
856                 }
857         }
858 }
859
860
861 int process_cddb_titles(int sock_fd, char *inbuff, int readbytes);
862 int process_cddb_titles(int sock_fd, char *inbuff, int readbytes)
863 {
864         int     finished = 0;
865         char    *p = inbuff;
866         int     ind = 0;
867         unsigned char **        target = &global.creator;
868
869         do {
870                 while (readbytes > 0) {
871                         /* do we have a complete line in the buffer? */
872                         p = (char *)memchr(inbuff+ind, '\n', readbytes);
873                         if (p == NULL) break;
874
875                         /* look for the terminator first */
876                         if (!strncmp(".\r\n", inbuff+ind, 3)) {
877                                 finished = 1;
878                                 break;
879                         }
880                         /* kill carriage return */
881                         if (p > inbuff+ind && *(p-1) == '\r') {
882                                 *(p-1) = '\0';
883                         }
884                         /* kill line feed */
885                         *p = '\0';
886
887                         /* handle escaped characters */
888
889                         {
890                                 char *q = inbuff+ind;
891                                 while (*q) {
892                                         if (*q++ == '\\' && *q != '\0') {
893                                                 if (*q == '\\') {
894                                                         readbytes--;
895                                                         p--;
896                                                         memmove(q, q+1, readbytes - (q-inbuff-ind));
897                                                 } else if (*q == 'n') {
898                                                         *(q-1) = '\n';
899                                                         readbytes--;
900                                                         p--;
901                                                         memmove(q, q+1, readbytes - (q-inbuff-ind));
902                                                 } else if (*q == 't') {
903                                                         *(q-1) = '\t';
904                                                         readbytes--;
905                                                         p--;
906                                                         memmove(q, q+1, readbytes - (q-inbuff-ind));
907                                                 }
908                                         }
909                                 }
910                                                 
911                         }
912
913                         /* handle multi line entries concatenate fields */
914
915 /* TODO if the delimiter is split into two lines, it is not recognized. */
916                         if (!strncmp(inbuff+ind, "DTITLE=", 7)) {
917                                 char *res = strstr(inbuff+ind+7, " / ");
918                                 int clen;
919                                 char *q;
920
921                                 if (res == NULL) {
922                                         /* no limiter found yet */
923                                         /* copy until the end */
924                                         q = p;
925                                 } else {
926                                         /* limiter found */
927                                         /* copy until the limiter */
928                                         q = res;
929                                         *q = '\0';
930                                 }
931
932                                 clen = q - (inbuff+ind+7);
933                                 if (*target == NULL) {
934                                         *target = malloc(clen+1);
935                                         if (*target != NULL)
936                                                 **target = '\0';
937                                 } else {
938                                         *target = realloc(*target, strlen((char *)*target) + clen - 1);
939                                 }
940                                 if (*target != NULL) {
941                                         strcat((char *)*target, inbuff+ind+7);
942                                 }
943
944                                 /* handle part after the delimiter, if present */
945                                 if (res != NULL) {
946                                         target = (unsigned char **)&global.disctitle;
947                                         /* skip the delimiter */
948                                         q += 3;
949                                         clen = p - q;
950                                         if (*target == NULL) {
951                                                 *target = malloc(clen+1);
952                                                 if (*target != NULL)
953                                                         **target = '\0';
954                                         }
955                                         if (*target != NULL) {
956                                                 strcat((char *)*target, q);
957                                         }
958                                 }
959                         } else if (!strncmp(inbuff+ind, "TTITLE", 6)) {
960                                 char    *q = (char *)memchr(inbuff+ind, '=', readbytes);
961                                 unsigned tno;
962
963                                 if (q != NULL) {
964                                         *q = '\0';
965                                         tno = (unsigned)atoi(inbuff+ind+6);
966                                         tno++;
967                                         if (tno < 100) {
968                                                 if (global.tracktitle[tno] == NULL) {
969                                                         global.tracktitle[tno] = malloc( p - q + 1 );
970                                                         if (global.tracktitle[tno] != NULL)
971                                                                 *(global.tracktitle[tno]) = '\0';
972                                                 } else {
973                                                         global.tracktitle[tno] = realloc(global.tracktitle[tno], strlen((char *)global.tracktitle[tno]) + p - q + 1 );
974                                                 }
975                                                 if (global.tracktitle[tno] != NULL) {
976                                                         strcat((char *)global.tracktitle[tno], q+1);
977                                                 }
978                                         }
979                                 }
980                         } else if (!strncmp(inbuff+ind, "DYEAR", 5)) {
981                                 char    *q = (char *)memchr(inbuff+ind, '=', readbytes);
982                                 if (q++ != NULL) {
983                                         sscanf(q, "%d", &global.cddb_year);
984                                 }
985                         } else if (!strncmp(inbuff+ind, "DGENRE", 6)) {
986                                 char    *q = (char *)memchr(inbuff+ind, '=', readbytes);
987                                 if (q++ != NULL) {
988                                         /* patch from Joe Nuzman, thanks */
989                                         /* might have significant whitespace */
990                                         strncpy(global.cddb_genre, q, sizeof(global.cddb_genre)-1);
991                                         /* always have a terminator */
992                                         global.cddb_genre[sizeof(global.cddb_genre)-1] = '\0';
993                                 }
994                         } else if (!strncmp(inbuff+ind, "# Revision: ", 12)) {
995                                 char    *q = inbuff+ind+11;
996                                 sscanf(q, "%d", &global.cddb_revision);
997                                 global.cddb_revision++;
998                         }
999                         readbytes -= (p - inbuff -ind) + 1;
1000                         ind = (p - inbuff) + 1;
1001                 }
1002                 if (!finished) {
1003                         int     newbytes;
1004                         memmove(inbuff, inbuff+ind, readbytes);
1005                         newbytes = readn(sock_fd, inbuff+readbytes, SOCKBUFF-readbytes);
1006                         if (newbytes < 0) {
1007                                 fprintf(stderr, "Could not read from socket.\n");
1008                                 return 0; /* Caller checks for != 1 */
1009                         }
1010                         filter_nonprintable(inbuff+readbytes, newbytes);
1011                         if (newbytes <= 0)
1012                                 break;
1013                         readbytes += newbytes;
1014                         ind = 0;
1015                 }
1016         } while (!(finished || readbytes == 0));
1017         return finished;
1018 }
1019
1020 static int handle_userchoice(char *p, unsigned size);
1021
1022 static int handle_userchoice(char *p, unsigned size)
1023 {
1024         unsigned        nr = 0;
1025         unsigned        user_choice;
1026         int             i;
1027         char            *q;
1028         char            *o;
1029
1030         /* count lines. */
1031         q = p;
1032         while ((q = (char *)memchr(q, '\n', size - (q-p))) != NULL) {
1033                 nr++;
1034                 q++;
1035         }
1036         if (nr > 1) nr--;
1037
1038         /* handle escaped characters */
1039
1040         {
1041                 char *r = p;
1042                 while (*r) {
1043                         if (*r++ == '\\' && *r != '\0') {
1044                                 if (*r == '\\') {
1045                                         size--;
1046                                         memmove(r, r+1, size - (r-p));
1047                                 } else if (*r == 'n') {
1048                                         *(r-1) = '\n';
1049                                         size--;
1050                                         memmove(r, r+1, size - (r-p));
1051                                 } else if (*r == 't') {
1052                                         *(r-1) = '\t';
1053                                         size--;
1054                                         memmove(r, r+1, size - (r-p));
1055                                 }
1056                         }
1057                 }
1058         }
1059
1060         /* list entries. */
1061         q = p;
1062         fprintf(stderr, "%u entries found:\n", nr);
1063         for (q = (char *)memchr(q, '\n', size - (q-p)), o = p, i = 0; i < nr; i++) {
1064                 *q = '\0';
1065                 fprintf(stderr, "%02u: %s\n", i, o);
1066                 o = q+1;
1067                 q = (char *)memchr(q, '\n', size - (q-p));
1068         }
1069         fprintf(stderr, "%02u: ignore\n", i);
1070
1071         /* get user response. */
1072         do {
1073                 fprintf(stderr, "please choose one (0-%u): ", nr);
1074                 scanf("%u", &user_choice); /* FIXME: check return value */
1075         } while (user_choice > nr);
1076
1077         if (user_choice == nr)
1078                 return -1;
1079
1080         /* skip to choice. */
1081         q = p;
1082         for (i = 0; i <= (int)user_choice - 1; i++) {
1083                 q = (char *)memchr(q, '\0', size - (q-p)) + 1;
1084         }
1085         return  q-p;
1086 }
1087
1088 /* request disc and track titles from a cddbp server.
1089  *
1090  * return values:
1091  *      0       titles have been found exactly (success)
1092  *      -1      some communication error happened.
1093  *      1       titles have not been found.
1094  *      2       multiple fuzzy matches have been found.
1095  */
1096 int
1097 request_titles(void)
1098 {
1099         int             retval = 0;
1100         int             sock_fd;
1101         struct sockaddr_in sa;
1102         struct hostent *he;
1103         struct servent *se;
1104         struct passwd *pw = getpwuid(getuid());
1105         char            hostname[HOST_NAME_MAX];
1106         char            inbuff[SOCKBUFF];
1107         char            outbuff[SOCKBUFF];
1108         int             i;
1109         char            category[64];
1110         unsigned        cat_offset;
1111         unsigned        disc_id;
1112         ssize_t         readbytes;
1113
1114         sock_fd = socket(AF_INET, SOCK_STREAM, 0);
1115         if (sock_fd < 0) {
1116                 perror("cddb socket failed: ");
1117                 retval = -1;
1118                 goto errout;
1119         }
1120
1121         /* TODO fallbacks
1122          * freedb.freedb.org
1123          * de.freedb.org
1124          * at.freedb.org
1125          */
1126         if (global.cddbp_server != NULL)
1127                 he = gethostbyname(global.cddbp_server);
1128         else
1129                 he = gethostbyname(CDDBHOST /*"freedb.freedb.org"*/);
1130
1131         if (he == NULL) {
1132                 perror("cddb cannot resolve freedb host: ");
1133                 he = malloc(sizeof(struct hostent));
1134                 memset(he, 0 , sizeof(struct hostent));
1135                 he->h_length = 4;
1136                 he->h_addrtype = AF_INET;
1137                 he->h_addr_list = malloc(4);
1138                 he->h_addr_list[0] = malloc(4);
1139                 ((struct in_addr *)(he->h_addr_list[0]))->s_addr =
1140                         /* kingfisher.berlios.de          freedb.freedb.de */
1141                          htonl(UINT_C(0xc3254d85));     /*0xc2610412*/
1142                 he->h_name = "freedb.freedb.org";
1143 #if     0
1144                 retval = -1;
1145                 goto errout;
1146 #endif
1147         }
1148
1149         /* save result data IMMEDIATELY!! */
1150         memset(&sa, 0 , sizeof(struct sockaddr_in));
1151         sa.sin_family      = he->h_addrtype;    /* AF_INET; */
1152         sa.sin_addr.s_addr = ((struct in_addr *)((he->h_addr_list)[0]))->s_addr;
1153
1154         se = NULL;
1155         if (global.cddbp_port == NULL)
1156                 se = getservbyname("cddbp-alt", "tcp");
1157
1158         if (se == NULL) {
1159                 if (global.cddbp_port == NULL) {
1160                         se = getservbyname("cddbp", "tcp");
1161                 }
1162                 if (se == NULL) {
1163                         se = malloc(sizeof(struct servent));
1164                         memset(se, 0 , sizeof(struct servent));
1165                         se->s_port = htons(CDDBPORT /*8880*/);
1166 #if     0       
1167                         perror("cddb cannot resolve cddbp or cddbp-alt port:\n "); 
1168                         retval = -1;
1169                         goto errout;
1170 #endif
1171                 }
1172         }
1173         if (global.cddbp_port != NULL) {
1174                 se->s_port = htons(atoi(global.cddbp_port));
1175         }
1176
1177         sa.sin_port        = se->s_port;
1178
1179 /* TODO timeout */
1180         if (0 > connect(sock_fd, (struct sockaddr *)&sa, 
1181                         sizeof(struct sockaddr_in))) {
1182                 perror("cddb connect failed: ");
1183                 retval = -1;
1184                 goto errout;
1185         }
1186
1187         /* read banner */
1188         readbytes = readn(sock_fd, inbuff, sizeof(inbuff));
1189         if (readbytes < 0) {
1190                 fprintf(stderr, "Could not read from socket\n");
1191                 retval = -1;
1192                 goto errout;
1193         }
1194
1195         if (strncmp(inbuff, "200 ", 4) && strncmp(inbuff, "201 ", 4)) {
1196                 if(readbytes == sizeof(inbuff))
1197                         --readbytes;
1198                 inbuff[readbytes] = '\0';
1199                 filter_nonprintable(inbuff, readbytes);
1200                 fprintf(stderr, "bad status from freedb server during sign-on banner: %s\n", inbuff);
1201                 retval = -1;
1202                 goto errout;
1203         }
1204
1205         /* say hello */
1206         hostname[0] = '\0'; 
1207         if (0 > gethostname(hostname, sizeof(hostname)))
1208                 strcpy(hostname, "unknown_host"); 
1209         hostname[sizeof(hostname)-1] = '\0';
1210         writez(sock_fd, "cddb hello ");
1211         if (pw != NULL) {
1212                 BOOL    space_err = FALSE;
1213                 BOOL    ascii_err = FALSE;
1214                 /* change spaces to underscores */
1215                 char *q = pw->pw_name;
1216                 while (*q != '\0') {
1217                         if (*q == ' ') {
1218                                 if (!space_err) {
1219                                         space_err = TRUE;
1220                                         errmsgno(EX_BAD,
1221                                         "Warning: Space in user name '%s'.\n",
1222                                         pw->pw_name);
1223                                 }
1224                                 *q = '_';
1225                         }
1226                         if (*q < ' ' || *q > '~') {
1227                                 if (!ascii_err) {
1228                                         ascii_err = TRUE;
1229                                         errmsgno(EX_BAD,
1230                                         "Warning: Nonascii character in user name '%s'.\n",
1231                                         pw->pw_name);
1232                                 }
1233                                 *q = '_';
1234                         }
1235                         q++;
1236                 }
1237                 writez(sock_fd, pw->pw_name);
1238                 writez(sock_fd, " ");
1239         } else {
1240                 writez(sock_fd, "unknown ");
1241         }
1242
1243         /* change spaces to underscores */
1244         {
1245                 char *q = hostname;
1246                 BOOL    space_err = FALSE;
1247                 BOOL    ascii_err = FALSE;
1248
1249                 while (*q != '\0') {
1250                         if (*q == ' ') {
1251                                 if (!space_err) {
1252                                         space_err = TRUE;
1253                                         errmsgno(EX_BAD,
1254                                         "Warning: Space in hostname '%s'.\n",
1255                                         hostname);
1256                                 }
1257                                 *q = '_';
1258                         }
1259                         if (*q < ' ' || *q > '~') {
1260                                 if (!ascii_err) {
1261                                         ascii_err = TRUE;
1262                                         errmsgno(EX_BAD,
1263                                         "Warning: Nonascii character in hostname '%s'.\n",
1264                                         hostname);
1265                                 }
1266                                 *q = '_';
1267                         }
1268                         q++;
1269                 }
1270         }
1271
1272         writez(sock_fd, hostname);
1273         writez(sock_fd, " icedax " VERSION "\n");
1274
1275         readbytes = readn(sock_fd, inbuff, sizeof(inbuff));
1276         if (readbytes < 0) {
1277                 fprintf(stderr, "Could not read from socket\n");
1278                 retval = -1;
1279                 goto errout;
1280         }
1281         if (strncmp(inbuff, "200 ", 4)) {
1282                 if(readbytes == sizeof(inbuff))
1283                         --readbytes;
1284                 inbuff[readbytes] = '\0';
1285                 filter_nonprintable(inbuff, readbytes);
1286                 fprintf(stderr, "bad status from freedb server during hello: %s\n", inbuff);
1287                 retval = -1;
1288                 goto signoff;
1289         }
1290
1291         /* enable new protocol variant. Weird command here, no cddb prefix ?!?! */
1292         writez(sock_fd, "proto\n");
1293         readbytes = readn(sock_fd, inbuff, sizeof(inbuff));
1294         if (readbytes < 0) {
1295                 fprintf(stderr, "Could not read from socket\n");
1296                 retval = -1;
1297                 goto errout;
1298         }
1299         /* check for errors and maximum supported protocol level */
1300         if (strncmp(inbuff, "201 ", 4) > 0) {
1301                 if(readbytes == sizeof(inbuff))
1302                         --readbytes;
1303                 inbuff[readbytes] = '\0';
1304                 filter_nonprintable(inbuff, readbytes);
1305                 fprintf(stderr, "bad status from freedb server during proto command: %s\n", inbuff);
1306                 retval = -1;
1307                 goto signoff;
1308         }
1309         
1310         /* check the supported protocol level */
1311         if (!memcmp(inbuff, "200 CDDB protocol level: current 1, supported ", 46)) {
1312                 char *q = strstr(inbuff, " supported ");
1313                 unsigned        pr_level;
1314
1315                 if (q != NULL) {
1316                         q += 11;
1317                         sscanf(q, "%u\n", &pr_level);
1318                         if (pr_level > 1) {
1319                                 if (pr_level > 5)
1320                                         pr_level = 5;
1321                                 sprintf(inbuff, "proto %1u\n", pr_level);
1322                                 writez(sock_fd, inbuff);
1323                                 readbytes = readn(sock_fd, inbuff, sizeof(inbuff));
1324                                 if (readbytes < 0) {
1325                                         fprintf(stderr, "Could not read from socket\n");
1326                                         retval = -1;
1327                                         goto errout;
1328                                 }
1329                                 /* check for errors and maximum supported protocol level */
1330                                 if (strncmp(inbuff, "201 ", 4) > 0) {
1331                                         if(readbytes == sizeof(inbuff))
1332                                                 --readbytes;
1333                                         inbuff[readbytes] = '\0';
1334                                         filter_nonprintable(inbuff,
1335                                           readbytes);
1336                                         fprintf(stderr, "bad status from freedb server during proto x: %s\n", inbuff);
1337                                         retval = -1;
1338                                         goto signoff;
1339                                 }
1340                         }
1341                 }
1342         }
1343
1344         /* format query string */
1345         /* query */
1346 #define CDDPB_INCLUDING_DATATRACKS
1347 #ifdef  CDDPB_INCLUDING_DATATRACKS
1348         sprintf(outbuff, "cddb query %08lx %ld ", (unsigned long)global.cddb_id, LastTrack() - FirstTrack() + 1);
1349         /* first all leading datatracks */
1350         {
1351                 int j = FirstAudioTrack();
1352                 if (j < 0)
1353                         j = LastTrack() +1;
1354                 for (i = FirstTrack(); i < j; i++) {
1355                         sprintf(outbuff + strlen(outbuff), "%ld ", 150 + Get_StartSector(i));
1356                 }
1357         }
1358 #else
1359         sprintf(outbuff, "cddb query %08lx %ld ", global.cddb_id, LastAudioTrack() - FirstAudioTrack() + 1);
1360 #endif
1361         /* all audio tracks */
1362         for (i = FirstAudioTrack(); i != -1 && i <= LastAudioTrack(); i++) {
1363                 sprintf(outbuff + strlen(outbuff), "%ld ", 150 + Get_AudioStartSector(i));
1364         }
1365 #ifdef  CDDPB_INCLUDING_DATATRACKS
1366         /* now all trailing datatracks */
1367         for (; i != -1 && i <= LastTrack(); i++) {
1368                 sprintf(outbuff + strlen(outbuff), "%ld ", 150 + Get_StartSector(i));
1369         }
1370         sprintf(outbuff + strlen(outbuff), "%lu\n",
1371            (150 + Get_StartSector(CDROM_LEADOUT)) / 75);
1372 #else
1373         sprintf(outbuff + strlen(outbuff), "%lu\n",
1374            (150 + Get_LastSectorOnCd(FirstAudioTrack())) / 75);
1375 #endif
1376 /*      strcpy(outbuff, "cddb query 9709210c 12 150 12010 33557 50765 65380 81467 93235 109115 124135 137732 152575 166742 2339\n"); */
1377 /*      strcpy(outbuff, "cddb query 03015501 1 296 344\n"); */
1378         writez(sock_fd, outbuff);
1379
1380         readbytes = readn(sock_fd, inbuff, sizeof(inbuff) - 1);
1381         if (readbytes < 0) {
1382                 fprintf(stderr, "Could not read from socket\n");
1383                 retval = -1;
1384                 goto errout;
1385         }
1386         inbuff[readbytes] = '\0';
1387         filter_nonprintable(inbuff, readbytes);
1388         cat_offset = 4;
1389         if (!strncmp(inbuff, "210 ", 4)
1390            || !strncmp(inbuff, "211 ", 4)) {
1391                 /* Check if there are really multiple entries. */
1392                 char *p = (char *)memchr(inbuff, '\n', readbytes-1);
1393
1394                 if (p != NULL) cat_offset = p+1 - inbuff;
1395                 /* first entry */
1396                 if (p) p = (char *)memchr(p+1, '\n', inbuff+readbytes - p);
1397                 /* second entry */
1398                 if (p) p = (char *)memchr(p+1, '\n', inbuff+readbytes - p);
1399                 /* . */
1400                 if (p) p = (char *)memchr(p+1, '\n', inbuff+readbytes - p);
1401                 if (p) {
1402                         /* multiple entries */
1403                         switch (global.cddbp) {
1404                                 case    2:      /* take the first entry */
1405                                 break;
1406                                 case    1:      /* ask user */
1407                                         if (!global.gui) {
1408                                                 int userret = handle_userchoice(inbuff+cat_offset, readbytes - cat_offset);
1409                                                 if (userret == -1) {
1410                                                         /* ignore any selection */
1411                                                         retval = -1;
1412                                                         goto signoff;
1413                                                 }
1414                                                 cat_offset += userret;
1415                                         }
1416                                 break;
1417                                 default:
1418                                         fprintf(stderr, "multiple entries found: %s\n", inbuff);
1419                                         retval = 2;
1420                                         goto signoff;
1421                         }
1422                 }
1423
1424         } else if (strncmp(inbuff, "200 ", 4)) {
1425                 if (!strncmp(inbuff, "202 ", 4)) {
1426                         fprintf(stderr, "no cddb entry found: %s\n", inbuff);
1427                         retval = 1;
1428                 } else {
1429                         fprintf(stderr, "bad status from freedb server during query: %s\n%s", inbuff, outbuff);
1430                         retval = -1;
1431                 }
1432                 goto signoff;
1433         }
1434         sscanf(inbuff + cat_offset, "%s %x", category, &disc_id );
1435
1436
1437         /* read */
1438         sprintf(inbuff, "cddb read %s %08x\n", category, disc_id);
1439         writez(sock_fd, inbuff);
1440
1441         /* read status and first buffer size. */
1442         readbytes = readn(sock_fd, inbuff, sizeof(inbuff));
1443         if (readbytes < 0) {
1444                 fprintf(stderr, "Could not read from socket\n");
1445                 retval = -1;
1446                 goto errout;
1447         }
1448         filter_nonprintable(inbuff, readbytes);
1449         if (strncmp(inbuff, "210 ", 4)) {
1450                 if(readbytes == sizeof(inbuff))
1451                         --readbytes;
1452                 inbuff[readbytes] = '\0';
1453                 fprintf(stderr, "bad status from freedb server during read: %s\n", inbuff);
1454                 retval = -1;
1455                 goto signoff;
1456         }
1457
1458         if (1 != process_cddb_titles(sock_fd, inbuff, readbytes)) {
1459                 fprintf(stderr, "cddb read finished not correctly!\n");
1460         }
1461
1462 signoff:
1463         /* sign-off */
1464         writez(sock_fd, "quit\n");
1465         readbytes = readn(sock_fd, inbuff, sizeof(inbuff));
1466         if (readbytes < 0) {
1467                 fprintf(stderr, "Could not read from socket\n");
1468                 retval = -1;
1469                 goto errout;
1470         }
1471         if (strncmp(inbuff, "230 ", 4)) {
1472                 if(readbytes == sizeof(inbuff))
1473                         --readbytes;
1474                 inbuff[readbytes] = '\0';
1475                 filter_nonprintable(inbuff, readbytes);
1476                 fprintf(stderr, "bad status from freedb server during quit: %s\n", inbuff);
1477                 goto errout;
1478         }
1479
1480 errout:
1481         close(sock_fd);
1482         return retval;
1483 }
1484 #endif
1485 #endif
1486
1487 #if     defined CDINDEX_SUPPORT
1488
1489 static int IsSingleArtist(void);
1490
1491 /* check, if there are more than one track creators */
1492 static int IsSingleArtist(void)
1493 {
1494         static struct iterator i;
1495         InitIterator(&i, 1);
1496
1497         while (i.hasNextTrack(&i)) {
1498                 struct TOC *p = i.getNextTrack(&i);
1499                 int ii;
1500
1501                 if (IS__DATA(p) || GETTRACK(p) == CDROM_LEADOUT) continue;
1502
1503                 ii = GETTRACK(p);
1504                 if (global.creator && global.trackcreator[ii]
1505                         && strcmp((char *) global.creator,
1506                                   (char *) global.trackcreator[ii]) != 0)
1507                         return 0;
1508         }
1509         return 1;
1510 }
1511
1512 static const char *a2h[255-191] = {
1513 "&Agrave;",
1514 "&Aacute;",
1515 "&Acirc;",
1516 "&Atilde;",
1517 "&Auml;",
1518 "&Aring;",
1519 "&AElig;",
1520 "&Ccedil;",
1521 "&Egrave;",
1522 "&Eacute;",
1523 "&Ecirc;",
1524 "&Euml;",
1525 "&Igrave;",
1526 "&Iacute;",
1527 "&Icirc;",
1528 "&Iuml;",
1529 "&ETH;",
1530 "&Ntilde;",
1531 "&Ograve;",
1532 "&Oacute;",
1533 "&Ocirc;",
1534 "&Otilde;",
1535 "&Ouml;",
1536 "&times;",
1537 "&Oslash;",
1538 "&Ugrave;",
1539 "&Uacute;",
1540 "&Ucirc;",
1541 "&Uuml;",
1542 "&Yacute;",
1543 "&THORN;",
1544 "&szlig;",
1545 "&agrave;",
1546 "&aacute;",
1547 "&acirc;",
1548 "&atilde;",
1549 "&auml;",
1550 "&aring;",
1551 "&aelig;",
1552 "&ccedil;",
1553 "&egrave;",
1554 "&eacute;",
1555 "&ecirc;",
1556 "&euml;",
1557 "&igrave;",
1558 "&iacute;",
1559 "&icirc;",
1560 "&iuml;",
1561 "&eth;",
1562 "&ntilde;",
1563 "&ograve;",
1564 "&oacute;",
1565 "&ocirc;",
1566 "&otilde;",
1567 "&ouml;",
1568 "&divide;",
1569 "&oslash;",
1570 "&ugrave;",
1571 "&uacute;",
1572 "&ucirc;",
1573 "&uuml;",
1574 "&yacute;",
1575 "&thorn;",
1576 "&yuml;",
1577 };
1578
1579 static char *ascii2html(unsigned char *inp)
1580 {
1581         static size_t buflen = 256;
1582         static char *outline = 0;
1583         size_t pos = 0;
1584     size_t l=0;
1585
1586         /* init */
1587         if(!outline) {
1588                 outline = malloc(buflen);
1589                 if(outline == 0) {
1590                         fprintf(stderr, "error: memory exhausted\n");
1591                         _exit(EXIT_FAILURE);
1592                 }
1593         }
1594
1595         outline[pos] = '\0';
1596
1597         while (*inp != '\0') {
1598
1599                 /* Pick the sequence to insert */
1600                 const char *insert;
1601                 char b[2];
1602                 const int c = (unsigned char)*inp;
1603                 switch(c) {
1604                         case '"':       insert = "&quot;";      break;
1605                         case '&':       insert = "&amp;";       break;
1606                         case '<':       insert = "&lt;";        break;
1607                         case '>':       insert = "&gt;";        break;
1608                         case 160:       insert = "&nbsp;";      break;
1609                         default: {
1610                                          if(c < 192) {
1611                                                  b[0] = c;
1612                                                  b[1] = '\0';
1613                                                  insert = b;
1614                                          } else {
1615                                                  insert = a2h[c - 192];
1616                                          }
1617                                  }
1618                 };
1619
1620                 /* Resize buffer */
1621                 l = strlen(insert);
1622                 while(pos + l + 1 >= buflen) {
1623                         outline = realloc(outline, buflen *= 2);
1624                         if(outline == 0) {
1625                                 fprintf(stderr, "error: memory exhausted\n");
1626                                 _exit(EXIT_FAILURE);
1627                         }
1628                 }
1629
1630                 /* Copy in */
1631                 strcpy(&outline[pos], insert);
1632                 pos += l;
1633
1634                 ++inp;
1635         }
1636
1637         return outline;
1638 }
1639
1640 static void emit_cdindex_form(char *fname_baseval)
1641 {
1642   FILE *cdindex_form;
1643   char fname[200];
1644   char *pp;
1645
1646   if (fname_baseval == NULL || fname_baseval[0] == 0)
1647         return;
1648
1649   strncpy(fname, fname_baseval, sizeof(fname) -1);
1650   fname[sizeof(fname) -1] = 0;
1651   pp = strrchr(fname, '.');
1652   if (pp == NULL) {
1653     pp = fname + strlen(fname);
1654   }
1655   strncpy(pp, ".cdindex", sizeof(fname) - 1 - (pp - fname));
1656
1657   cdindex_form = fopen(fname, "w");
1658   if (cdindex_form == NULL) return;
1659
1660 #define CDINDEX_URL     "http://www.musicbrainz.org/dtd/CDInfo.dtd"
1661
1662   /* format XML page according to cdindex DTD (see www.musicbrainz.org) */
1663   fprintf( cdindex_form, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<!DOCTYPE CDInfo SYSTEM \"%s\">\n\n<CDInfo>\n",
1664                   CDINDEX_URL);
1665
1666   fprintf( cdindex_form, "   <Title>%s</Title>\n",
1667          global.disctitle ? ascii2html(global.disctitle) : "");
1668   /* 
1669    * In case of mixed mode and Extra-CD, nonaudio tracks are included!
1670    */
1671   fprintf( cdindex_form, "   <NumTracks>%d</NumTracks>\n\n", cdtracks);
1672   fprintf( cdindex_form, "   <IdInfo>\n      <DiskId>\n         <Id>%s</Id>\n      </DiskId>\n", global.cdindex_id); 
1673
1674   fprintf( cdindex_form, "   </IdInfo>\n\n");
1675
1676   if (IsSingleArtist()) {
1677     static struct iterator i;
1678     InitIterator(&i, 1);
1679
1680     fprintf( cdindex_form, "   <SingleArtistCD>\n      <Artist>%s</Artist>\n",
1681          global.creator ? ascii2html(global.creator) : "");
1682
1683     while (i.hasNextTrack(&i)) {
1684             struct TOC *p = i.getNextTrack(&i);
1685             int ii = GETTRACK(p);
1686
1687             if (ii == CDROM_LEADOUT) break;
1688             if (IS__AUDIO(p)) {
1689                     fprintf( cdindex_form,
1690                              "      <Track Num=\"%d\">\n         <Name>%s</Name>\n      </Track>\n",
1691                              ii, global.tracktitle[ii] ? ascii2html(global.tracktitle[ii]) : "");
1692             } else {
1693                     fprintf( cdindex_form,
1694                              "      <Track Num=\"%d\">\n         <Name>data track</Name>\n      </Track>\n",
1695                              ii );
1696             }
1697     }
1698     fprintf( cdindex_form, "   </SingleArtistCD>\n");
1699   } else {
1700     static struct iterator i;
1701     InitIterator(&i, 1);
1702
1703     fprintf( cdindex_form, "   <MultipleArtistCD>\n");
1704
1705     while (i.hasNextTrack(&i)) {
1706             struct TOC *p = i.getNextTrack(&i);
1707             int ii = GETTRACK(p);
1708
1709             if (ii == CDROM_LEADOUT) break;
1710             if (IS__AUDIO(p)) {
1711                     fprintf( cdindex_form, "         <Artist>%s</Artist>\n",
1712                              global.trackcreator[ii] ? ascii2html(global.trackcreator[ii]) : "");
1713                     fprintf( cdindex_form, "         <Name>%s</Name>\n      </Track>\n",
1714                   global.tracktitle[ii] ? ascii2html(global.tracktitle[ii]) : "");
1715             } else {
1716                     fprintf( cdindex_form,
1717                              "         <Artist>data track</Artist>\n         <Name>data track</Name>\n      </Track>\n");
1718             }
1719     }
1720     fprintf( cdindex_form, "   </MultipleArtistCD>\n");
1721   }
1722   fprintf( cdindex_form, "</CDInfo>\n");
1723
1724   fclose( cdindex_form );
1725 }
1726 #endif
1727
1728 static void dump_cdtext_info(void)
1729 {
1730 #ifdef CD_TEXT
1731   /* interpret the contents of CD Text information based on an early draft
1732      of SCSI-3 mmc version 2 from jan 2, 1998
1733      CD Text information consists of a text group containing up to
1734      8 language blocks containing up to
1735      255 Pack data chunks of
1736      18 bytes each.
1737      So we have at most 36720 bytes to cope with.
1738    */
1739   {
1740     short int datalength;
1741     unsigned char *p = bufferTOC;
1742     unsigned char lastline[255*12];
1743     int         lastitem = -1;
1744     int         itemcount = 0;
1745     int         inlinecount = 0;
1746     int         outlinecount = 0;
1747
1748     lastline[0] = '\0';
1749     datalength = ((p[0] << 8) + p[1]) - 2;
1750     datalength = min(datalength, 2048-4);
1751     p += 4;
1752     for (;datalength > 0;
1753         datalength -= sizeof (cdtextpackdata),
1754         p += sizeof (cdtextpackdata)) {
1755       unsigned char *zeroposition;
1756
1757       /* handle one packet of CD Text Information Descriptor Pack Data */
1758       /* this is raw R-W subchannel data converted to 8 bit values. */
1759       cdtextpackdata *c = (cdtextpackdata *)p;
1760       int dbcc;
1761       int crc_error;
1762       unsigned tracknr;
1763
1764 #ifdef DEBUG_CDTEXT
1765       fprintf(stderr, "datalength =%d\n", datalength);
1766 #endif
1767       crc_error = !cdtext_crc_ok(c);
1768
1769       if (lastitem != c->headerfield[0]) {
1770         itemcount = 0;
1771         lastitem = c->headerfield[0];
1772       }
1773
1774       tracknr = c->headerfield[1] & 0x7f;
1775       dbcc = ((unsigned)(c->headerfield[3] & 0x80)) >> 7; /* double byte character code */
1776
1777 #if defined DEBUG_CDTEXT
1778         {
1779       int extension_flag;
1780       int sequence_number;
1781       int block_number;
1782       int character_position;
1783
1784       extension_flag = ((unsigned)(c->headerfield[1] & 0x80)) >> 7;
1785       sequence_number = c->headerfield[2];
1786       block_number = ((unsigned)(c->headerfield[3] & 0x30)) >> 4; /* language */
1787       character_position = c->headerfield[3] & 0x0f;
1788
1789       fprintf(stderr, "CDText: ext_fl=%d, trnr=%u, seq_nr=%d, dbcc=%d, block_nr=%d, char_pos=%d\n",
1790              extension_flag, tracknr, sequence_number, dbcc, block_number, character_position);
1791         }
1792 #endif
1793
1794       /* print ASCII information */
1795       memcpy(lastline+inlinecount, c->textdatafield, 12);
1796       inlinecount += 12;
1797       zeroposition = (unsigned char *)memchr(lastline+outlinecount, '\0', inlinecount-outlinecount);
1798       while (zeroposition != NULL) {
1799           process_header(c, tracknr, dbcc, lastline+outlinecount);
1800           outlinecount += zeroposition - (lastline+outlinecount) + 1;
1801
1802 #if defined DEBUG_CDTEXT
1803           fprintf(stderr, "\tin=%d, out=%d, items=%d, trcknum=%u\n", inlinecount, outlinecount, itemcount, tracknr);
1804 { int q; for (q= outlinecount; q < inlinecount; q++) fprintf (stderr, "%c", lastline[q] ? lastline[q] : 'ß'); fputs("\n", stderr); }
1805 #else
1806           if (DETAILED) {
1807             if (crc_error) fputs(" ! uncorr. CRC-Error", stderr);
1808             fputs("\n", stderr);
1809           }
1810 #endif
1811
1812           itemcount++;
1813           if (itemcount > (int)cdtracks
1814                 || (c->headerfield[0] == 0x8f
1815                 || (c->headerfield[0] <= 0x8d && c->headerfield[0] >= 0x86))) {
1816             outlinecount = inlinecount;
1817             break;
1818           }
1819           tracknr++;
1820           zeroposition = (unsigned char *)memchr(lastline+outlinecount, '\0', inlinecount-outlinecount);
1821       }
1822     }
1823   }
1824 #endif
1825 }
1826
1827
1828
1829 static void dump_extra_info(unsigned int from)
1830 {
1831 #ifdef CD_EXTRA
1832   unsigned char *p;
1833   unsigned pos, length;
1834
1835   if (from == 0) return;
1836
1837   p = Extra_buffer + 48;
1838   while (*p != '\0') {
1839     pos    = GET_BE_UINT_FROM_CHARP(p+2);
1840     length = GET_BE_UINT_FROM_CHARP(p+6);
1841     if (pos == (unsigned)-1) {
1842       pos = from+1;
1843     } else {
1844       pos += session_start;
1845     }
1846
1847 #ifdef DEBUG_XTRA
1848     if (global.gui == 0 && global.verbose != 0) {
1849         fprintf(stderr, "Language: %c%c (as defined by ISO 639)", *p, *(p+1));
1850         fprintf(stderr, " at sector %u, len=%u (sessionstart=%u)", pos, length, session_start);
1851         fputs("\n", stderr);
1852     }
1853 #endif
1854     /* dump this entry */
1855     Read_Subinfo(pos, length);
1856     p += 10;
1857
1858     if (p + 9 > (Extra_buffer + CD_FRAMESIZE))
1859       break;
1860   }
1861 #endif
1862 }
1863
1864 static char *quote(unsigned char *string);
1865
1866 static char *quote(unsigned char *string)
1867 {
1868   static char result[200];
1869   unsigned char *p = (unsigned char *)result;
1870
1871   while (*string) {
1872     if (*string == '\'' || *string == '\\') {
1873         *p++ = '\\';
1874     }
1875     *p++ = *string++;
1876   }
1877   *p = '\0';
1878
1879   return result;
1880 }
1881
1882
1883
1884 static void DisplayToc_with_gui(unsigned long dw);
1885
1886 static void DisplayToc_with_gui(unsigned long dw)
1887 {
1888         unsigned mins;
1889         unsigned secnds;
1890         unsigned frames;
1891         int count_audio_trks;
1892         static struct iterator i;
1893         if (i.reset == NULL) InitIterator(&i, 1);
1894         else i.reset(&i);
1895
1896         mins    =   dw / ( 60*75 );
1897         secnds  = ( dw % ( 60*75 ) ) / 75;
1898         frames  = ( dw %      75   );
1899
1900         /* summary */
1901         count_audio_trks = 0;
1902
1903         if ((global.verbose & SHOW_STARTPOSITIONS) != 0) {
1904                 if (global.illleadout_cd != 0 && have_CD_extra == 0) {
1905                         fprintf( stderr, "Tracks:%u > %u:%02u.%02u\n", cdtracks, mins, secnds, frames );
1906                 } else {
1907                         fprintf( stderr, "Tracks:%u %u:%02u.%02u\n", cdtracks, mins, secnds, frames );
1908                 }
1909         }
1910
1911         if (global.quiet == 0) {
1912                 fprintf( stderr, "CDINDEX discid: %s\n", global.cdindex_id);
1913                 fprintf( stderr, "CDDB discid: 0x%08lx", (unsigned long) global.cddb_id);
1914
1915                 if (have_CDDB != 0) {
1916                         fprintf(stderr, " CDDBP titles: resolved\n");
1917                 } else {
1918                         fprintf(stderr, "\n");
1919                 }
1920                 if (have_CD_text != 0) {
1921                         fprintf(stderr, "CD-Text: detected\n");
1922                         dump_cdtext_info();
1923                 } else {
1924                         fprintf(stderr, "CD-Text: not detected\n");
1925                 }
1926                 if (have_CD_extra != 0) {
1927                         fprintf(stderr, "CD-Extra: detected\n");
1928                         dump_extra_info(have_CD_extra);
1929                 } else {
1930                         fprintf(stderr, "CD-Extra: not detected\n");
1931                 }
1932  
1933                 fprintf( stderr, 
1934                          "Album title: '%s'", (void *)global.disctitle != NULL
1935                          ? quote(global.disctitle) : "");
1936
1937                 fprintf( stderr, " from '%s'\n", (void *)global.creator != NULL 
1938                          ? quote(global.creator) : "");
1939         }
1940         count_audio_trks = 0;
1941
1942
1943         if ((global.verbose & (SHOW_TOC | SHOW_STARTPOSITIONS | SHOW_SUMMARY | SHOW_TITLES)) != 0
1944             && i.hasNextTrack(&i)) {
1945                 TOC *o = i.getNextTrack(&i);
1946                 while (i.hasNextTrack(&i)) {
1947                         TOC *p = i.getNextTrack(&i);
1948                         int from;
1949                         from = GETTRACK(o);
1950
1951                         fprintf(stderr, "T%02d:", from);
1952
1953                         if (IS__DATA(o)) {
1954                                 /*
1955                                  * Special case of cd extra
1956                                  */
1957                                 unsigned int real_start = have_CD_extra
1958                                         ? have_CD_extra : GETSTART(o);
1959
1960
1961                                 dw = (unsigned long) (GETSTART(p) - real_start);
1962
1963                                 mins   =   dw / ( 60*75 );
1964                                 secnds = ( dw % ( 60*75 )) / 75;
1965                                 frames = ( dw %      75   );
1966
1967                                 if ( global.verbose & SHOW_STARTPOSITIONS )
1968                                         fprintf(stderr,
1969                                                 " %7u",
1970                                                 real_start
1971                                         );
1972
1973                                 if ( global.verbose & SHOW_TOC )
1974                                         fprintf(stderr,
1975                                                 " %2u:%02u.%02u",
1976                                                 mins, secnds, frames
1977                                         );
1978
1979                                 if ( global.verbose & SHOW_SUMMARY )
1980                                         fprintf(stderr,
1981                                                 " data %s %s N/A",
1982                                                 
1983                                                 /* how recorded */
1984                                                 IS__INCREMENTAL(o)
1985                                                 ? "incremental" : "uninterrupted",
1986
1987                                                 /* copy-permission */
1988                                                 IS__COPYRIGHTED(o)
1989                                                 ? "copydenied" : "copyallowed"
1990                                         );
1991                                 fputs("\n", stderr);
1992                         } else {
1993                                 dw = (unsigned long) (GETSTART(p) - GETSTART(o));
1994                                 mins   =   dw / ( 60*75 );
1995                                 secnds = ( dw % ( 60*75 )) / 75;
1996                                 frames = ( dw %      75   );
1997                                         
1998                                 if ( global.verbose & SHOW_STARTPOSITIONS )
1999                                         fprintf(stderr,
2000                                                 " %7u",
2001                                                 GETSTART(o)
2002                                         );
2003
2004                                 if ( global.verbose & SHOW_TOC )
2005                                         fprintf(stderr,
2006                                                 " %2u:%02u.%02u",
2007                                                 mins, secnds, frames
2008                                         );
2009
2010                                 if ( global.verbose & SHOW_SUMMARY )
2011                                         fprintf(stderr,
2012                                                 " audio %s %s %s",
2013
2014                                         /* how recorded */
2015                                         IS__PREEMPHASIZED(o)
2016                                         ? "pre-emphasized" : "linear",
2017                                                 
2018                                         /* copy-permission */
2019                                         IS__COPYRIGHTED(o)
2020                                         ? "copydenied" : "copyallowed",
2021
2022                                         /* channels */
2023                                         IS__QUADRO(o)
2024                                                 ? "quadro" : "stereo");
2025
2026                                 /* Title */
2027                                 if ( global.verbose & SHOW_TITLES ) {
2028                                         fprintf(stderr,
2029                                                 " title '%s' from ",
2030
2031                                                 (void *) global.tracktitle[GETTRACK(o)] != NULL
2032                                                 ? quote(global.tracktitle[GETTRACK(o)]) : ""
2033                                         );
2034                                         
2035                                         fprintf(stderr,
2036                                                 "'%s'",
2037
2038                                                 (void *) global.trackcreator[GETTRACK(o)] != NULL
2039                                                 ? quote(global.trackcreator[GETTRACK(o)]) : ""
2040                                         );
2041                                 }
2042                                 fputs("\n", stderr);
2043                                 count_audio_trks++;
2044                         }
2045                         o = p;
2046                 } /* while */
2047                 if ( global.verbose & SHOW_STARTPOSITIONS )
2048                         if (GETTRACK(o) == CDROM_LEADOUT) {
2049                                 fprintf(stderr, "Leadout: %7u\n", GETSTART(o));
2050                         }
2051         } /* if */
2052 }
2053
2054 static void DisplayToc_no_gui(unsigned long dw);
2055
2056 static void DisplayToc_no_gui(unsigned long dw)
2057 {
2058         unsigned mins;
2059         unsigned secnds;
2060         unsigned frames;
2061         int count_audio_trks;
2062         unsigned ii = 0;
2063         static struct iterator i;
2064         if (i.reset == NULL) InitIterator(&i, 1);
2065         else i.reset(&i);
2066
2067         mins    =   dw / ( 60*75 );
2068         secnds  = ( dw % ( 60*75 ) ) / 75;
2069         frames  = ( dw %      75   );
2070
2071         /* summary */
2072         count_audio_trks = 0;
2073
2074         if (i.hasNextTrack(&i)) {
2075                 TOC *o = i.getNextTrack(&i);
2076                 while (i.hasNextTrack(&i)) {
2077                         TOC *p = i.getNextTrack(&i);
2078                         int from;
2079                         from = GETTRACK(o);
2080
2081
2082                         while ( p != NULL && GETTRACK(p) != CDROM_LEADOUT
2083                                 && GETFLAGS(o) == GETFLAGS(p) ) {
2084                                 o = p;
2085                                 p = i.getNextTrack(&i);
2086                         }
2087                         if ((global.verbose & SHOW_SUMMARY) == 0) continue;
2088
2089                         if (IS__DATA(o)) {
2090                                 fputs( " DATAtrack recorded      copy-permitted tracktype\n" , stderr);
2091                                 fprintf(stderr,
2092                                         "     %2d-%2d %13.13s %14.14s      data\n",
2093                                         from,
2094                                         GETTRACK(o),
2095                                         /* how recorded */
2096                                         IS__INCREMENTAL(o) 
2097                                          ? "incremental" : "uninterrupted",
2098
2099                                         /* copy-perm */
2100                                         IS__COPYRIGHTED(o) ? "no" : "yes"
2101                                         );
2102                         } else { 
2103                                 fputs( "AUDIOtrack pre-emphasis  copy-permitted tracktype channels\n" , stderr);
2104                                 fprintf(stderr,
2105                                         "     %2d-%2d %12.12s  %14.14s     audio    %1c\n",
2106                                         from,
2107                                         GETTRACK(o),
2108                                         IS__PREEMPHASIZED(o) 
2109                                          ? "yes" : "no",
2110                                         IS__COPYRIGHTED(o) ? "no" : "yes",
2111                                         IS__QUADRO(o) ? '4' : '2'
2112                                         );
2113                                 count_audio_trks++;
2114                         }
2115                         o = p;
2116                 }
2117         }
2118         if ((global.verbose & SHOW_STARTPOSITIONS) != 0) {
2119                 if (global.illleadout_cd != 0 && have_multisession == 0) {
2120
2121                         fprintf ( stderr, 
2122                                   "Table of Contents: total tracks:%u, (total time more than %u:%02u.%02u)\n",
2123                                   cdtracks, mins, secnds, frames );
2124                 } else {
2125                         fprintf ( stderr, 
2126                                   "Table of Contents: total tracks:%u, (total time %u:%02u.%02u)\n",
2127                                   cdtracks, mins, secnds, frames );
2128                 }
2129         }
2130
2131         i.reset(&i);
2132         if ((global.verbose & SHOW_TOC) != 0 &&
2133                 i.hasNextTrack(&i)) {
2134                 TOC *o = i.getNextTrack(&i);
2135
2136                 for (; i.hasNextTrack(&i);) {
2137                         TOC *p = i.getNextTrack(&i);
2138
2139                         if ( GETTRACK(o) <= MAXTRK ) {
2140                                 unsigned char brace1, brace2;
2141                                 unsigned trackbeg;
2142                                 trackbeg = have_multisession && IS__DATA(o) ? have_multisession : GETSTART(o);
2143                         
2144                                 dw = (unsigned long) (GETSTART(p) - trackbeg);
2145                                 mins   =   dw / ( 60*75 );
2146                                 secnds = ( dw % ( 60*75 )) / 75;
2147                                 frames = ( dw %      75   );
2148
2149                                 if ( IS__DATA(o) ) {
2150                                         /* data track display */
2151                                         brace1 = '[';
2152                                         brace2 = ']';
2153                                 } else if (have_multisession
2154                                            && GETTRACK(o) == LastAudioTrack()) {
2155                                         /* corrected length of
2156                                          * last audio track in cd extra
2157                                          */
2158                                         brace1 = '|';
2159                                         brace2 = '|';
2160                                 } else {
2161                                         /* audio track display */
2162                                         brace1 = '(';
2163                                         brace2 = ')';
2164                                 }
2165                                 fprintf ( stderr,
2166                                           " %2u.%c%2u:%02u.%02u%c",
2167                                           GETTRACK(o),
2168                                           brace1,
2169                                           mins, secnds, frames,
2170                                           brace2
2171                                         );
2172                                 ii++;
2173                         
2174                                 if ( ii % 5 == 0 )
2175                                         fputs( ",\n", stderr );
2176                                 else if (ii != cdtracks)
2177                                         fputc ( ',', stderr );
2178                         }
2179                         o = p;
2180                 } /* for */
2181                 if ( (ii % 5) != 0 )
2182                         fputs( "\n", stderr );
2183         
2184         } /* if */
2185
2186         if ((global.verbose & SHOW_STARTPOSITIONS) != 0) {
2187                 fputs ("\nTable of Contents: starting sectors\n", stderr);
2188
2189                 ii = 0;
2190                 i.reset(&i);
2191                 if (i.hasNextTrack(&i)) {
2192                         TOC *o = i.getNextTrack(&i);
2193                         for ( ; i.hasNextTrack(&i);) {
2194                                 TOC *p = i.getNextTrack(&i);
2195                                 fprintf ( stderr,
2196                                           " %2u.(%8u)",
2197                                           GETTRACK(o),
2198                                           have_multisession
2199                                            && GETTRACK(o) == FirstDataTrack()
2200                                             ? have_multisession
2201                                             : GETSTART(o)
2202 #ifdef DEBUG_CDDB
2203                                           +150
2204 #endif
2205                                         );
2206
2207                                 ii++;
2208                                 if ( (ii) % 5 == 0 )
2209                                         fputs( ",\n", stderr );
2210                                 else
2211                                         fputc ( ',', stderr );
2212                                 o = p;
2213                         }
2214                         fprintf ( stderr, " lead-out(%8u)", GETSTART(o));
2215                         fputs ("\n", stderr);
2216                 }
2217         }
2218         if (global.quiet == 0) {
2219                 fprintf(stderr, "CDINDEX discid: %s\n", global.cdindex_id);
2220                 fprintf( stderr, "CDDB discid: 0x%08lx", (unsigned long) global.cddb_id);
2221
2222                 if (have_CDDB != 0) {
2223                         fprintf(stderr, " CDDBP titles: resolved\n");
2224                 } else {
2225                         fprintf(stderr, "\n");
2226                 }
2227                 if (have_CD_text != 0) {
2228                         fprintf(stderr, "CD-Text: detected\n");
2229                 } else {
2230                         fprintf(stderr, "CD-Text: not detected\n");
2231                 }
2232                 if (have_CD_extra != 0) {
2233                         fprintf(stderr, "CD-Extra: detected\n");
2234                 } else {
2235                         fprintf(stderr, "CD-Extra: not detected\n");
2236                 }
2237         }
2238         if ((global.verbose & SHOW_TITLES) != 0) {
2239                 int maxlen = 0;
2240                 
2241                 if ( global.disctitle != NULL ) {
2242                         fprintf( stderr, "Album title: '%s'", global.disctitle);
2243                         if ( global.creator != NULL ) {
2244                                 fprintf( stderr, "\t[from %s]", global.creator);
2245                         }
2246                         fputs("\n", stderr);
2247                 }
2248
2249                 i.reset(&i);
2250                 for ( ; i.hasNextTrack(&i);) {
2251                         TOC *p = i.getNextTrack(&i);
2252                         int jj = GETTRACK(p);
2253
2254                         if ( global.tracktitle[jj] != NULL ) {
2255                                 int len = strlen((char *)global.tracktitle[jj]);
2256                                 maxlen = max(maxlen, len);
2257                         }
2258                 }
2259                 maxlen = (maxlen + 12 + 8 + 7)/8;
2260                 
2261                 i.reset(&i);
2262                 for ( ; i.hasNextTrack(&i); ) {
2263                         TOC *p = i.getNextTrack(&i);
2264                         int jj;
2265
2266                         if (IS__DATA(p))
2267                                 continue;
2268
2269                         jj = GETTRACK(p);
2270
2271                         if (jj == CDROM_LEADOUT)
2272                                 break;
2273                         
2274                         if ( maxlen != 3 ) {
2275                                 if ( global.tracktitle[jj] != NULL ) {
2276                                         fprintf( stderr, "Track %2u: '%s'", jj, global.tracktitle[jj]);
2277                                 } else {
2278                                         fprintf( stderr, "Track %2u: '%s'", jj, "");
2279                                 }
2280                                 if ( global.trackcreator[jj] != NULL
2281                                      && global.trackcreator[jj][0] != '\0'
2282 #if 1
2283                                      && (global.creator == NULL
2284                                          || 0 != strcmp((char *)global.creator,(char *)global.trackcreator[jj]))
2285 #endif
2286                                         ) {
2287                                         int j;
2288                                         char *o = global.tracktitle[jj] != NULL
2289                                                 ? (char *)global.tracktitle[jj]
2290                                                 : "";
2291                                         for ( j = 0;
2292                                               j < (maxlen - ((int)strlen(o) + 12)/8);
2293                                               j++)
2294                                                 fprintf(stderr, "\t");
2295                                         fprintf( stderr, "[from %s]", global.trackcreator[jj]);
2296                                 }
2297                                 fputs("\n", stderr);
2298                         }
2299                 }
2300         }
2301 }
2302
2303 void DisplayToc(void)
2304 {
2305         unsigned long dw;
2306
2307         /* special handling of pseudo-red-book-audio cds */
2308         if (cdtracks > 1
2309             && Get_StartSector(CDROM_LEADOUT) < Get_StartSector(cdtracks)) {
2310                 global.illleadout_cd = 1;
2311                 can_read_illleadout();
2312         }
2313
2314
2315         /* get total time */
2316         if (global.illleadout_cd == 0)
2317                 dw = (unsigned long) Get_StartSector(CDROM_LEADOUT) - Get_StartSector(1);
2318         else
2319                 dw = (unsigned long) Get_StartSector(cdtracks     ) - Get_StartSector(1);
2320
2321         if ( global.gui == 0 ) {
2322                 /* table formatting when in cmdline mode */
2323                 DisplayToc_no_gui( dw );
2324         } else if (global.gui == 1) {
2325                 /* line formatting when in gui mode */
2326                 DisplayToc_with_gui( dw );
2327         }
2328
2329         if (global.illleadout_cd != 0) {
2330                 if (global.quiet == 0) {
2331                         fprintf(stderr, "CD with illegal leadout position detected!\n");
2332                 }
2333
2334                 if (global.reads_illleadout == 0) {
2335                         /* limit accessible tracks 
2336                          * to lowered leadout position
2337                          */
2338                         restrict_tracks_illleadout();
2339
2340                         if (global.quiet == 0) {
2341                                 fprintf(stderr,
2342                                         "The cdrom drive firmware does not permit access beyond the leadout position!\n");
2343                         }
2344                         if (global.verbose & (SHOW_ISRC | SHOW_INDICES)) {
2345                                 global.verbose &= ~(SHOW_ISRC | SHOW_INDICES);
2346                                 fprintf(stderr, "Switching index scan and ISRC scan off!\n");
2347                         }
2348
2349                         if (global.quiet == 0) {
2350                                 fprintf(stderr,
2351                                         "Audio extraction will be limited to track %ld with maximal %ld sectors...\n",
2352                                         LastTrack(),
2353                                         Get_EndSector(LastTrack())+1
2354                                         );
2355                         }
2356                 } else {
2357                         /* The cdrom drive can read beyond the
2358                          * indicated leadout. We patch a new leadout
2359                          * position to the maximum:
2360                          *   99 minutes, 59 seconds, 74 frames
2361                          */
2362                         patch_real_end(150 + (99*60+59)*75 + 74);
2363                         if (global.quiet == 0) {
2364                                 fprintf(stderr,
2365                                         "Restrictions apply, since the size of the last track is unknown!\n");
2366                         }
2367                 }
2368         }
2369 }
2370
2371 static void Read_MCN_toshiba(subq_chnl **sub_ch);
2372
2373 static void Read_MCN_toshiba(subq_chnl **sub_ch)
2374 {
2375         if (Toshiba3401() != 0 && global.quiet == 0
2376             && ((*sub_ch) != 0
2377                 || (((subq_catalog *)(*sub_ch)->data)->mc_valid & 0x80))) {
2378                 /* no valid MCN yet. do more searching */
2379                 long h = Get_AudioStartSector(1);
2380                 
2381                 while (h <= Get_AudioStartSector(1) + 100) {
2382                         if (Toshiba3401())
2383                                 ReadCdRom(get_scsi_p(), RB_BASE->data, h, global.nsectors);
2384                         (*sub_ch) = ReadSubQ(get_scsi_p(), GET_CATALOGNUMBER,0);
2385                         if ((*sub_ch) != NULL) {
2386                                 subq_catalog *subq_cat;
2387
2388                                 subq_cat = (subq_catalog *) (*sub_ch)->data;
2389                                 if ((subq_cat->mc_valid & 0x80) != 0) {
2390                                         break;
2391                                 }
2392                         }
2393                         h += global.nsectors;
2394                 }
2395         }
2396 }
2397
2398 static void Get_Set_MCN(void);
2399
2400 static void Get_Set_MCN(void)
2401 {
2402         subq_chnl *sub_ch;
2403         subq_catalog *subq_cat = NULL;
2404         fprintf(stderr, "scanning for MCN...");
2405     
2406         sub_ch = ReadSubQ(get_scsi_p(), GET_CATALOGNUMBER,0);
2407
2408 #define EXPLICIT_READ_MCN_ISRC 1
2409 #if EXPLICIT_READ_MCN_ISRC == 1 /* TOSHIBA HACK */
2410         Read_MCN_toshiba( &sub_ch );
2411 #endif
2412
2413         if (sub_ch != NULL)
2414                 subq_cat = (subq_catalog *)sub_ch->data;
2415                         
2416         if (sub_ch != NULL
2417             && (subq_cat->mc_valid & 0x80) != 0
2418             && global.quiet == 0) {
2419
2420                 /* unified format guesser:
2421                  * format MCN all digits in bcd
2422                  *     1                                  13
2423                  * A: ab cd ef gh ij kl m0  0  0  0  0  0  0  Plextor 6x Rel. 1.02
2424                  * B: 0a 0b 0c 0d 0e 0f 0g 0h 0i 0j 0k 0l 0m  Toshiba 3401
2425                  * C: AS AS AS AS AS AS AS AS AS AS AS AS AS  ASCII SCSI-2 Plextor 4.5x and 6x Rel. 1.06
2426                  */
2427                 unsigned char *cp = subq_cat->media_catalog_number;
2428                 if (!(cp[8] | cp[9] | cp[10] | cp[11] | cp[12])
2429                     && ((cp[0] & 0xf0) | (cp[1] & 0xf0)
2430                         | (cp[2] & 0xf0) | (cp[3] & 0xf0)
2431                         | (cp[4] & 0xf0) | (cp[5] & 0xf0)
2432                         | (cp[6] & 0xf0))) {
2433                         /* reformat A: to B: */
2434                         cp[12] = cp[6] >> 4; cp[11] = cp[5] & 0xf;
2435                         cp[10] = cp[5] >> 4; cp[ 9] = cp[4] & 0xf;
2436                         cp[ 8] = cp[4] >> 4; cp[ 7] = cp[3] & 0xf;
2437                         cp[ 6] = cp[3] >> 4; cp[ 5] = cp[2] & 0xf;
2438                         cp[ 4] = cp[2] >> 4; cp[ 3] = cp[1] & 0xf;
2439                         cp[ 2] = cp[1] >> 4; cp[ 1] = cp[0] & 0xf;
2440                         cp[ 0] = cp[0] >> 4;
2441                 }
2442
2443                 if (!isdigit(cp[0])
2444                     && (memcmp(subq_cat->media_catalog_number,
2445                                "\0\0\0\0\0\0\0\0\0\0\0\0\0", 13) != 0)) {
2446                         sprintf((char *)
2447                                 subq_cat->media_catalog_number, 
2448                                 "%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X", 
2449                                 subq_cat->media_catalog_number [0],
2450                                 subq_cat->media_catalog_number [1],
2451                                 subq_cat->media_catalog_number [2],
2452                                 subq_cat->media_catalog_number [3],
2453                                 subq_cat->media_catalog_number [4],
2454                                 subq_cat->media_catalog_number [5],
2455                                 subq_cat->media_catalog_number [6],
2456                                 subq_cat->media_catalog_number [7],
2457                                 subq_cat->media_catalog_number [8],
2458                                 subq_cat->media_catalog_number [9],
2459                                 subq_cat->media_catalog_number [10],
2460                                 subq_cat->media_catalog_number [11],
2461                                 subq_cat->media_catalog_number [12]
2462                                 );
2463                 }
2464
2465                 if (memcmp(subq_cat->media_catalog_number,"0000000000000",13)
2466                     != 0) {
2467                         Set_MCN(subq_cat->media_catalog_number);
2468                 }
2469         }
2470 }
2471
2472
2473 static void Read_ISRC_toshiba(subq_chnl **sub_ch, unsigned tr);
2474
2475 static void Read_ISRC_toshiba(subq_chnl **sub_ch, unsigned tr)
2476 {
2477         if (Toshiba3401() != 0) {
2478                 int j;
2479                 j = (Get_AudioStartSector(tr)/100 + 1) * 100;
2480                 do {
2481                         ReadCdRom(get_scsi_p(), RB_BASE->data, j, global.nsectors);
2482                         *sub_ch = ReadSubQ(get_scsi_p(), GET_TRACK_ISRC, Get_Tracknumber(tr));
2483                         if (*sub_ch != NULL) {
2484                                 subq_track_isrc * subq_tr;
2485
2486                                 subq_tr = (subq_track_isrc *) (*sub_ch)->data;
2487                                 if (subq_tr != NULL && (subq_tr->tc_valid & 0x80) != 0)
2488                                         break;
2489                         }
2490                         j += global.nsectors;
2491                 } while (j < (Get_AudioStartSector(tr)/100 + 1) * 100 + 100);
2492         }
2493 }
2494
2495
2496 static void Get_Set_ISRC(unsigned tr);
2497
2498 static void Get_Set_ISRC(unsigned tr)
2499 {
2500         subq_chnl *sub_ch;
2501         subq_track_isrc * subq_tr;
2502
2503         fprintf(stderr, "\rscanning for ISRCs: %d ...", tr);
2504
2505         subq_tr = NULL;
2506         sub_ch = ReadSubQ(get_scsi_p(), GET_TRACK_ISRC, tr);
2507
2508 #if EXPLICIT_READ_MCN_ISRC == 1 /* TOSHIBA HACK */
2509         Read_ISRC_toshiba( &sub_ch, tr );
2510 #endif
2511     
2512         if (sub_ch != NULL)
2513                 subq_tr = (subq_track_isrc *)sub_ch->data;
2514         
2515         if (sub_ch != NULL && (subq_tr->tc_valid & 0x80)
2516             && global.quiet == 0) {
2517                 unsigned char p_start[16];
2518                 unsigned char *p = p_start;
2519                 unsigned char *cp = subq_tr->track_isrc;
2520
2521                 /* unified format guesser:
2522                  * there are 60 bits and 15 bytes available.
2523                  * 5 * 6bit-items + two zero fill bits + 7 * 4bit-items
2524                  *
2525                  * A: ab cd ef gh ij kl mn o0 0  0  0  0  0  0  0  Plextor 6x Rel. 1.02
2526                  * B: 0a 0b 0c 0d 0e 0f 0g 0h 0i 0j 0k 0l 0m 0n 0o Toshiba 3401
2527                  * C: AS AS AS AS AS AS AS AS AS AS AS AS AS AS AS ASCII SCSI-2
2528                  * eg 'G''B''-''A''0''7''-''6''8''-''0''0''2''7''0' makes most sense
2529                  * D: 'G''B''A''0''7''6''8''0''0''2''7''0'0  0  0  Plextor 6x Rel. 1.06 and 4.5x R. 1.01 and 1.04
2530                  */
2531
2532                 /* Check for format A: */
2533                 if (!(cp[8] | cp[9] | cp[10] | cp[11] | cp[12] | cp[13] | cp[14]) &&
2534                     ((cp[0] & 0xf0) | (cp[1] & 0xf0) | (cp[2] & 0xf0) | 
2535                      (cp[3] & 0xf0) | (cp[4] & 0xf0) | (cp[5] & 0xf0) | 
2536                      (cp[6] & 0xf0) | (cp[7] & 0xf0))) {
2537 #if DEBUG_ISRC
2538         fprintf(stderr, "a!\t");
2539 #endif
2540                         /* reformat A: to B: */
2541                         cp[14] = cp[7] >> 4; cp[13] = cp[6] & 0xf;
2542                         cp[12] = cp[6] >> 4; cp[11] = cp[5] & 0xf;
2543                         cp[10] = cp[5] >> 4; cp[ 9] = cp[4] & 0xf;
2544                         cp[ 8] = cp[4] >> 4; cp[ 7] = cp[3] & 0xf;
2545                         cp[ 6] = cp[3] >> 4; cp[ 5] = cp[2] & 0xf;
2546                         cp[ 4] = cp[2] >> 4; cp[ 3] = cp[1] & 0xf;
2547                         cp[ 2] = cp[1] >> 4; cp[ 1] = cp[0] & 0xf;
2548                         cp[ 0] = cp[0] >> 4;
2549 #if DEBUG_ISRC
2550         fprintf(stderr, "a->b: %15.15s\n", cp);
2551 #endif
2552                 }
2553       
2554                 /* Check for format B:
2555                  * If not yet in ASCII format, do the conversion
2556                  */
2557                 if (cp[0] < '0' && cp[1] < '0') {
2558                         /* coding table for International Standard Recording Code */
2559                         static char bin2ISRC[] = {
2560                          '0','1','2','3','4','5','6','7','8','9',      /* 10 */
2561                          ':',';','<','=','>','?','@',                  /* 17 */
2562                          'A','B','C','D','E','F','G','H','I','J','K',  /* 28 */
2563                          'L','M','N','O','P','Q','R','S','T','U','V',  /* 39 */
2564                          'W','X','Y','Z',                              /* 43 */
2565 #if 1
2566                          '[','\\',']','^','_','`',                     /* 49 */
2567                          'a','b','c','d','e','f','g','h','i','j','k',  /* 60 */
2568                          'l','m','n','o'                               /* 64 */
2569 #endif
2570                         };
2571         
2572                         /* build 6-bit vector of coded values */
2573                         unsigned ind;
2574                         int bits;
2575         
2576 #if DEBUG_ISRC
2577         fprintf(stderr, "b!\n");
2578 #endif
2579                         ind =   (cp[0] << 26) +
2580                                 (cp[1] << 22) +
2581                                 (cp[2] << 18) + 
2582                                 (cp[3] << 14) +
2583                                 (cp[4] << 10) +
2584                                 (cp[5] << 6) +
2585                                 (cp[6] << 2) +
2586                                 (cp[7] >> 2);
2587
2588                         if ((cp[7] & 3) == 3) {
2589                                 if (global.verbose) {
2590                                         fprintf(stderr,
2591                                                 "Recorder-ID encountered: ");
2592                                         for (bits = 0; bits < 30; bits +=6) {
2593                                                 unsigned binval = (ind & (ULONG_C(0x3f) << (24-bits)))
2594                                                                                         >> (24-bits);
2595                                                 if ((binval < sizeof(bin2ISRC)) &&
2596                                                     (binval <= 9 || binval >= 16)) {
2597                                                         fprintf(stderr, "%X", bin2ISRC[binval]);
2598                                                 }
2599                                         }
2600
2601                                         fprintf(stderr, "%.1X%.1X%.1X%.1X%.1X%.1X%.1X",
2602                                             subq_tr->track_isrc [8] & 0x0f,
2603                                             subq_tr->track_isrc [9] & 0x0f,
2604                                             subq_tr->track_isrc [10] & 0x0f,
2605                                             subq_tr->track_isrc [11] & 0x0f,
2606                                             subq_tr->track_isrc [12] & 0x0f,
2607                                             subq_tr->track_isrc [13] & 0x0f,
2608                                             subq_tr->track_isrc [14] & 0x0f
2609                                             );
2610                                         fprintf(stderr, "\n");
2611                                 }
2612                                 return;
2613                         }
2614                         if ((cp[7] & 3) != 0) {
2615                                 fprintf(stderr, "unknown mode 3 entry C1=0x%02x, C2=0x%02x\n",
2616                                         (cp[7] >> 1) & 1, cp[7] & 1);
2617                                 return;
2618                         }
2619           
2620                         /* decode ISRC due to IEC 908 */
2621                         for (bits = 0; bits < 30; bits +=6) {
2622                                 unsigned binval = (ind & ((unsigned long) 0x3fL << (24L-bits))) >> (24L-bits);
2623                                 if ((binval >= sizeof(bin2ISRC)) ||
2624                                     (binval > 9 && binval < 16)) {
2625                                         /* Illegal ISRC, dump and skip */
2626                                         int y;
2627                                                     
2628                                         Get_ISRC(tr)[0] = '\0';
2629                                         fprintf(stderr, "\nIllegal ISRC for track %d, skipped: ", tr);
2630                                         for (y = 0; y < 15; y++) {
2631                                                 fprintf(stderr, "%02x ", cp[y]);
2632                                         }
2633                                         fputs("\n", stderr);
2634                                         return;
2635                                 }
2636                                 *p++ = bin2ISRC[binval];
2637                                 
2638                                 /* insert a dash after two country characters for legibility */
2639                                 if (bits == 6)
2640                                         *p++ = '-';
2641                         }
2642                         
2643                         /* format year and serial number */
2644                         sprintf ((char *)p, "-%.1X%.1X-%.1X%.1X%.1X%.1X%.1X",
2645                                  subq_tr->track_isrc [8] & 0x0f,
2646                                  subq_tr->track_isrc [9] & 0x0f,
2647                                  subq_tr->track_isrc [10] & 0x0f,
2648                                  subq_tr->track_isrc [11] & 0x0f,
2649                                  subq_tr->track_isrc [12] & 0x0f,
2650                                  subq_tr->track_isrc [13] & 0x0f,
2651                                  subq_tr->track_isrc [14] & 0x0f
2652                                 ); 
2653 #if DEBUG_ISRC
2654         fprintf(stderr, "b: %15.15s!\n", p_start);
2655 #endif
2656                 } else {
2657                         /* It might be in ASCII, surprise */
2658                         int ii;
2659                         for (ii = 0; ii < 12; ii++) {
2660                                 if (cp[ii] < '0' || cp[ii] > 'Z') {
2661                                         break;
2662                                 }
2663                         }
2664                         if (ii != 12) {
2665                                 int y;
2666                                 
2667                                 Get_ISRC(ii)[0] = '\0';
2668                                 fprintf(stderr, "\nIllegal ISRC for track %d, skipped: ", ii+1);
2669                                 for (y = 0; y < 15; y++) {
2670                                         fprintf(stderr, "%02x ", cp[y]);
2671                                 }
2672                                 fputs("\n", stderr);
2673                                 return;
2674                         }
2675                         
2676 #if DEBUG_ISRC
2677         fprintf(stderr, "ascii: %15.15s!\n", cp);
2678 #endif
2679                         for (ii = 0; ii < 12; ii++) {
2680 #if 1
2681                                 if ((ii == 2 || ii == 5 || ii == 7) && cp[ii] != ' ')
2682                                         *p++ = '-';
2683 #endif
2684                                 *p++ = cp[ii];
2685                         }
2686                         if (p - p_start >= 16)
2687                                 *(p_start + 15) = '\0';
2688                         else
2689                                 *p = '\0';
2690                 }
2691
2692                 if (memcmp(p_start,"00-000-00-00000",15) != 0) {
2693                         Set_ISRC(tr, p_start);
2694                 }
2695         }
2696 }
2697
2698 /* get and display Media Catalog Number ( one per disc )
2699  *  and Track International Standard Recording Codes (for each track)
2700  */
2701 void Read_MCN_ISRC(void)
2702 {
2703         if ((global.verbose & SHOW_MCN) != 0) {
2704
2705                 if (Get_MCN()[0] == '\0') {
2706                         Get_Set_MCN();
2707                 }
2708
2709                 if (Get_MCN()[0] != '\0')
2710                         fprintf(stderr, "\rMedia catalog number: %13.13s\n", Get_MCN());
2711                 else
2712                         fprintf(stderr, "\rNo media catalog number present.\n");
2713         }
2714
2715
2716
2717         if ((global.verbose & SHOW_ISRC) != 0) {
2718                 static struct iterator i;
2719
2720                 InitIterator(&i, 1);
2721
2722                 while (i.hasNextTrack(&i)) {
2723                         struct TOC *p = i.getNextTrack(&i);
2724                         unsigned ii = GETTRACK(p);
2725                         
2726                         if (ii == CDROM_LEADOUT) break;
2727                         
2728                         if (!IS__AUDIO(p))
2729                                 continue;
2730
2731                         if (GETISRC(p)[0] == '\0') {
2732                                 Get_Set_ISRC(ii);
2733                         }
2734
2735                         if (GETISRC(p)[0] != '\0') {
2736                                 fprintf (stderr, "\rT: %2d ISRC: %15.15s\n", ii, GETISRC(p));
2737                                 fflush(stderr); 
2738                         }
2739                 } /* for all tracks */
2740
2741                 fputs("\n", stderr);
2742         } /* if SHOW_ISRC */
2743 }
2744
2745 static int playing = 0;
2746
2747 static subq_chnl *ReadSubChannel(unsigned sec);
2748
2749 static subq_chnl *ReadSubChannel(unsigned sec)
2750 {
2751         subq_chnl *sub_ch;
2752
2753         /*
2754          * For modern drives implement a direct method. If the drive supports
2755          * reading of subchannel data, do direct reads.
2756          */
2757         if (ReadSubChannels != NULL) {
2758                 get_scsi_p()->silent++;
2759                 sub_ch = ReadSubChannels(get_scsi_p(), sec);
2760                 get_scsi_p()->silent--;
2761                 if (sub_ch == NULL /*&& (usal_sense_key(get_scsi_p()) == 5)*/) {
2762                         /* command is not implemented */
2763                         ReadSubChannels = NULL;
2764 #if     defined DEBUG_SUB
2765 fprintf(stderr, "\nCommand not implemented: switching ReadSubChannels off !\n");
2766 #endif
2767                         goto fallback;
2768                 }
2769
2770                 /* check the adress mode field */
2771                 if ((sub_ch->control_adr & 0x0f) == 0) {
2772                         /* no Q mode information present at all, weird */
2773                         sub_ch->control_adr = 0xAA;
2774                 }
2775
2776                 if ((int)(sub_ch->control_adr & 0x0f) > 0x01) {
2777                         /* this sector just has no position information.
2778                          * we try the one before and then the one after.
2779                          */
2780                         if (sec > 1) {
2781                                 sec -= 1;
2782                                 sub_ch = ReadSubChannels(get_scsi_p(), sec);
2783                                 if (sub_ch == NULL) return NULL;
2784                                 sec += 1;
2785                         }
2786                         if ((sub_ch->control_adr & 0x0f) != 0x01) {
2787                                 sec += 2;
2788                                 sub_ch = ReadSubChannels(get_scsi_p(), sec);
2789                                 if (sub_ch == NULL) return NULL;
2790                                 sec -= 2;
2791                         }
2792                 }
2793
2794                 /* check adress mode field for position information */
2795                 if ((sub_ch->control_adr & 0x0f) == 0x01) {
2796                         return sub_ch;
2797                 }
2798                 ReadSubChannels = NULL;
2799 fprintf(stderr, "\nCould not get position information (%02x) for sectors %d, %d, %d: switching ReadSubChannels off !\n", sub_ch->control_adr &0x0f, sec-1, sec, sec+2);
2800         }
2801
2802         /*
2803          * We rely on audio sectors here!!!
2804          * The only method that worked even with my antique Toshiba 3401,
2805          * is playing the sector and then request the subchannel afterwards.
2806          */
2807 fallback:
2808         /* We need a conformed audio track here! */
2809
2810         /* Fallback to ancient method */
2811         if (-1 == Play_at(get_scsi_p(), sec, 1)) {
2812                 return NULL;
2813         }
2814         playing = 1;
2815         sub_ch = ReadSubQ(get_scsi_p(), GET_POSITIONDATA,0);
2816         return sub_ch;
2817 }
2818
2819 static int ReadSubControl(unsigned sec);
2820 static int ReadSubControl(unsigned sec)
2821 {
2822         subq_chnl *sub_ch = ReadSubChannel(sec);
2823         if (sub_ch == NULL) return -1;
2824
2825         return  sub_ch->control_adr & 0xf0;
2826 }
2827
2828 static int HaveSCMS(unsigned StartSector);
2829 static int HaveSCMS(unsigned StartSector)
2830 {
2831         int i;
2832         int     cr;
2833         int     copy_bits_set = 0;
2834
2835         for (i = 0; i < 8; i++) {
2836                 cr = ReadSubControl(StartSector + i);
2837                 if (cr == -1) continue;
2838                 (cr & 0x20) ? copy_bits_set++ : 0;
2839         }
2840         return (copy_bits_set >= 1 && copy_bits_set < 8);
2841 }
2842
2843 void Check_Toc(void)
2844 {
2845         /* detect layout */
2846         
2847         /* detect tracks */
2848 }
2849
2850 static int GetIndexOfSector(unsigned sec, unsigned track)
2851 {
2852         subq_chnl *sub_ch = ReadSubChannel(sec);
2853         if (sub_ch == NULL) {
2854                 if ((long)sec == Get_EndSector(track)) {
2855                         fprintf(stderr, "Driver and/or firmware bug detected! Drive cannot play the very last sector (%u)!\n", sec);
2856                 }
2857                 return -1;
2858         }
2859
2860         /* can we trust that these values are hex and NOT bcd? */
2861         if ((sub_ch->track >= 0x10) && (sub_ch->track - track > 5)) {
2862                 /* change all values from bcd to hex */
2863                 sub_ch->track = (sub_ch->track >> 4)*10 + (sub_ch->track & 0x0f);
2864                 sub_ch->index = (sub_ch->index >> 4)*10 + (sub_ch->index & 0x0f);
2865         }
2866
2867 #if 1
2868     /* compare tracks */
2869     if (sub_ch->index != 0 && track != sub_ch->track) {
2870         if (global.verbose) fprintf(stderr, "\ntrack mismatch: %1d, in-track subchannel: %1d (index %1d, sector %1d)\n",
2871                 track, sub_ch->track, sub_ch->index, sec);
2872     }
2873 #endif
2874
2875     /* compare control field with the one from the TOC */
2876     if ((Get_Flags(track) & 0xf0) != (sub_ch->control_adr & 0xf0)) {
2877         int     diffbits = (Get_Flags(track) & 0xf0) ^ (sub_ch->control_adr & 0xf0);
2878         if ((diffbits & 0x80) == 0x80) {
2879                 /* broadcast difference */
2880                 if (global.verbose) fprintf(stderr, "broadcast type conflict detected -> TOC:%s, subchannel:%s\n",
2881                 (sub_ch->control_adr & 0x80) == 0 ? "broadcast" : "nonbroadcast"
2882                 ,(sub_ch->control_adr & 0x80) != 0 ? "broadcast" : "nonbroadcast"
2883                 );
2884         }
2885         if ((diffbits & 0x40) == 0x40) {
2886                 /* track type difference */
2887                 if (global.verbose) fprintf(stderr, "track type conflict detected -> TOC:%s, subchannel:%s\n",
2888                 (sub_ch->control_adr & 0x40) == 0 ? "data" : "audio"
2889                 ,(sub_ch->control_adr & 0x40) != 0 ? "data" : "audio"
2890                 );
2891         }
2892         if ((diffbits & 0x20) == 0x20 && !Get_SCMS(track)) {
2893                 /* copy permission difference is a sign for SCMS
2894                  * and is treated elsewhere. */
2895                 if (global.verbose) fprintf(stderr, "difference: TOC:%s, subchannel:%s\ncorrecting TOC...\n",
2896                 (sub_ch->control_adr & 0x20) == 0 ? "unprotected" : "copyright protected",
2897                 (sub_ch->control_adr & 0x20) != 0 ? "unprotected" : "copyright protected"
2898                 );
2899                 toc_entry(track, 
2900                   (Get_Flags(track) & 0xDF) | (sub_ch->control_adr & 0x20),
2901                   Get_Tracknumber(track),
2902                   Get_ISRC(track),
2903                   Get_AudioStartSector(track),
2904                   Get_Mins(track),
2905                   Get_Secs(track),
2906                   Get_Frames(track)
2907                   );
2908         }
2909         if ((diffbits & 0x10) == 0x10) {
2910                 /* preemphasis difference */
2911                 if (global.verbose) fprintf(stderr, "difference: TOC:%s, subchannel:%s preemphasis\ncorrecting TOC...\n",
2912                 (sub_ch->control_adr & 0x10) == 0 ? "with" : "without",
2913                 (sub_ch->control_adr & 0x10) != 0 ? "with" : "without"
2914                 );
2915                 toc_entry(track, 
2916                   (Get_Flags(track) & 0xEF) | (sub_ch->control_adr & 0x10),
2917                   Get_Tracknumber(track),
2918                   Get_ISRC(track),
2919                   Get_AudioStartSector(track),
2920                   Get_Mins(track),
2921                   Get_Secs(track),
2922                   Get_Frames(track)
2923                   );
2924         }
2925
2926     }
2927
2928     return sub_ch ? sub_ch->index == 244 ? 1 : sub_ch->index : -1;
2929 }
2930
2931 static int ScanBackwardFrom(unsigned sec, unsigned limit, int *where, 
2932                                                                          unsigned track);
2933
2934 static int ScanBackwardFrom(unsigned sec, unsigned limit, int *where, 
2935                                                                          unsigned track)
2936 {
2937         unsigned lastindex = 0;
2938         unsigned mysec = sec;
2939
2940         /* try to find the transition of index n to index 0,
2941          * if the track ends with an index 0.
2942          */
2943         while ((lastindex = GetIndexOfSector(mysec, track)) == 0) {
2944                 if (mysec < limit+75) {
2945                         break;
2946                 }
2947                 mysec -= 75;
2948         }
2949         if (mysec == sec) {
2950                 /* there is no pre-gap in this track */
2951                 if (where != NULL) *where = -1;
2952         } else {
2953                 /* we have a pre-gap in this track */
2954
2955                 if (lastindex == 0) {
2956                         /* we did not cross the transition yet -> search backward */
2957                         do {
2958                                 if (mysec < limit+1) {
2959                                         break;
2960                                 }
2961                                 mysec --;
2962                         } while ((lastindex = GetIndexOfSector(mysec,track)) == 0);
2963                         if (lastindex != 0) {
2964                                 /* successful */
2965                                 mysec ++;
2966                                 /* register mysec as transition */
2967                                 if (where != NULL) *where = (int) mysec;
2968                         } else {
2969                                 /* could not find transition */
2970                                 if (!global.quiet)
2971                                         fprintf(stderr,
2972                                          "Could not find index transition for pre-gap.\n");
2973                                 if (where != NULL) *where = -1;
2974                         }
2975                 } else {
2976                         int myindex = -1;
2977                         /* we have crossed the transition -> search forward */
2978                         do {
2979                                 if (mysec >= sec) {
2980                                         break;
2981                                 }
2982                                 mysec ++;
2983                         } while ((myindex = GetIndexOfSector(mysec,track)) != 0);
2984                         if (myindex == 0) {
2985                                 /* successful */
2986                                 /* register mysec as transition */
2987                                 if (where != NULL) *where = (int) mysec;
2988                         } else {
2989                                 /* could not find transition */
2990                                 if (!global.quiet)
2991                                         fprintf(stderr,
2992                                          "Could not find index transition for pre-gap.\n");
2993                                 if (where != NULL) *where = -1;
2994                         }
2995                 }
2996         }
2997         return lastindex;
2998 }
2999
3000 #ifdef  USE_LINEAR_SEARCH
3001 static int linear_search(int searchInd, unsigned int Start, unsigned int End, 
3002                                                                  unsigned track);
3003
3004 static int linear_search(int searchInd, unsigned int Start, unsigned int End, 
3005                                                                  unsigned track)
3006 {
3007       int l = Start;
3008       int r = End;
3009
3010       for (; l <= r; l++ ) {
3011           int ind;
3012
3013           ind = GetIndexOfSector(l, track);
3014           if ( searchInd == ind ) {
3015               break;
3016           }
3017       }
3018       if ( l <= r ) {
3019         /* Index found. */
3020         return l;
3021       }
3022
3023       return -1;
3024 }
3025 #endif
3026
3027 #ifndef USE_LINEAR_SEARCH
3028 #undef DEBUG_BINSEARCH
3029 static int binary_search(int searchInd, unsigned int Start, unsigned int End, 
3030                                                                  unsigned track);
3031
3032 static int binary_search(int searchInd, unsigned Start, unsigned End, 
3033                                                                  unsigned track)
3034 {
3035       int l = Start;
3036       int r = End;
3037       int x = 0;
3038       int ind;
3039
3040       while ( l <= r ) {
3041           x = ( l + r ) / 2;
3042           /* try to avoid seeking */
3043           ind = GetIndexOfSector(x, track);
3044           if ( searchInd == ind ) {
3045               break;
3046           } else {
3047               if ( searchInd < ind ) r = x - 1;
3048               else                   l = x + 1;
3049           }
3050       }
3051 #ifdef DEBUG_BINSEARCH
3052 fprintf(stderr, "(%d,%d,%d > ",l,x,r);
3053 #endif
3054       if ( l <= r ) {
3055         /* Index found. Now find the first position of this index */
3056         /* l=LastPos    x=found         r=NextPos */
3057         r = x;
3058         while ( l < r-1 ) {
3059           x = ( l + r ) / 2;
3060           /* try to avoid seeking */
3061           ind = GetIndexOfSector(x, track);
3062           if ( searchInd == ind ) {
3063               r = x;
3064           } else {
3065               l = x;
3066           }
3067 #ifdef DEBUG_BINSEARCH
3068 fprintf(stderr, "%d -> ",x);
3069 #endif
3070         }
3071 #ifdef DEBUG_BINSEARCH
3072 fprintf(stderr, "%d,%d)\n",l,r);
3073 #endif
3074         if (searchInd == GetIndexOfSector(l, track))
3075           return l;
3076         else
3077           return r;
3078       }
3079
3080       return -1;
3081 }
3082 #endif
3083
3084
3085 static void register_index_position(int IndexOffset, 
3086                                                                                                 index_list **last_index_entry);
3087
3088 static void register_index_position(int IndexOffset, 
3089                                                                                                 index_list **last_index_entry)
3090 {
3091       index_list *indexentry;
3092
3093       /* register higher index entries */
3094       if (*last_index_entry != NULL) {
3095         indexentry = (index_list *) malloc( sizeof(index_list) );
3096       } else {
3097         indexentry = NULL;
3098       }
3099       if (indexentry != NULL) {
3100         indexentry->next = NULL;
3101         (*last_index_entry)->next = indexentry;
3102         *last_index_entry = indexentry;
3103         indexentry->frameoffset = IndexOffset;
3104 #if defined INFOFILES
3105       } else {
3106         fprintf( stderr, "No memory for index lists. Index positions\nwill not be written in info file!\n");
3107 #endif
3108       }
3109 }
3110
3111 static void Set_SCMS(unsigned long p_track);
3112
3113 #undef DEBUG_INDLIST
3114 /* experimental code */
3115 /* search for indices (audio mode required) */
3116 unsigned ScanIndices(unsigned track, unsigned cd_index, int bulk)
3117 {
3118   /* scan for indices. */
3119   /* look at last sector of track. */
3120   /* when the index is not equal 1 scan by bipartition 
3121    * for offsets of all indices */
3122
3123   unsigned starttrack, endtrack;
3124   unsigned startindex, endindex;
3125
3126   unsigned j;
3127   int LastIndex=0;
3128   int n_0_transition;
3129   unsigned StartSector;
3130   unsigned retval = 0;
3131
3132   index_list *baseindex_pool;
3133   index_list *last_index_entry;
3134
3135   SCSI *usalp = get_scsi_p();
3136
3137   static struct iterator i;
3138   InitIterator(&i, 1);
3139   
3140   EnableCdda(usalp, 0, 0);
3141   EnableCdda(usalp, 1, CD_FRAMESIZE_RAW + 16);
3142
3143   if (!global.quiet && !(global.verbose & SHOW_INDICES))
3144     fprintf(stderr, "seeking index start ...");
3145
3146   if (bulk != 1) {
3147     starttrack = track; endtrack = track;
3148   } else {
3149     starttrack = 1; endtrack = cdtracks;
3150   }
3151   baseindex_pool = (index_list *) malloc( sizeof(index_list) * (endtrack - starttrack + 1));
3152 #ifdef DEBUG_INDLIST
3153   fprintf(stderr, "index0-mem-pool %p\n", baseindex_pool);
3154 #endif
3155
3156
3157   while (i.hasNextTrack(&i)) {
3158           struct TOC *p = i.getNextTrack(&i);
3159           unsigned ii = GETTRACK(p);
3160
3161           if ( ii < starttrack || IS__DATA(p) )
3162                   continue;     /* skip nonaudio tracks */
3163
3164           if ( ii > endtrack )
3165                   break;
3166
3167           if ( global.verbose & SHOW_INDICES ) { 
3168                   if (global.illleadout_cd && global.reads_illleadout && ii == endtrack) {
3169                           fprintf(stderr, "Analysis of track %d skipped due to unknown length\n", ii);
3170                   }
3171           }
3172           if (global.illleadout_cd && global.reads_illleadout 
3173               && ii == endtrack) continue;
3174
3175           StartSector = Get_AudioStartSector(ii);
3176           if (HaveSCMS(StartSector)) {
3177                 Set_SCMS(ii);
3178           }
3179           if ( global.verbose & SHOW_INDICES ) { 
3180                   fprintf( stderr, "\rindex scan: %d...", ii ); 
3181                   fflush (stderr);
3182           }
3183           LastIndex = ScanBackwardFrom(Get_EndSector(ii), StartSector, &n_0_transition, ii);
3184           if (LastIndex > 99) continue;
3185
3186           if (baseindex_pool != NULL) {
3187 #ifdef DEBUG_INDLIST
3188 #endif
3189                   /* register first index entry for this track */
3190                   baseindex_pool[ii - starttrack].next = NULL;
3191                   baseindex_pool[ii - starttrack].frameoffset = StartSector;
3192                   global.trackindexlist[ii] = &baseindex_pool[ii - starttrack];
3193 #ifdef DEBUG_INDLIST
3194 #endif
3195           } else {
3196                   global.trackindexlist[ii] = NULL;
3197           }
3198           last_index_entry = global.trackindexlist[ii];
3199
3200           if (LastIndex < 2) {
3201                   register_index_position(n_0_transition, &last_index_entry);
3202                   continue;
3203           }
3204
3205           if ((global.verbose & SHOW_INDICES) && LastIndex > 1)
3206                   fprintf(stderr, "\rtrack %2d has %d indices, index table (pairs of 'index: frame offset')\n", ii, LastIndex);
3207           
3208           startindex = 0;
3209           endindex = LastIndex;
3210
3211           for (j = startindex; j <= endindex; j++) {
3212                   int IndexOffset;
3213                   
3214                   /* this track has indices */
3215
3216 #ifdef  USE_LINEAR_SEARCH
3217                   /* do a linear search */
3218                   IndexOffset = linear_search(j, StartSector, Get_EndSector(ii), ii);
3219 #else
3220                   /* do a binary search */
3221                   IndexOffset = binary_search(j, StartSector, Get_EndSector(ii), ii);
3222 #endif
3223
3224                   if (IndexOffset != -1) {
3225                           StartSector = IndexOffset;
3226                   }
3227
3228                   if (j == 1)
3229                           last_index_entry->frameoffset = IndexOffset;
3230                   else if (j > 1)
3231                           register_index_position(IndexOffset, &last_index_entry);
3232
3233                   if ( IndexOffset == -1 ) {
3234                           if (global.verbose & SHOW_INDICES) {
3235                                   if (global.gui == 0) {
3236                                           fprintf(stderr, "%2u: N/A   ",j);
3237                                           if (((j + 1) % 8) == 0) fputs("\n", stderr);
3238                                   } else {
3239                                           fprintf(stderr, "\rT%02d I%02u N/A\n",ii,j);
3240                                   }
3241                           }
3242                   } else {
3243                           if (global.verbose & SHOW_INDICES) {
3244                                   if (global.gui == 0) {
3245                                           fprintf(stderr, 
3246                                                 "%2u:%6lu ",
3247                                                 j,
3248                                                 IndexOffset-Get_AudioStartSector(ii)
3249                                                  );
3250                                           if (((j + 1) % 8) == 0) fputs("\n", stderr);
3251                                   } else {
3252                                           fprintf(stderr,
3253                                                 "\rT%02d I%02u %06lu\n",
3254                                                 ii,
3255                                                 j,
3256                                                 IndexOffset-Get_AudioStartSector(ii)
3257                                                  );
3258                                   }
3259                           }
3260
3261                           if (track == ii && cd_index == j) {
3262                                   retval = IndexOffset-Get_AudioStartSector(ii);
3263                           }
3264                   } /* if IndexOffset */
3265           } /* for index */
3266           register_index_position(n_0_transition, &last_index_entry);
3267
3268           /* sanity check. clear all consecutive nonindex entries (frameoffset -1) from the end. */
3269           {
3270                 index_list *ip = global.trackindexlist[ii];
3271                 index_list *iq = NULL;
3272                 index_list *lastgood = iq;
3273
3274                 while (ip != NULL)
3275                 {
3276                         if (ip->frameoffset == -1)
3277                         {
3278                                 /* no index available */
3279                                 if (lastgood == NULL)
3280                                 {
3281                                         /* if this is the first one in a sequence, store predecessor */
3282                                         lastgood = iq;
3283                                 }
3284                         } else {
3285                                 /* this is a valid index, reset marker */
3286                                 lastgood = NULL;
3287                         }
3288
3289                         iq = ip;
3290                         ip = ip->next;
3291                 }
3292                 /* terminate chain at the last well defined entry. */
3293                 if (lastgood != NULL)
3294                         lastgood->next = NULL;
3295           }
3296
3297           if (global.gui == 0 && (global.verbose & SHOW_INDICES)
3298               && ii != endtrack)
3299                   fputs("\n", stderr);
3300   } /* for tracks */
3301   if (global.gui == 0 && (global.verbose & SHOW_INDICES))
3302           fputs("\n", stderr);
3303   if (playing != 0) StopPlay(get_scsi_p());
3304
3305   EnableCdda(usalp, 0, 0);
3306   EnableCdda(usalp, 1, CD_FRAMESIZE_RAW);
3307
3308   return retval;
3309 }
3310
3311 static unsigned char MCN[14];
3312
3313 static void Set_MCN(unsigned char *MCN_arg)
3314 {
3315         memcpy(MCN, MCN_arg, 14);
3316         MCN[13] = '\0';
3317 }
3318
3319 unsigned char *Get_MCN(void)
3320 {
3321         return MCN;
3322 }
3323
3324
3325 static TOC g_toc [MAXTRK+1]; /* hidden track + 100 regular tracks */
3326
3327 /*#define IS_AUDIO(i) (!(g_toc[i].bFlags & 0x40))*/
3328
3329 int 
3330 TOC_entries(unsigned tracks, unsigned char *a, unsigned char *b, int binvalid)
3331 {
3332         int i;
3333         for (i = 1; i <= (int)tracks; i++) {
3334                 unsigned char *p;
3335                 unsigned long dwStartSector;
3336
3337                 if (binvalid) {
3338                         p = a + 8*(i-1);
3339
3340                         g_toc[i].bFlags = p[1];
3341                         g_toc[i].bTrack = p[2];
3342                         g_toc[i].ISRC[0] = 0;
3343                         dwStartSector = a_to_u_4_byte(p+4);
3344                         g_toc[i].dwStartSector = dwStartSector;
3345                         lba_2_msf((long)dwStartSector,
3346                                   &g_toc[i].mins,
3347                                   &g_toc[i].secs,
3348                                   &g_toc[i].frms);
3349                 } else {
3350                         p = b + 8*(i-1);
3351                         g_toc[i].bFlags = p[1];
3352                         g_toc[i].bTrack = p[2];
3353                         g_toc[i].ISRC[0] = 0;
3354                         if ((int)((p[5]*60 + p[6])*75 + p[7]) >= 150) {
3355                                 g_toc[i].dwStartSector = (p[5]*60 + p[6])*75 + p[7] -150;
3356                         } else {
3357                                 g_toc[i].dwStartSector = 0;
3358                         }
3359                         g_toc[i].mins = p[5];
3360                         g_toc[i].secs = p[6];
3361                         g_toc[i].frms = p[7];
3362                 }
3363         }
3364         return 0;
3365 }
3366
3367 void toc_entry(unsigned nr, unsigned flag, unsigned tr, unsigned char *ISRC, 
3368                unsigned long lba, int m, int s, int f)
3369 {
3370         if (nr > MAXTRK) return;
3371
3372         g_toc[nr].bFlags = flag;
3373         g_toc[nr].bTrack = tr;
3374         if (ISRC) {
3375                 strncpy((char *)g_toc[nr].ISRC, (char *)ISRC,
3376                         sizeof(g_toc[nr].ISRC) -1);
3377                 g_toc[nr].ISRC[sizeof(g_toc[nr].ISRC) -1] = '\0';
3378         }
3379         g_toc[nr].dwStartSector = lba;
3380         g_toc[nr].mins = m;
3381         g_toc[nr].secs = s;
3382         g_toc[nr].frms = f;
3383 }
3384
3385 int patch_real_end(unsigned long sector)
3386 {
3387         g_toc[cdtracks+1].dwStartSector = sector;
3388         return 0;
3389 }
3390
3391 static int patch_cd_extra(unsigned track, unsigned long sector)
3392 {
3393         if (track <= cdtracks)
3394                 g_toc[track].dwStartSector = sector;
3395         return 0;
3396 }
3397
3398 static int restrict_tracks_illleadout(void)
3399 {
3400         struct TOC *o = &g_toc[cdtracks+1];
3401         int i;
3402         for (i = cdtracks; i >= 0; i--) {
3403                 struct TOC *p = &g_toc[i];
3404                 if (GETSTART(o) > GETSTART(p)) break;
3405         }
3406         patch_cd_extra(i+1, GETSTART(o));
3407         cdtracks = i;
3408
3409         return 0;
3410 }
3411
3412 static void Set_ISRC(int track, const unsigned char *ISRC_arg)
3413 {
3414         if (track <= (int)cdtracks) {
3415                 memcpy(Get_ISRC(track), ISRC_arg, 16);
3416         }
3417 }
3418
3419
3420 unsigned char *Get_ISRC(unsigned long p_track)
3421 {
3422         if (p_track <= cdtracks)
3423                 return g_toc[p_track].ISRC;
3424         return NULL;
3425 }
3426
3427 static void patch_to_audio(unsigned long p_track)
3428 {
3429         if (p_track <= cdtracks)
3430                 g_toc[p_track].bFlags &= ~0x40;
3431 }
3432
3433 int Get_Flags(unsigned long p_track)
3434 {
3435         if (p_track <= cdtracks)
3436                 return g_toc[p_track].bFlags;
3437         return -1;
3438 }
3439
3440 int Get_Mins(unsigned long p_track)
3441 {
3442         if (p_track <= cdtracks)
3443                 return g_toc[p_track].mins;
3444         return -1;
3445 }
3446
3447 int Get_Secs(unsigned long p_track)
3448 {
3449         if (p_track <= cdtracks)
3450                 return g_toc[p_track].secs;
3451         return -1;
3452 }
3453
3454 int Get_Frames(unsigned long p_track)
3455 {
3456         if (p_track <= cdtracks)
3457                 return g_toc[p_track].frms;
3458         return -1;
3459 }
3460
3461 int Get_Preemphasis(unsigned long p_track)
3462 {
3463         if (p_track <= cdtracks)
3464                 return g_toc[p_track].bFlags & 0x10;
3465         return -1;
3466 }
3467
3468 static void Set_SCMS(unsigned long p_track)
3469 {
3470         g_toc[p_track].SCMS = 1;
3471 }
3472
3473 int Get_SCMS(unsigned long p_track)
3474 {
3475         if (p_track <= cdtracks)
3476                 return g_toc[p_track].SCMS;
3477         return -1;
3478 }
3479
3480 int Get_Copyright(unsigned long p_track)
3481 {
3482         if (p_track <= cdtracks) {
3483                 if (g_toc[p_track].SCMS) return 1;
3484                 return ((int)g_toc[p_track].bFlags & 0x20) >> 4;
3485         }
3486         return -1;
3487 }
3488
3489 int Get_Datatrack(unsigned long p_track)
3490 {
3491         if (p_track <= cdtracks)
3492                 return g_toc[p_track].bFlags & 0x40;
3493         return -1;
3494 }
3495
3496 int Get_Channels(unsigned long p_track)
3497 {
3498         if (p_track <= cdtracks)
3499                 return g_toc[p_track].bFlags & 0x80;
3500         return -1;
3501 }
3502
3503 int Get_Tracknumber(unsigned long p_track)
3504 {
3505         if (p_track <= cdtracks)
3506                 return g_toc[p_track].bTrack;
3507         return -1;
3508 }
3509
3510 static int useHiddenTrack(void)
3511 {
3512         return 0;
3513 }
3514
3515
3516
3517 static void it_reset(struct iterator *this);
3518
3519 static void it_reset(struct iterator *this)
3520 {
3521         this->index = this->startindex;
3522 }
3523
3524
3525 static int it_hasNextTrack(struct iterator *this);
3526 static struct TOC *it_getNextTrack(struct iterator *this);
3527
3528 static int it_hasNextTrack(struct iterator *this)
3529 {
3530         return this->index <= (int)cdtracks+1;
3531 }
3532
3533
3534
3535 static struct TOC *it_getNextTrack(struct iterator *this)
3536 {
3537         /* if ( (*this->hasNextTrack)(this) == 0 ) return NULL; */
3538         if ( this->index > (int)cdtracks+1 ) return NULL;
3539
3540         return &g_toc[ this->index++ ];
3541 }
3542
3543
3544 static void InitIterator(struct iterator *iter, unsigned long p_track)
3545 {
3546         if (iter == NULL) return;
3547
3548         iter->index = iter->startindex = useHiddenTrack() ? 0 : p_track;
3549         iter->reset = it_reset;
3550         iter->getNextTrack = it_getNextTrack;
3551         iter->hasNextTrack = it_hasNextTrack;
3552 }
3553
3554 #if     0
3555 static struct iterator *NewIterator(void);
3556
3557 static struct iterator *NewIterator ()
3558 {
3559         struct iterator *retval;
3560
3561         retval = malloc (sizeof(struct iterator));
3562         if (retval != NULL) {
3563                 InitIterator(retval, 1);
3564         }
3565         return retval;
3566 }
3567 #endif
3568
3569 long Get_AudioStartSector(unsigned long p_track)
3570 {
3571 #if     1
3572         if (p_track == CDROM_LEADOUT)
3573                 p_track = cdtracks + 1;
3574
3575         if (p_track <= cdtracks +1
3576                 && IS__AUDIO(&g_toc[p_track]))
3577                 return GETSTART(&g_toc[p_track]);
3578 #else
3579         static struct iterator i;
3580         if (i.reset == NULL) InitIterator(&i, p_track);
3581         else i.reset(&i);
3582
3583         if (p_track == cdtracks + 1) p_track = CDROM_LEADOUT;
3584
3585         while (i.hasNextTrack(&i)) {
3586                 TOC *p = i.getNextTrack(&i);
3587
3588                 if (GETTRACK(p) == p_track) {
3589                         if (IS__DATA(p)) {
3590                                 return -1;
3591                         }
3592                         return GETSTART(p);
3593                 }
3594         }
3595 #endif
3596         return -1;
3597 }
3598
3599
3600 long Get_StartSector(unsigned long p_track)
3601 {
3602 #if     1
3603         if (p_track == CDROM_LEADOUT)
3604                 p_track = cdtracks + 1;
3605
3606         if (p_track <= cdtracks +1)
3607                 return GETSTART(&g_toc[p_track]);
3608 #else
3609         static struct iterator i;
3610         if (i.reset == NULL) InitIterator(&i, p_track);
3611         else i.reset(&i);
3612
3613         if (p_track == cdtracks + 1) p_track = CDROM_LEADOUT;
3614
3615         while (i.hasNextTrack(&i)) {
3616                 TOC *p = i.getNextTrack(&i);
3617
3618                 if (GETTRACK(p) == p_track) {
3619                         return GETSTART(p);
3620                 }
3621         }
3622 #endif
3623         return -1;
3624 }
3625
3626
3627 long Get_EndSector(unsigned long p_track)
3628 {
3629 #if     1
3630         if (p_track <= cdtracks)
3631                 return GETSTART(&g_toc[p_track+1])-1;
3632 #else
3633         static struct iterator i;
3634         if (i.reset == NULL) InitIterator(&i, p_track);
3635         else i.reset(&i);
3636
3637         if (p_track == cdtracks + 1) p_track = CDROM_LEADOUT;
3638
3639         while (i.hasNextTrack(&i)) {
3640                 TOC *p = i.getNextTrack(&i);
3641                 if (GETTRACK(p) == p_track) {
3642                         p = i.getNextTrack(&i);
3643                         if (p == NULL) {
3644                                 return -1;
3645                         }
3646                         return GETSTART(p)-1;
3647                 }
3648         }
3649 #endif
3650         return -1;
3651 }
3652
3653 long FirstTrack(void)
3654 {
3655         static struct iterator i;
3656         if (i.reset == NULL) InitIterator(&i, 1);
3657         else i.reset(&i);
3658
3659         if (i.hasNextTrack(&i)) {
3660                 return GETTRACK(i.getNextTrack(&i));
3661         }
3662         return -1;
3663 }
3664
3665 long FirstAudioTrack(void)
3666 {
3667         static struct iterator i;
3668         if (i.reset == NULL) InitIterator(&i, 1);
3669         else i.reset(&i);
3670
3671         while (i.hasNextTrack(&i)) {
3672                 TOC *p = i.getNextTrack(&i);
3673                 unsigned ii = GETTRACK(p);
3674
3675                 if (ii == CDROM_LEADOUT) break;
3676                 if (IS__AUDIO(p)) {
3677                         return ii;
3678                 }
3679         }
3680         return -1;
3681 }
3682
3683 long FirstDataTrack(void)
3684 {
3685         static struct iterator i;
3686         if (i.reset == NULL) InitIterator(&i, 1);
3687         else i.reset(&i);
3688
3689         while (i.hasNextTrack(&i)) {
3690                 TOC *p = i.getNextTrack(&i);
3691                 if (IS__DATA(p)) {
3692                         return GETTRACK(p);
3693                 }
3694         }
3695         return -1;
3696 }
3697
3698 long LastTrack(void)
3699 {
3700         return g_toc[cdtracks].bTrack;
3701 }
3702
3703 long LastAudioTrack(void)
3704 {
3705         long j = -1;
3706         static struct iterator i;
3707         if (i.reset == NULL) InitIterator(&i, 1);
3708         else i.reset(&i);
3709
3710         while (i.hasNextTrack(&i)) {
3711                 TOC *p = i.getNextTrack(&i);
3712                 if (IS__AUDIO(p) && (GETTRACK(p) != CDROM_LEADOUT)) {
3713                         j = GETTRACK(p);
3714                 }
3715         }
3716         return j;
3717 }
3718
3719 long Get_LastSectorOnCd(unsigned long p_track)
3720 {
3721         long LastSec = 0;
3722         static struct iterator i;
3723
3724         if (global.illleadout_cd && global.reads_illleadout)
3725                 return 150+(99*60+59)*75+74;
3726
3727         if (i.reset == NULL) InitIterator(&i, p_track);
3728         else i.reset(&i);
3729
3730         if (p_track == cdtracks + 1) p_track = CDROM_LEADOUT;
3731
3732         while (i.hasNextTrack(&i)) {
3733                 TOC *p = i.getNextTrack(&i);
3734
3735                 if (GETTRACK(p) < p_track)
3736                         continue;
3737
3738                 LastSec = GETSTART(p);
3739
3740                 if (IS__DATA(p)) break;
3741         }
3742         return LastSec;
3743 }
3744
3745 int Get_Track(unsigned long sector)
3746 {
3747         static struct iterator i;
3748         if (i.reset == NULL) InitIterator(&i, 1);
3749         else i.reset(&i);
3750
3751         if (i.hasNextTrack(&i)) {
3752                 TOC *o = i.getNextTrack(&i);
3753                 while (i.hasNextTrack(&i)) {
3754                         TOC *p = i.getNextTrack(&i);
3755                         if ((GETSTART(o) <= sector) && (GETSTART(p) > sector)) {
3756                                 if (IS__DATA(o)) {
3757                                         return -1;
3758                                 } else {
3759                                         return GETTRACK(o);
3760                                 }
3761                         }
3762                         o = p;
3763                 }
3764         }
3765         return -1;
3766 }
3767
3768 int CheckTrackrange(unsigned long from, unsigned long upto)
3769 {
3770         static struct iterator i;
3771         if (i.reset == NULL) InitIterator(&i, from);
3772         else i.reset(&i);
3773
3774         while (i.hasNextTrack(&i)) {
3775                 TOC *p = i.getNextTrack(&i);
3776
3777                 if (GETTRACK(p) < from)
3778                         continue;
3779
3780                 if (GETTRACK(p) == upto)
3781                         return 1;
3782
3783                 /* data tracks terminate the search */
3784                 if (IS__DATA(p))
3785                         return 0;
3786         }
3787         /* track not found */
3788         return 0;
3789 }
3790
3791 #ifdef  USE_PARANOIA
3792 long cdda_disc_firstsector(void *d);
3793
3794 long cdda_disc_firstsector(void *d)
3795 {
3796         return Get_StartSector(FirstAudioTrack());
3797 }
3798
3799 int cdda_tracks(void *d);
3800
3801 int cdda_tracks(void *d)
3802 {
3803         return LastAudioTrack() - FirstAudioTrack() +1;
3804 }
3805
3806 int cdda_track_audiop(void *d, int track);
3807
3808 int cdda_track_audiop(void *d, int track)
3809 {
3810         return Get_Datatrack(track) == 0;
3811 }
3812
3813 long cdda_track_firstsector(void *d, int track);
3814
3815 long cdda_track_firstsector(void *d, int track)
3816 {
3817         return Get_AudioStartSector(track);
3818 }
3819
3820 long cdda_track_lastsector(void *d, int track);
3821
3822 long cdda_track_lastsector(void *d, int track)
3823 {
3824         return Get_EndSector(track);
3825 }
3826
3827 long cdda_disc_lastsector(void *d);
3828
3829 long cdda_disc_lastsector(void *d)
3830 {
3831         return Get_LastSectorOnCd(cdtracks) - 1;
3832 }
3833
3834 int cdda_sector_gettrack(void *d,long sector);
3835
3836 int cdda_sector_gettrack(void *d, long sector)
3837 {
3838         return Get_Track(sector);
3839 }
3840
3841 #endif