1 /*
2  *   cdinfo - CD Information Management Library
3  *
4  *   Copyright (C) 1993-2004  Ti Kan
5  *   E-mail: xmcd@amb.org
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22 #ifndef lint
23 static char *_cdinfo_i_c_ident_ = "@(#)cdinfo_i.c	7.190 04/04/20";
24 #endif
25 
26 #ifdef __VMS
27 typedef char *	caddr_t;
28 #endif
29 
30 #define _CDINFO_INTERN	/* Expose internal function protos in cdinfo.h */
31 #define XMCD_CDDB	/* Enable correct includes in CDDB2API.h */
32 
33 #include "common_d/appenv.h"
34 #include "common_d/version.h"
35 #include "common_d/util.h"
36 #include "libdi_d/libdi.h"
37 #include "cdda_d/cdda.h"
38 #include "cdinfo_d/cdinfo.h"
39 #include "cddb_d/CDDB2API.h"
40 #if defined(_AIX) || defined(__QNX__)
41 #include <sys/select.h>
42 #endif
43 
44 
45 /* Time interval to run workproc while waiting for I/O */
46 #define CDINFO_WAIT_SEC		0
47 #define CDINFO_WAIT_USEC	200000
48 
49 
50 extern appdata_t	app_data;
51 extern FILE		*errfp;
52 
53 /* Internal data not to be used outside of libcdinfo */
54 cdinfo_client_t		*cdinfo_clinfo;		/* Client info */
55 cdinfo_incore_t		*cdinfo_dbp;		/* In core CD info struct */
56 cdinfo_cddb_t		*cdinfo_cddbp;		/* Opened CDDB handle */
57 w_ent_t			*cdinfo_discog,		/* Local discog menu ptr */
58 			*cdinfo_scddb;		/* Search CDDB menu ptr */
59 bool_t			cdinfo_ischild;		/* Is a child process */
60 
61 STATIC bool_t		cdinfo_ctrl_initted = FALSE,
62 						/* CDDB ctrl initialized */
63 			cdinfo_genurl_initted = FALSE,
64 						/* Gen URLs list initialized */
65 			cdinfo_glist_initted = FALSE,
66 						/* Genre list initialized */
67 			cdinfo_relist_initted = FALSE,
68 						/* Region list initialized */
69 			cdinfo_langlist_initted = FALSE,
70 						/* Language list initialized */
71 			cdinfo_rolist_initted = FALSE,
72 						/* Role list initialized */
73 			cdinfo_user_regd = FALSE;
74 						/* User registered */
75 
76 /* Data structure used for checking wwwwarp.cfg entries */
77 typedef struct w_entchk {
78 	w_ent_t		*ent;
79 	struct w_entchk	*next;
80 } w_entchk_t;
81 
82 STATIC w_entchk_t	*cdinfo_wentchk_head = NULL;
83 
84 
85 /* Data structure for play lists */
86 typedef struct playls {
87 	char		*path;		/* File path string */
88 	struct playls	*prev;		/* List link pointer */
89 	struct playls	*next;		/* List link pointer */
90 	struct playls	*prev2;		/* Sorted list link pointer */
91 	struct playls	*next2;		/* Sorted list link pointer */
92 } playls_t;
93 
94 
95 /* CDDB1 to CDDB2 genre mapping table - This assumes that the
96  * CDDB2 genre ID is invariant.
97  */
98 struct {
99 	char	*cddb1_genre;	/* CDDB1 category name */
100 	char	*cddb2_genre;	/* CDDB2 genre ID */
101 } cdinfo_genre_map[] = {
102 	{ "blues",	"32"	/* Blues -> General Blues */		},
103 	{ "classical",	"46"	/* Classical -> General Classical */	},
104 	{ "country",	"60"	/* Country -> General Country */	},
105 	{ "data",	"71"	/* Data -> General Data */		},
106 	{ "folk",	"96"	/* Folk -> General Folk */		},
107 	{ "jazz",	"160"	/* Jazz -> General Jazz */		},
108 	{ "misc",	"221"	/* Unclassifiable -> General Unclass */	},
109 	{ "newage",	"169"	/* New Age -> General New Age */	},
110 	{ "reggae",	"246"	/* Reggae -> General Reggae */		},
111 	{ "rock",	"191"	/* Rock -> General Rock */		},
112 	{ "soundtrack",	"214"	/* Sountrack -> General Soundtrack */	},
113 	{ "unclass",	"221"	/* Unclassifiable -> General Unclass */	},
114 	{ NULL,		NULL						}
115 };
116 
117 
118 /***********************
119  *  internal routines  *
120  ***********************/
121 
122 
123 /*
124  * cdinfo_line_filter
125  *	Given a string, process it such that becomes only one
126  *	single line (i.e., filter out all text including and
127  *	following any newline character).  A newline character
128  *	is denotes as the characters '\' and 'n' (NOT '\n').
129  *	Used for handling local CD info file data.
130  *
131  * Arg:
132  *	str - The string to be processed
133  *
134  * Return:
135  *	Nothing.  The input string may be modified.
136  */
137 STATIC void
cdinfo_line_filter(char * str)138 cdinfo_line_filter(char *str)
139 {
140 	if (str == NULL)
141 		return;
142 
143 	for (; *str != '\0'; str++) {
144 		if (*str == '\\' && *(str+1) == 'n') {
145 			*str = '\0';
146 			break;
147 		}
148 	}
149 }
150 
151 
152 /*
153  * cdinfo_concatstr
154  *	Concatenate two text strings with special handling for newline
155  *	and tab character translations.  s1 will be dynamically allocated
156  *	or reallocated as needed, and must not point to statically-allocated
157  *	or stack space.  Used for handling local CD info file data.
158  *
159  * Args:
160  *	s1 - Location of the pointer to the first text string.
161  *	s2 - The second text string.
162  *
163  * Return:
164  *	TRUE - success
165  *	FALSE - failure
166  */
167 STATIC bool_t
cdinfo_concatstr(char ** s1,char * s2)168 cdinfo_concatstr(char **s1, char *s2)
169 {
170 	int	n;
171 	char	*str;
172 	bool_t	proc_slash;
173 
174 	if (s1 == NULL || s2 == NULL)
175 		return FALSE;
176 
177 	if (*s1 == NULL) {
178 		*s1 = (char *) MEM_ALLOC("s1", strlen(s2) + 1);
179 		if (*s1 != NULL)
180 			*s1[0] = '\0';
181 	}
182 	else {
183 		*s1 = (char *) MEM_REALLOC("s1", *s1,
184 					   strlen(*s1) + strlen(s2) + 1);
185 	}
186 	if (*s1 == NULL)
187 		return FALSE;
188 
189 	/* Concatenate the two strings, with special handling for newline
190 	 * and tab characters.
191 	 */
192 	str = *s1;
193 	proc_slash = FALSE;
194 	n = strlen(str);
195 	str += n;
196 
197 	if (n > 0 && *(str - 1) == '\\') {
198 		proc_slash = TRUE;	/* Handle broken escape sequences */
199 		str--;
200 	}
201 
202 	for (; *s2 != '\0'; str++, s2++) {
203 		if (*s2 == '\\') {
204 			if (proc_slash) {
205 				proc_slash = FALSE;
206 				continue;
207 			}
208 			proc_slash = TRUE;
209 			s2++;
210 		}
211 
212 		if (proc_slash) {
213 			proc_slash = FALSE;
214 
215 			switch (*s2) {
216 			case 'n':
217 				*str = '\n';
218 				break;
219 			case 't':
220 				*str = '\t';
221 				break;
222 			case '\\':
223 				*str = '\\';
224 				break;
225 			case '\0':
226 				*str = '\\';
227 				s2--;
228 				break;
229 			default:
230 				*str++ = '\\';
231 				*str = *s2;
232 				break;
233 			}
234 		}
235 		else
236 			*str = *s2;
237 	}
238 	*str = '\0';
239 
240 	return TRUE;
241 }
242 
243 
244 /*
245  * cdinfo_sort_playlist
246  *	Given a linked list of playls_t structures, sort them
247  *	alphabetically based on the path field.  The sorted list head
248  *	is returned.  The original list links are not modified.
249  *	To traverse the sorted list, use returned listhead and follow the
250  *	next2 pointers of the playls_t structure.
251  *
252  * Args:
253  *	listhead - The original playlist head pointer.
254  *
255  * Return:
256  *	The sorted playlist head pointer.
257  */
258 STATIC playls_t *
cdinfo_sort_playlist(playls_t * listhead)259 cdinfo_sort_playlist(playls_t *listhead)
260 {
261 	playls_t	*hp,
262 			*sp,
263 			*sp2;
264 
265 	for (sp = hp = listhead; sp != NULL; sp = sp->next) {
266 		for (sp2 = hp; sp2 != NULL; sp2 = sp2->next2) {
267 			if (sp == sp2)
268 				continue;
269 
270 			if (strcmp(sp->path, sp2->path) > 0)
271 				continue;
272 
273 			sp->prev2 = sp2->prev2;
274 			sp->next2 = sp2;
275 
276 			if (sp2 == hp)
277 				hp = sp;
278 			else
279 				sp2->prev2->next2 = sp;
280 
281 			break;
282 		}
283 	}
284 
285 	return (hp);
286 }
287 
288 
289 /*
290  * cdinfo_onterm
291  *	Signal handler for SIGTERM
292  *
293  * Args:
294  *	signo - The signal number
295  *
296  * Return:
297  *	Nothing.
298  */
299 void
cdinfo_onterm(int signo)300 cdinfo_onterm(int signo)
301 {
302 	(void) util_signal(signo, SIG_IGN);
303 	DBGPRN(DBG_CDI)(errfp, "\ncdinfo_onterm: SIGTERM received\n");
304 
305 	/* Close CDDB connection if necessary */
306 	if (cdinfo_cddbp != NULL)
307 		cdinfo_closecddb(cdinfo_cddbp);
308 	_exit(0);
309 }
310 
311 
312 /*
313  * cdinfo_sum
314  *      Convert an integer to its text string representation, and
315  *      compute its checksum.  Used by cdinfo_discid.
316  *
317  * Args:
318  *      n - The integer value.
319  *
320  * Return:
321  *      The integer checksum.
322  */
323 int
cdinfo_sum(int n)324 cdinfo_sum(int n)
325 {
326  	int	ret;
327 
328 	/* For backward compatibility this algorithm must not change */
329 	for (ret = 0; n > 0; n /= 10)
330 		ret += n % 10;
331 
332 	return (ret);
333 }
334 
335 
336 /*
337  * cdinfo_free_glist
338  *	Deallocate genre list.
339  *
340  * Args:
341  *	None
342  *
343  * Return:
344  *	Nothing
345  */
346 STATIC void
cdinfo_free_glist(void)347 cdinfo_free_glist(void)
348 {
349 	cdinfo_genre_t	*p,
350 			*q,
351 			*a,
352 			*b;
353 
354 	for (p = q = cdinfo_dbp->genrelist; p != NULL; p = q) {
355 		q = p->next;
356 
357 		if (p->id != NULL)
358 			MEM_FREE(p->id);
359 		if (p->name != NULL)
360 			MEM_FREE(p->name);
361 
362 		for (a = b = p->child; a != NULL; a = b) {
363 			b = a->next;
364 
365 			if (a->id != NULL)
366 				MEM_FREE(a->id);
367 			if (a->name != NULL)
368 				MEM_FREE(a->name);
369 
370 			MEM_FREE(a);
371 		}
372 
373 		MEM_FREE(p);
374 	}
375 
376 	cdinfo_dbp->genrelist = NULL;
377 }
378 
379 
380 /*
381  * cdinfo_free_relist
382  *	Deallocate region list.
383  *
384  * Args:
385  *	None
386  *
387  * Return:
388  *	Nothing
389  */
390 STATIC void
cdinfo_free_relist(void)391 cdinfo_free_relist(void)
392 {
393 	cdinfo_region_t	*p,
394 			*q;
395 
396 	for (p = q = cdinfo_dbp->regionlist; p != NULL; p = q) {
397 		q = p->next;
398 
399 		if (p->id != NULL)
400 			MEM_FREE(p->id);
401 		if (p->name != NULL)
402 			MEM_FREE(p->name);
403 
404 		MEM_FREE(p);
405 	}
406 	cdinfo_dbp->regionlist = NULL;
407 }
408 
409 
410 /*
411  * cdinfo_free_langlist
412  *	Deallocate language list.
413  *
414  * Args:
415  *	None
416  *
417  * Return:
418  *	Nothing
419  */
420 STATIC void
cdinfo_free_langlist(void)421 cdinfo_free_langlist(void)
422 {
423 	cdinfo_lang_t	*p,
424 			*q;
425 
426 	for (p = q = cdinfo_dbp->langlist; p != NULL; p = q) {
427 		q = p->next;
428 
429 		if (p->id != NULL)
430 			MEM_FREE(p->id);
431 		if (p->name != NULL)
432 			MEM_FREE(p->name);
433 
434 		MEM_FREE(p);
435 	}
436 	cdinfo_dbp->langlist = NULL;
437 }
438 
439 
440 /*
441  * cdinfo_free_rolist
442  *	Deallocate role list.
443  *
444  * Args:
445  *	None
446  *
447  * Return:
448  *	Nothing
449  */
450 STATIC void
cdinfo_free_rolist(void)451 cdinfo_free_rolist(void)
452 {
453 	cdinfo_role_t	*p,
454 			*q,
455 			*a,
456 			*b;
457 
458 	for (p = q = cdinfo_dbp->rolelist; p != NULL; p = q) {
459 		q = p->next;
460 
461 		if (p->id != NULL)
462 			MEM_FREE(p->id);
463 		if (p->name != NULL)
464 			MEM_FREE(p->name);
465 
466 		for (a = b = p->child; a != NULL; a = b) {
467 			b = a->next;
468 			if (a->id != NULL)
469 				MEM_FREE(a->id);
470 			if (a->name != NULL)
471 				MEM_FREE(a->name);
472 			MEM_FREE(a);
473 		}
474 
475 		MEM_FREE(p);
476 	}
477 
478 	cdinfo_dbp->rolelist = NULL;
479 }
480 
481 
482 /*
483  * cdinfo_set_errstr
484  *	Set the error message string in the incore structure based on the
485  *	CDDB service result code.
486  *
487  * Args:
488  *	code - The CDDB result code
489  *
490  * Return:
491  *	Nothing
492  */
493 /*ARGSUSED*/
494 STATIC void
cdinfo_set_errstr(CddbResult code)495 cdinfo_set_errstr(CddbResult code)
496 {
497 	if (code == Cddb_OK)
498 		return;
499 
500 	if (cdinfo_dbp->cddb_errstr != NULL)
501 		MEM_FREE(cdinfo_dbp->cddb_errstr);
502 
503 	cdinfo_dbp->cddb_errstr = (char *) MEM_ALLOC(
504 		"CddbErrorString", ERR_BUF_SZ
505 	);
506 	if (cdinfo_dbp->cddb_errstr == NULL)
507 		return;
508 
509 	cdinfo_dbp->cddb_errstr[0] = '\0';
510 
511 	CddbGetErrorString(code, cdinfo_dbp->cddb_errstr, ERR_BUF_SZ);
512 
513 	if (cdinfo_dbp->cddb_errstr[0] == '\0') {
514 		MEM_FREE(cdinfo_dbp->cddb_errstr);
515 		cdinfo_dbp->cddb_errstr = NULL;
516 	}
517 	else {
518 		DBGPRN(DBG_CDI)(errfp, "%s\n", cdinfo_dbp->cddb_errstr);
519 	}
520 }
521 
522 
523 #ifndef SYNCHRONOUS
524 
525 /*
526  * cdinfo_waitio
527  *	Check if read data is pending.  If no data and a workproc is
528  *	specified, then call workproc.  Keep waiting until there is
529  *	data or until timeout.
530  *
531  * Args:
532  *	pp - Pointer to the cdinfo_pipe_t structure
533  *	tmout - Timeout interval (in seconds).  If set to 0, no
534  *		timeout will occur.
535  *
536  * Return:
537  *	TRUE - There is data pending.
538  */
539 STATIC bool_t
cdinfo_waitio(cdinfo_pipe_t * pp,int tmout)540 cdinfo_waitio(cdinfo_pipe_t *pp, int tmout)
541 {
542 	int		ret;
543 	fd_set		rfds;
544 	fd_set		efds;
545 	struct timeval	to;
546 	time_t		start = 0,
547 			now;
548 
549 	if (tmout > 0)
550 		start = time(NULL);
551 
552 	do {
553 		errno = 0;
554 		FD_ZERO(&efds);
555 		FD_ZERO(&rfds);
556 		FD_SET(pp->r.fd, &rfds);
557 
558 		to.tv_sec = CDINFO_WAIT_SEC;
559 		to.tv_usec = CDINFO_WAIT_USEC;
560 #ifdef __hpux
561 		ret = select(pp->r.fd+1, (int *) &rfds,
562 			     NULL, (int *) &efds, &to);
563 #else
564 		ret = select(pp->r.fd+1, &rfds, NULL, &efds, &to);
565 #endif
566 
567 		if (tmout > 0 && ret == 0) {
568 			now = time(NULL);
569 			if ((now - start) > tmout) {
570 				/* Timeout */
571 				DBGPRN(DBG_CDI)(errfp,
572 					"Timed out waiting for data.\n");
573 				errno = ETIME;
574 				ret = -1;
575 			}
576 		}
577 
578 		if (ret == 0 && !cdinfo_ischild &&
579 		    cdinfo_clinfo->workproc != NULL)
580 			cdinfo_clinfo->workproc(cdinfo_clinfo->arg);
581 
582 	} while (ret == 0);
583 
584 	/* Hack: some implementations of select() does not work
585 	 * on non-socket file descriptors, so just fake a
586 	 * success status.
587 	 */
588 	return TRUE;
589 }
590 
591 
592 /*
593  * cdinfo_getc
594  *	Return a character from the file stream.  Perform buffered
595  *	read from file if necessary.
596  *
597  * Args:
598  *	pp - Pointer to the cdinfo_pipe_t structure.
599  *
600  * Return:
601  *	The character, or -1 on EOF or failure.
602  */
603 STATIC int
cdinfo_getc(cdinfo_pipe_t * pp)604 cdinfo_getc(cdinfo_pipe_t *pp)
605 {
606 	static int	i = 0;
607 
608 	/* Do some work every 10 characters read */
609 	if (!cdinfo_ischild && (i % 10) == 0 &&
610 	    cdinfo_clinfo->workproc != NULL)
611 		cdinfo_clinfo->workproc(cdinfo_clinfo->arg);
612 
613 	if (++i > 100)
614 		i = 0;	/* Reset count */
615 
616 	if (pp->r.cache == NULL) {
617 		/* Allocate read cache */
618 		pp->r.cache = (unsigned char *) MEM_ALLOC(
619 			"read_cache", CDINFO_CACHESZ
620 		);
621 		if (pp->r.cache == NULL)
622 			return -1;
623 	}
624 
625 	if (pp->r.pos == pp->r.cnt) {
626 		/* Wait for data */
627 		if (!cdinfo_waitio(pp, 0))
628 			return -1;
629 
630 		/* Load cache */
631 		pp->r.cnt = read(pp->r.fd, pp->r.cache, CDINFO_CACHESZ);
632 		if (pp->r.cnt <= 0) {
633 			pp->r.cnt = pp->r.pos;
634 			return -1;
635 		}
636 		pp->r.pos = 1;
637 	}
638 	else {
639 		pp->r.pos++;
640 	}
641 
642 	return ((int) pp->r.cache[pp->r.pos - 1]);
643 }
644 
645 
646 /*
647  * cdinfo_gets
648  *	Read a line of text from the stream.  The read terminates
649  *	when it encounters a newline character, EOF, or if len
650  *	characters have been read.
651  *
652  * Args:
653  *	pp - The pipe descriptor obtained via cdinfo_openpipe()
654  *	buf - Pointer to return string buffer
655  *	len - Maximum number of characters to read
656  *
657  * Return:
658  *	TRUE - Successfully read a line of text
659  *	FALSE - Reached EOF or read failure
660  */
661 STATIC bool_t
cdinfo_gets(cdinfo_pipe_t * pp,char * buf,int len)662 cdinfo_gets(cdinfo_pipe_t *pp, char *buf, int len)
663 {
664 	int	tot = 0,
665 		c = 0;
666 
667 	while ((c = cdinfo_getc(pp)) > 0) {
668 		*buf = (char) c;
669 
670 		tot++;
671 		buf++;
672 		len--;
673 
674 		if (c == '\n') {
675 			/* Translate CR-LF into just LF */
676 			if (*(buf-2) == '\r') {
677 				*(buf-2) = '\n';
678 				*(buf-1) = '\0';
679 				tot--;
680 				buf--;
681 			}
682 			break;
683 		}
684 
685 		if (len <= 0)
686 			break;
687 	}
688 	*buf = '\0';
689 	return ((bool_t) (tot > 0));
690 }
691 
692 
693 /*
694  * cdinfo_puts
695  *	Write a text string into the pipe.
696  *
697  * Args:
698  *	pp - The pipe descriptor obtained via cdinfo_openpipe()
699  *	buf - Pointer to string buffer
700  *
701  * Return:
702  *	TRUE - Success
703  *	FALSE - Failure
704  */
705 STATIC bool_t
cdinfo_puts(cdinfo_pipe_t * pp,char * buf)706 cdinfo_puts(cdinfo_pipe_t *pp, char *buf)
707 {
708 	char		prevchar;
709 	bool_t		done;
710 
711 	if (buf == NULL)
712 		return FALSE;
713 
714 	if (pp->w.cache == NULL) {
715 		/* Allocate write cache */
716 		pp->w.cache = (unsigned char *) MEM_ALLOC(
717 			"write_cache", CDINFO_CACHESZ
718 		);
719 		if (pp->w.cache == NULL)
720 			return FALSE;
721 	}
722 
723 	prevchar = '\0';
724 	done = FALSE;
725 
726 	while (!done) {
727 		if (*buf == '\0') {
728 			/* Insert a newline at end of string if the
729 			 * string doesn't already have one
730 			 */
731 			if (prevchar != '\n')
732 				buf = "\n";
733 			else
734 				break;
735 		}
736 
737 		if (pp->w.pos == CDINFO_CACHESZ) {
738 			unsigned char	*p;
739 			int		resid,
740 					n = 0;
741 
742 			/* Flush write cache */
743 			p = pp->w.cache;
744 			for (resid = pp->w.pos; resid > 0; resid -= n) {
745 				if ((n = write(pp->w.fd, p, resid)) < 0) {
746 					pp->w.pos = 0;
747 					return FALSE;
748 				}
749 				p += n;
750 			}
751 			pp->w.pos = 0;
752 		}
753 
754 		pp->w.cache[pp->w.pos] = (unsigned char) *buf;
755 		pp->w.pos++;
756 		prevchar = *buf;
757 		buf++;
758 	}
759 
760 	return TRUE;
761 }
762 
763 
764 /*
765  * cdinfo_getline
766  *	Read a line from pipe buffer and allocate data structure element
767  *	to store the data.  This version is used for single-line character
768  *	string elements.
769  *
770  * Args:
771  *	pp - Pointer to cdinfo_pipe_t
772  *	name - Name of element
773  *	ptr - Incore CD info structure element location
774  *
775  * Return:
776  *	TRUE - success
777  *	FALSE - failure
778  */
779 /*ARGSUSED*/
780 STATIC bool_t
cdinfo_getline(cdinfo_pipe_t * pp,char * name,char ** ptr)781 cdinfo_getline(cdinfo_pipe_t *pp, char *name, char **ptr)
782 {
783 	size_t		n;
784 	bool_t		ret = FALSE;
785 	static char	buf[2048];
786 
787 	while ((ret = cdinfo_gets(pp, buf, sizeof(buf))) == TRUE) {
788 		if (buf[0] == '\n')
789 			/* Null string */
790 			return TRUE;
791 
792 		n = strlen(buf);
793 
794 		if (buf[n-1] == '\n') {
795 			buf[n-1] = '\0';	/* Zap newline */
796 			ret = TRUE;
797 		}
798 		else
799 			ret = FALSE;
800 
801 		if (*ptr == NULL) {
802 			*ptr = (char *) MEM_ALLOC(name, n + 1);
803 			if (*ptr != NULL)
804 				*ptr[0] = '\0';
805 		}
806 		else {
807 			*ptr = (char *) MEM_REALLOC(name, *ptr,
808 						    strlen(*ptr) + n + 1);
809 		}
810 
811 		if (*ptr == NULL) {
812 			CDINFO_FATAL(app_data.str_nomemory);
813 			return FALSE;
814 		}
815 		(void) strcat(*ptr, buf);
816 
817 		if (ret)
818 			break;
819 	}
820 
821 	return (ret);
822 }
823 
824 
825 /*
826  * cdinfo_getmultiline
827  *	Read lines from pipe buffer and allocate data structure
828  *	element to store the data.  This version is used for multi-line
829  *	character string elements.
830  *
831  * Args:
832  *	pp - Pointer to cdinfo_pipe_t
833  *	name - Name of element
834  *	ptr - Incore CD info structure element location
835  *
836  * Return:
837  *	TRUE - success
838  *	FALSE - failure
839  */
840 /*ARGSUSED*/
841 STATIC bool_t
cdinfo_getmultiline(cdinfo_pipe_t * pp,char * name,char ** ptr)842 cdinfo_getmultiline(cdinfo_pipe_t *pp, char *name, char **ptr)
843 {
844 	bool_t		ret;
845 	char		*cp;
846 	static char	buf[2048];
847 
848 	while ((ret = cdinfo_gets(pp, buf, sizeof(buf))) == TRUE) {
849 		if (strncmp(buf, XMCD_PIPESIG, strlen(XMCD_PIPESIG)) == 0) {
850 			/* End of multi-line */
851 			if (*ptr != NULL) {
852 				/* Zap the last newline */
853 				cp = *ptr + strlen(*ptr) - 1;
854 				if (*cp == '\n')
855 					*cp = '\0';
856 			}
857 			break;
858 		}
859 
860 		if (*ptr == NULL) {
861 			*ptr = (char *) MEM_ALLOC(name, strlen(buf) + 1);
862 			if (*ptr != NULL)
863 				*ptr[0] = '\0';
864 		}
865 		else {
866 			*ptr = (char *) MEM_REALLOC(name, *ptr,
867 						    strlen(*ptr) +
868 						    strlen(buf) + 1);
869 		}
870 
871 		if (*ptr == NULL) {
872 			CDINFO_FATAL(app_data.str_nomemory);
873 			return FALSE;
874 		}
875 		(void) strcat(*ptr, buf);
876 	}
877 
878 	return (ret);
879 }
880 
881 
882 /*
883  * cdinfo_geturl_ents
884  *	Read URL elements from pipe, used by the parent.
885  *
886  * Args:
887  *	pp - Pointer to cdinfo_pipe_t
888  *	key - match element key string
889  *
890  * Return:
891  *	TRUE - success
892  *	FALSE - failure
893  */
894 STATIC bool_t
cdinfo_geturl_ents(cdinfo_pipe_t * pp,char * key)895 cdinfo_geturl_ents(cdinfo_pipe_t *pp, char *key)
896 {
897 	static cdinfo_url_t	*p,
898 				*q = NULL;
899 
900 	if (strcmp(key, ".gen.new") == 0) {
901 		p = (cdinfo_url_t *)(void *) MEM_ALLOC("cdinfo_url_t",
902 			sizeof(cdinfo_url_t)
903 		);
904 		if (p == NULL) {
905 			CDINFO_FATAL(app_data.str_nomemory);
906 			return FALSE;
907 		}
908 		(void) memset(p, 0, sizeof(cdinfo_url_t));
909 
910 		p->wtype = WTYPE_GEN;
911 
912 		if (cdinfo_dbp->gen_url_list == NULL)
913 			cdinfo_dbp->gen_url_list = q = p;
914 		else {
915 			q->next = p;
916 			q = p;
917 		}
918 
919 		cdinfo_genurl_initted = TRUE;
920 	}
921 	else if (strcmp(key, ".gen.type") == 0) {
922 		if (!cdinfo_getline(pp, "url.gen.type", &p->type))
923 			return FALSE;
924 	}
925 	else if (strcmp(key, ".gen.href") == 0) {
926 		if (!cdinfo_getline(pp, "url.gen.href", &p->href))
927 			return FALSE;
928 	}
929 	else if (strcmp(key, ".gen.displink") == 0) {
930 		if (!cdinfo_getline(pp, "url.gen.displink", &p->displink))
931 			return FALSE;
932 	}
933 	else if (strcmp(key, ".gen.disptext") == 0) {
934 		if (!cdinfo_getline(pp, "url.gen.disptext", &p->disptext))
935 			return FALSE;
936 	}
937 	else if (strcmp(key, ".gen.categ") == 0) {
938 		if (!cdinfo_getline(pp, "url.gen.categ", &p->categ))
939 			return FALSE;
940 	}
941 	else if (strcmp(key, ".gen.size") == 0) {
942 		if (!cdinfo_getline(pp, "url.gen.size", &p->size))
943 			return FALSE;
944 	}
945 	else if (strcmp(key, ".gen.weight") == 0) {
946 		if (!cdinfo_getline(pp, "url.gen.weight", &p->weight))
947 			return FALSE;
948 	}
949 	else if (strcmp(key, ".disc.new") == 0) {
950 		p = (cdinfo_url_t *)(void *) MEM_ALLOC("cdinfo_url_t",
951 			sizeof(cdinfo_url_t)
952 		);
953 		if (p == NULL) {
954 			CDINFO_FATAL(app_data.str_nomemory);
955 			return FALSE;
956 		}
957 		(void) memset(p, 0, sizeof(cdinfo_url_t));
958 
959 		p->wtype = WTYPE_ALBUM;
960 
961 		if (cdinfo_dbp->disc_url_list == NULL)
962 			cdinfo_dbp->disc_url_list = q = p;
963 		else {
964 			q->next = p;
965 			q = p;
966 		}
967 	}
968 	else if (strcmp(key, ".disc.type") == 0) {
969 		if (!cdinfo_getline(pp, "url.disc.type", &p->type))
970 			return FALSE;
971 	}
972 	else if (strcmp(key, ".disc.href") == 0) {
973 		if (!cdinfo_getline(pp, "url.disc.href", &p->href))
974 			return FALSE;
975 	}
976 	else if (strcmp(key, ".disc.displink") == 0) {
977 		if (!cdinfo_getline(pp, "url.disc.displink", &p->displink))
978 			return FALSE;
979 	}
980 	else if (strcmp(key, ".disc.disptext") == 0) {
981 		if (!cdinfo_getline(pp, "url.disc.disptext", &p->disptext))
982 			return FALSE;
983 	}
984 	else if (strcmp(key, ".disc.categ") == 0) {
985 		if (!cdinfo_getline(pp, "url.disc.categ", &p->categ))
986 			return FALSE;
987 	}
988 	else if (strcmp(key, ".disc.size") == 0) {
989 		if (!cdinfo_getline(pp, "url.disc.size", &p->size))
990 			return FALSE;
991 	}
992 	else if (strcmp(key, ".disc.weight") == 0) {
993 		if (!cdinfo_getline(pp, "url.disc.weight", &p->weight))
994 			return FALSE;
995 	}
996 
997 	return TRUE;
998 }
999 
1000 
1001 /*
1002  * cdinfo_getctrl_ents
1003  *	Read CDDB control information from pipe, used by the parent.
1004  *
1005  * Args:
1006  *	pp - Pointer to cdinfo_pipe_t
1007  *	key - control element key string
1008  *
1009  * Return:
1010  *	TRUE - success
1011  *	FALSE - failure
1012  */
1013 STATIC bool_t
cdinfo_getctrl_ents(cdinfo_pipe_t * pp,char * key)1014 cdinfo_getctrl_ents(cdinfo_pipe_t *pp, char *key)
1015 {
1016 	if (strcmp(key, ".ver") == 0) {
1017 		if (!cdinfo_getline(pp, "control.ver",
1018 				    &cdinfo_dbp->ctrl_ver))
1019 			return FALSE;
1020 	}
1021 
1022 	cdinfo_ctrl_initted = TRUE;
1023 	return TRUE;
1024 }
1025 
1026 
1027 /*
1028  * cdinfo_getglist_ents
1029  *	Read genre list elements from pipe, used by the parent.
1030  *
1031  * Args:
1032  *	pp - Pointer to cdinfo_pipe_t
1033  *	key - genre element key string
1034  *
1035  * Return:
1036  *	TRUE - success
1037  *	FALSE - failure
1038  */
1039 STATIC bool_t
cdinfo_getglist_ents(cdinfo_pipe_t * pp,char * key)1040 cdinfo_getglist_ents(cdinfo_pipe_t *pp, char *key)
1041 {
1042 	cdinfo_genre_t		*p;
1043 	static cdinfo_genre_t	*gp = NULL,
1044 				*sgp = NULL;
1045 
1046 	if (strcmp(key, ".new") == 0) {
1047 		p = (cdinfo_genre_t *)(void *) MEM_ALLOC("genre",
1048 			sizeof(cdinfo_genre_t)
1049 		);
1050 		if (p == NULL) {
1051 			CDINFO_FATAL(app_data.str_nomemory);
1052 			return FALSE;
1053 		}
1054 		(void) memset(p, 0, sizeof(cdinfo_genre_t));
1055 
1056 		if (cdinfo_dbp->genrelist == NULL)
1057 			cdinfo_dbp->genrelist = gp = p;
1058 		else {
1059 			gp->next = p;
1060 			gp = p;
1061 		}
1062 		sgp = NULL;
1063 	}
1064 	else if (strcmp(key, ".id") == 0) {
1065 		if (!cdinfo_getline(pp, "genre.id", &gp->id)) {
1066 			gp = sgp = NULL;
1067 			cdinfo_free_glist();
1068 			return FALSE;
1069 		}
1070 	}
1071 	else if (strcmp(key, ".name") == 0) {
1072 		if (!cdinfo_getline(pp, "genre.name", &gp->name)) {
1073 			gp = sgp = NULL;
1074 			cdinfo_free_glist();
1075 			return FALSE;
1076 		}
1077 	}
1078 	else if (strcmp(key, ".subgenre.new") == 0) {
1079 		p = (cdinfo_genre_t *)(void *) MEM_ALLOC("genre",
1080 			sizeof(cdinfo_genre_t)
1081 		);
1082 		if (p == NULL) {
1083 			CDINFO_FATAL(app_data.str_nomemory);
1084 			return FALSE;
1085 		}
1086 		(void) memset(p, 0, sizeof(cdinfo_genre_t));
1087 
1088 		p->parent = gp;
1089 		if (sgp == NULL)
1090 			gp->child = sgp = p;
1091 		else {
1092 			sgp->next = p;
1093 			sgp = p;
1094 		}
1095 	}
1096 	else if (strcmp(key, ".subgenre.id") == 0) {
1097 		if (!cdinfo_getline(pp, "subgenre.id", &sgp->id)) {
1098 			gp = sgp = NULL;
1099 			cdinfo_free_glist();
1100 			return FALSE;
1101 		}
1102 	}
1103 	else if (strcmp(key, ".subgenre.name") == 0) {
1104 		if (!cdinfo_getline(pp, "subgenre.name", &sgp->name)) {
1105 			gp = sgp = NULL;
1106 			cdinfo_free_glist();
1107 			return FALSE;
1108 		}
1109 	}
1110 
1111 	cdinfo_glist_initted = TRUE;
1112 	return TRUE;
1113 }
1114 
1115 
1116 /*
1117  * cdinfo_getrelist_ents
1118  *	Read region list elements from pipe, used by the parent.
1119  *
1120  * Args:
1121  *	pp - Pointer to cdinfo_pipe_t
1122  *	key - region element key string
1123  *
1124  * Return:
1125  *	TRUE - success
1126  *	FALSE - failure
1127  */
1128 STATIC bool_t
cdinfo_getrelist_ents(cdinfo_pipe_t * pp,char * key)1129 cdinfo_getrelist_ents(cdinfo_pipe_t *pp, char *key)
1130 {
1131 	cdinfo_region_t		*p;
1132 	static cdinfo_region_t	*rp = NULL;
1133 
1134 	if (strcmp(key, ".new") == 0) {
1135 		p = (cdinfo_region_t *)(void *) MEM_ALLOC("region",
1136 			sizeof(cdinfo_region_t)
1137 		);
1138 		if (p == NULL) {
1139 			CDINFO_FATAL(app_data.str_nomemory);
1140 			return FALSE;
1141 		}
1142 		(void) memset(p, 0, sizeof(cdinfo_region_t));
1143 
1144 		if (cdinfo_dbp->regionlist == NULL)
1145 			cdinfo_dbp->regionlist = rp = p;
1146 		else {
1147 			rp->next = p;
1148 			rp = p;
1149 		}
1150 	}
1151 	else if (strcmp(key, ".id") == 0) {
1152 		if (!cdinfo_getline(pp, "region.id", &rp->id)) {
1153 			rp = NULL;
1154 			cdinfo_free_relist();
1155 			return FALSE;
1156 		}
1157 	}
1158 	else if (strcmp(key, ".name") == 0) {
1159 		if (!cdinfo_getline(pp, "region.name", &rp->name)) {
1160 			rp = NULL;
1161 			cdinfo_free_relist();
1162 			return FALSE;
1163 		}
1164 	}
1165 
1166 	cdinfo_relist_initted = TRUE;
1167 	return TRUE;
1168 }
1169 
1170 
1171 /*
1172  * cdinfo_getlanglist_ents
1173  *	Read language list elements from pipe, used by the parent.
1174  *
1175  * Args:
1176  *	pp - Pointer to cdinfo_pipe_t
1177  *	key - language element key string
1178  *
1179  * Return:
1180  *	TRUE - success
1181  *	FALSE - failure
1182  */
1183 STATIC bool_t
cdinfo_getlanglist_ents(cdinfo_pipe_t * pp,char * key)1184 cdinfo_getlanglist_ents(cdinfo_pipe_t *pp, char *key)
1185 {
1186 	cdinfo_lang_t		*p;
1187 	static cdinfo_lang_t	*lp = NULL;
1188 
1189 	if (strcmp(key, ".new") == 0) {
1190 		p = (cdinfo_lang_t *)(void *) MEM_ALLOC("language",
1191 			sizeof(cdinfo_lang_t)
1192 		);
1193 		if (p == NULL) {
1194 			CDINFO_FATAL(app_data.str_nomemory);
1195 			return FALSE;
1196 		}
1197 		(void) memset(p, 0, sizeof(cdinfo_lang_t));
1198 
1199 		if (cdinfo_dbp->langlist == NULL)
1200 			cdinfo_dbp->langlist = lp = p;
1201 		else {
1202 			lp->next = p;
1203 			lp = p;
1204 		}
1205 	}
1206 	else if (strcmp(key, ".id") == 0) {
1207 		if (!cdinfo_getline(pp, "lang.id", &lp->id)) {
1208 			lp = NULL;
1209 			cdinfo_free_langlist();
1210 			return FALSE;
1211 		}
1212 	}
1213 	else if (strcmp(key, ".name") == 0) {
1214 		if (!cdinfo_getline(pp, "lang.name", &lp->name)) {
1215 			lp = NULL;
1216 			cdinfo_free_langlist();
1217 			return FALSE;
1218 		}
1219 	}
1220 
1221 	cdinfo_langlist_initted = TRUE;
1222 	return TRUE;
1223 }
1224 
1225 
1226 /*
1227  * cdinfo_getrolist_ents
1228  *	Read role list elements from pipe, used by the parent.
1229  *
1230  * Args:
1231  *	pp - Pointer to cdinfo_pipe_t
1232  *	key - role element key string
1233  *
1234  * Return:
1235  *	TRUE - success
1236  *	FALSE - failure
1237  */
1238 STATIC bool_t
cdinfo_getrolist_ents(cdinfo_pipe_t * pp,char * key)1239 cdinfo_getrolist_ents(cdinfo_pipe_t *pp, char *key)
1240 {
1241 	cdinfo_role_t		*p;
1242 	static cdinfo_role_t	*rp = NULL,
1243 				*srp = NULL;
1244 
1245 	if (strcmp(key, ".new") == 0) {
1246 		p = (cdinfo_role_t *)(void *) MEM_ALLOC("role",
1247 			sizeof(cdinfo_role_t)
1248 		);
1249 		if (p == NULL) {
1250 			CDINFO_FATAL(app_data.str_nomemory);
1251 			return FALSE;
1252 		}
1253 		(void) memset(p, 0, sizeof(cdinfo_role_t));
1254 
1255 		if (cdinfo_dbp->rolelist == NULL)
1256 			cdinfo_dbp->rolelist = rp = p;
1257 		else {
1258 			rp->next = p;
1259 			rp = p;
1260 		}
1261 		srp = NULL;
1262 	}
1263 	else if (strcmp(key, ".id") == 0) {
1264 		if (!cdinfo_getline(pp, "role.id", &rp->id)) {
1265 			rp = srp = NULL;
1266 			cdinfo_free_rolist();
1267 			return FALSE;
1268 		}
1269 	}
1270 	else if (strcmp(key, ".name") == 0) {
1271 		if (!cdinfo_getline(pp, "role.name", &rp->name)) {
1272 			rp = srp = NULL;
1273 			cdinfo_free_rolist();
1274 			return FALSE;
1275 		}
1276 	}
1277 	else if (strcmp(key, ".subrole.new") == 0) {
1278 		p = (cdinfo_role_t *)(void *) MEM_ALLOC("role",
1279 			sizeof(cdinfo_role_t)
1280 		);
1281 		if (p == NULL) {
1282 			CDINFO_FATAL(app_data.str_nomemory);
1283 			return FALSE;
1284 		}
1285 		(void) memset(p, 0, sizeof(cdinfo_role_t));
1286 
1287 		p->parent = rp;
1288 		if (srp == NULL)
1289 			rp->child = srp = p;
1290 		else {
1291 			srp->next = p;
1292 			srp = p;
1293 		}
1294 	}
1295 	else if (strcmp(key, ".subrole.id") == 0) {
1296 		if (!cdinfo_getline(pp, "subrole.id", &srp->id)) {
1297 			rp = srp = NULL;
1298 			cdinfo_free_rolist();
1299 			return FALSE;
1300 		}
1301 	}
1302 	else if (strcmp(key, ".subrole.name") == 0) {
1303 		if (!cdinfo_getline(pp, "subrole.name", &srp->name)) {
1304 			rp = srp = NULL;
1305 			cdinfo_free_rolist();
1306 			return FALSE;
1307 		}
1308 	}
1309 	cdinfo_rolist_initted = TRUE;
1310 	return TRUE;
1311 }
1312 
1313 
1314 /*
1315  * cdinfo_getmatch_ents
1316  *	Read multiple match elements from pipe, used by the parent.
1317  *
1318  * Args:
1319  *	pp - Pointer to cdinfo_pipe_t
1320  *	key - match element key string
1321  *
1322  * Return:
1323  *	TRUE - success
1324  *	FALSE - failure
1325  */
1326 STATIC bool_t
cdinfo_getmatch_ents(cdinfo_pipe_t * pp,char * key)1327 cdinfo_getmatch_ents(cdinfo_pipe_t *pp, char *key)
1328 {
1329 	cdinfo_match_t		*p;
1330 	static cdinfo_match_t	*mp = NULL;
1331 
1332 	if (strcmp(key, ".new") == 0) {
1333 		p = (cdinfo_match_t *)(void *) MEM_ALLOC("match",
1334 			sizeof(cdinfo_match_t)
1335 		);
1336 		if (p == NULL) {
1337 			CDINFO_FATAL(app_data.str_nomemory);
1338 			return FALSE;
1339 		}
1340 		(void) memset(p, 0, sizeof(cdinfo_match_t));
1341 
1342 		if (cdinfo_dbp->matchlist == NULL)
1343 			cdinfo_dbp->matchlist = mp = p;
1344 		else {
1345 			mp->next = p;
1346 			mp = p;
1347 		}
1348 	}
1349 	else if (strcmp(key, ".artist") == 0) {
1350 		if (!cdinfo_getline(pp, "match.artist", &mp->artist)) {
1351 			mp = NULL;
1352 			cdinfo_free_matchlist();
1353 			return FALSE;
1354 		}
1355 	}
1356 	else if (strcmp(key, ".title") == 0) {
1357 		if (!cdinfo_getline(pp, "match.title", &mp->title)) {
1358 			mp = NULL;
1359 			cdinfo_free_matchlist();
1360 			return FALSE;
1361 		}
1362 	}
1363 	else if (strcmp(key, ".genre") == 0) {
1364 		if (!cdinfo_getline(pp, "match.genre", &mp->genre)) {
1365 			mp = NULL;
1366 			cdinfo_free_matchlist();
1367 			return FALSE;
1368 		}
1369 	}
1370 
1371 	return TRUE;
1372 }
1373 
1374 
1375 /*
1376  * cdinfo_getuserreg_ents
1377  *	Read user registration related elements from pipe, used by the parent.
1378  *
1379  * Args:
1380  *	pp - Pointer to cdinfo_pipe_t
1381  *	key - userreg element key string
1382  *
1383  * Return:
1384  *	TRUE - success
1385  *	FALSE - failure
1386  */
1387 STATIC bool_t
cdinfo_getuserreg_ents(cdinfo_pipe_t * pp,char * key)1388 cdinfo_getuserreg_ents(cdinfo_pipe_t *pp, char *key)
1389 {
1390 	char	*str;
1391 
1392 	if (strcmp(key, ".handle") == 0) {
1393 		if (cdinfo_dbp->userreg.handle != NULL) {
1394 			MEM_FREE(cdinfo_dbp->userreg.handle);
1395 			cdinfo_dbp->userreg.handle = NULL;
1396 		}
1397 		if (!cdinfo_getline(pp, "userreg.handle",
1398 				    &cdinfo_dbp->userreg.handle))
1399 			return FALSE;
1400 	}
1401 	else if (strcmp(key, ".hint") == 0) {
1402 		if (cdinfo_dbp->userreg.hint != NULL) {
1403 			MEM_FREE(cdinfo_dbp->userreg.hint);
1404 			cdinfo_dbp->userreg.hint = NULL;
1405 		}
1406 		if (!cdinfo_getline(pp, "userreg.hint",
1407 				    &cdinfo_dbp->userreg.hint))
1408 			return FALSE;
1409 	}
1410 	else if (strcmp(key, ".email") == 0) {
1411 		if (cdinfo_dbp->userreg.email != NULL) {
1412 			MEM_FREE(cdinfo_dbp->userreg.email);
1413 			cdinfo_dbp->userreg.email = NULL;
1414 		}
1415 		if (!cdinfo_getline(pp, "userreg.email",
1416 				    &cdinfo_dbp->userreg.email))
1417 			return FALSE;
1418 	}
1419 	else if (strcmp(key, ".region") == 0) {
1420 		if (cdinfo_dbp->userreg.region != NULL) {
1421 			MEM_FREE(cdinfo_dbp->userreg.region);
1422 			cdinfo_dbp->userreg.region = NULL;
1423 		}
1424 		if (!cdinfo_getline(pp, "userreg.region",
1425 				    &cdinfo_dbp->userreg.region))
1426 			return FALSE;
1427 	}
1428 	else if (strcmp(key, ".postal") == 0) {
1429 		if (cdinfo_dbp->userreg.postal != NULL) {
1430 			MEM_FREE(cdinfo_dbp->userreg.postal);
1431 			cdinfo_dbp->userreg.postal = NULL;
1432 		}
1433 		if (!cdinfo_getline(pp, "userreg.postal",
1434 				    &cdinfo_dbp->userreg.postal))
1435 			return FALSE;
1436 	}
1437 	else if (strcmp(key, ".age") == 0) {
1438 		if (cdinfo_dbp->userreg.age != NULL) {
1439 			MEM_FREE(cdinfo_dbp->userreg.age);
1440 			cdinfo_dbp->userreg.age = NULL;
1441 		}
1442 		if (!cdinfo_getline(pp, "userreg.age",
1443 				    &cdinfo_dbp->userreg.age))
1444 			return FALSE;
1445 	}
1446 	else if (strcmp(key, ".gender") == 0) {
1447 		if (cdinfo_dbp->userreg.gender != NULL) {
1448 			MEM_FREE(cdinfo_dbp->userreg.gender);
1449 			cdinfo_dbp->userreg.gender = NULL;
1450 		}
1451 		if (!cdinfo_getline(pp, "userreg.gender",
1452 				    &cdinfo_dbp->userreg.gender))
1453 			return FALSE;
1454 	}
1455 	else if (strcmp(key, ".allowemail") == 0) {
1456 		str = NULL;
1457 		if (!cdinfo_getline(pp, "userreg.allowemail", &str))
1458 			return FALSE;
1459 		if (str != NULL) {
1460 			if (*str == '1')
1461 				cdinfo_dbp->userreg.allowemail = TRUE;
1462 			MEM_FREE(str);
1463 		}
1464 	}
1465 	else if (strcmp(key, ".allowstats") == 0) {
1466 		str = NULL;
1467 		if (!cdinfo_getline(pp, "userreg.allowstats", &str))
1468 			return FALSE;
1469 		if (str != NULL) {
1470 			if (*str == '1')
1471 				cdinfo_dbp->userreg.allowemail = TRUE;
1472 			MEM_FREE(str);
1473 		}
1474 	}
1475 
1476 	cdinfo_user_regd = TRUE;
1477 	return TRUE;
1478 }
1479 
1480 
1481 /*
1482  * cdinfo_getdisc_ents
1483  *	Read disc related elements from pipe, used by the parent.
1484  *
1485  * Args:
1486  *	pp - Pointer to cdinfo_pipe_t
1487  *	key - disc element key string
1488  *
1489  * Return:
1490  *	TRUE - success
1491  *	FALSE - failure
1492  */
1493 STATIC bool_t
cdinfo_getdisc_ents(cdinfo_pipe_t * pp,char * key)1494 cdinfo_getdisc_ents(cdinfo_pipe_t *pp, char *key)
1495 {
1496 	char			*str;
1497 	cdinfo_credit_t		*p;
1498 	cdinfo_segment_t	*q;
1499 	static cdinfo_credit_t	*cp = NULL;
1500 	static cdinfo_segment_t	*sp = NULL;
1501 
1502 	if (strcmp(key, ".flags") == 0) {
1503 		str = NULL;
1504 		if (!cdinfo_getline(pp, "disc.flags", &str))
1505 			return FALSE;
1506 		if (str != NULL) {
1507 			(void) sscanf(str, "%x", &cdinfo_dbp->flags);
1508 			MEM_FREE(str);
1509 		}
1510 	}
1511 	else if (strcmp(key, ".compilation") == 0) {
1512 		str = NULL;
1513 		if (!cdinfo_getline(pp, "disc.compilation", &str))
1514 			return FALSE;
1515 		if (str != NULL) {
1516 			if (*str == '1')
1517 				cdinfo_dbp->disc.compilation = TRUE;
1518 			MEM_FREE(str);
1519 		}
1520 	}
1521 	else if (strcmp(key, ".artistfname.dispname") == 0) {
1522 		if (!cdinfo_getline(pp, "disc.artistfname.dispname",
1523 				    &cdinfo_dbp->disc.artistfname.dispname))
1524 			return FALSE;
1525 	}
1526 	else if (strcmp(key, ".artistfname.lastname") == 0) {
1527 		if (!cdinfo_getline(pp, "disc.artistfname.lastname",
1528 				    &cdinfo_dbp->disc.artistfname.lastname))
1529 			return FALSE;
1530 	}
1531 	else if (strcmp(key, ".artistfname.firstname") == 0) {
1532 		if (!cdinfo_getline(pp, "disc.artistfname.firstname",
1533 				    &cdinfo_dbp->disc.artistfname.firstname))
1534 			return FALSE;
1535 	}
1536 	else if (strcmp(key, ".artistfname.the") == 0) {
1537 		if (!cdinfo_getline(pp, "disc.artistfname.the",
1538 				    &cdinfo_dbp->disc.artistfname.the))
1539 			return FALSE;
1540 	}
1541 	else if (strcmp(key, ".artist") == 0) {
1542 		if (!cdinfo_getline(pp,
1543 				    "disc.artist", &cdinfo_dbp->disc.artist))
1544 			return FALSE;
1545 	}
1546 	else if (strcmp(key, ".title") == 0) {
1547 		if (!cdinfo_getline(pp, "disc.title", &cdinfo_dbp->disc.title))
1548 			return FALSE;
1549 	}
1550 	else if (strcmp(key, ".sorttitle") == 0) {
1551 		if (!cdinfo_getline(pp, "disc.sorttitle",
1552 				    &cdinfo_dbp->disc.sorttitle))
1553 			return FALSE;
1554 	}
1555 	else if (strcmp(key, ".title_the") == 0) {
1556 		if (!cdinfo_getline(pp, "disc.title_the",
1557 				    &cdinfo_dbp->disc.title_the))
1558 			return FALSE;
1559 	}
1560 	else if (strcmp(key, ".year") == 0) {
1561 		if (!cdinfo_getline(pp, "disc.year", &cdinfo_dbp->disc.year))
1562 			return FALSE;
1563 	}
1564 	else if (strcmp(key, ".label") == 0) {
1565 		if (!cdinfo_getline(pp, "disc.label", &cdinfo_dbp->disc.label))
1566 			return FALSE;
1567 	}
1568 	else if (strcmp(key, ".genre") == 0) {
1569 		if (!cdinfo_getline(pp, "disc.genre", &cdinfo_dbp->disc.genre))
1570 			return FALSE;
1571 	}
1572 	else if (strcmp(key, ".genre2") == 0) {
1573 		if (!cdinfo_getline(pp, "disc.genre2",
1574 				    &cdinfo_dbp->disc.genre2))
1575 			return FALSE;
1576 	}
1577 	else if (strcmp(key, ".dnum") == 0) {
1578 		if (!cdinfo_getline(pp, "disc.dnum", &cdinfo_dbp->disc.dnum))
1579 			return FALSE;
1580 		}
1581 	else if (strcmp(key, ".tnum") == 0) {
1582 		if (!cdinfo_getline(pp, "disc.tnum", &cdinfo_dbp->disc.tnum))
1583 			return FALSE;
1584 	}
1585 	else if (strcmp(key, ".region") == 0) {
1586 		if (!cdinfo_getline(pp,
1587 				    "disc.region", &cdinfo_dbp->disc.region))
1588 			return FALSE;
1589 	}
1590 	else if (strcmp(key, ".lang") == 0) {
1591 		if (!cdinfo_getline(pp, "disc.lang", &cdinfo_dbp->disc.lang))
1592 			return FALSE;
1593 	}
1594 	else if (strcmp(key, ".notes") == 0) {
1595 		if (!cdinfo_getmultiline(pp, "disc.notes",
1596 					 &cdinfo_dbp->disc.notes))
1597 			return FALSE;
1598 	}
1599 	else if (strcmp(key, ".mediaid") == 0) {
1600 		if (!cdinfo_getline(pp, "disc.mediaid",
1601 				    &cdinfo_dbp->disc.mediaid))
1602 			return FALSE;
1603 	}
1604 	else if (strcmp(key, ".muiid") == 0) {
1605 		if (!cdinfo_getline(pp,
1606 				    "disc.muiid", &cdinfo_dbp->disc.muiid))
1607 			return FALSE;
1608 	}
1609 	else if (strcmp(key, ".titleuid") == 0) {
1610 		if (!cdinfo_getline(pp, "disc.titleuid",
1611 				    &cdinfo_dbp->disc.titleuid))
1612 			return FALSE;
1613 	}
1614 	else if (strcmp(key, ".revision") == 0) {
1615 		if (!cdinfo_getline(pp, "disc.revision",
1616 				    &cdinfo_dbp->disc.revision))
1617 			return FALSE;
1618 	}
1619 	else if (strcmp(key, ".revtag") == 0) {
1620 		if (!cdinfo_getline(pp,
1621 				    "disc.revtag", &cdinfo_dbp->disc.revtag))
1622 			return FALSE;
1623 	}
1624 	else if (strcmp(key, ".certifier") == 0) {
1625 		if (!cdinfo_getline(pp, "disc.certifier",
1626 				    &cdinfo_dbp->disc.certifier))
1627 			return FALSE;
1628 	}
1629 	else if (strcmp(key, ".credit.new") == 0) {
1630 		p = (cdinfo_credit_t *)(void *) MEM_ALLOC("cdinfo_credit_t",
1631 			sizeof(cdinfo_credit_t)
1632 		);
1633 		if (p == NULL) {
1634 			CDINFO_FATAL(app_data.str_nomemory);
1635 			return FALSE;
1636 		}
1637 		(void) memset(p, 0, sizeof(cdinfo_credit_t));
1638 
1639 		if (cdinfo_dbp->disc.credit_list == NULL) {
1640 			cdinfo_dbp->disc.credit_list = p;
1641 			p->prev = NULL;
1642 		}
1643 		else {
1644 			cp->next = p;
1645 			p->prev = cp;
1646 		}
1647 		cp = p;
1648 		p->next = NULL;
1649 	}
1650 	else if (strcmp(key, ".credit.role") == 0) {
1651 		str = NULL;
1652 		if (!cdinfo_getline(pp, "disc.credit.role", &str))
1653 			return FALSE;
1654 		if (str != NULL) {
1655 			cp->crinfo.role = cdinfo_role(str);
1656 			MEM_FREE(str);
1657 		}
1658 	}
1659 	else if (strcmp(key, ".credit.name") == 0) {
1660 		if (!cdinfo_getline(pp, "disc.credit.name",
1661 				    &cp->crinfo.name))
1662 			return FALSE;
1663 	}
1664 	else if (strcmp(key, ".credit.fullname.dispname") == 0) {
1665 		if (!cdinfo_getline(pp, "disc.credit.fullname.dispname",
1666 				    &cp->crinfo.fullname.dispname))
1667 			return FALSE;
1668 	}
1669 	else if (strcmp(key, ".credit.fullname.lastname") == 0) {
1670 		if (!cdinfo_getline(pp, "disc.credit.fullname.lastname",
1671 				    &cp->crinfo.fullname.lastname))
1672 			return FALSE;
1673 	}
1674 	else if (strcmp(key, ".credit.fullname.firstname") == 0) {
1675 		if (!cdinfo_getline(pp, "disc.credit.fullname.firstname",
1676 				    &cp->crinfo.fullname.firstname))
1677 			return FALSE;
1678 	}
1679 	else if (strcmp(key, ".credit.fullname.the") == 0) {
1680 		if (!cdinfo_getline(pp, "disc.credit.fullname.the",
1681 				    &cp->crinfo.fullname.the))
1682 			return FALSE;
1683 	}
1684 	else if (strcmp(key, ".credit.notes") == 0) {
1685 		if (!cdinfo_getmultiline(pp, "disc.credit.notes",
1686 				    &cp->notes))
1687 			return FALSE;
1688 	}
1689 	else if (strcmp(key, ".segment.new") == 0) {
1690 		q = (cdinfo_segment_t *)(void *) MEM_ALLOC("cdinfo_segment_t",
1691 			sizeof(cdinfo_segment_t)
1692 		);
1693 		if (q == NULL) {
1694 			CDINFO_FATAL(app_data.str_nomemory);
1695 			return FALSE;
1696 		}
1697 		(void) memset(q, 0, sizeof(cdinfo_segment_t));
1698 
1699 		if (cdinfo_dbp->disc.segment_list == NULL) {
1700 			cdinfo_dbp->disc.segment_list = q;
1701 			q->prev = NULL;
1702 		}
1703 		else {
1704 			sp->next = q;
1705 			q->prev = sp;
1706 		}
1707 		sp = q;
1708 		q->next = NULL;
1709 	}
1710 	else if (strcmp(key, ".segment.name") == 0) {
1711 		if (!cdinfo_getline(pp, "disc.segment.name",
1712 				    &sp->name))
1713 			return FALSE;
1714 	}
1715 	else if (strcmp(key, ".segment.notes") == 0) {
1716 		if (!cdinfo_getmultiline(pp, "disc.segment.notes",
1717 				    &sp->notes))
1718 			return FALSE;
1719 	}
1720 	else if (strcmp(key, ".segment.start_track") == 0) {
1721 		if (!cdinfo_getline(pp, "disc.segment.start_track",
1722 				    &sp->start_track))
1723 			return FALSE;
1724 	}
1725 	else if (strcmp(key, ".segment.start_frame") == 0) {
1726 		if (!cdinfo_getline(pp, "disc.segment.start_frame",
1727 				    &sp->start_frame))
1728 			return FALSE;
1729 	}
1730 	else if (strcmp(key, ".segment.end_track") == 0) {
1731 		if (!cdinfo_getline(pp, "disc.segment.end_track",
1732 				    &sp->end_track))
1733 			return FALSE;
1734 	}
1735 	else if (strcmp(key, ".segment.end_frame") == 0) {
1736 		if (!cdinfo_getline(pp, "disc.segment.end_frame",
1737 				    &sp->end_frame))
1738 			return FALSE;
1739 	}
1740 	else if (strcmp(key, ".segment.credit.new") == 0) {
1741 		p = (cdinfo_credit_t *)(void *) MEM_ALLOC("cdinfo_credit_t",
1742 			sizeof(cdinfo_credit_t)
1743 		);
1744 		if (p == NULL) {
1745 			CDINFO_FATAL(app_data.str_nomemory);
1746 			return FALSE;
1747 		}
1748 		(void) memset(p, 0, sizeof(cdinfo_credit_t));
1749 
1750 		if (sp->credit_list == NULL) {
1751 			sp->credit_list = p;
1752 			p->prev = NULL;
1753 		}
1754 		else {
1755 			cp->next = p;
1756 			p->prev = cp;
1757 		}
1758 		cp = p;
1759 		p->next = NULL;
1760 	}
1761 	else if (strcmp(key, ".segment.credit.role") == 0) {
1762 		str = NULL;
1763 		if (!cdinfo_getline(pp, "disc.segment.credit.role", &str))
1764 			return FALSE;
1765 		if (str != NULL) {
1766 			cp->crinfo.role = cdinfo_role(str);
1767 			MEM_FREE(str);
1768 		}
1769 	}
1770 	else if (strcmp(key, ".segment.credit.name") == 0) {
1771 		if (!cdinfo_getline(pp, "disc.segment.credit.name",
1772 				    &cp->crinfo.name))
1773 			return FALSE;
1774 	}
1775 	else if (strcmp(key, ".segment.credit.fullname.dispname") == 0) {
1776 		if (!cdinfo_getline(pp,
1777 				    "disc.segment.credit.fullname.dispname",
1778 				    &cp->crinfo.fullname.dispname))
1779 			return FALSE;
1780 	}
1781 	else if (strcmp(key, ".segment.credit.fullname.lastname") == 0) {
1782 		if (!cdinfo_getline(pp,
1783 				    "disc.segment.credit.fullname.lastname",
1784 				    &cp->crinfo.fullname.lastname))
1785 			return FALSE;
1786 	}
1787 	else if (strcmp(key, ".segment.credit.fullname.firstname") == 0) {
1788 		if (!cdinfo_getline(pp,
1789 				    "disc.segment.credit.fullname.firstname",
1790 				    &cp->crinfo.fullname.firstname))
1791 			return FALSE;
1792 	}
1793 	else if (strcmp(key, ".segment.credit.fullname.the") == 0) {
1794 		if (!cdinfo_getline(pp, "disc.segment.credit.fullname.the",
1795 				    &cp->crinfo.fullname.the))
1796 			return FALSE;
1797 	}
1798 	else if (strcmp(key, ".segment.credit.notes") == 0) {
1799 		if (!cdinfo_getmultiline(pp, "disc.segment.credit.notes",
1800 				    &cp->notes))
1801 			return FALSE;
1802 	}
1803 
1804 	return TRUE;
1805 }
1806 
1807 
1808 /*
1809  * cdinfo_gettrack_ents
1810  *	Read track related elements from pipe, used by the parent.
1811  *
1812  * Args:
1813  *	pp - Pointer to cdinfo_pipe_t
1814  *	key - track element key string
1815  *
1816  * Return:
1817  *	TRUE - success
1818  *	FALSE - failure
1819  */
1820 STATIC bool_t
cdinfo_gettrack_ents(cdinfo_pipe_t * pp,char * key)1821 cdinfo_gettrack_ents(cdinfo_pipe_t *pp, char *key)
1822 {
1823 	int			i;
1824 	char			*str,
1825 				*name;
1826 	cdinfo_credit_t		*p;
1827 	static cdinfo_credit_t	*cp = NULL;
1828 
1829 	if (sscanf(key, "%d.", &i) != 1)
1830 		return FALSE;	/* Unexpected data */
1831 
1832 	name = strchr(key, '.') + 1;
1833 
1834 	if (strcmp(name, "artistfname.dispname") == 0) {
1835 		if (!cdinfo_getline(pp, name,
1836 				&cdinfo_dbp->track[i].artistfname.dispname))
1837 			return FALSE;
1838 	}
1839 	else if (strcmp(name, "artistfname.lastname") == 0) {
1840 		if (!cdinfo_getline(pp, name,
1841 				&cdinfo_dbp->track[i].artistfname.lastname))
1842 			return FALSE;
1843 	}
1844 	else if (strcmp(name, "artistfname.firstname") == 0) {
1845 		if (!cdinfo_getline(pp, name,
1846 				&cdinfo_dbp->track[i].artistfname.firstname))
1847 			return FALSE;
1848 	}
1849 	else if (strcmp(name, "artistfname.the") == 0) {
1850 		if (!cdinfo_getline(pp, name,
1851 				    &cdinfo_dbp->track[i].artistfname.the))
1852 			return FALSE;
1853 	}
1854 	else if (strcmp(name, "artist") == 0) {
1855 		if (!cdinfo_getline(pp, name, &cdinfo_dbp->track[i].artist))
1856 			return FALSE;
1857 	}
1858 	else if (strcmp(name, "title") == 0) {
1859 		if (!cdinfo_getline(pp, name, &cdinfo_dbp->track[i].title))
1860 			return FALSE;
1861 	}
1862 	else if (strcmp(name, "sorttitle") == 0) {
1863 		if (!cdinfo_getline(pp, name, &cdinfo_dbp->track[i].sorttitle))
1864 			return FALSE;
1865 	}
1866 	else if (strcmp(name, "title_the") == 0) {
1867 		if (!cdinfo_getline(pp, name, &cdinfo_dbp->track[i].title_the))
1868 			return FALSE;
1869 	}
1870 	else if (strcmp(name, "year") == 0) {
1871 		if (!cdinfo_getline(pp, name, &cdinfo_dbp->track[i].year))
1872 			return FALSE;
1873 	}
1874 	else if (strcmp(name, "label") == 0) {
1875 		if (!cdinfo_getline(pp, name, &cdinfo_dbp->track[i].label))
1876 			return FALSE;
1877 	}
1878 	else if (strcmp(name, "genre") == 0) {
1879 		if (!cdinfo_getline(pp, name, &cdinfo_dbp->track[i].genre))
1880 			return FALSE;
1881 	}
1882 	else if (strcmp(name, "genre2") == 0) {
1883 		if (!cdinfo_getline(pp, name, &cdinfo_dbp->track[i].genre2))
1884 			return FALSE;
1885 	}
1886 	else if (strcmp(name, "bpm") == 0) {
1887 		if (!cdinfo_getline(pp, name, &cdinfo_dbp->track[i].bpm))
1888 			return FALSE;
1889 	}
1890 	else if (strcmp(name, "notes") == 0) {
1891 		if (!cdinfo_getmultiline(pp, name,
1892 					 &cdinfo_dbp->track[i].notes))
1893 			return FALSE;
1894 	}
1895 	else if (strcmp(name, "isrc") == 0) {
1896 		if (!cdinfo_getline(pp, name, &cdinfo_dbp->track[i].isrc))
1897 			return FALSE;
1898 	}
1899 	else if (strcmp(name, "credit.new") == 0) {
1900 		p = (cdinfo_credit_t *)(void *) MEM_ALLOC("cdinfo_credit_t",
1901 			sizeof(cdinfo_credit_t)
1902 		);
1903 		if (p == NULL) {
1904 			CDINFO_FATAL(app_data.str_nomemory);
1905 			return FALSE;
1906 		}
1907 		(void) memset(p, 0, sizeof(cdinfo_credit_t));
1908 
1909 		if (cdinfo_dbp->track[i].credit_list == NULL) {
1910 			cdinfo_dbp->track[i].credit_list = p;
1911 			p->prev = NULL;
1912 		}
1913 		else {
1914 			cp->next = p;
1915 			p->prev = cp;
1916 		}
1917 		cp = p;
1918 		p->next = NULL;
1919 	}
1920 	else if (strcmp(name, "credit.role") == 0) {
1921 		str = NULL;
1922 		if (!cdinfo_getline(pp, name, &str))
1923 			return FALSE;
1924 		if (str != NULL) {
1925 			cp->crinfo.role = cdinfo_role(str);
1926 			MEM_FREE(str);
1927 		}
1928 	}
1929 	else if (strcmp(name, "credit.name") == 0) {
1930 		if (!cdinfo_getline(pp, name, &cp->crinfo.name))
1931 			return FALSE;
1932 	}
1933 	else if (strcmp(name, "credit.fullname.dispname") == 0) {
1934 		if (!cdinfo_getline(pp, name, &cp->crinfo.fullname.dispname))
1935 			return FALSE;
1936 	}
1937 	else if (strcmp(name, "credit.fullname.lastname") == 0) {
1938 		if (!cdinfo_getline(pp, name, &cp->crinfo.fullname.lastname))
1939 			return FALSE;
1940 	}
1941 	else if (strcmp(name, "credit.fullname.firstname") == 0) {
1942 		if (!cdinfo_getline(pp, name, &cp->crinfo.fullname.firstname))
1943 			return FALSE;
1944 	}
1945 	else if (strcmp(name, "credit.fullname.the") == 0) {
1946 		if (!cdinfo_getline(pp, name, &cp->crinfo.fullname.the))
1947 			return FALSE;
1948 	}
1949 	else if (strcmp(name, "credit.notes") == 0) {
1950 		if (!cdinfo_getmultiline(pp, name, &cp->notes))
1951 			return FALSE;
1952 	}
1953 
1954 	return TRUE;
1955 }
1956 
1957 
1958 /*
1959  * cdinfo_puturl_ents
1960  *	Write URL match elements into pipe, used by the child.
1961  *
1962  * Args:
1963  *	pp - Pointer to cdinfo_pipe_t
1964  *
1965  * Return:
1966  *	TRUE - success
1967  *	FALSE - failure
1968  */
1969 STATIC bool_t
cdinfo_puturl_ents(cdinfo_pipe_t * pp)1970 cdinfo_puturl_ents(cdinfo_pipe_t *pp)
1971 {
1972 	cdinfo_url_t	*p;
1973 
1974 	if (!cdinfo_genurl_initted) {
1975 	    for (p = cdinfo_dbp->gen_url_list; p != NULL; p = p->next) {
1976 		if (!cdinfo_puts(pp, XMCD_PIPESIG "url.gen.new"))
1977 			return FALSE;
1978 
1979 		if (p->type != NULL) {
1980 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.gen.type"))
1981 				return FALSE;
1982 			if (!cdinfo_puts(pp, p->type))
1983 				return FALSE;
1984 		}
1985 		if (p->href != NULL) {
1986 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.gen.href"))
1987 				return FALSE;
1988 			if (!cdinfo_puts(pp, p->href))
1989 				return FALSE;
1990 		}
1991 		if (p->displink != NULL) {
1992 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.gen.displink"))
1993 				return FALSE;
1994 			if (!cdinfo_puts(pp, p->displink))
1995 				return FALSE;
1996 		}
1997 		if (p->disptext != NULL) {
1998 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.gen.disptext"))
1999 				return FALSE;
2000 			if (!cdinfo_puts(pp, p->disptext))
2001 				return FALSE;
2002 		}
2003 		if (p->categ != NULL) {
2004 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.gen.categ"))
2005 				return FALSE;
2006 			if (!cdinfo_puts(pp, p->categ))
2007 				return FALSE;
2008 		}
2009 		if (p->size != NULL) {
2010 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.gen.size"))
2011 				return FALSE;
2012 			if (!cdinfo_puts(pp, p->size))
2013 				return FALSE;
2014 		}
2015 		if (p->weight != NULL) {
2016 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.gen.weight"))
2017 				return FALSE;
2018 			if (!cdinfo_puts(pp, p->weight))
2019 				return FALSE;
2020 		}
2021 
2022 		cdinfo_genurl_initted = TRUE;
2023 	    }
2024 	}
2025 
2026 	for (p = cdinfo_dbp->disc_url_list; p != NULL; p = p->next) {
2027 		if (!cdinfo_puts(pp, XMCD_PIPESIG "url.disc.new"))
2028 			return FALSE;
2029 
2030 		if (p->type != NULL) {
2031 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.disc.type"))
2032 				return FALSE;
2033 			if (!cdinfo_puts(pp, p->type))
2034 				return FALSE;
2035 		}
2036 		if (p->href != NULL) {
2037 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.disc.href"))
2038 				return FALSE;
2039 			if (!cdinfo_puts(pp, p->href))
2040 				return FALSE;
2041 		}
2042 		if (p->displink != NULL) {
2043 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.disc.displink"))
2044 				return FALSE;
2045 			if (!cdinfo_puts(pp, p->displink))
2046 				return FALSE;
2047 		}
2048 		if (p->disptext != NULL) {
2049 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.disc.disptext"))
2050 				return FALSE;
2051 			if (!cdinfo_puts(pp, p->disptext))
2052 				return FALSE;
2053 		}
2054 		if (p->categ != NULL) {
2055 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.disc.categ"))
2056 				return FALSE;
2057 			if (!cdinfo_puts(pp, p->categ))
2058 				return FALSE;
2059 		}
2060 		if (p->size != NULL) {
2061 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.disc.size"))
2062 				return FALSE;
2063 			if (!cdinfo_puts(pp, p->size))
2064 				return FALSE;
2065 		}
2066 		if (p->weight != NULL) {
2067 			if (!cdinfo_puts(pp, XMCD_PIPESIG "url.disc.weight"))
2068 				return FALSE;
2069 			if (!cdinfo_puts(pp, p->weight))
2070 				return FALSE;
2071 		}
2072 	}
2073 
2074 	return TRUE;
2075 }
2076 
2077 
2078 /*
2079  * cdinfo_putctrl_ents
2080  *	Write CDDB control information into pipe, used by the child.
2081  *
2082  * Args:
2083  *	pp - Pointer to cdinfo_pipe_t
2084  *
2085  * Return:
2086  *	TRUE - success
2087  *	FALSE - failure
2088  */
2089 STATIC bool_t
cdinfo_putctrl_ents(cdinfo_pipe_t * pp)2090 cdinfo_putctrl_ents(cdinfo_pipe_t *pp)
2091 {
2092 	if (cdinfo_ctrl_initted)
2093 		return TRUE;
2094 
2095 	if (cdinfo_dbp->ctrl_ver != NULL) {
2096 		if (!cdinfo_puts(pp, XMCD_PIPESIG "control.ver"))
2097 			return FALSE;
2098 		if (!cdinfo_puts(pp, cdinfo_dbp->ctrl_ver))
2099 			return FALSE;
2100 	}
2101 
2102 	cdinfo_ctrl_initted = TRUE;
2103 	return TRUE;
2104 }
2105 
2106 
2107 /*
2108  * cdinfo_putglist_ents
2109  *	Write genre list elements into pipe, used by the child.
2110  *
2111  * Args:
2112  *	pp - Pointer to cdinfo_pipe_t
2113  *
2114  * Return:
2115  *	TRUE - success
2116  *	FALSE - failure
2117  */
2118 STATIC bool_t
cdinfo_putglist_ents(cdinfo_pipe_t * pp)2119 cdinfo_putglist_ents(cdinfo_pipe_t *pp)
2120 {
2121 	cdinfo_genre_t	*p,
2122 			*q;
2123 
2124 	if (cdinfo_glist_initted)
2125 		return TRUE;
2126 
2127 	for (p = cdinfo_dbp->genrelist; p != NULL; p = p->next) {
2128 		if (!cdinfo_puts(pp, XMCD_PIPESIG "genre.new"))
2129 			return FALSE;
2130 
2131 		if (!cdinfo_puts(pp, XMCD_PIPESIG "genre.id"))
2132 			return FALSE;
2133 		if (!cdinfo_puts(pp, p->id))
2134 			return FALSE;
2135 
2136 		if (!cdinfo_puts(pp, XMCD_PIPESIG "genre.name"))
2137 			return FALSE;
2138 		if (!cdinfo_puts(pp, p->name))
2139 			return FALSE;
2140 
2141 		for (q = p->child; q != NULL; q = q->next) {
2142 			if (!cdinfo_puts(pp,
2143 					 XMCD_PIPESIG "genre.subgenre.new"))
2144 				return FALSE;
2145 
2146 			if (!cdinfo_puts(pp,
2147 					 XMCD_PIPESIG "genre.subgenre.id"))
2148 				return FALSE;
2149 			if (!cdinfo_puts(pp, q->id))
2150 				return FALSE;
2151 
2152 			if (!cdinfo_puts(pp,
2153 					 XMCD_PIPESIG "genre.subgenre.name"))
2154 				return FALSE;
2155 			if (!cdinfo_puts(pp, q->name))
2156 				return FALSE;
2157 		}
2158 	}
2159 
2160 	cdinfo_glist_initted = TRUE;
2161 	return TRUE;
2162 }
2163 
2164 
2165 /*
2166  * cdinfo_putrelist_ents
2167  *	Write region list elements into pipe, used by the child.
2168  *
2169  * Args:
2170  *	pp - Pointer to cdinfo_pipe_t
2171  *
2172  * Return:
2173  *	TRUE - success
2174  *	FALSE - failure
2175  */
2176 STATIC bool_t
cdinfo_putrelist_ents(cdinfo_pipe_t * pp)2177 cdinfo_putrelist_ents(cdinfo_pipe_t *pp)
2178 {
2179 	cdinfo_region_t	*p;
2180 
2181 	if (cdinfo_relist_initted)
2182 		return TRUE;
2183 
2184 	for (p = cdinfo_dbp->regionlist; p != NULL; p = p->next) {
2185 		if (!cdinfo_puts(pp, XMCD_PIPESIG "region.new"))
2186 			return FALSE;
2187 
2188 		if (!cdinfo_puts(pp, XMCD_PIPESIG "region.id"))
2189 			return FALSE;
2190 		if (!cdinfo_puts(pp, p->id))
2191 			return FALSE;
2192 
2193 		if (!cdinfo_puts(pp, XMCD_PIPESIG "region.name"))
2194 			return FALSE;
2195 		if (!cdinfo_puts(pp, p->name))
2196 			return FALSE;
2197 	}
2198 
2199 	cdinfo_relist_initted = TRUE;
2200 	return TRUE;
2201 }
2202 
2203 
2204 /*
2205  * cdinfo_putlanglist_ents
2206  *	Write language list elements into pipe, used by the child.
2207  *
2208  * Args:
2209  *	pp - Pointer to cdinfo_pipe_t
2210  *
2211  * Return:
2212  *	TRUE - success
2213  *	FALSE - failure
2214  */
2215 STATIC bool_t
cdinfo_putlanglist_ents(cdinfo_pipe_t * pp)2216 cdinfo_putlanglist_ents(cdinfo_pipe_t *pp)
2217 {
2218 	cdinfo_lang_t	*p;
2219 
2220 	if (cdinfo_langlist_initted)
2221 		return TRUE;
2222 
2223 	for (p = cdinfo_dbp->langlist; p != NULL; p = p->next) {
2224 		if (!cdinfo_puts(pp, XMCD_PIPESIG "lang.new"))
2225 			return FALSE;
2226 
2227 		if (!cdinfo_puts(pp, XMCD_PIPESIG "lang.id"))
2228 			return FALSE;
2229 		if (!cdinfo_puts(pp, p->id))
2230 			return FALSE;
2231 
2232 		if (!cdinfo_puts(pp, XMCD_PIPESIG "lang.name"))
2233 			return FALSE;
2234 		if (!cdinfo_puts(pp, p->name))
2235 			return FALSE;
2236 	}
2237 
2238 	cdinfo_langlist_initted = TRUE;
2239 	return TRUE;
2240 }
2241 
2242 
2243 /*
2244  * cdinfo_putrolist_ents
2245  *	Write role list elements into pipe, used by the child.
2246  *
2247  * Args:
2248  *	pp - Pointer to cdinfo_pipe_t
2249  *
2250  * Return:
2251  *	TRUE - success
2252  *	FALSE - failure
2253  */
2254 STATIC bool_t
cdinfo_putrolist_ents(cdinfo_pipe_t * pp)2255 cdinfo_putrolist_ents(cdinfo_pipe_t *pp)
2256 {
2257 	cdinfo_role_t	*p,
2258 			*q;
2259 
2260 	if (cdinfo_rolist_initted)
2261 		return TRUE;
2262 
2263 	for (p = cdinfo_dbp->rolelist; p != NULL; p = p->next) {
2264 		if (!cdinfo_puts(pp, XMCD_PIPESIG "role.new"))
2265 			return FALSE;
2266 
2267 		if (!cdinfo_puts(pp, XMCD_PIPESIG "role.id"))
2268 			return FALSE;
2269 		if (!cdinfo_puts(pp, p->id))
2270 			return FALSE;
2271 
2272 		if (!cdinfo_puts(pp, XMCD_PIPESIG "role.name"))
2273 			return FALSE;
2274 		if (!cdinfo_puts(pp, p->name))
2275 			return FALSE;
2276 
2277 		for (q = p->child; q != NULL; q = q->next) {
2278 			if (!cdinfo_puts(pp,
2279 					 XMCD_PIPESIG "role.subrole.new"))
2280 				return FALSE;
2281 
2282 			if (!cdinfo_puts(pp,
2283 					 XMCD_PIPESIG "role.subrole.id"))
2284 				return FALSE;
2285 			if (!cdinfo_puts(pp, q->id))
2286 				return FALSE;
2287 
2288 			if (!cdinfo_puts(pp,
2289 					 XMCD_PIPESIG "role.subrole.name"))
2290 				return FALSE;
2291 			if (!cdinfo_puts(pp, q->name))
2292 				return FALSE;
2293 		}
2294 	}
2295 
2296 	cdinfo_rolist_initted = TRUE;
2297 	return TRUE;
2298 }
2299 
2300 
2301 /*
2302  * cdinfo_putmatch_ents
2303  *	Write multiple match elements into pipe, used by the child.
2304  *
2305  * Args:
2306  *	pp - Pointer to cdinfo_pipe_t
2307  *
2308  * Return:
2309  *	TRUE - success
2310  *	FALSE - failure
2311  */
2312 STATIC bool_t
cdinfo_putmatch_ents(cdinfo_pipe_t * pp)2313 cdinfo_putmatch_ents(cdinfo_pipe_t *pp)
2314 {
2315 	cdinfo_match_t	*p;
2316 
2317 	for (p = cdinfo_dbp->matchlist; p != NULL; p = p->next) {
2318 		if (!cdinfo_puts(pp, XMCD_PIPESIG "match.new"))
2319 			return FALSE;
2320 		if (!cdinfo_puts(pp, XMCD_PIPESIG "match.artist"))
2321 			return FALSE;
2322 		if (!cdinfo_puts(pp, p->artist))
2323 			return FALSE;
2324 		if (!cdinfo_puts(pp, XMCD_PIPESIG "match.title"))
2325 			return FALSE;
2326 		if (!cdinfo_puts(pp, p->title))
2327 			return FALSE;
2328 		if (!cdinfo_puts(pp, XMCD_PIPESIG "match.genre"))
2329 			return FALSE;
2330 		if (!cdinfo_puts(pp, p->genre))
2331 			return FALSE;
2332 	}
2333 
2334 	return TRUE;
2335 }
2336 
2337 
2338 /*
2339  * cdinfo_putuserreg_ents
2340  *	Write user registration related elements into pipe, used by the child.
2341  *
2342  * Args:
2343  *	pp - Pointer to cdinfo_pipe_t
2344  *
2345  * Return:
2346  *	TRUE - success
2347  *	FALSE - failure
2348  */
2349 STATIC bool_t
cdinfo_putuserreg_ents(cdinfo_pipe_t * pp)2350 cdinfo_putuserreg_ents(cdinfo_pipe_t *pp)
2351 {
2352 	if (cdinfo_user_regd)
2353 		return TRUE;
2354 
2355 	if (cdinfo_dbp->userreg.handle != NULL) {
2356 		if (!cdinfo_puts(pp, XMCD_PIPESIG "userreg.handle"))
2357 			return FALSE;
2358 		if (!cdinfo_puts(pp, cdinfo_dbp->userreg.handle))
2359 			return FALSE;
2360 	}
2361 	if (cdinfo_dbp->userreg.hint != NULL) {
2362 		if (!cdinfo_puts(pp, XMCD_PIPESIG "userreg.hint"))
2363 			return FALSE;
2364 		if (!cdinfo_puts(pp, cdinfo_dbp->userreg.hint))
2365 			return FALSE;
2366 	}
2367 	if (cdinfo_dbp->userreg.email != NULL) {
2368 		if (!cdinfo_puts(pp, XMCD_PIPESIG "userreg.email"))
2369 			return FALSE;
2370 		if (!cdinfo_puts(pp, cdinfo_dbp->userreg.email))
2371 			return FALSE;
2372 	}
2373 	if (cdinfo_dbp->userreg.region != NULL) {
2374 		if (!cdinfo_puts(pp, XMCD_PIPESIG "userreg.region"))
2375 			return FALSE;
2376 		if (!cdinfo_puts(pp, cdinfo_dbp->userreg.region))
2377 			return FALSE;
2378 	}
2379 	if (cdinfo_dbp->userreg.postal != NULL) {
2380 		if (!cdinfo_puts(pp, XMCD_PIPESIG "userreg.postal"))
2381 			return FALSE;
2382 		if (!cdinfo_puts(pp, cdinfo_dbp->userreg.postal))
2383 			return FALSE;
2384 	}
2385 	if (cdinfo_dbp->userreg.age != NULL) {
2386 		if (!cdinfo_puts(pp, XMCD_PIPESIG "userreg.age"))
2387 			return FALSE;
2388 		if (!cdinfo_puts(pp, cdinfo_dbp->userreg.age))
2389 			return FALSE;
2390 	}
2391 	if (cdinfo_dbp->userreg.gender != NULL) {
2392 		if (!cdinfo_puts(pp, XMCD_PIPESIG "userreg.gender"))
2393 			return FALSE;
2394 		if (!cdinfo_puts(pp, cdinfo_dbp->userreg.gender))
2395 			return FALSE;
2396 	}
2397 	if (cdinfo_dbp->userreg.allowemail) {
2398 		if (!cdinfo_puts(pp, XMCD_PIPESIG "userreg.allowemail"))
2399 			return FALSE;
2400 		if (!cdinfo_puts(pp, "1\n"))
2401 			return FALSE;
2402 	}
2403 	if (cdinfo_dbp->userreg.allowstats) {
2404 		if (!cdinfo_puts(pp, XMCD_PIPESIG "userreg.allowstats"))
2405 			return FALSE;
2406 		if (!cdinfo_puts(pp, "1\n"))
2407 			return FALSE;
2408 	}
2409 
2410 	cdinfo_user_regd = TRUE;
2411 	return TRUE;
2412 }
2413 
2414 
2415 /*
2416  * cdinfo_putdisc_ents
2417  *	Write disc related elements into pipe, used by the child.
2418  *
2419  * Args:
2420  *	pp - Pointer to cdinfo_pipe_t
2421  *
2422  * Return:
2423  *	TRUE - success
2424  *	FALSE - failure
2425  */
2426 STATIC bool_t
cdinfo_putdisc_ents(cdinfo_pipe_t * pp)2427 cdinfo_putdisc_ents(cdinfo_pipe_t *pp)
2428 {
2429 	char			buf[32];
2430 	cdinfo_credit_t		*p;
2431 	cdinfo_segment_t	*q;
2432 
2433 	if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.flags"))
2434 		return FALSE;
2435 	(void) sprintf(buf, "%x", cdinfo_dbp->flags);
2436 	if (!cdinfo_puts(pp, buf))
2437 		return FALSE;
2438 
2439 	if (cdinfo_dbp->disc.compilation) {
2440 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.compilation"))
2441 			return FALSE;
2442 		if (!cdinfo_puts(pp, "1\n"))
2443 			return FALSE;
2444 	}
2445 	if (cdinfo_dbp->disc.artistfname.dispname != NULL) {
2446 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.artistfname.dispname"))
2447 			return FALSE;
2448 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.artistfname.dispname))
2449 			return FALSE;
2450 	}
2451 	if (cdinfo_dbp->disc.artistfname.lastname != NULL) {
2452 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.artistfname.lastname"))
2453 			return FALSE;
2454 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.artistfname.lastname))
2455 			return FALSE;
2456 	}
2457 	if (cdinfo_dbp->disc.artistfname.firstname != NULL) {
2458 		if (!cdinfo_puts(pp,
2459 				 XMCD_PIPESIG "disc.artistfname.firstname"))
2460 			return FALSE;
2461 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.artistfname.firstname))
2462 			return FALSE;
2463 	}
2464 	if (cdinfo_dbp->disc.artistfname.the != NULL) {
2465 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.artistfname.the"))
2466 			return FALSE;
2467 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.artistfname.the))
2468 			return FALSE;
2469 	}
2470 	if (cdinfo_dbp->disc.artist != NULL) {
2471 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.artist"))
2472 			return FALSE;
2473 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.artist))
2474 			return FALSE;
2475 	}
2476 	if (cdinfo_dbp->disc.title != NULL) {
2477 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.title"))
2478 			return FALSE;
2479 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.title))
2480 			return FALSE;
2481 	}
2482 	if (cdinfo_dbp->disc.sorttitle != NULL) {
2483 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.sorttitle"))
2484 			return FALSE;
2485 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.sorttitle))
2486 			return FALSE;
2487 	}
2488 	if (cdinfo_dbp->disc.title_the != NULL) {
2489 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.title_the"))
2490 			return FALSE;
2491 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.title_the))
2492 			return FALSE;
2493 	}
2494 	if (cdinfo_dbp->disc.year != NULL) {
2495 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.year"))
2496 			return FALSE;
2497 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.year))
2498 			return FALSE;
2499 	}
2500 	if (cdinfo_dbp->disc.label != NULL) {
2501 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.label"))
2502 			return FALSE;
2503 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.label))
2504 			return FALSE;
2505 	}
2506 	if (cdinfo_dbp->disc.genre != NULL) {
2507 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.genre"))
2508 			return FALSE;
2509 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.genre))
2510 			return FALSE;
2511 	}
2512 	if (cdinfo_dbp->disc.genre2 != NULL) {
2513 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.genre2"))
2514 			return FALSE;
2515 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.genre2))
2516 			return FALSE;
2517 	}
2518 	if (cdinfo_dbp->disc.dnum != NULL) {
2519 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.dnum"))
2520 			return FALSE;
2521 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.dnum))
2522 			return FALSE;
2523 	}
2524 	if (cdinfo_dbp->disc.tnum != NULL) {
2525 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.tnum"))
2526 			return FALSE;
2527 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.tnum))
2528 			return FALSE;
2529 	}
2530 	if (cdinfo_dbp->disc.region != NULL) {
2531 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.region"))
2532 			return FALSE;
2533 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.region))
2534 			return FALSE;
2535 	}
2536 	if (cdinfo_dbp->disc.lang != NULL) {
2537 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.lang"))
2538 			return FALSE;
2539 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.lang))
2540 			return FALSE;
2541 	}
2542 	if (cdinfo_dbp->disc.notes != NULL) {
2543 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.notes"))
2544 			return FALSE;
2545 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.notes))
2546 			return FALSE;
2547 		if (!cdinfo_puts(pp, XMCD_PIPESIG "multi.end"))
2548 			return FALSE;
2549 	}
2550 	if (cdinfo_dbp->disc.mediaid != NULL) {
2551 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.mediaid"))
2552 			return FALSE;
2553 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.mediaid))
2554 			return FALSE;
2555 	}
2556 	if (cdinfo_dbp->disc.muiid != NULL) {
2557 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.muiid"))
2558 			return FALSE;
2559 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.muiid))
2560 			return FALSE;
2561 	}
2562 	if (cdinfo_dbp->disc.titleuid != NULL) {
2563 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.titleuid"))
2564 			return FALSE;
2565 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.titleuid))
2566 			return FALSE;
2567 	}
2568 	if (cdinfo_dbp->disc.revision != NULL) {
2569 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.revision"))
2570 			return FALSE;
2571 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.revision))
2572 			return FALSE;
2573 	}
2574 	if (cdinfo_dbp->disc.revtag != NULL) {
2575 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.revtag"))
2576 			return FALSE;
2577 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.revtag))
2578 			return FALSE;
2579 	}
2580 	if (cdinfo_dbp->disc.certifier != NULL) {
2581 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.certifier"))
2582 			return FALSE;
2583 		if (!cdinfo_puts(pp, cdinfo_dbp->disc.certifier))
2584 			return FALSE;
2585 	}
2586 	for (p = cdinfo_dbp->disc.credit_list; p != NULL; p = p->next) {
2587 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.credit.new"))
2588 			return FALSE;
2589 		if (p->crinfo.role != NULL) {
2590 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2591 					 "disc.credit.role"))
2592 				return FALSE;
2593 			if (!cdinfo_puts(pp, p->crinfo.role->id))
2594 				return FALSE;
2595 		}
2596 		if (p->crinfo.name != NULL) {
2597 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2598 					 "disc.credit.name"))
2599 				return FALSE;
2600 			if (!cdinfo_puts(pp, p->crinfo.name))
2601 				return FALSE;
2602 		}
2603 		if (p->crinfo.fullname.dispname != NULL) {
2604 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2605 					 "disc.credit.fullname.dispname"))
2606 				return FALSE;
2607 			if (!cdinfo_puts(pp, p->crinfo.fullname.dispname))
2608 				return FALSE;
2609 		}
2610 		if (p->crinfo.fullname.lastname != NULL) {
2611 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2612 					 "disc.credit.fullname.lastname"))
2613 				return FALSE;
2614 			if (!cdinfo_puts(pp, p->crinfo.fullname.lastname))
2615 				return FALSE;
2616 		}
2617 		if (p->crinfo.fullname.firstname != NULL) {
2618 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2619 					 "disc.credit.fullname.firstname"))
2620 				return FALSE;
2621 			if (!cdinfo_puts(pp, p->crinfo.fullname.firstname))
2622 				return FALSE;
2623 		}
2624 		if (p->crinfo.fullname.the != NULL) {
2625 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2626 					 "disc.credit.fullname.the"))
2627 				return FALSE;
2628 			if (!cdinfo_puts(pp, p->crinfo.fullname.the))
2629 				return FALSE;
2630 		}
2631 		if (p->notes != NULL) {
2632 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2633 					 "disc.credit.notes"))
2634 				return FALSE;
2635 			if (!cdinfo_puts(pp, p->notes))
2636 				return FALSE;
2637 			if (!cdinfo_puts(pp, XMCD_PIPESIG "multi.end"))
2638 				return FALSE;
2639 		}
2640 	}
2641 	for (q = cdinfo_dbp->disc.segment_list; q != NULL; q = q->next) {
2642 		if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.segment.new"))
2643 			return FALSE;
2644 		if (q->name != NULL) {
2645 			if (!cdinfo_puts(pp, XMCD_PIPESIG "disc.segment.name"))
2646 				return FALSE;
2647 			if (!cdinfo_puts(pp, q->name))
2648 				return FALSE;
2649 		}
2650 		if (q->notes != NULL) {
2651 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2652 					 "disc.segment.notes"))
2653 				return FALSE;
2654 			if (!cdinfo_puts(pp, q->notes))
2655 				return FALSE;
2656 			if (!cdinfo_puts(pp, XMCD_PIPESIG "multi.end"))
2657 				return FALSE;
2658 		}
2659 		if (q->start_track != NULL) {
2660 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2661 					 "disc.segment.start_track"))
2662 				return FALSE;
2663 			if (!cdinfo_puts(pp, q->start_track))
2664 				return FALSE;
2665 		}
2666 		if (q->start_frame != NULL) {
2667 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2668 					 "disc.segment.start_frame"))
2669 				return FALSE;
2670 			if (!cdinfo_puts(pp, q->start_frame))
2671 				return FALSE;
2672 		}
2673 		if (q->end_track != NULL) {
2674 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2675 					 "disc.segment.end_track"))
2676 				return FALSE;
2677 			if (!cdinfo_puts(pp, q->end_track))
2678 				return FALSE;
2679 		}
2680 		if (q->end_frame != NULL) {
2681 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2682 					 "disc.segment.end_frame"))
2683 				return FALSE;
2684 			if (!cdinfo_puts(pp, q->end_frame))
2685 				return FALSE;
2686 		}
2687 		for (p = q->credit_list; p != NULL; p = p->next) {
2688 			if (!cdinfo_puts(pp, XMCD_PIPESIG
2689 					 "disc.segment.credit.new"))
2690 				return FALSE;
2691 			if (p->crinfo.role != NULL) {
2692 				if (!cdinfo_puts(pp, XMCD_PIPESIG
2693 						 "disc.segment.credit.role"))
2694 					return FALSE;
2695 				if (!cdinfo_puts(pp, p->crinfo.role->id))
2696 					return FALSE;
2697 			}
2698 			if (p->crinfo.name != NULL) {
2699 				if (!cdinfo_puts(pp, XMCD_PIPESIG
2700 						 "disc.segment.credit.name"))
2701 					return FALSE;
2702 				if (!cdinfo_puts(pp, p->crinfo.name))
2703 					return FALSE;
2704 			}
2705 			if (p->crinfo.fullname.dispname != NULL) {
2706 				if (!cdinfo_puts(pp, XMCD_PIPESIG
2707 				    "disc.segment.credit.fullname.dispname"))
2708 					return FALSE;
2709 				if (!cdinfo_puts(pp,
2710 						 p->crinfo.fullname.dispname))
2711 					return FALSE;
2712 			}
2713 			if (p->crinfo.fullname.lastname != NULL) {
2714 				if (!cdinfo_puts(pp, XMCD_PIPESIG
2715 				     "disc.segment.credit.fullname.lastname"))
2716 					return FALSE;
2717 				if (!cdinfo_puts(pp,
2718 						 p->crinfo.fullname.lastname))
2719 					return FALSE;
2720 			}
2721 			if (p->crinfo.fullname.firstname != NULL) {
2722 				if (!cdinfo_puts(pp, XMCD_PIPESIG
2723 				     "disc.segment.credit.fullname.firstname"))
2724 					return FALSE;
2725 				if (!cdinfo_puts(pp,
2726 						 p->crinfo.fullname.firstname))
2727 					return FALSE;
2728 			}
2729 			if (p->crinfo.fullname.the != NULL) {
2730 				if (!cdinfo_puts(pp, XMCD_PIPESIG
2731 				     "disc.segment.credit.fullname.the"))
2732 					return FALSE;
2733 				if (!cdinfo_puts(pp, p->crinfo.fullname.the))
2734 					return FALSE;
2735 			}
2736 			if (p->notes != NULL) {
2737 				if (!cdinfo_puts(pp, XMCD_PIPESIG
2738 				     "disc.segment.credit.notes"))
2739 					return FALSE;
2740 				if (!cdinfo_puts(pp, p->notes))
2741 					return FALSE;
2742 				if (!cdinfo_puts(pp, XMCD_PIPESIG "multi.end"))
2743 					return FALSE;
2744 			}
2745 		}
2746 	}
2747 
2748 	return TRUE;
2749 }
2750 
2751 
2752 /*
2753  * cdinfo_puttrack_ents
2754  *	Write track related elements into pipe, used by the child.
2755  *
2756  * Args:
2757  *	pp - Pointer to cdinfo_pipe_t
2758  *	s - Pointer to the curstat_t structure
2759  *
2760  * Return:
2761  *	TRUE - success
2762  *	FALSE - failure
2763  */
2764 STATIC bool_t
cdinfo_puttrack_ents(cdinfo_pipe_t * pp,curstat_t * s)2765 cdinfo_puttrack_ents(cdinfo_pipe_t *pp, curstat_t *s)
2766 {
2767 	int		i;
2768 	char		buf[80];
2769 	cdinfo_credit_t	*p;
2770 
2771 	for (i = 0; i < (int) s->tot_trks; i++) {
2772 	    if (cdinfo_dbp->track[i].artistfname.dispname != NULL) {
2773 		(void) sprintf(buf, "%strack%d.artistfname.dispname",
2774 				XMCD_PIPESIG, i);
2775 		if (!cdinfo_puts(pp, buf))
2776 			return FALSE;
2777 		if (!cdinfo_puts(pp,
2778 				 cdinfo_dbp->track[i].artistfname.dispname))
2779 			return FALSE;
2780 	    }
2781 	    if (cdinfo_dbp->track[i].artistfname.lastname != NULL) {
2782 		(void) sprintf(buf, "%strack%d.artistfname.lastname",
2783 				XMCD_PIPESIG, i);
2784 		if (!cdinfo_puts(pp, buf))
2785 			return FALSE;
2786 		if (!cdinfo_puts(pp,
2787 				 cdinfo_dbp->track[i].artistfname.lastname))
2788 			return FALSE;
2789 	    }
2790 	    if (cdinfo_dbp->track[i].artistfname.firstname != NULL) {
2791 		(void) sprintf(buf, "%strack%d.artistfname.firstname",
2792 				XMCD_PIPESIG, i);
2793 		if (!cdinfo_puts(pp, buf))
2794 			return FALSE;
2795 		if (!cdinfo_puts(pp,
2796 				 cdinfo_dbp->track[i].artistfname.firstname))
2797 			return FALSE;
2798 	    }
2799 	    if (cdinfo_dbp->track[i].artistfname.the != NULL) {
2800 		(void) sprintf(buf, "%strack%d.artistfname.the",
2801 				XMCD_PIPESIG, i);
2802 		if (!cdinfo_puts(pp, buf))
2803 			return FALSE;
2804 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].artistfname.the))
2805 			return FALSE;
2806 	    }
2807 	    if (cdinfo_dbp->track[i].artist != NULL) {
2808 		(void) sprintf(buf, "%strack%d.artist", XMCD_PIPESIG, i);
2809 		if (!cdinfo_puts(pp, buf))
2810 			return FALSE;
2811 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].artist))
2812 			return FALSE;
2813 	    }
2814 	    if (cdinfo_dbp->track[i].title != NULL) {
2815 		(void) sprintf(buf, "%strack%d.title", XMCD_PIPESIG, i);
2816 		if (!cdinfo_puts(pp, buf))
2817 			return FALSE;
2818 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].title))
2819 			return FALSE;
2820 	    }
2821 	    if (cdinfo_dbp->track[i].sorttitle != NULL) {
2822 		(void) sprintf(buf, "%strack%d.sorttitle", XMCD_PIPESIG, i);
2823 		if (!cdinfo_puts(pp, buf))
2824 			return FALSE;
2825 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].sorttitle))
2826 			return FALSE;
2827 	    }
2828 	    if (cdinfo_dbp->track[i].title_the != NULL) {
2829 		(void) sprintf(buf, "%strack%d.title_the", XMCD_PIPESIG, i);
2830 		if (!cdinfo_puts(pp, buf))
2831 			return FALSE;
2832 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].title_the))
2833 			return FALSE;
2834 	    }
2835 	    if (cdinfo_dbp->track[i].year != NULL) {
2836 		(void) sprintf(buf, "%strack%d.year", XMCD_PIPESIG, i);
2837 		if (!cdinfo_puts(pp, buf))
2838 			return FALSE;
2839 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].year))
2840 			return FALSE;
2841 	    }
2842 	    if (cdinfo_dbp->track[i].label != NULL) {
2843 		(void) sprintf(buf, "%strack%d.label", XMCD_PIPESIG, i);
2844 		if (!cdinfo_puts(pp, buf))
2845 			return FALSE;
2846 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].label))
2847 			return FALSE;
2848 	    }
2849 	    if (cdinfo_dbp->track[i].genre != NULL) {
2850 		(void) sprintf(buf, "%strack%d.genre", XMCD_PIPESIG, i);
2851 		if (!cdinfo_puts(pp, buf))
2852 			return FALSE;
2853 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].genre))
2854 			return FALSE;
2855 	    }
2856 	    if (cdinfo_dbp->track[i].genre2 != NULL) {
2857 		(void) sprintf(buf, "%strack%d.genre2", XMCD_PIPESIG, i);
2858 		if (!cdinfo_puts(pp, buf))
2859 			return FALSE;
2860 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].genre2))
2861 			return FALSE;
2862 	    }
2863 	    if (cdinfo_dbp->track[i].bpm != NULL) {
2864 		(void) sprintf(buf, "%strack%d.bpm", XMCD_PIPESIG, i);
2865 		if (!cdinfo_puts(pp, buf))
2866 			return FALSE;
2867 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].bpm))
2868 			return FALSE;
2869 	    }
2870 	    if (cdinfo_dbp->track[i].notes != NULL) {
2871 		(void) sprintf(buf, "%strack%d.notes", XMCD_PIPESIG, i);
2872 		if (!cdinfo_puts(pp, buf))
2873 			return FALSE;
2874 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].notes))
2875 			return FALSE;
2876 		(void) sprintf(buf, "%smulti.end", XMCD_PIPESIG);
2877 		if (!cdinfo_puts(pp, buf))
2878 			return FALSE;
2879 	    }
2880 	    if (cdinfo_dbp->track[i].isrc != NULL) {
2881 		(void) sprintf(buf, "%strack%d.isrc", XMCD_PIPESIG, i);
2882 		if (!cdinfo_puts(pp, buf))
2883 			return FALSE;
2884 		if (!cdinfo_puts(pp, cdinfo_dbp->track[i].isrc))
2885 			return FALSE;
2886 	    }
2887 
2888 	    for (p = cdinfo_dbp->track[i].credit_list; p != NULL; p = p->next){
2889 		(void) sprintf(buf, "%strack%d.credit.new", XMCD_PIPESIG, i);
2890 		if (!cdinfo_puts(pp, buf))
2891 			return FALSE;
2892 		if (p->crinfo.role != NULL) {
2893 			(void) sprintf(buf, "%strack%d.credit.role",
2894 					XMCD_PIPESIG, i);
2895 			if (!cdinfo_puts(pp, buf))
2896 				return FALSE;
2897 			if (!cdinfo_puts(pp, p->crinfo.role->id))
2898 				return FALSE;
2899 		}
2900 		if (p->crinfo.name != NULL) {
2901 			(void) sprintf(buf, "%strack%d.credit.name",
2902 					XMCD_PIPESIG, i);
2903 			if (!cdinfo_puts(pp, buf))
2904 				return FALSE;
2905 			if (!cdinfo_puts(pp, p->crinfo.name))
2906 				return FALSE;
2907 		}
2908 		if (p->crinfo.fullname.dispname != NULL) {
2909 			(void) sprintf(buf,
2910 					"%strack%d.credit.fullname.dispname",
2911 					XMCD_PIPESIG, i);
2912 			if (!cdinfo_puts(pp, buf))
2913 				return FALSE;
2914 			if (!cdinfo_puts(pp, p->crinfo.fullname.dispname))
2915 				return FALSE;
2916 		}
2917 		if (p->crinfo.fullname.lastname != NULL) {
2918 			(void) sprintf(buf,
2919 					"%strack%d.credit.fullname.lastname",
2920 					XMCD_PIPESIG, i);
2921 			if (!cdinfo_puts(pp, buf))
2922 				return FALSE;
2923 			if (!cdinfo_puts(pp, p->crinfo.fullname.lastname))
2924 				return FALSE;
2925 		}
2926 		if (p->crinfo.fullname.firstname != NULL) {
2927 			(void) sprintf(buf,
2928 					"%strack%d.credit.fullname.firstname",
2929 					XMCD_PIPESIG, i);
2930 			if (!cdinfo_puts(pp, buf))
2931 				return FALSE;
2932 			if (!cdinfo_puts(pp, p->crinfo.fullname.firstname))
2933 				return FALSE;
2934 		}
2935 		if (p->crinfo.fullname.the != NULL) {
2936 			(void) sprintf(buf,
2937 					"%strack%d.credit.fullname.the",
2938 					XMCD_PIPESIG, i);
2939 			if (!cdinfo_puts(pp, buf))
2940 				return FALSE;
2941 			if (!cdinfo_puts(pp, p->crinfo.fullname.the))
2942 				return FALSE;
2943 		}
2944 		if (p->notes != NULL) {
2945 			(void) sprintf(buf, "%strack%d.credit.notes",
2946 					XMCD_PIPESIG, i);
2947 			if (!cdinfo_puts(pp, buf))
2948 				return FALSE;
2949 			if (!cdinfo_puts(pp, p->notes))
2950 				return FALSE;
2951 			if (!cdinfo_puts(pp, XMCD_PIPESIG "multi.end"))
2952 				return FALSE;
2953 		}
2954 	    }
2955 	}
2956 
2957 	return TRUE;
2958 }
2959 
2960 
2961 /*
2962  * cdinfo_flushpipe
2963  *	Flush the pipe write cache.
2964  *
2965  * Args:
2966  *	pp - Pointer to the cdinfo_pipe_t structure.
2967  *
2968  * Return:
2969  *	TRUE - success
2970  *	FALSE - failure
2971  */
2972 bool_t
cdinfo_flushpipe(cdinfo_pipe_t * pp)2973 cdinfo_flushpipe(cdinfo_pipe_t *pp)
2974 {
2975 	if (pp == NULL)
2976 		return FALSE;
2977 
2978 	if (pp->w.cache != NULL && pp->w.pos > 0) {
2979 		unsigned char	*p;
2980 		int		resid,
2981 				n = 0;
2982 
2983 		/* Flush write cache */
2984 		p = pp->w.cache;
2985 		for (resid = pp->w.pos; resid > 0; resid -= n) {
2986 			if ((n = write(pp->w.fd, p, resid)) < 0) {
2987 				pp->w.pos = 0;
2988 				return FALSE;
2989 			}
2990 			p += n;
2991 		}
2992 		pp->w.pos = 0;
2993 	}
2994 
2995 	return TRUE;
2996 }
2997 
2998 
2999 /*
3000  * cdinfo_openpipe
3001  *	Create a one-way pipe and set up for buffered I/O
3002  *
3003  * Args:
3004  *	dir - pipe data direction: CDINFO_DATAIN or CDINFO_DATAOUT
3005  *	      (from the perspective of parent process)
3006  *
3007  * Return:
3008  *	A pointer to the cdinfo_pipe_t structure which contains pipe
3009  *	file descriptors and FILE stream pointers.
3010  */
3011 cdinfo_pipe_t *
cdinfo_openpipe(int dir)3012 cdinfo_openpipe(int dir)
3013 {
3014 	int		pfd[2];
3015 	cdinfo_pipe_t	*pp;
3016 
3017 	/* Allocate cdinfo_pipe_t */
3018 	pp = (cdinfo_pipe_t *)(void *) MEM_ALLOC(
3019 		"cdinfo_pipe_t",
3020 		sizeof(cdinfo_pipe_t)
3021 	);
3022 	if (pp == NULL) {
3023 		CDINFO_FATAL(app_data.str_nomemory);
3024 		return NULL;
3025 	}
3026 
3027 	/* Create pipe */
3028 	if (PIPE(pfd) < 0) {
3029 		MEM_FREE(pp);
3030 		return NULL;
3031 	}
3032 
3033 	pp->dir = dir;
3034 	pp->r.fd = pfd[0];
3035 	pp->w.fd = pfd[1];
3036 	pp->r.rw = O_RDONLY;
3037 	pp->w.rw = O_WRONLY;
3038 	pp->r.pos = pp->w.pos = 0;
3039 	pp->r.cnt = pp->w.cnt = 0;
3040 
3041 	/* The caches are allocated on first I/O */
3042 	pp->r.cache = pp->w.cache = NULL;
3043 
3044 	return (pp);
3045 }
3046 
3047 
3048 /*
3049  * cdinfo_closepipe
3050  *	Close the pipe created with cdinfo_openpipe.
3051  *
3052  * Args:
3053  *	pp - Pointer to the cdinfo_pipe_t structure.
3054  *
3055  * Return:
3056  *	TRUE - success
3057  *	FALSE - failure
3058  */
3059 bool_t
cdinfo_closepipe(cdinfo_pipe_t * pp)3060 cdinfo_closepipe(cdinfo_pipe_t *pp)
3061 {
3062 	int	fd;
3063 
3064 	if (pp == NULL)
3065 		return FALSE;
3066 
3067 	if (pp->w.cache != NULL && pp->w.pos > 0) {
3068 		unsigned char	*p;
3069 		int		resid,
3070 				n = 0;
3071 
3072 		/* Flush write cache */
3073 		p = pp->w.cache;
3074 		for (resid = pp->w.pos; resid > 0; resid -= n) {
3075 			if ((n = write(pp->w.fd, p, resid)) < 0) {
3076 				pp->w.pos = 0;
3077 				return FALSE;
3078 			}
3079 			p += n;
3080 		}
3081 		pp->w.pos = 0;
3082 	}
3083 
3084 	/* Close file descriptor */
3085 	if (pp->dir == CDINFO_DATAIN) {
3086 		if (cdinfo_ischild)
3087 			fd = pp->w.fd;
3088 		else
3089 			fd = pp->r.fd;
3090 	}
3091 	else {
3092 		if (cdinfo_ischild)
3093 			fd = pp->r.fd;
3094 		else
3095 			fd = pp->w.fd;
3096 	}
3097 	if (fd != -1)
3098 		(void) close(fd);
3099 
3100 	/* Free cache storage */
3101 	if (pp->r.cache != NULL)
3102 		MEM_FREE(pp->r.cache);
3103 	if (pp->w.cache != NULL)
3104 		MEM_FREE(pp->w.cache);
3105 
3106 	/* Free cdinfo_pipe_t structure */
3107 	MEM_FREE(pp);
3108 
3109 	return TRUE;
3110 }
3111 
3112 
3113 /*
3114  * cdinfo_write_datapipe
3115  *	Write incore CD information into pipe.  Used by child process.
3116  *
3117  * Args:
3118  *	pp - Pointer to the cdinfo_pipe_t structure.
3119  *	s - Pointer to the curstat_t structure.
3120  *
3121  * Return:
3122  *	TRUE - Success
3123  *	FALSE - Failure
3124  */
3125 bool_t
cdinfo_write_datapipe(cdinfo_pipe_t * pp,curstat_t * s)3126 cdinfo_write_datapipe(cdinfo_pipe_t *pp, curstat_t *s)
3127 {
3128 	if (!cdinfo_putctrl_ents(pp))
3129 		return FALSE;
3130 
3131 	if (!cdinfo_putglist_ents(pp))
3132 		return FALSE;
3133 
3134 	if (!cdinfo_putrelist_ents(pp))
3135 		return FALSE;
3136 
3137 	if (!cdinfo_putlanglist_ents(pp))
3138 		return FALSE;
3139 
3140 	if (!cdinfo_putrolist_ents(pp))
3141 		return FALSE;
3142 
3143 	if (!cdinfo_putuserreg_ents(pp))
3144 		return FALSE;
3145 
3146 	if (cdinfo_dbp->matchlist != NULL) {
3147 		/* Fuzzy matches */
3148 		if (!cdinfo_putmatch_ents(pp))
3149 			return FALSE;
3150 	}
3151 	else {
3152 		/* Exact match */
3153 		if (!cdinfo_putdisc_ents(pp))
3154 			return FALSE;
3155 
3156 		if (!cdinfo_puttrack_ents(pp, s))
3157 			return FALSE;
3158 	}
3159 
3160 	/* URLs */
3161 	if (!cdinfo_puturl_ents(pp))
3162 		return FALSE;
3163 
3164 	if (!cdinfo_puts(pp, XMCD_PIPESIG "end"))
3165 		return FALSE;
3166 
3167 	/* Flush write cache in pipe */
3168 	if (!cdinfo_flushpipe(pp))
3169 		return FALSE;
3170 
3171 	return TRUE;
3172 }
3173 
3174 
3175 /*
3176  * cdinfo_read_datapipe
3177  *	Read CDDB data from pipe and update in-core structures.
3178  *	Used by parent process.
3179  *
3180  * Args:
3181  *	pp - Pointer to the cdinfo_pipe_t structure.
3182  *
3183  * Return:
3184  *	TRUE - Success
3185  *	FALSE - Failure
3186  */
3187 bool_t
cdinfo_read_datapipe(cdinfo_pipe_t * pp)3188 cdinfo_read_datapipe(cdinfo_pipe_t *pp)
3189 {
3190 	int		n;
3191 	char		*key;
3192 	static char	buf[2048];
3193 
3194 	n = strlen(XMCD_PIPESIG);
3195 	key = &buf[n];
3196 	while (cdinfo_gets(pp, buf, sizeof(buf))) {
3197 		if (strncmp(buf, XMCD_PIPESIG, n) == 0) {
3198 			buf[strlen(buf) - 1] = '\0';	/* Zap newline */
3199 
3200 			if (strncmp(key, "disc", 4) == 0 &&
3201 			    !cdinfo_getdisc_ents(pp, key + 4)) {
3202 				return FALSE;
3203 			}
3204 			else if (strncmp(key, "track", 5) == 0 &&
3205 				 !cdinfo_gettrack_ents(pp, key + 5)) {
3206 				return FALSE;
3207 			}
3208 			else if (strncmp(key, "url", 3) == 0 &&
3209 				 !cdinfo_geturl_ents(pp, key + 3)) {
3210 				return FALSE;
3211 			}
3212 			else if (strncmp(key, "genre", 5) == 0 &&
3213 				 !cdinfo_getglist_ents(pp, key + 5)) {
3214 				return FALSE;
3215 			}
3216 			else if (strncmp(key, "region", 6) == 0 &&
3217 				 !cdinfo_getrelist_ents(pp, key + 6)) {
3218 				return FALSE;
3219 			}
3220 			else if (strncmp(key, "lang", 4) == 0 &&
3221 				 !cdinfo_getlanglist_ents(pp, key + 4)) {
3222 				return FALSE;
3223 			}
3224 			else if (strncmp(key, "role", 4) == 0 &&
3225 				 !cdinfo_getrolist_ents(pp, key + 4)) {
3226 				return FALSE;
3227 			}
3228 			else if (strncmp(key, "match", 5) == 0 &&
3229 				 !cdinfo_getmatch_ents(pp, key + 5)) {
3230 				return FALSE;
3231 			}
3232 			else if (strncmp(key, "userreg", 7) == 0 &&
3233 				 !cdinfo_getuserreg_ents(pp, key + 7)) {
3234 				return FALSE;
3235 			}
3236 			else if (strncmp(key, "control", 7) == 0 &&
3237 			    !cdinfo_getctrl_ents(pp, key + 7)) {
3238 				return FALSE;
3239 			}
3240 			else if (strcmp(key, "end") == 0) {
3241 				break;
3242 			}
3243 		}
3244 		else {
3245 			/* Unexpected data */
3246 			return FALSE;
3247 		}
3248 	}
3249 
3250 	return TRUE;
3251 }
3252 
3253 
3254 /*
3255  * cdinfo_write_selpipe
3256  *	Write multiple match selection to pipe.  Used by parent process.
3257  *
3258  * Args:
3259  *	pp - Pointer to the cdinfo_pipe_t structure.
3260  *
3261  * Return:
3262  *	TRUE - Success
3263  *	FALSE - Failure
3264  */
3265 bool_t
cdinfo_write_selpipe(cdinfo_pipe_t * pp)3266 cdinfo_write_selpipe(cdinfo_pipe_t *pp)
3267 {
3268 	char	buf[16];
3269 
3270 	if (!cdinfo_puts(pp, XMCD_PIPESIG "match.tag"))
3271 		return FALSE;
3272 
3273 	(void) sprintf(buf, "%ld", cdinfo_dbp->match_tag);
3274 	if (!cdinfo_puts(pp, buf))
3275 		return FALSE;
3276 
3277 	if (!cdinfo_puts(pp, XMCD_PIPESIG "end"))
3278 		return FALSE;
3279 
3280 	/* Flush write cache in pipe */
3281 	if (!cdinfo_flushpipe(pp))
3282 		return FALSE;
3283 
3284 	return TRUE;
3285 }
3286 
3287 
3288 /*
3289  * cdinfo_read_selpipe
3290  *	Read multiple match selection from pipe.  Used by child process.
3291  *
3292  * Args:
3293  *	pp - Pointer to the cdinfo_pipe_t structure.
3294  *
3295  * Return:
3296  *	TRUE - Success
3297  *	FALSE - Failure
3298  */
3299 bool_t
cdinfo_read_selpipe(cdinfo_pipe_t * pp)3300 cdinfo_read_selpipe(cdinfo_pipe_t *pp)
3301 {
3302 	int		n;
3303 	char		*key,
3304 			*str;
3305 	static char	buf[80];
3306 
3307 	n = strlen(XMCD_PIPESIG);
3308 	key = &buf[n];
3309 	while (cdinfo_gets(pp, buf, sizeof(buf))) {
3310 		if (strncmp(buf, XMCD_PIPESIG, n) == 0) {
3311 			buf[strlen(buf) - 1] = '\0';	/* Zap newline */
3312 
3313 			if (strncmp(key, "match.tag", 9) == 0) {
3314 				str = NULL;
3315 				if (!cdinfo_getline(pp, "match.tag", &str))
3316 					return FALSE;
3317 
3318 				if (str != NULL) {
3319 					cdinfo_dbp->match_tag = atol(str);
3320 					MEM_FREE(str);
3321 				}
3322 			}
3323 			else if (strcmp(key, "end") == 0) {
3324 				break;
3325 			}
3326 		}
3327 		else {
3328 			/* Unexpected data */
3329 			return FALSE;
3330 		}
3331 	}
3332 
3333 	return TRUE;
3334 }
3335 
3336 #endif	/* SYNCHRONOUS */
3337 
3338 
3339 /*
3340  * cdinfo_tocstr
3341  *      Return a text string containing the CD's TOC frame offset
3342  *	information suitable for use with the CDDB service.
3343  *
3344  * Args:
3345  *      s - Pointer to the curstat_t structure.
3346  *
3347  * Return:
3348  *      The TOC text string.
3349  */
3350 char *
cdinfo_tocstr(curstat_t * s)3351 cdinfo_tocstr(curstat_t *s)
3352 {
3353 	int		i;
3354 	static char	toc[512];
3355 
3356 	toc[0] = '\0';
3357 
3358 	for (i = 0; i <= (int) s->tot_trks; i++) {
3359 		(void) sprintf(toc, "%s%s%d", toc, (i == 0) ? "" : " ",
3360 				(((s->trkinfo[i].min * 60) +
3361 				   s->trkinfo[i].sec) * FRAME_PER_SEC) +
3362 				   s->trkinfo[i].frame);
3363 	}
3364 
3365 	return (toc);
3366 }
3367 
3368 
3369 /*
3370  * cdinfo_get_str
3371  *	CDDB object string property retrieval handler.
3372  *
3373  * Args:
3374  *	funcname - The name of the CDDB service function
3375  *	func - CDDB service function to call
3376  *	objp - CDDB object
3377  *	datap - Return string property
3378  *
3379  * Return:
3380  *	TRUE - Success
3381  *	FALSE - Failure
3382  */
3383 STATIC bool_t
cdinfo_get_str(char * funcname,CddbResult (* func)(),void * objp,char ** datap)3384 cdinfo_get_str(
3385 	char		*funcname,
3386 	CddbResult	(*func)(),
3387 	void		*objp,
3388 	char		**datap
3389 )
3390 {
3391 	CddbResult	ret;
3392 	char		*str;
3393 
3394 	DBGPRN(DBG_CDI)(errfp, "%s: ", funcname);
3395 	ret = (*func)(objp, &str);
3396 	DBGPRN(DBG_CDI)(errfp, "0x%lx %s\n", ret, str == NULL ? "-" : str);
3397 
3398 	cdinfo_set_errstr(ret);
3399 
3400 	return (util_newstr(datap, str));
3401 }
3402 
3403 
3404 /*
3405  * cdinfo_get_bool
3406  *	CDDB object boolean property retrieval handler.
3407  *
3408  * Args:
3409  *	funcname - The name of the CDDB service function
3410  *	func - CDDB service function to call
3411  *	objp - CDDB object
3412  *	datap - Return boolean property
3413  *
3414  * Return:
3415  *	TRUE - Success
3416  *	FALSE - Failure
3417  */
3418 STATIC bool_t
cdinfo_get_bool(char * funcname,CddbResult (* func)(),void * objp,bool_t * datap)3419 cdinfo_get_bool(
3420 	char		*funcname,
3421 	CddbResult	(*func)(),
3422 	void		*objp,
3423 	bool_t		*datap
3424 )
3425 {
3426 	CddbResult	ret;
3427 	CddbBoolean	b;
3428 
3429 	DBGPRN(DBG_CDI)(errfp, "%s: ", funcname);
3430 	ret = (*func)(objp, &b);
3431 	DBGPRN(DBG_CDI)(errfp, "0x%lx %s\n", ret, b ? "Yes" : "No");
3432 
3433 	cdinfo_set_errstr(ret);
3434 
3435 	*datap = (bool_t) b;
3436 	return TRUE;
3437 }
3438 
3439 
3440 /*
3441  * cdinfo_get_fullname
3442  *	CDDB object fullname property retrieval handler.
3443  *
3444  * Args:
3445  *	funcname - The name of the CDDB service function
3446  *	func - CDDB service function to call
3447  *	objp - CDDB object
3448  *	dispname - Return name string
3449  *	lastname - Return last name string
3450  *	firstname - Return first name string
3451  *	the - Return "the"
3452  *
3453  * Return:
3454  *	TRUE - Success
3455  *	FALSE - Failure
3456  */
3457 STATIC bool_t
cdinfo_get_fullname(char * funcname,CddbResult (* func)(),void * objp,char ** dispname,char ** lastname,char ** firstname,char ** the)3458 cdinfo_get_fullname(
3459 	char		*funcname,
3460 	CddbResult	(*func)(),
3461 	void		*objp,
3462 	char		**dispname,
3463 	char		**lastname,
3464 	char		**firstname,
3465 	char		**the
3466 )
3467 {
3468 	CddbResult	ret;
3469 	CddbFullNamePtr	f;
3470 
3471 	DBGPRN(DBG_CDI)(errfp, "%s: ", funcname);
3472 	ret = (*func)(objp, &f);
3473 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
3474 
3475 	cdinfo_set_errstr(ret);
3476 
3477 	if (ret != Cddb_OK || f == NULL) {
3478 		*dispname = *lastname = *firstname = *the = NULL;
3479 	}
3480 	else {
3481 		if (!cdinfo_get_str("    CddbFullName_GetName",
3482 				      CddbFullName_GetName, f,
3483 				      dispname)) {
3484 			CddbReleaseObject(f);
3485 			return FALSE;
3486 		}
3487 
3488 		if (!cdinfo_get_str("    CddbFullName_GetLastName",
3489 				      CddbFullName_GetLastName, f,
3490 				      lastname)) {
3491 			CddbReleaseObject(f);
3492 			return FALSE;
3493 		}
3494 		if (!cdinfo_get_str("    CddbFullName_GetFirstName",
3495 				      CddbFullName_GetFirstName, f,
3496 				      firstname)) {
3497 			CddbReleaseObject(f);
3498 			return FALSE;
3499 		}
3500 		if (!cdinfo_get_str("    CddbFullName_GetThe",
3501 				      CddbFullName_GetThe, f, the)) {
3502 			CddbReleaseObject(f);
3503 			return FALSE;
3504 		}
3505 		CddbReleaseObject(f);
3506 	}
3507 	return TRUE;
3508 }
3509 
3510 
3511 /*
3512  * cdinfo_put_str
3513  *	CDDB object string property put handler.
3514  *
3515  * Args:
3516  *	funcname - The name of the CDDB service function
3517  *	func - CDDB service function to call
3518  *	objp - CDDB object
3519  *	datap - String property to put
3520  *
3521  * Return:
3522  *	TRUE - Success
3523  *	FALSE - Failure
3524  */
3525 STATIC bool_t
cdinfo_put_str(char * funcname,CddbResult (* func)(),void * objp,char * datap)3526 cdinfo_put_str(
3527 	char		*funcname,
3528 	CddbResult	(*func)(),
3529 	void		*objp,
3530 	char		*datap
3531 )
3532 {
3533 	CddbResult	ret;
3534 
3535 	DBGPRN(DBG_CDI)(errfp, "%s: ", funcname);
3536 	ret = (*func)(objp, (CddbStr) datap);
3537 	DBGPRN(DBG_CDI)(errfp, "0x%lx", ret);
3538 
3539 	cdinfo_set_errstr(ret);
3540 
3541 	if (util_strstr(funcname, "Password") == NULL) {
3542 		DBGPRN(DBG_CDI)(errfp, " %s\n", datap == NULL ? "-" : datap);
3543 	}
3544 	else {
3545 		/* Don't show any password related strings in debug output */
3546 		DBGPRN(DBG_CDI)(errfp, "\n");
3547 	}
3548 
3549 	return (ret == Cddb_OK);
3550 }
3551 
3552 
3553 /*
3554  * cdinfo_put_fullname
3555  *	CDDB object fullname property put handler.
3556  *
3557  * Args:
3558  *	funcname - The name of the CDDB service function
3559  *	func - CDDB service function to call
3560  *	objp - CDDB object
3561  *	dispname - Return name string
3562  *	lastname - Return last name string
3563  *	firstname - Return first name string
3564  *	the - Return "the"
3565  *
3566  * Return:
3567  *	TRUE - Success
3568  *	FALSE - Failure
3569  */
3570 STATIC bool_t
cdinfo_put_fullname(char * funcname,CddbResult (* func)(),void * objp,char * dispname,char * lastname,char * firstname,char * the)3571 cdinfo_put_fullname(
3572 	char		*funcname,
3573 	CddbResult	(*func)(),
3574 	void		*objp,
3575 	char		*dispname,
3576 	char		*lastname,
3577 	char		*firstname,
3578 	char		*the
3579 )
3580 {
3581 	CddbResult	ret;
3582 	CddbFullNamePtr	f;
3583 
3584 	if ((f = (CddbFullNamePtr) CddbCreateObject(CddbFullNameType)) == NULL)
3585 		return FALSE;
3586 
3587 	if (!cdinfo_put_str("    CddbFullName_PutName",
3588 			      CddbFullName_PutName, f, dispname)) {
3589 		CddbReleaseObject(f);
3590 		return FALSE;
3591 	}
3592 
3593 	if (!cdinfo_put_str("    CddbFullName_PutLastName",
3594 			      CddbFullName_PutLastName, f, lastname)) {
3595 		CddbReleaseObject(f);
3596 		return FALSE;
3597 	}
3598 	if (!cdinfo_put_str("    CddbFullName_PutFirstName",
3599 			      CddbFullName_PutFirstName, f, firstname)) {
3600 		CddbReleaseObject(f);
3601 		return FALSE;
3602 	}
3603 	if (!cdinfo_put_str("    CddbFullName_PutThe",
3604 			      CddbFullName_PutThe, f, the)) {
3605 		CddbReleaseObject(f);
3606 		return FALSE;
3607 	}
3608 
3609 	DBGPRN(DBG_CDI)(errfp, "%s: ", funcname);
3610 	ret = (*func)(objp, f);
3611 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
3612 
3613 	cdinfo_set_errstr(ret);
3614 
3615 	CddbReleaseObject(f);
3616 	return (ret == Cddb_OK);
3617 }
3618 
3619 
3620 /*
3621  * cdinfo_check_userreg
3622  *	Check CDDB user registration and update structures
3623  *
3624  * Args:
3625  *	cp - cdinfo_cddb_t pointer for the CDDB connection
3626  *
3627  * Return:
3628  *	TRUE - success
3629  *	FALSE - failure
3630  */
3631 STATIC bool_t
cdinfo_check_userreg(cdinfo_cddb_t * cp)3632 cdinfo_check_userreg(cdinfo_cddb_t *cp)
3633 {
3634 	CddbUserInfoPtr	uip = NULL;
3635 	CddbResult	ret;
3636 	CddbBoolean	registered = 0;
3637 	bool_t		yn;
3638 
3639 	/* Check if user is registered */
3640 	DBGPRN(DBG_CDI)(errfp, "CddbControl_IsRegistered: ");
3641 	ret = CddbControl_IsRegistered(cp->ctrlp, 0, &registered);
3642 	DBGPRN(DBG_CDI)(errfp, "0x%lx %s\n", ret, registered ? "Yes" : "No");
3643 
3644 	cdinfo_set_errstr(ret);
3645 
3646 	if (!registered) {
3647 		DBGPRN(DBG_CDI)(errfp, "User is not registered with CDDB.\n");
3648 		return FALSE;
3649 	}
3650 
3651 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetUserInfo: ");
3652 	ret = CddbControl_GetUserInfo(cp->ctrlp, &uip);
3653 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
3654 
3655 	cdinfo_set_errstr(ret);
3656 
3657 	if (ret != Cddb_OK || uip == NULL)
3658 		return FALSE;
3659 
3660 	if (!cdinfo_get_str("CddbUserInfo_GetUserHandle",
3661 			      CddbUserInfo_GetUserHandle, uip,
3662 			      &cdinfo_dbp->userreg.handle)) {
3663 		CddbReleaseObject(uip);
3664 		return FALSE;
3665 	}
3666 
3667 	DBGPRN(DBG_CDI)(errfp, "User \"%s\" is registered.\n",
3668 			cdinfo_dbp->userreg.handle == NULL ?
3669 			"(null)" : cdinfo_dbp->userreg.handle);
3670 
3671 	if (!cdinfo_get_str("CddbUserInfo_GetPasswordHint",
3672 			      CddbUserInfo_GetPasswordHint, uip,
3673 			      &cdinfo_dbp->userreg.hint)) {
3674 		CddbReleaseObject(uip);
3675 		return FALSE;
3676 	}
3677 	if (!cdinfo_get_str("CddbUserInfo_GetEmailAddress",
3678 			      CddbUserInfo_GetEmailAddress, uip,
3679 			      &cdinfo_dbp->userreg.email)) {
3680 		CddbReleaseObject(uip);
3681 		return FALSE;
3682 	}
3683 	if (!cdinfo_get_str("CddbUserInfo_GetRegionId",
3684 			      CddbUserInfo_GetRegionId, uip,
3685 			      &cdinfo_dbp->userreg.region)) {
3686 		CddbReleaseObject(uip);
3687 		return FALSE;
3688 	}
3689 	if (!cdinfo_get_str("CddbUserInfo_GetPostalCode",
3690 			      CddbUserInfo_GetPostalCode, uip,
3691 			      &cdinfo_dbp->userreg.postal)) {
3692 		CddbReleaseObject(uip);
3693 		return FALSE;
3694 	}
3695 	if (!cdinfo_get_str("CddbUserInfo_GetAge",
3696 			      CddbUserInfo_GetAge, uip,
3697 			      &cdinfo_dbp->userreg.age)) {
3698 		CddbReleaseObject(uip);
3699 		return FALSE;
3700 	}
3701 	if (!cdinfo_get_str("CddbUserInfo_GetSex",
3702 			      CddbUserInfo_GetSex, uip,
3703 			      &cdinfo_dbp->userreg.gender)) {
3704 		CddbReleaseObject(uip);
3705 		return FALSE;
3706 	}
3707 	if (!cdinfo_get_bool("CddbUserInfo_GetAllowEmail",
3708 			       CddbUserInfo_GetAllowEmail, uip, &yn)) {
3709 		CddbReleaseObject(uip);
3710 		return FALSE;
3711 	}
3712 	cdinfo_dbp->userreg.allowemail = (bool_t) yn;
3713 	if (!cdinfo_get_bool("CddbUserInfo_GetAllowStats",
3714 			       CddbUserInfo_GetAllowStats, uip, &yn)) {
3715 		CddbReleaseObject(uip);
3716 		return FALSE;
3717 	}
3718 	cdinfo_dbp->userreg.allowstats = (bool_t) yn;
3719 
3720 	CddbReleaseObject(uip);
3721 	return TRUE;
3722 }
3723 
3724 
3725 /*
3726  * cdinfo_allocinit_genre
3727  *	CDDB genre information initialization routine
3728  *
3729  * Args:
3730  *	genrep - CddbGenre object
3731  *	ret - cddb_genre_t return structure
3732  *	sub - Whether a sub-genre is being processed
3733  *
3734  * Return:
3735  *	TRUE - Success
3736  *	FALSE - Failure
3737  */
3738 STATIC bool_t
cdinfo_allocinit_genre(CddbGenrePtr genrep,cdinfo_genre_t ** ret,bool_t sub)3739 cdinfo_allocinit_genre(CddbGenrePtr genrep, cdinfo_genre_t **ret, bool_t sub)
3740 {
3741 	cdinfo_genre_t	*p;
3742 
3743 	*ret = NULL;
3744 
3745 	p = (cdinfo_genre_t *)(void *) MEM_ALLOC("genre",
3746 		sizeof(cdinfo_genre_t)
3747 	);
3748 	if (p == NULL) {
3749 		CDINFO_FATAL(app_data.str_nomemory);
3750 		return FALSE;
3751 	}
3752 	(void) memset(p, 0, sizeof(cdinfo_genre_t));
3753 
3754 	/* Genre ID */
3755 	if (!cdinfo_get_str(sub ? "    CddbGenre_GetId" :
3756 				    "  CddbGenre_GetId",
3757 			      CddbGenre_GetId,
3758 			      genrep, &p->id)) {
3759 		return FALSE;
3760 	}
3761 
3762 	/* Genre name */
3763 	if (!cdinfo_get_str(sub ? "    CddbGenre_GetName" :
3764 				    "  CddbGenre_GetName",
3765 			      CddbGenre_GetName,
3766 			      genrep, &p->name)) {
3767 		return FALSE;
3768 	}
3769 
3770 	*ret = p;
3771 	return TRUE;
3772 }
3773 
3774 
3775 /*
3776  * cdinfo_allocinit_region
3777  *	CDDB region information initialization routine
3778  *
3779  * Args:
3780  *	regionp - CddbRegion object
3781  *	ret - cddb_region_t return structure
3782  *
3783  * Return:
3784  *	TRUE - Success
3785  *	FALSE - Failure
3786  */
3787 STATIC bool_t
cdinfo_allocinit_region(CddbRegionPtr regionp,cdinfo_region_t ** ret)3788 cdinfo_allocinit_region(CddbRegionPtr regionp, cdinfo_region_t **ret)
3789 {
3790 	cdinfo_region_t	*p;
3791 
3792 	*ret = NULL;
3793 
3794 	p = (cdinfo_region_t *)(void *) MEM_ALLOC("region",
3795 		sizeof(cdinfo_region_t)
3796 	);
3797 	if (p == NULL) {
3798 		CDINFO_FATAL(app_data.str_nomemory);
3799 		return FALSE;
3800 	}
3801 	(void) memset(p, 0, sizeof(cdinfo_region_t));
3802 
3803 	/* Region ID */
3804 	if (!cdinfo_get_str("  CddbRegion_GetId",
3805 			      CddbRegion_GetId,
3806 			      regionp, &p->id)) {
3807 		return FALSE;
3808 	}
3809 
3810 	/* Region name */
3811 	if (!cdinfo_get_str("  CddbRegion_GetName",
3812 			      CddbRegion_GetName,
3813 			      regionp, &p->name)) {
3814 		return FALSE;
3815 	}
3816 
3817 	*ret = p;
3818 	return TRUE;
3819 }
3820 
3821 
3822 /*
3823  * cdinfo_allocinit_lang
3824  *	CDDB language information initialization routine
3825  *
3826  * Args:
3827  *	langp - CddbLanguage object
3828  *	ret - cddb_lang_t return structure
3829  *
3830  * Return:
3831  *	TRUE - Success
3832  *	FALSE - Failure
3833  */
3834 STATIC bool_t
cdinfo_allocinit_lang(CddbLanguagePtr langp,cdinfo_lang_t ** ret)3835 cdinfo_allocinit_lang(CddbLanguagePtr langp, cdinfo_lang_t **ret)
3836 {
3837 	cdinfo_lang_t	*p;
3838 
3839 	*ret = NULL;
3840 
3841 	p = (cdinfo_lang_t *)(void *) MEM_ALLOC("lang",
3842 		sizeof(cdinfo_lang_t)
3843 	);
3844 	if (p == NULL) {
3845 		CDINFO_FATAL(app_data.str_nomemory);
3846 		return FALSE;
3847 	}
3848 	(void) memset(p, 0, sizeof(cdinfo_lang_t));
3849 
3850 	/* Language ID */
3851 	if (!cdinfo_get_str("  CddbLanguage_GetId",
3852 			      CddbLanguage_GetId,
3853 			      langp, &p->id)) {
3854 		return FALSE;
3855 	}
3856 
3857 	/* Language name */
3858 	if (!cdinfo_get_str("  CddbLanguage_GetName",
3859 			      CddbLanguage_GetName,
3860 			      langp, &p->name)) {
3861 		return FALSE;
3862 	}
3863 
3864 	*ret = p;
3865 	return TRUE;
3866 }
3867 
3868 
3869 /*
3870  * cdinfo_allocinit_role
3871  *	CDDB role information initialization routine
3872  *
3873  * Args:
3874  *	rolep - CddbRole object
3875  *	ret - cddb_role_t return structure
3876  *
3877  * Return:
3878  *	TRUE - Success
3879  *	FALSE - Failure
3880  */
3881 STATIC bool_t
cdinfo_allocinit_role(CddbRolePtr rolep,cdinfo_role_t ** ret)3882 cdinfo_allocinit_role(CddbRolePtr rolep, cdinfo_role_t **ret)
3883 {
3884 	cdinfo_role_t	*p;
3885 
3886 	*ret = NULL;
3887 
3888 	p = (cdinfo_role_t *)(void *) MEM_ALLOC("role",
3889 		sizeof(cdinfo_role_t)
3890 	);
3891 	if (p == NULL) {
3892 		CDINFO_FATAL(app_data.str_nomemory);
3893 		return FALSE;
3894 	}
3895 	(void) memset(p, 0, sizeof(cdinfo_role_t));
3896 
3897 	/* Role ID */
3898 	if (!cdinfo_get_str("    CddbRole_GetId",
3899 			      CddbRole_GetId, rolep, &p->id)) {
3900 		return FALSE;
3901 	}
3902 
3903 	/* Role name */
3904 	if (!cdinfo_get_str("    CddbRole_GetName",
3905 			      CddbRole_GetName, rolep, &p->name)) {
3906 		return FALSE;
3907 	}
3908 
3909 	*ret = p;
3910 	return TRUE;
3911 }
3912 
3913 
3914 /*
3915  * cdinfo_discinfo_query
3916  *	Query CDDB for album information
3917  *
3918  * Args:
3919  *	discp - CddbDisc object
3920  *
3921  * Return:
3922  *	TRUE - Success
3923  *	FALSE - Failure
3924  */
3925 STATIC bool_t
cdinfo_discinfo_query(CddbDiscPtr discp)3926 cdinfo_discinfo_query(CddbDiscPtr discp)
3927 {
3928 	CddbResult		ret;
3929 	CddbCreditPtr		credp = NULL;
3930 	CddbSegmentPtr		segp = NULL;
3931 	char			*str;
3932 	long			ncreds,
3933 				nsegs;
3934 	int			i,
3935 				j;
3936 	cdinfo_genre_t		*gp,
3937 				*sgp;
3938 	cdinfo_credit_t		*p,
3939 				*q;
3940 	cdinfo_segment_t	*r,
3941 				*s;
3942 	cdinfo_role_t		*rp;
3943 
3944 	/* Disc artist */
3945 	if (!cdinfo_get_str("CddbDisc_GetArtist",
3946 				CddbDisc_GetArtist,
3947 				discp, &cdinfo_dbp->disc.artist)) {
3948 		return FALSE;
3949 	}
3950 
3951 	/* Disc title */
3952 	if (!cdinfo_get_str("CddbDisc_GetTitle",
3953 				CddbDisc_GetTitle,
3954 				discp, &cdinfo_dbp->disc.title)) {
3955 		return FALSE;
3956 	}
3957 
3958 	/* Artist full name */
3959 	if (!cdinfo_get_fullname("CddbDisc_GetArtistFullName",
3960 				CddbDisc_GetArtistFullName,
3961 				discp,
3962 				&cdinfo_dbp->disc.artistfname.dispname,
3963 				&cdinfo_dbp->disc.artistfname.lastname,
3964 				&cdinfo_dbp->disc.artistfname.firstname,
3965 				&cdinfo_dbp->disc.artistfname.the)) {
3966 		return FALSE;
3967 	}
3968 
3969 	/* Disc sort title */
3970 	if (!cdinfo_get_str("CddbDisc_GetTitleSort",
3971 				CddbDisc_GetTitleSort,
3972 				discp, &cdinfo_dbp->disc.sorttitle)) {
3973 		return FALSE;
3974 	}
3975 
3976 	/* Disc sort title */
3977 	if (!cdinfo_get_str("CddbDisc_GetTitleThe",
3978 				CddbDisc_GetTitleThe,
3979 				discp, &cdinfo_dbp->disc.title_the)) {
3980 		return FALSE;
3981 	}
3982 
3983 	/* Year */
3984 	if (!cdinfo_get_str("CddbDisc_GetYear",
3985 				CddbDisc_GetYear,
3986 				discp, &cdinfo_dbp->disc.year)) {
3987 		return FALSE;
3988 	}
3989 
3990 	/* Label */
3991 	if (!cdinfo_get_str("CddbDisc_GetLabel",
3992 				CddbDisc_GetLabel,
3993 				discp, &cdinfo_dbp->disc.label)) {
3994 		return FALSE;
3995 	}
3996 
3997 	/* Compilation */
3998 	if (!cdinfo_get_bool("CddbDisc_GetCompilation",
3999 				CddbDisc_GetCompilation,
4000 				discp, &cdinfo_dbp->disc.compilation)) {
4001 		return FALSE;
4002 	}
4003 
4004 	/* Genre */
4005 	if (!cdinfo_get_str("CddbDisc_GetGenreId",
4006 				CddbDisc_GetGenreId,
4007 				discp, &cdinfo_dbp->disc.genre)) {
4008 		return FALSE;
4009 	}
4010 	gp = cdinfo_genre(cdinfo_dbp->disc.genre);
4011 	if (gp != NULL && gp->parent == NULL) {
4012 		/* Illegal: the primary genre is set to a genre category.
4013 		 * "Fix" it by setting it to the category's "General"
4014 		 * subgenre.  If not found, then set it to the first
4015 		 * subgenre.
4016 		 */
4017 		for (sgp = gp->child; sgp != NULL; sgp = sgp->next) {
4018 			if (sgp->name != NULL &&
4019 			    strncmp(sgp->name, "General ", 8) == 0) {
4020 				if (!util_newstr(&cdinfo_dbp->disc.genre,
4021 						 sgp->id)) {
4022 					CDINFO_FATAL(app_data.str_nomemory);
4023 					return FALSE;
4024 				}
4025 				break;
4026 			}
4027 		}
4028 		if (sgp == NULL) {
4029 			if (gp->child != NULL) {
4030 				if (!util_newstr(&cdinfo_dbp->disc.genre,
4031 						 gp->child->id)) {
4032 				    CDINFO_FATAL(app_data.str_nomemory);
4033 				    return FALSE;
4034 				}
4035 			}
4036 			else {
4037 				MEM_FREE(cdinfo_dbp->disc.genre);
4038 				cdinfo_dbp->disc.genre = NULL;
4039 			}
4040 		}
4041 	}
4042 
4043 	/* Secondary Genre */
4044 	if (!cdinfo_get_str("CddbDisc_GetSecondaryGenreId",
4045 				CddbDisc_GetSecondaryGenreId,
4046 				discp, &cdinfo_dbp->disc.genre2)) {
4047 		return FALSE;
4048 	}
4049 	gp = cdinfo_genre(cdinfo_dbp->disc.genre2);
4050 	if (gp != NULL && gp->parent == NULL) {
4051 		/* Illegal: the secondary genre is set to a genre category.
4052 		 * "Fix" it by setting it to the category's "General"
4053 		 * subgenre.  If not found, then set it to the first
4054 		 * subgenre.
4055 		 */
4056 		for (sgp = gp->child; sgp != NULL; sgp = sgp->next) {
4057 			if (sgp->name != NULL &&
4058 			    strncmp(sgp->name, "General ", 8) == 0) {
4059 				if (!util_newstr(&cdinfo_dbp->disc.genre2,
4060 						 sgp->id)) {
4061 					CDINFO_FATAL(app_data.str_nomemory);
4062 					return FALSE;
4063 				}
4064 				break;
4065 			}
4066 		}
4067 		if (sgp == NULL) {
4068 			if (gp->child != NULL) {
4069 				if (!util_newstr(&cdinfo_dbp->disc.genre2,
4070 						 gp->child->id)) {
4071 				    CDINFO_FATAL(app_data.str_nomemory);
4072 				    return FALSE;
4073 				}
4074 			}
4075 			else {
4076 				MEM_FREE(cdinfo_dbp->disc.genre2);
4077 				cdinfo_dbp->disc.genre2 = NULL;
4078 			}
4079 		}
4080 	}
4081 
4082 	/* Disc number in set */
4083 	if (!cdinfo_get_str("CddbDisc_GetNumberInSet",
4084 				CddbDisc_GetNumberInSet,
4085 				discp, &cdinfo_dbp->disc.dnum)) {
4086 		return FALSE;
4087 	}
4088 
4089 	/* Total number in set */
4090 	if (!cdinfo_get_str("CddbDisc_GetTotalInSet",
4091 				CddbDisc_GetTotalInSet,
4092 				discp, &cdinfo_dbp->disc.tnum)) {
4093 		return FALSE;
4094 	}
4095 
4096 	/* Region */
4097 	if (!cdinfo_get_str("CddbDisc_GetRegionId",
4098 				CddbDisc_GetRegionId,
4099 				discp, &cdinfo_dbp->disc.region)) {
4100 		return FALSE;
4101 	}
4102 
4103 	/* Language ID */
4104 	if (!cdinfo_get_str("CddbDisc_GetLanguageId",
4105 				CddbDisc_GetLanguageId,
4106 				discp, &cdinfo_dbp->disc.lang)) {
4107 		return FALSE;
4108 	}
4109 
4110 	/* Notes */
4111 	if (!cdinfo_get_str("CddbDisc_GetNotes",
4112 				CddbDisc_GetNotes,
4113 				discp, &cdinfo_dbp->disc.notes)) {
4114 		return FALSE;
4115 	}
4116 
4117 	/* Media ID */
4118 	if (!cdinfo_get_str("CddbDisc_GetMediaId",
4119 				CddbDisc_GetMediaId,
4120 				discp, &cdinfo_dbp->disc.mediaid)) {
4121 		return FALSE;
4122 	}
4123 
4124 	/* Media unique ID */
4125 	if (!cdinfo_get_str("CddbDisc_GetMuiId",
4126 				CddbDisc_GetMuiId,
4127 				discp, &cdinfo_dbp->disc.muiid)) {
4128 		return FALSE;
4129 	}
4130 
4131 	/* Title unique ID */
4132 	if (!cdinfo_get_str("CddbDisc_GetTitleUId",
4133 				CddbDisc_GetTitleUId,
4134 				discp, &cdinfo_dbp->disc.titleuid)) {
4135 		return FALSE;
4136 	}
4137 
4138 	/* Revision */
4139 	if (!cdinfo_get_str("CddbDisc_GetRevision",
4140 				CddbDisc_GetRevision,
4141 				discp, &cdinfo_dbp->disc.revision)) {
4142 		return FALSE;
4143 	}
4144 
4145 	/* Revision Tag */
4146 	if (!cdinfo_get_str("CddbDisc_GetRevisionTag",
4147 				CddbDisc_GetRevisionTag,
4148 				discp, &cdinfo_dbp->disc.revtag)) {
4149 		return FALSE;
4150 	}
4151 
4152 	/* Certifier */
4153 	if (!cdinfo_get_str("CddbDisc_GetCertifier",
4154 				CddbDisc_GetCertifier,
4155 				discp, &cdinfo_dbp->disc.certifier)) {
4156 		return FALSE;
4157 	}
4158 
4159 	/* Disc Credits */
4160 	DBGPRN(DBG_CDI)(errfp, "CddbDisc_GetNumCredits: ");
4161 	ret = CddbDisc_GetNumCredits(discp, &ncreds);
4162 	DBGPRN(DBG_CDI)(errfp, "0x%lx %ld credits\n", ret, ncreds);
4163 
4164 	cdinfo_set_errstr(ret);
4165 
4166 	q = NULL;
4167 	for (i = 0; i < (int) ncreds; i++) {
4168 		DBGPRN(DBG_CDI)(errfp, "CddbDisc_GetCredit[%02d]: ", i+1);
4169 		ret = CddbDisc_GetCredit(discp, (long) (i+1), &credp);
4170 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
4171 
4172 		if (ret != Cddb_OK)
4173 			continue;
4174 
4175 		/* Allocate a credit structure */
4176 		p = (cdinfo_credit_t *) MEM_ALLOC(
4177 			"cdinfo_credit_t",
4178 			sizeof(cdinfo_credit_t)
4179 		);
4180 		if (p == NULL) {
4181 			CDINFO_FATAL(app_data.str_nomemory);
4182 			return FALSE;
4183 		}
4184 		(void) memset(p, 0, sizeof(cdinfo_credit_t));
4185 
4186 		/* Credit role */
4187 		str = NULL;
4188 		if (!cdinfo_get_str("  CddbCredit_GetId",
4189 				      CddbCredit_GetId, credp, &str)) {
4190 			MEM_FREE(p);
4191 			return FALSE;
4192 		}
4193 		rp = cdinfo_role(str);
4194 		if (rp->parent == NULL) {
4195 			/* Illegal: role set to the category role
4196 			 * "Fix" it by setting the role to the
4197 			 * first subrole of that category instead.
4198 			 * If for some reason there are no subroles
4199 			 * then the child would be NULL and thus the
4200 			 * role would be "None -> None".
4201 			 */
4202 			rp = rp->child;
4203 		}
4204 		p->crinfo.role = rp;
4205 		MEM_FREE(str);
4206 		str = NULL;
4207 
4208 		/* Credit name */
4209 		if (!cdinfo_get_str("  CddbCredit_GetName",
4210 				      CddbCredit_GetName,
4211 				      credp, &p->crinfo.name)) {
4212 			MEM_FREE(p);
4213 			return FALSE;
4214 		}
4215 
4216 		/* Credit full name */
4217 		if (!cdinfo_get_fullname("  CddbCredit_GetFullName",
4218 					CddbCredit_GetFullName,
4219 					credp,
4220 					&p->crinfo.fullname.dispname,
4221 					&p->crinfo.fullname.lastname,
4222 					&p->crinfo.fullname.firstname,
4223 					&p->crinfo.fullname.the)) {
4224 			MEM_FREE(p);
4225 			return FALSE;
4226 		}
4227 
4228 		/* Credit notes */
4229 		if (!cdinfo_get_str("  CddbCredit_GetNotes",
4230 				      CddbCredit_GetNotes,
4231 				      credp, &p->notes)) {
4232 			MEM_FREE(p);
4233 			return FALSE;
4234 		}
4235 
4236 		CddbReleaseObject(credp);
4237 
4238 		if (cdinfo_dbp->disc.credit_list == NULL) {
4239 			cdinfo_dbp->disc.credit_list = p;
4240 			p->prev = NULL;
4241 		}
4242 		else {
4243 			q->next = p;
4244 			p->prev = q;
4245 		}
4246 		q = p;
4247 		p->next = NULL;
4248 	}
4249 
4250 	/* Segments */
4251 	DBGPRN(DBG_CDI)(errfp, "CddbDisc_GetNumSegments: ");
4252 	ret = CddbDisc_GetNumSegments(discp, &nsegs);
4253 	DBGPRN(DBG_CDI)(errfp, "0x%lx %ld segments\n", ret, nsegs);
4254 
4255 	cdinfo_set_errstr(ret);
4256 
4257 	s = NULL;
4258 	for (i = 0; i < (int) nsegs; i++) {
4259 		DBGPRN(DBG_CDI)(errfp, "CddbDisc_GetSegment[%02d]: ", i+1);
4260 		ret = CddbDisc_GetSegment(discp, (long) (i+1), &segp);
4261 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
4262 
4263 		if (ret != Cddb_OK)
4264 			continue;
4265 
4266 		/* Allocate a segment structure */
4267 		r = (cdinfo_segment_t *) MEM_ALLOC(
4268 			"cdinfo_segment_t",
4269 			sizeof(cdinfo_segment_t)
4270 		);
4271 		if (r == NULL) {
4272 			CDINFO_FATAL(app_data.str_nomemory);
4273 			return FALSE;
4274 		}
4275 		(void) memset(r, 0, sizeof(cdinfo_segment_t));
4276 
4277 		/* Segment name */
4278 		if (!cdinfo_get_str("  CddbSegment_GetName",
4279 				      CddbSegment_GetName,
4280 				      segp, &r->name)) {
4281 			MEM_FREE(r);
4282 			return FALSE;
4283 		}
4284 
4285 		/* Segment notes */
4286 		if (!cdinfo_get_str("  CddbSegment_GetNotes",
4287 				      CddbSegment_GetNotes,
4288 				      segp, &r->notes)) {
4289 			MEM_FREE(r);
4290 			return FALSE;
4291 		}
4292 
4293 		/* Segment start track */
4294 		if (!cdinfo_get_str("  CddbSegment_GetStartTrack",
4295 				      CddbSegment_GetStartTrack,
4296 				      segp, &r->start_track)) {
4297 			MEM_FREE(r);
4298 			return FALSE;
4299 		}
4300 
4301 		/* Segment start frame */
4302 		if (!cdinfo_get_str("  CddbSegment_GetStartFrame",
4303 				      CddbSegment_GetStartFrame,
4304 				      segp, &r->start_frame)) {
4305 			MEM_FREE(r);
4306 			return FALSE;
4307 		}
4308 
4309 		/* Segment end track */
4310 		if (!cdinfo_get_str("  CddbSegment_GetEndTrack",
4311 				      CddbSegment_GetEndTrack,
4312 				      segp, &r->end_track)) {
4313 			MEM_FREE(r);
4314 			return FALSE;
4315 		}
4316 
4317 		/* Segment end frame */
4318 		if (!cdinfo_get_str("  CddbSegment_GetEndFrame",
4319 				      CddbSegment_GetEndFrame,
4320 				      segp, &r->end_frame)) {
4321 			MEM_FREE(r);
4322 			return FALSE;
4323 		}
4324 
4325 		/* Segment Credits */
4326 		DBGPRN(DBG_CDI)(errfp, "  CddbSegment_GetNumCredits: ");
4327 		ret = CddbSegment_GetNumCredits(segp, &ncreds);
4328 		DBGPRN(DBG_CDI)(errfp, "0x%lx %ld credits\n", ret, ncreds);
4329 
4330 		cdinfo_set_errstr(ret);
4331 
4332 		q = NULL;
4333 		for (j = 0; j < (int) ncreds; j++) {
4334 			DBGPRN(DBG_CDI)(errfp,
4335 				"CddbSegment_GetCredit[%02d]: ", j+1);
4336 			ret = CddbSegment_GetCredit(segp, (long) (j+1),
4337 						    &credp);
4338 			DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
4339 
4340 			if (ret != Cddb_OK)
4341 				continue;
4342 
4343 			/* Allocate a credit structure */
4344 			p = (cdinfo_credit_t *) MEM_ALLOC(
4345 				"cdinfo_credit_t",
4346 				sizeof(cdinfo_credit_t)
4347 			);
4348 			if (p == NULL) {
4349 				CDINFO_FATAL(app_data.str_nomemory);
4350 				return FALSE;
4351 			}
4352 			(void) memset(p, 0, sizeof(cdinfo_credit_t));
4353 
4354 			/* Credit role */
4355 			str = NULL;
4356 			if (!cdinfo_get_str("    CddbCredit_GetId",
4357 					      CddbCredit_GetId, credp,
4358 					      &str)) {
4359 				MEM_FREE(p);
4360 				return FALSE;
4361 			}
4362 			rp = cdinfo_role(str);
4363 			if (rp->parent == NULL) {
4364 				/* Illegal: role set to the category role
4365 				 * "Fix" it by setting the role to the
4366 				 * first subrole of that category instead.
4367 				 * If for some reason there are no subroles
4368 				 * then the child would be NULL and thus the
4369 				 * role would be "None -> None".
4370 				 */
4371 				rp = rp->child;
4372 			}
4373 			p->crinfo.role = rp;
4374 			MEM_FREE(str);
4375 			str = NULL;
4376 
4377 			/* Credit name */
4378 			if (!cdinfo_get_str("    CddbCredit_GetName",
4379 					      CddbCredit_GetName,
4380 					      credp, &p->crinfo.name)) {
4381 				MEM_FREE(p);
4382 				return FALSE;
4383 			}
4384 
4385 			/* Credit full name */
4386 			if (!cdinfo_get_fullname("    CddbCredit_GetFullName",
4387 					CddbCredit_GetFullName,
4388 					credp,
4389 					&p->crinfo.fullname.dispname,
4390 					&p->crinfo.fullname.lastname,
4391 					&p->crinfo.fullname.firstname,
4392 					&p->crinfo.fullname.the)) {
4393 				MEM_FREE(p);
4394 				return FALSE;
4395 			}
4396 
4397 			/* Credit notes */
4398 			if (!cdinfo_get_str("    CddbCredit_GetNotes",
4399 					      CddbCredit_GetNotes,
4400 					      credp, &p->notes)) {
4401 				MEM_FREE(p);
4402 				return FALSE;
4403 			}
4404 
4405 			CddbReleaseObject(credp);
4406 
4407 			if (r->credit_list == NULL) {
4408 				r->credit_list = p;
4409 				p->prev = NULL;
4410 			}
4411 			else {
4412 				q->next = p;
4413 				p->prev = q;
4414 			}
4415 			q = p;
4416 			p->next = NULL;
4417 		}
4418 
4419 		CddbReleaseObject(segp);
4420 
4421 		if (cdinfo_dbp->disc.segment_list == NULL) {
4422 			cdinfo_dbp->disc.segment_list = r;
4423 			r->prev = NULL;
4424 		}
4425 		else {
4426 			s->next = r;
4427 			r->prev = s;
4428 		}
4429 		s = r;
4430 		r->next = NULL;
4431 	}
4432 
4433 	return TRUE;
4434 }
4435 
4436 
4437 /*
4438  * cdinfo_trackinfo_query
4439  *	Query CDDB for track information
4440  *
4441  * Args:
4442  *	discp - CddbDisc object
4443  *
4444  * Return:
4445  *	TRUE - Success
4446  *	FALSE - Failure
4447  */
4448 STATIC bool_t
cdinfo_trackinfo_query(CddbDiscPtr discp)4449 cdinfo_trackinfo_query(CddbDiscPtr discp)
4450 {
4451 	CddbResult	ret;
4452 	CddbTrackPtr	trkp = NULL;
4453 	CddbCreditPtr	credp = NULL;
4454 	long		ntrks,
4455 			ncreds;
4456 	int		i,
4457 			j;
4458 	char		*str;
4459 	cdinfo_genre_t	*gp,
4460 			*sgp;
4461 	cdinfo_credit_t	*p,
4462 			*q;
4463 	cdinfo_role_t	*rp;
4464 
4465 	/* Track information */
4466 	DBGPRN(DBG_CDI)(errfp, "CddbDisc_GetNumTracks: ");
4467 	ret = CddbDisc_GetNumTracks(discp, &ntrks);
4468 	DBGPRN(DBG_CDI)(errfp, "0x%lx %ld tracks\n", ret, ntrks);
4469 
4470 	cdinfo_set_errstr(ret);
4471 
4472 	for (i = 0; i < (int) ntrks; i++) {
4473 		DBGPRN(DBG_CDI)(errfp, "CddbDisc_GetTrack[%02d]: ", i+1);
4474 		ret = CddbDisc_GetTrack(discp, (long) (i+1), &trkp);
4475 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
4476 
4477 		if (ret != Cddb_OK)
4478 			continue;
4479 
4480 		/* Track artist */
4481 		if (!cdinfo_get_str("  CddbTrack_GetArtist",
4482 				CddbTrack_GetArtist,
4483 				trkp, &cdinfo_dbp->track[i].artist)) {
4484 			return FALSE;
4485 		}
4486 
4487 		/* Track title */
4488 		if (!cdinfo_get_str("  CddbTrack_GetTitle",
4489 				CddbTrack_GetTitle,
4490 				trkp, &cdinfo_dbp->track[i].title)) {
4491 			return FALSE;
4492 		}
4493 
4494 		/* Artist full name */
4495 		if (!cdinfo_get_fullname("  CddbTrack_GetArtistFullName",
4496 				CddbTrack_GetArtistFullName,
4497 				trkp,
4498 				&cdinfo_dbp->track[i].artistfname.dispname,
4499 				&cdinfo_dbp->track[i].artistfname.lastname,
4500 				&cdinfo_dbp->track[i].artistfname.firstname,
4501 				&cdinfo_dbp->track[i].artistfname.the)) {
4502 			return FALSE;
4503 		}
4504 
4505 		/* Track sort title */
4506 		if (!cdinfo_get_str("  CddbTrack_GetTitleSort",
4507 				CddbTrack_GetTitleSort,
4508 				trkp, &cdinfo_dbp->track[i].sorttitle)) {
4509 			return FALSE;
4510 		}
4511 
4512 		/* Track sort title */
4513 		if (!cdinfo_get_str("  CddbTrack_GetTitleThe",
4514 				CddbTrack_GetTitleThe,
4515 				trkp, &cdinfo_dbp->track[i].title_the)) {
4516 			return FALSE;
4517 		}
4518 
4519 		/* Year */
4520 		if (!cdinfo_get_str("  CddbTrack_GetYear",
4521 				CddbTrack_GetYear,
4522 				trkp, &cdinfo_dbp->track[i].year)) {
4523 			return FALSE;
4524 		}
4525 
4526 		/* Label */
4527 		if (!cdinfo_get_str("  CddbTrack_GetLabel",
4528 				CddbTrack_GetLabel,
4529 				trkp, &cdinfo_dbp->track[i].label)) {
4530 			return FALSE;
4531 		}
4532 
4533 		/* Genre */
4534 		if (!cdinfo_get_str("  CddbTrack_GetGenreId",
4535 				CddbTrack_GetGenreId,
4536 				trkp, &cdinfo_dbp->track[i].genre)) {
4537 			return FALSE;
4538 		}
4539 		gp = cdinfo_genre(cdinfo_dbp->track[i].genre);
4540 		if (gp != NULL && gp->parent == NULL) {
4541 			/* Illegal: the primary genre is set to a genre
4542 			 * category.  "Fix" it by setting it to the category's
4543 			 * "General" subgenre.  If not found, then set it to
4544 			 * the first subgenre.
4545 			 */
4546 			for (sgp = gp->child; sgp != NULL; sgp = sgp->next) {
4547 			    if (sgp->name != NULL &&
4548 				strncmp(sgp->name, "General ", 8) == 0) {
4549 				if (!util_newstr(&cdinfo_dbp->track[i].genre,
4550 						 sgp->id)) {
4551 				    CDINFO_FATAL(app_data.str_nomemory);
4552 				    return FALSE;
4553 				}
4554 				break;
4555 			    }
4556 			}
4557 			if (sgp == NULL) {
4558 			    if (gp->child != NULL) {
4559 				if (!util_newstr(&cdinfo_dbp->track[i].genre,
4560 						 gp->child->id)) {
4561 				    CDINFO_FATAL(app_data.str_nomemory);
4562 				    return FALSE;
4563 				}
4564 			    }
4565 			    else {
4566 				MEM_FREE(cdinfo_dbp->track[i].genre);
4567 				cdinfo_dbp->track[i].genre = NULL;
4568 			    }
4569 			}
4570 		}
4571 
4572 		/* Secondary Genre */
4573 		if (!cdinfo_get_str("  CddbTrack_GetSecondaryGenreId",
4574 				CddbTrack_GetSecondaryGenreId,
4575 				trkp, &cdinfo_dbp->track[i].genre2)) {
4576 			return FALSE;
4577 		}
4578 		gp = cdinfo_genre(cdinfo_dbp->track[i].genre2);
4579 		if (gp != NULL && gp->parent == NULL) {
4580 			/* Illegal: the secondary genre is set to a genre
4581 			 * category.  "Fix" it by setting it to the category's
4582 			 * "General" subgenre.  If not found, then set it to
4583 			 * the first subgenre.
4584 			 */
4585 			for (sgp = gp->child; sgp != NULL; sgp = sgp->next) {
4586 			    if (sgp->name != NULL &&
4587 				strncmp(sgp->name, "General ", 8) == 0) {
4588 				if (!util_newstr(&cdinfo_dbp->track[i].genre2,
4589 						 sgp->id)) {
4590 				    CDINFO_FATAL(app_data.str_nomemory);
4591 				    return FALSE;
4592 				}
4593 				break;
4594 			    }
4595 			}
4596 			if (sgp == NULL) {
4597 			    if (gp->child != NULL) {
4598 				if (!util_newstr(&cdinfo_dbp->track[i].genre2,
4599 						 gp->child->id)) {
4600 				    CDINFO_FATAL(app_data.str_nomemory);
4601 				    return FALSE;
4602 				}
4603 			    }
4604 			    else {
4605 				MEM_FREE(cdinfo_dbp->track[i].genre2);
4606 				cdinfo_dbp->track[i].genre2 = NULL;
4607 			    }
4608 			}
4609 		}
4610 
4611 		/* BPM */
4612 		if (!cdinfo_get_str("  CddbTrack_GetBeatsPerMinute",
4613 				CddbTrack_GetBeatsPerMinute,
4614 				trkp, &cdinfo_dbp->track[i].bpm)) {
4615 			return FALSE;
4616 		}
4617 
4618 		/* Notes */
4619 		if (!cdinfo_get_str("  CddbTrack_GetNotes",
4620 				CddbTrack_GetNotes,
4621 				trkp, &cdinfo_dbp->track[i].notes)) {
4622 			return FALSE;
4623 		}
4624 
4625 		/* ISRC */
4626 		if (!cdinfo_get_str("  CddbTrack_GetISRC",
4627 				CddbTrack_GetISRC,
4628 				trkp, &cdinfo_dbp->track[i].isrc)) {
4629 			return FALSE;
4630 		}
4631 
4632 		/* Track Credits */
4633 		DBGPRN(DBG_CDI)(errfp, "  CddbTrack_GetNumCredits: ");
4634 		ret = CddbTrack_GetNumCredits(trkp, &ncreds);
4635 		DBGPRN(DBG_CDI)(errfp, "0x%lx %ld credits\n", ret, ncreds);
4636 
4637 		cdinfo_set_errstr(ret);
4638 
4639 		q = NULL;
4640 		for (j = 0; j < (int) ncreds; j++) {
4641 			DBGPRN(DBG_CDI)(errfp,
4642 				"  CddbTrack_GetCredit[%02d]: ", j+1);
4643 			ret = CddbTrack_GetCredit(trkp, (long) (j+1), &credp);
4644 			DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
4645 
4646 			if (ret != Cddb_OK)
4647 				continue;
4648 
4649 			/* Allocate a credit structure */
4650 			p = (cdinfo_credit_t *) MEM_ALLOC(
4651 				"cdinfo_credit_t",
4652 				sizeof(cdinfo_credit_t)
4653 			);
4654 			if (p == NULL) {
4655 				CDINFO_FATAL(app_data.str_nomemory);
4656 				return FALSE;
4657 			}
4658 			(void) memset(p, 0, sizeof(cdinfo_credit_t));
4659 
4660 			/* Credit role */
4661 			str = NULL;
4662 			if (!cdinfo_get_str("    CddbCredit_GetId",
4663 					      CddbCredit_GetId, credp, &str)) {
4664 				MEM_FREE(p);
4665 				return FALSE;
4666 			}
4667 			rp = cdinfo_role(str);
4668 			if (rp->parent == NULL) {
4669 				/* Illegal: role set to the category role
4670 				 * "Fix" it by setting the role to the
4671 				 * first subrole of that category instead.
4672 				 * If for some reason there are no subroles
4673 				 * then the child would be NULL and thus the
4674 				 * role would be "None -> None".
4675 				 */
4676 				rp = rp->child;
4677 			}
4678 			p->crinfo.role = rp;
4679 			MEM_FREE(str);
4680 			str = NULL;
4681 
4682 			/* Credit name */
4683 			if (!cdinfo_get_str("    CddbCredit_GetName",
4684 					      CddbCredit_GetName,
4685 					      credp, &p->crinfo.name)) {
4686 				MEM_FREE(p);
4687 				return FALSE;
4688 			}
4689 
4690 			/* Credit full name */
4691 			if (!cdinfo_get_fullname("    CddbCredit_GetFullName",
4692 						CddbCredit_GetFullName,
4693 						credp,
4694 						&p->crinfo.fullname.dispname,
4695 						&p->crinfo.fullname.lastname,
4696 						&p->crinfo.fullname.firstname,
4697 						&p->crinfo.fullname.the)) {
4698 				MEM_FREE(p);
4699 				return FALSE;
4700 			}
4701 
4702 			/* Credit notes */
4703 			if (!cdinfo_get_str("    CddbCredit_GetNotes",
4704 					      CddbCredit_GetNotes,
4705 					      credp, &p->notes)) {
4706 				MEM_FREE(p);
4707 				return FALSE;
4708 			}
4709 
4710 			CddbReleaseObject(credp);
4711 
4712 			if (cdinfo_dbp->track[i].credit_list == NULL) {
4713 				cdinfo_dbp->track[i].credit_list = p;
4714 				p->prev = NULL;
4715 			}
4716 			else {
4717 				q->next = p;
4718 				p->prev = q;
4719 			}
4720 			q = p;
4721 			p->next = NULL;
4722 		}
4723 
4724 		CddbReleaseObject(trkp);
4725 	}
4726 
4727 	return TRUE;
4728 }
4729 
4730 
4731 /*
4732  * cdinfo_add_urllist
4733  *	Given a CddbURLList, add the items in that list to the URL list
4734  *	specified by *listhead.
4735  *
4736  * Args:
4737  *	listhead - Address of the listhead
4738  *	urllistp - The CddbURLList
4739  *	type - WTYPE_ALBUM or WTYPE_GEN
4740  *
4741  * Return:
4742  *	TRUE - Success
4743  *	FALSE - Failure (cannot allocate memory)
4744  */
4745 STATIC bool_t
cdinfo_add_urllist(cdinfo_url_t ** listhead,CddbURLListPtr urllistp,int wtype)4746 cdinfo_add_urllist(cdinfo_url_t **listhead, CddbURLListPtr urllistp, int wtype)
4747 {
4748 	CddbURLPtr		urlp;
4749 	CddbResult		ret;
4750 	long			cnt,
4751 				i;
4752 	cdinfo_url_t		*p;
4753 	static cdinfo_url_t	*q = NULL;
4754 
4755 	cnt = 0;
4756 	DBGPRN(DBG_CDI)(errfp, "CddbURLList_GetCount: ");
4757 	ret = CddbURLList_GetCount(urllistp, &cnt);
4758 	DBGPRN(DBG_CDI)(errfp, "0x%lx %ld entries\n", ret, cnt);
4759 
4760 	if (ret != Cddb_OK || cnt == 0)
4761 		return TRUE;
4762 
4763 	for (i = 1; i <= cnt; i++) {
4764 		urlp = NULL;
4765 		DBGPRN(DBG_CDI)(errfp, "CddbURLList_GetURL: ");
4766 		ret = CddbURLList_GetURL(urllistp, i, &urlp);
4767 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
4768 
4769 		if (ret != Cddb_OK || urlp == NULL)
4770 			return TRUE;
4771 
4772 		p = (cdinfo_url_t *)(void *) MEM_ALLOC(
4773 			"cdinfo_url_t", sizeof(cdinfo_url_t)
4774 		);
4775 		if (p == NULL) {
4776 			CDINFO_FATAL(app_data.str_nomemory);
4777 			return FALSE;
4778 		}
4779 		(void) memset(p, 0, sizeof(cdinfo_url_t));
4780 
4781 		if (!cdinfo_get_str("CddbURL_GetType",
4782 					CddbURL_GetType,
4783 					urlp, &p->type)) {
4784 			MEM_FREE(p);
4785 			return FALSE;
4786 		}
4787 		if (!cdinfo_get_str("CddbURL_GetHref",
4788 					CddbURL_GetHref,
4789 					urlp, &p->href)) {
4790 			MEM_FREE(p);
4791 			return FALSE;
4792 		}
4793 		if (!cdinfo_get_str("CddbURL_GetDisplayLink",
4794 					CddbURL_GetDisplayLink,
4795 					urlp, &p->displink)) {
4796 			MEM_FREE(p);
4797 			return FALSE;
4798 		}
4799 		if (!cdinfo_get_str("CddbURL_GetDisplayText",
4800 					CddbURL_GetDisplayText,
4801 					urlp, &p->disptext)) {
4802 			MEM_FREE(p);
4803 			return FALSE;
4804 		}
4805 		if (!cdinfo_get_str("CddbURL_GetCategory",
4806 					CddbURL_GetCategory,
4807 					urlp, &p->categ)) {
4808 			MEM_FREE(p);
4809 			return FALSE;
4810 		}
4811 		if (!cdinfo_get_str("CddbURL_GetSize",
4812 					CddbURL_GetSize,
4813 					urlp, &p->size)) {
4814 			MEM_FREE(p);
4815 			return FALSE;
4816 		}
4817 		if (!cdinfo_get_str("CddbURL_GetWeight",
4818 					CddbURL_GetWeight,
4819 					urlp, &p->weight)) {
4820 			MEM_FREE(p);
4821 			return FALSE;
4822 		}
4823 
4824 		p->wtype = wtype;
4825 
4826 		if (*listhead == NULL)
4827 			*listhead = q = p;
4828 		else {
4829 			q->next = p;
4830 			q = p;
4831 		}
4832 
4833 		CddbReleaseObject(urlp);
4834 	}
4835 
4836 	return TRUE;
4837 }
4838 
4839 
4840 /*
4841  * cdinfo_urls_query
4842  *	Query CDDB for URLs information
4843  *
4844  * Args:
4845  *	cp - cdinfo_cddb_t pointer for the CDDB connection
4846  *	discp - CddbDisc object.  If NULL, then general-interest URLs
4847  *		are queried.
4848  *
4849  * Return:
4850  *	TRUE - Success
4851  *	FALSE - Failure
4852  */
4853 STATIC bool_t
cdinfo_urls_query(cdinfo_cddb_t * cp,CddbDiscPtr discp)4854 cdinfo_urls_query(cdinfo_cddb_t *cp, CddbDiscPtr discp)
4855 {
4856 	CddbURLManagerPtr	urlmgrp = NULL;
4857 	CddbURLListPtr		urllistp = NULL;
4858 	CddbResult		ret;
4859 	int			wtype;
4860 	cdinfo_url_t		**listhead;
4861 
4862 	/* Get URLS from the service */
4863 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetURLList: ");
4864 	ret = CddbControl_GetURLList(cp->ctrlp, discp, 0, &urllistp);
4865 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
4866 
4867 	if (urllistp != NULL)
4868 		CddbReleaseObject(urllistp);
4869 
4870 	if (discp == NULL) {
4871 		listhead = &cdinfo_dbp->gen_url_list;
4872 		wtype = WTYPE_GEN;
4873 	}
4874 	else {
4875 		listhead = &cdinfo_dbp->disc_url_list;
4876 		wtype = WTYPE_ALBUM;
4877 	}
4878 
4879 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetURLManager: ");
4880 	ret = CddbControl_GetURLManager(cp->ctrlp, &urlmgrp);
4881 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
4882 
4883 	if (ret != Cddb_OK || urlmgrp == NULL)
4884 		return FALSE;
4885 
4886 #if 0	/* Not currently used */
4887 	/* Cover URLs */
4888 	DBGPRN(DBG_CDI)(errfp, "CddbURLManager_GetCoverURLs: ");
4889 	ret = CddbURLManager_GetCoverURLs(urlmgrp, discp, &urllistp);
4890 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
4891 	if (ret == Cddb_OK && urllistp != NULL) {
4892 		if (!cdinfo_add_urllist(listhead, urllistp, wtype)) {
4893 			CddbReleaseObject(urllistp);
4894 			CddbReleaseObject(urlmgrp);
4895 			return FALSE;
4896 		}
4897 		CddbReleaseObject(urllistp);
4898 	}
4899 #endif
4900 
4901 	/* Menu URLs */
4902 	DBGPRN(DBG_CDI)(errfp, "CddbURLManager_GetMenuURLs: ");
4903 	ret = CddbURLManager_GetMenuURLs(urlmgrp, discp, &urllistp);
4904 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
4905 	if (ret == Cddb_OK && urllistp != NULL) {
4906 		if (!cdinfo_add_urllist(listhead, urllistp, wtype)) {
4907 			CddbReleaseObject(urllistp);
4908 			CddbReleaseObject(urlmgrp);
4909 			return FALSE;
4910 		}
4911 		CddbReleaseObject(urllistp);
4912 	}
4913 
4914 	CddbReleaseObject(urlmgrp);
4915 
4916 	return TRUE;
4917 }
4918 
4919 
4920 /*
4921  * cdinfo_build_matchlist
4922  *	Build multiple fuzzy match disc elements list.  This is used
4923  *	to query the user for a selection.
4924  *
4925  * Args:
4926  *	discs - CddbDiscs object pointer
4927  *
4928  * Return:
4929  *	TRUE - success
4930  *	FALSE - failure
4931  */
4932 STATIC bool_t
cdinfo_build_matchlist(CddbDiscsPtr discsp)4933 cdinfo_build_matchlist(CddbDiscsPtr discsp)
4934 {
4935 	CddbResult	ret;
4936 	CddbDiscPtr	discp;
4937 	long		cnt,
4938 			i;
4939 	cdinfo_genre_t	*gp,
4940 			*sgp;
4941 	cdinfo_match_t	*mp,
4942 			*mp2;
4943 
4944 	DBGPRN(DBG_CDI)(errfp, "CddbDiscs_GetCount: ");
4945 	ret = CddbDiscs_GetCount(discsp, &cnt);
4946 	DBGPRN(DBG_CDI)(errfp, "0x%lx %ld matches\n", ret, cnt);
4947 
4948 	if (ret != Cddb_OK || cnt <= 0)
4949 		return FALSE;
4950 
4951 	mp = NULL;
4952 	for (i = 1; i <= cnt; i++) {
4953 		DBGPRN(DBG_CDI)(errfp, "CddbDiscs_GetDisc[%ld]: ", i);
4954 		ret = CddbDiscs_GetDisc(discsp, i, &discp);
4955 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
4956 
4957 		if (ret == Cddb_OK && discp != NULL) {
4958 			mp2 = (cdinfo_match_t *)(void *) MEM_ALLOC(
4959 				"cdinfo_match_t",
4960 				sizeof(cdinfo_match_t)
4961 			);
4962 			if (mp2 == NULL) {
4963 				CDINFO_FATAL(app_data.str_nomemory);
4964 				return FALSE;
4965 			}
4966 			(void) memset(mp2, 0, sizeof(cdinfo_match_t));
4967 
4968 			mp2->tag = i;
4969 
4970 			if (!cdinfo_get_str("  CddbDisc_GetArtist",
4971 						CddbDisc_GetArtist,
4972 						discp, &mp2->artist)) {
4973 				return FALSE;
4974 			}
4975 			if (!cdinfo_get_str("  CddbDisc_GetTitle",
4976 						CddbDisc_GetTitle,
4977 						discp, &mp2->title)) {
4978 				return FALSE;
4979 			}
4980 			if (!cdinfo_get_str("  CddbDisc_GetGenreId",
4981 						CddbDisc_GetGenreId,
4982 						discp, &mp2->genre)) {
4983 				return FALSE;
4984 			}
4985 			gp = cdinfo_genre(cdinfo_dbp->disc.genre);
4986 			if (gp != NULL && gp->parent == NULL) {
4987 			    /* Illegal: the genre is set to a genre category.
4988 			     * "Fix" it by setting it to the category's
4989 			     * "General" subgenre.  If not found, then set
4990 			     * it to the first subgenre.
4991 			     */
4992 			    for (sgp = gp->child; sgp != NULL;
4993 				 sgp = sgp->next) {
4994 				if (sgp->name != NULL &&
4995 				    strncmp(sgp->name, "General ", 8) == 0) {
4996 				    if (!util_newstr(&cdinfo_dbp->disc.genre,
4997 						     sgp->id)) {
4998 					CDINFO_FATAL(app_data.str_nomemory);
4999 					return FALSE;
5000 				    }
5001 				    break;
5002 				}
5003 			    }
5004 			    if (sgp == NULL) {
5005 				if (gp->child != NULL) {
5006 				    if (!util_newstr(&cdinfo_dbp->disc.genre,
5007 						     gp->child->id)) {
5008 					CDINFO_FATAL(app_data.str_nomemory);
5009 					return FALSE;
5010 				    }
5011 				}
5012 				else {
5013 				    MEM_FREE(cdinfo_dbp->disc.genre);
5014 				    cdinfo_dbp->disc.genre = NULL;
5015 				}
5016 			    }
5017 			}
5018 
5019 			if (cdinfo_dbp->matchlist == NULL)
5020 				cdinfo_dbp->matchlist = mp = mp2;
5021 			else {
5022 				mp->next = mp2;
5023 				mp = mp2;
5024 			}
5025 
5026 			CddbReleaseObject(discp);
5027 		}
5028 	}
5029 	return TRUE;
5030 }
5031 
5032 
5033 /*
5034  * cdinfo_ctrlver_init
5035  *	Query CDDB control version information initialize the incore struct.
5036  *
5037  * Args:
5038  *	cp - cdinfo_cddb_t pointer for the CDDB connection
5039  *
5040  * Return:
5041  *	TRUE - success
5042  *	FALSE - failure
5043  */
5044 STATIC bool_t
cdinfo_ctrlver_init(cdinfo_cddb_t * cp)5045 cdinfo_ctrlver_init(cdinfo_cddb_t *cp)
5046 {
5047 	return cdinfo_get_str("CddbControl_GetVersion",
5048 				CddbControl_GetVersion, cp->ctrlp,
5049 				&cdinfo_dbp->ctrl_ver);
5050 }
5051 
5052 
5053 /*
5054  * cdinfo_chk_service
5055  *	Check CDDB service for good network connectivity, and that the
5056  *	server is up and functional.
5057  *
5058  * Args:
5059  *	cp - cdinfo_cddb_t pointer for the CDDB connection
5060  *
5061  * Return:
5062  *	TRUE - success
5063  *	FALSE - failure
5064  */
5065 STATIC bool_t
cdinfo_chk_service(cdinfo_cddb_t * cp)5066 cdinfo_chk_service(cdinfo_cddb_t *cp)
5067 {
5068 	CddbResult	ret;
5069 	CddbStr		str;
5070 
5071 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetServiceStatus: ");
5072 	ret = CddbControl_GetServiceStatus(cp->ctrlp, &str);
5073 	if ((app_data.debug & DBG_CDI) && str != NULL) {
5074 		/* Strip out extra newlines */
5075 		while (str[strlen(str)-1] == '\n')
5076 			str[strlen(str)-1] = '\0';
5077 	}
5078 	DBGPRN(DBG_CDI)(errfp, "0x%lx %s\n", ret, str == NULL ? "" : str);
5079 
5080 	cdinfo_set_errstr(ret);
5081 
5082 	if (ret != Cddb_OK)
5083 		return FALSE;
5084 
5085 	DBGPRN(DBG_CDI)(errfp, "CddbControl_ServerNoop: ");
5086 	ret = CddbControl_ServerNoop(cp->ctrlp, 0);
5087 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5088 
5089 	cdinfo_set_errstr(ret);
5090 
5091 	return (ret == Cddb_OK);
5092 }
5093 
5094 
5095 /*
5096  * cdinfo_genrelist_init
5097  *	Query genre tree information from CDDB and initialize the genre list.
5098  *
5099  * Args:
5100  *	cp - cdinfo_cddb_t pointer for the CDDB connection
5101  *
5102  * Return:
5103  *	TRUE - Success
5104  *	FALSE - Failure
5105  */
5106 STATIC bool_t
cdinfo_genrelist_init(cdinfo_cddb_t * cp)5107 cdinfo_genrelist_init(cdinfo_cddb_t *cp)
5108 {
5109 	CddbResult		ret;
5110 	CddbGenreTreePtr	gtreep;
5111 	CddbGenreListPtr	glistp;
5112 	CddbGenrePtr		genrep;
5113 	long			cnt,
5114 				subcnt;
5115 	int			i,
5116 				j;
5117 	cdinfo_genre_t		*p,
5118 				*q,
5119 				*r,
5120 				*s;
5121 
5122 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetGenreTree: ");
5123 	ret = CddbControl_GetGenreTree(cp->ctrlp, 0, &gtreep);
5124 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5125 
5126 	cdinfo_set_errstr(ret);
5127 
5128 	if (ret != Cddb_OK || gtreep == NULL)
5129 		return FALSE;
5130 
5131 	DBGPRN(DBG_CDI)(errfp, "CddbGenreTree_GetCount: ");
5132 	ret = CddbGenreTree_GetCount(gtreep, &cnt);
5133 	DBGPRN(DBG_CDI)(errfp, "0x%lx %ld\n", ret, cnt);
5134 
5135 	q = NULL;
5136 	for (i = 1; i <= (int) cnt; i++) {
5137 		DBGPRN(DBG_CDI)(errfp, "CddbGenreTree_GetMetaGenre[%d]: ", i);
5138 		ret = CddbGenreTree_GetMetaGenre(gtreep, (long) i, &genrep);
5139 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5140 
5141 		if (ret != Cddb_OK) {
5142 			CddbReleaseObject(gtreep);
5143 			return FALSE;
5144 		}
5145 
5146 		/* Allocate genre entry and fill it with genre info */
5147 		if (!cdinfo_allocinit_genre(genrep, &p, FALSE)) {
5148 			CddbReleaseObject(genrep);
5149 			CddbReleaseObject(gtreep);
5150 			return FALSE;
5151 		}
5152 
5153 		CddbReleaseObject(genrep);
5154 
5155 		/* Sub-Genre list */
5156 		DBGPRN(DBG_CDI)(errfp, "    CddbGenreTree_GetSubGenreList: ");
5157 		ret = CddbGenreTree_GetSubGenreList(gtreep, p->id, &glistp);
5158 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5159 
5160 		if (ret != Cddb_OK) {
5161 			CddbReleaseObject(gtreep);
5162 			return FALSE;
5163 		}
5164 
5165 		DBGPRN(DBG_CDI)(errfp, "    CddbGenreList_GetCount: ");
5166 		ret = CddbGenreList_GetCount(glistp, &subcnt);
5167 		DBGPRN(DBG_CDI)(errfp, "0x%lx %ld\n", ret, subcnt);
5168 
5169 		r = NULL;
5170 		for (j = 1; j <= (int) subcnt; j++) {
5171 			DBGPRN(DBG_CDI)(errfp,
5172 				"    CddbGenreList_GetGenre[%d]: ", j);
5173 			ret = CddbGenreList_GetGenre(glistp,
5174 						     (long) j, &genrep);
5175 			DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5176 
5177 			/* Allocate genre entry and fill it with genre info */
5178 			if (!cdinfo_allocinit_genre(genrep, &s, TRUE)) {
5179 				CddbReleaseObject(genrep);
5180 				CddbReleaseObject(glistp);
5181 				CddbReleaseObject(gtreep);
5182 				return FALSE;
5183 			}
5184 
5185 			CddbReleaseObject(genrep);
5186 
5187 			s->parent = p;
5188 			if (p->child == NULL)
5189 				p->child = r = s;
5190 			else {
5191 				r->next = s;
5192 				r = s;
5193 			}
5194 		}
5195 
5196 		CddbReleaseObject(glistp);
5197 
5198 		if (cdinfo_dbp->genrelist == NULL)
5199 			cdinfo_dbp->genrelist = q = p;
5200 		else {
5201 			q->next = p;
5202 			q = p;
5203 		}
5204 		p->parent = NULL;
5205 	}
5206 
5207 	CddbReleaseObject(gtreep);
5208 	return TRUE;
5209 }
5210 
5211 
5212 /*
5213  * cdinfo_regionlist_init
5214  *	Query region list information from CDDB and initialize the region list.
5215  *
5216  * Args:
5217  *	cp - cdinfo_cddb_t pointer for the CDDB connection
5218  *
5219  * Return:
5220  *	TRUE - Success
5221  *	FALSE - Failure
5222  */
5223 STATIC bool_t
cdinfo_regionlist_init(cdinfo_cddb_t * cp)5224 cdinfo_regionlist_init(cdinfo_cddb_t *cp)
5225 {
5226 	CddbResult		ret;
5227 	CddbRegionListPtr	relistp;
5228 	CddbRegionPtr		regionp;
5229 	cdinfo_region_t		*p,
5230 				*q;
5231 	long			cnt;
5232 	int			i;
5233 
5234 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetRegionList: ");
5235 	ret = CddbControl_GetRegionList(cp->ctrlp, 0, &relistp);
5236 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5237 
5238 	cdinfo_set_errstr(ret);
5239 
5240 	if (ret != Cddb_OK)
5241 		return FALSE;
5242 
5243 	DBGPRN(DBG_CDI)(errfp, "CddbRegionList_GetCount: ");
5244 	ret = CddbRegionList_GetCount(relistp, &cnt);
5245 	DBGPRN(DBG_CDI)(errfp, "0x%lx %ld\n", ret, cnt);
5246 
5247 	q = NULL;
5248 	for (i = 1; i <= (int) cnt; i++) {
5249 		DBGPRN(DBG_CDI)(errfp, "CddbRegionList_GetRegion[%d]: ", i);
5250 		ret = CddbRegionList_GetRegion(relistp, (long) i, &regionp);
5251 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5252 
5253 		if (ret != Cddb_OK) {
5254 			CddbReleaseObject(relistp);
5255 			return FALSE;
5256 		}
5257 
5258 		/* Allocate region entry and fill it with region info */
5259 		if (!cdinfo_allocinit_region(regionp, &p)) {
5260 			CddbReleaseObject(regionp);
5261 			CddbReleaseObject(relistp);
5262 			return FALSE;
5263 		}
5264 
5265 		CddbReleaseObject(regionp);
5266 
5267 		if (cdinfo_dbp->regionlist == NULL)
5268 			cdinfo_dbp->regionlist = q = p;
5269 		else {
5270 			q->next = p;
5271 			q = p;
5272 		}
5273 	}
5274 
5275 	CddbReleaseObject(relistp);
5276 	return TRUE;
5277 }
5278 
5279 
5280 /*
5281  * cdinfo_langlist_init
5282  *	Query language list information from CDDB and initialize the
5283  *	language list.
5284  *
5285  * Args:
5286  *	cp - cdinfo_cddb_t pointer for the CDDB connection
5287  *
5288  * Return:
5289  *	TRUE - Success
5290  *	FALSE - Failure
5291  */
5292 STATIC bool_t
cdinfo_langlist_init(cdinfo_cddb_t * cp)5293 cdinfo_langlist_init(cdinfo_cddb_t *cp)
5294 {
5295 	CddbResult		ret;
5296 	CddbLanguageListPtr	langlistp;
5297 	CddbLanguagePtr		langp;
5298 	cdinfo_lang_t		*p,
5299 				*q;
5300 	long			cnt;
5301 	int			i;
5302 
5303 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetLanguageList: ");
5304 	ret = CddbControl_GetLanguageList(cp->ctrlp, 0, &langlistp);
5305 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5306 
5307 	cdinfo_set_errstr(ret);
5308 
5309 	if (ret != Cddb_OK)
5310 		return FALSE;
5311 
5312 	DBGPRN(DBG_CDI)(errfp, "CddbLanguageList_GetCount: ");
5313 	ret = CddbLanguageList_GetCount(langlistp, &cnt);
5314 	DBGPRN(DBG_CDI)(errfp, "0x%lx %ld\n", ret, cnt);
5315 
5316 	q = NULL;
5317 	for (i = 1; i <= (int) cnt; i++) {
5318 		DBGPRN(DBG_CDI)(errfp,
5319 			"CddbLanguageList_GetLanguage[%d]: ", i);
5320 		ret = CddbLanguageList_GetLanguage(
5321 			langlistp, (long) i, &langp
5322 		);
5323 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5324 
5325 		if (ret != Cddb_OK) {
5326 			CddbReleaseObject(langlistp);
5327 			return FALSE;
5328 		}
5329 
5330 		/* Allocate language entry and fill it with language info */
5331 		if (!cdinfo_allocinit_lang(langp, &p)) {
5332 			CddbReleaseObject(langp);
5333 			CddbReleaseObject(langlistp);
5334 			return FALSE;
5335 		}
5336 
5337 		CddbReleaseObject(langp);
5338 
5339 		if (cdinfo_dbp->langlist == NULL)
5340 			cdinfo_dbp->langlist = q = p;
5341 		else {
5342 			q->next = p;
5343 			q = p;
5344 		}
5345 	}
5346 
5347 	CddbReleaseObject(langlistp);
5348 	return TRUE;
5349 }
5350 
5351 
5352 /*
5353  * cdinfo_rolelist_init
5354  *	Query role list information from CDDB and initialize the role list.
5355  *
5356  * Args:
5357  *	cp - cdinfo_cddb_t pointer for the CDDB connection
5358  *
5359  * Return:
5360  *	TRUE - Success
5361  *	FALSE - Failure
5362  */
5363 STATIC bool_t
cdinfo_rolelist_init(cdinfo_cddb_t * cp)5364 cdinfo_rolelist_init(cdinfo_cddb_t *cp)
5365 {
5366 	CddbResult		ret;
5367 	CddbRoleTreePtr		rotreep;
5368 	CddbRoleListPtr		rolistp;
5369 	CddbRolePtr		rolep;
5370 	long			tcnt,
5371 				lcnt;
5372 	int			i,
5373 				j;
5374 	cdinfo_role_t		*p,
5375 				*q,
5376 				*r,
5377 				*s;
5378 
5379 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetRoleTree: ");
5380 	ret = CddbControl_GetRoleTree(cp->ctrlp, 0, &rotreep);
5381 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5382 
5383 	cdinfo_set_errstr(ret);
5384 
5385 	if (ret != Cddb_OK)
5386 		return FALSE;
5387 
5388 	DBGPRN(DBG_CDI)(errfp, "CddbRoleTree_GetCount: ");
5389 	ret = CddbRoleTree_GetCount(rotreep, &tcnt);
5390 	DBGPRN(DBG_CDI)(errfp, "0x%lx %ld\n", ret, tcnt);
5391 
5392 	q = NULL;
5393 	for (i = 1; i <= (int) tcnt; i++) {
5394 		DBGPRN(DBG_CDI)(errfp, "CddbRoleTree_GetRoleList[%d]: ", i);
5395 		ret = CddbRoleTree_GetRoleList(rotreep, (long) i, &rolistp);
5396 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5397 
5398 		if (ret != Cddb_OK) {
5399 			CddbReleaseObject(rotreep);
5400 			return FALSE;
5401 		}
5402 
5403 		DBGPRN(DBG_CDI)(errfp, "  CddbRoleList_GetCategoryRole: ");
5404 		ret = CddbRoleList_GetCategoryRole(rolistp, &rolep);
5405 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5406 
5407 		if (ret != Cddb_OK) {
5408 			CddbReleaseObject(rolistp);
5409 			CddbReleaseObject(rotreep);
5410 			return FALSE;
5411 		}
5412 
5413 		/* Allocate role entry and fill it with role info */
5414 		if (!cdinfo_allocinit_role(rolep, &p)) {
5415 			CddbReleaseObject(rolep);
5416 			CddbReleaseObject(rolistp);
5417 			CddbReleaseObject(rotreep);
5418 			return FALSE;
5419 		}
5420 
5421 		CddbReleaseObject(rolep);
5422 
5423 		DBGPRN(DBG_CDI)(errfp, "  CddbRoleList_GetCount: ");
5424 		ret = CddbRoleList_GetCount(rolistp, &lcnt);
5425 		DBGPRN(DBG_CDI)(errfp, "0x%lx %ld\n", ret, lcnt);
5426 
5427 		r = NULL;
5428 		for (j = 1; j <= (int) lcnt; j++) {
5429 			DBGPRN(DBG_CDI)(errfp,
5430 				"  CddbRoleList_GetRole[%d]: ", j);
5431 			ret = CddbRoleList_GetRole(rolistp, (long) j, &rolep);
5432 			DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5433 
5434 			if (ret != Cddb_OK) {
5435 				CddbReleaseObject(rolistp);
5436 				CddbReleaseObject(rotreep);
5437 				return FALSE;
5438 			}
5439 
5440 			/* Allocate role entry and fill it with role info */
5441 			if (!cdinfo_allocinit_role(rolep, &s)) {
5442 				CddbReleaseObject(rolep);
5443 				CddbReleaseObject(rolistp);
5444 				CddbReleaseObject(rotreep);
5445 				return FALSE;
5446 			}
5447 
5448 			CddbReleaseObject(rolep);
5449 
5450 			s->parent = p;
5451 			if (p->child == NULL)
5452 				p->child = r = s;
5453 			else {
5454 				r->next = s;
5455 				r = s;
5456 			}
5457 		}
5458 
5459 		CddbReleaseObject(rolistp);
5460 
5461 		if (cdinfo_dbp->rolelist == NULL)
5462 			cdinfo_dbp->rolelist = q = p;
5463 		else {
5464 			q->next = p;
5465 			q = p;
5466 		}
5467 		p->parent = NULL;
5468 	}
5469 
5470 	CddbReleaseObject(rotreep);
5471 	return TRUE;
5472 }
5473 
5474 
5475 /*
5476  * cdinfo_opencddb
5477  *	Open a remote CDDB connection
5478  *
5479  * Args:
5480  *	s - Pointer to the curstat_t structure
5481  *	query - Whether we're opening CDDB connection for a query operation
5482  *	retcode - return status code
5483  *
5484  * Return:
5485  *	Open descriptor cdbinfo_file_t
5486  */
5487 /*ARGSUSED*/
5488 cdinfo_cddb_t *
cdinfo_opencddb(curstat_t * s,bool_t query,int * retcode)5489 cdinfo_opencddb(curstat_t *s, bool_t query, int *retcode)
5490 {
5491 	CddbOptionsPtr	optp = NULL;
5492 	cdinfo_cddb_t	*cp;
5493 	CddbResult	ret;
5494 	int		i;
5495 	long		cacheflags;
5496 	char		cache_path[FILE_PATH_SZ];
5497 
5498 	/* Default is success */
5499 	*retcode = 0;
5500 
5501 	if (cdinfo_cddbp != NULL) {
5502 		/* Already opened - only one open allowed at a time */
5503 		*retcode = OPEN_ERR;
5504 		return NULL;
5505 	}
5506 
5507 	/* Allocate cdinfo_cddb_t */
5508 	cp = (cdinfo_cddb_t *)(void *) MEM_ALLOC(
5509 		"cdinfo_cddb_t",
5510 		sizeof(cdinfo_cddb_t)
5511 	);
5512 	if (cp == NULL) {
5513 		*retcode = MEM_ERR;
5514 		CDINFO_FATAL(app_data.str_nomemory);
5515 		return NULL;
5516 	}
5517 
5518 	/* Save pointer for signal handler */
5519 	cdinfo_cddbp = cp;
5520 
5521 	DBGPRN(DBG_CDI)(errfp, "\nOpening CDDB service...\n");
5522 
5523 	DBGPRN(DBG_CDI)(errfp, "CddbInitialize: ");
5524 	ret = CddbInitialize((CddbControlPtr *) &cp->ctrlp);
5525 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5526 
5527 	switch (ret) {
5528 	case Cddb_OK:
5529 		if (cddb_ifver() != 2) {
5530 			*retcode = LIBCDDB_ERR;
5531 			(void) fprintf(errfp,
5532 			    "ERROR: libcddb and libcddbkey mismatch (2:1).\n");
5533 			return NULL;
5534 		}
5535 		break;
5536 
5537 	case Cddb_ISCDDB1:
5538 		if (cddb_ifver() != 1) {
5539 			*retcode = LIBCDDB_ERR;
5540 			(void) fprintf(errfp,
5541 			    "ERROR: libcddb and libcddbkey mismatch (1:2).\n");
5542 			return NULL;
5543 		}
5544 		break;
5545 
5546 	default:
5547 		cdinfo_set_errstr(ret);
5548 		*retcode = INIT_ERR;
5549 		return NULL;
5550 	}
5551 
5552 	if (cp->ctrlp == NULL ||
5553 	    !cddb_setkey(cp, cdinfo_clinfo, &app_data, s, errfp)) {
5554 		*retcode = INIT_ERR;
5555 		return NULL;
5556 	}
5557 
5558 	i = 0;
5559 	for (;;) {
5560 		DBGPRN(DBG_CDI)(errfp, "CddbControl_Initialize: ");
5561 		ret = CddbControl_Initialize(
5562 			cp->ctrlp, 0,
5563 			app_data.cdinfo_inetoffln ?
5564 				CACHE_DONT_CONNECT : CACHE_DEFAULT
5565 		);
5566 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5567 
5568 		if (ret == Cddb_OK || ret == Cddb_FALSE)
5569 			break;
5570 
5571 		if (++i > 1) {
5572 			cdinfo_set_errstr(ret);
5573 			(void) cdinfo_closecddb(cp);
5574 			*retcode = INIT_ERR;
5575 			return NULL;
5576 		}
5577 
5578 		/* Try removing the cache file */
5579 		(void) sprintf(cache_path, "%s/.cddb2/%s/cddb.ds",
5580 				util_homedir(util_get_ouid()),
5581 				XMCD_CLIENT_ID);
5582 		(void) UNLINK(cache_path);
5583 	}
5584 
5585 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetOptions: ");
5586 	ret = CddbControl_GetOptions(cp->ctrlp, &optp);
5587 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5588 
5589 	if (ret == Cddb_OK && optp != NULL) {
5590 		if (app_data.use_proxy) {
5591 			char	*p;
5592 			long	port = HTTP_PORT;
5593 
5594 			if ((p = strchr(app_data.proxy_server, ':')) != NULL){
5595 				*p = '\0';
5596 				port = atol(p+1);
5597 			}
5598 
5599 			/* Proxy server */
5600 			(void) cdinfo_put_str("CddbOptions_PutProxyServer",
5601 				CddbOptions_PutProxyServer, optp,
5602 				app_data.proxy_server
5603 			);
5604 
5605 			/* Proxy server port */
5606 			DBGPRN(DBG_CDI)(errfp,
5607 				"CddbOptions_PutProxyServerPort: ");
5608 			ret = CddbOptions_PutProxyServerPort(optp, port);
5609 			DBGPRN(DBG_CDI)(errfp, "0x%lx port %ld\n", ret, port);
5610 
5611 			if (p != NULL)
5612 				*p = ':';
5613 
5614 			if (app_data.proxy_auth) {
5615 				if (cdinfo_dbp->proxy_user == NULL ||
5616 				    cdinfo_dbp->proxy_passwd == NULL) {
5617 					CddbReleaseObject(optp);
5618 
5619 					*retcode = AUTH_ERR;
5620 					(void) cdinfo_closecddb(cp);
5621 					return NULL;
5622 				}
5623 
5624 #ifdef __VMS
5625 				/* Hack to work around a memory
5626 				 * corruption problem on VMS.
5627 				 */
5628 				{
5629 				    static char	*sav_user = NULL,
5630 						*sav_pass = NULL;
5631 
5632 				    if (cdinfo_dbp->proxy_user[0] == '\0' ||
5633 					cdinfo_dbp->proxy_passwd[0] == '\0') {
5634 					if (sav_user != NULL &&
5635 					    sav_pass != NULL) {
5636 					    (void) strcpy(
5637 						    cdinfo_dbp->proxy_user,
5638 						    sav_user
5639 					    );
5640 					    (void) strcpy(
5641 						    cdinfo_dbp->proxy_passwd,
5642 						    sav_pass
5643 					    );
5644 					}
5645 				    }
5646 				    else {
5647 					if (!util_newstr(&sav_user,
5648 						    cdinfo_dbp->proxy_user) ||
5649 					    !util_newstr(&sav_pass,
5650 						    cdinfo_dbp->proxy_passwd)){
5651 					    *retcode = MEM_ERR;
5652 					    return NULL;
5653 					}
5654 				    }
5655 				}
5656 #endif	/* __VMS */
5657 
5658 				/* Proxy user name */
5659 				(void) cdinfo_put_str(
5660 					"CddbOptions_PutProxyUserName",
5661 					CddbOptions_PutProxyUserName, optp,
5662 					cdinfo_dbp->proxy_user
5663 				);
5664 
5665 				/* Proxy password */
5666 				(void) cdinfo_put_str(
5667 					"CddbOptions_PutProxyPassword",
5668 					CddbOptions_PutProxyPassword, optp,
5669 					cdinfo_dbp->proxy_passwd
5670 				);
5671 			}
5672 		}
5673 		else {
5674 			/* Clear proxy server settings if any */
5675 			(void) cdinfo_put_str(
5676 				"CddbOptions_PutProxyServer",
5677 				CddbOptions_PutProxyServer, optp,
5678 				NULL
5679 			);
5680 
5681 			/* Clear proxy server user name if any */
5682 			(void) cdinfo_put_str(
5683 				"CddbOptions_PutProxyUserName",
5684 				CddbOptions_PutProxyUserName, optp,
5685 				NULL
5686 			);
5687 
5688 			/* Clear proxy server password if any */
5689 			(void) cdinfo_put_str(
5690 				"CddbOptions_PutProxyPassword",
5691 				CddbOptions_PutProxyPassword, optp,
5692 				NULL
5693 			);
5694 		}
5695 
5696 		/* Set local cache flags */
5697 		cacheflags = app_data.cdinfo_inetoffln ?
5698 			CACHE_DONT_CONNECT : CACHE_DEFAULT;
5699 		DBGPRN(DBG_CDI)(errfp, "CddbOptions_PutLocalCacheFlags: ");
5700 		ret = CddbOptions_PutLocalCacheFlags(optp, cacheflags);
5701 		DBGPRN(DBG_CDI)(errfp, "0x%lx flags=0x%lx\n", ret, cacheflags);
5702 
5703 		/* Set local cache timeout value */
5704 		DBGPRN(DBG_CDI)(errfp, "CddbOptions_PutLocalCacheTimeout: ");
5705 		ret = CddbOptions_PutLocalCacheTimeout(
5706 			optp, (long) app_data.cache_timeout
5707 		);
5708 		DBGPRN(DBG_CDI)(errfp,
5709 			"0x%lx %d\n", ret, app_data.cache_timeout);
5710 
5711 		/* Set server timeout value */
5712 		DBGPRN(DBG_CDI)(errfp, "CddbOptions_PutServerTimeout: ");
5713 		ret = CddbOptions_PutServerTimeout(
5714 			optp, (long) (app_data.srv_timeout * 1000)
5715 		);
5716 		DBGPRN(DBG_CDI)(errfp,
5717 			"0x%lx %d\n", ret, app_data.srv_timeout * 1000);
5718 
5719 		DBGPRN(DBG_CDI)(errfp, "CddbOptions_PutTestSubmitMode: ");
5720 #ifdef CDINFO_PRODUCTION
5721 		ret = CddbOptions_PutTestSubmitMode(optp, 0);
5722 		DBGPRN(DBG_CDI)(errfp, "0x%lx False\n", ret);
5723 #else
5724 		ret = CddbOptions_PutTestSubmitMode(optp, 1);
5725 		DBGPRN(DBG_CDI)(errfp, "0x%lx True\n", ret);
5726 #endif
5727 
5728 		/* Write out options */
5729 		DBGPRN(DBG_CDI)(errfp, "CddbControl_SetOptions: ");
5730 		ret = CddbControl_SetOptions(cp->ctrlp, optp);
5731 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5732 
5733 		CddbReleaseObject(optp);
5734 	}
5735 
5736 	return (cp);
5737 }
5738 
5739 
5740 /*
5741  * cdinfo_closecddb
5742  *	Close a remote CDDB connection
5743  *
5744  * Args:
5745  *	cp - Pointer to the cdinfo_cddb_t structure returned from
5746  *	cdinfo_opencddb.
5747  *
5748  * Return:
5749  *	TRUE - Success
5750  *	FALSE - Failure
5751  */
5752 bool_t
cdinfo_closecddb(cdinfo_cddb_t * cp)5753 cdinfo_closecddb(cdinfo_cddb_t *cp)
5754 {
5755 	CddbResult	ret;
5756 
5757 	if (cp == NULL)
5758 		return FALSE;
5759 
5760 	if (cp->ctrlp != NULL) {
5761 		DBGPRN(DBG_CDI)(errfp, "CddbControl_Shutdown: ");
5762 		ret = CddbControl_Shutdown(cp->ctrlp);
5763 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5764 
5765 		DBGPRN(DBG_CDI)(errfp, "CddbTerminate: ");
5766 		ret = CddbTerminate(cp->ctrlp);
5767 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5768 	}
5769 
5770 	MEM_FREE(cp);
5771 	cdinfo_cddbp = NULL;
5772 
5773 	return TRUE;
5774 }
5775 
5776 
5777 /*
5778  * cdinfo_initcddb
5779  *	Perform CDDB initializations
5780  *
5781  * Args:
5782  *	cp - Pointer to the cdinfo_cddb_t structure returned from
5783  *	     cdinfo_opencddb.
5784  *	retcode - Pointer to location where a cdinfo_ret_t code is returned.
5785  *
5786  * Return:
5787  *	TRUE - Success
5788  *	FALSE - Failure
5789  */
5790 bool_t
cdinfo_initcddb(cdinfo_cddb_t * cp,cdinfo_ret_t * retcode)5791 cdinfo_initcddb(cdinfo_cddb_t *cp, cdinfo_ret_t *retcode)
5792 {
5793 	*retcode = 0;
5794 
5795 	/* Get CDDB control version */
5796 	if (cdinfo_dbp->ctrl_ver == NULL && !cdinfo_ctrlver_init(cp)) {
5797 		*retcode = READ_ERR;
5798 		return FALSE;
5799 	}
5800 
5801 	/* Set up region list if not done */
5802 	if (cdinfo_dbp->regionlist == NULL && !cdinfo_regionlist_init(cp)) {
5803 		*retcode = READ_ERR;
5804 		return FALSE;
5805 	}
5806 
5807 	/* Set up language list if not done */
5808 	if (cdinfo_dbp->langlist == NULL && !cdinfo_langlist_init(cp)) {
5809 		*retcode = READ_ERR;
5810 		return FALSE;
5811 	}
5812 
5813 	if ((app_data.debug & DBG_CDI) != 0 && !app_data.cdinfo_inetoffln &&
5814 	    !cdinfo_chk_service(cp)) {
5815 		*retcode = READ_ERR;
5816 		return FALSE;
5817 	}
5818 
5819 	/* Check user registration */
5820 	if (!cdinfo_check_userreg(cp)) {
5821 		cdinfo_dbp->flags |= CDINFO_NEEDREG;
5822 		return TRUE;
5823 	}
5824 
5825 	/* Set up role list if not done */
5826 	if (cdinfo_dbp->rolelist == NULL && !cdinfo_rolelist_init(cp)) {
5827 		*retcode = READ_ERR;
5828 		return FALSE;
5829 	}
5830 
5831 	/* Set up genre list if not done */
5832 	if (cdinfo_dbp->genrelist == NULL && !cdinfo_genrelist_init(cp)) {
5833 		*retcode = READ_ERR;
5834 		return FALSE;
5835 	}
5836 
5837 	/* Query CDDB about general URLs if not done */
5838 	if (cdinfo_dbp->gen_url_list == NULL && !cdinfo_urls_query(cp, NULL)) {
5839 		*retcode = READ_ERR;
5840 		return FALSE;
5841 	}
5842 
5843 	return TRUE;
5844 }
5845 
5846 
5847 /*
5848  * cdinfo_querycddb
5849  *	Read CDDB data for the current CD and update incore structures.
5850  *
5851  * Args:
5852  *	cp - Pointer to the cdinfo_cddb_t structure returned from
5853  *	cdinfo_opencddb.
5854  *	s - Pointer to curstat_t structure.
5855  *	retcode - Pointer to location where a cdinfo_ret_t code is returned.
5856  *
5857  * Return:
5858  *	TRUE - Success
5859  *	FALSE - Failure
5860  */
5861 bool_t
cdinfo_querycddb(cdinfo_cddb_t * cp,curstat_t * s,cdinfo_ret_t * retcode)5862 cdinfo_querycddb(cdinfo_cddb_t *cp, curstat_t *s, cdinfo_ret_t *retcode)
5863 {
5864 	CddbDiscPtr	discp = NULL,
5865 			discp2;
5866 	CddbDiscsPtr	discsp = NULL;
5867 	CddbStr		tocstr;
5868 	CddbResult	ret;
5869 	CDDBMatchCode	matchcode = MATCH_NONE;
5870 
5871 	if (!cdinfo_initcddb(cp, retcode))
5872 		return FALSE;
5873 
5874 	if ((cdinfo_dbp->flags & CDINFO_NEEDREG) != 0)
5875 		return TRUE;
5876 
5877 	if (cdinfo_dbp->match_tag == -1) {
5878 		/* Query by TOC */
5879 
5880 		tocstr = (CddbStr) cdinfo_tocstr(s);
5881 		DBGPRN(DBG_CDI)(errfp, "TOC string: %s\n", tocstr);
5882 
5883 		DBGPRN(DBG_CDI)(errfp, "CddbControl_LookupMediaByToc: ");
5884 		ret = CddbControl_LookupMediaByToc(
5885 			cp->ctrlp, tocstr, 0, &matchcode
5886 		);
5887 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5888 
5889 		cdinfo_set_errstr(ret);
5890 
5891 		if (ret != Cddb_OK) {
5892 			if (ret == CDDBTRNHTTPProxyError)
5893 				*retcode = AUTH_ERR;
5894 			else
5895 				*retcode = READ_ERR;
5896 			return FALSE;
5897 		}
5898 
5899 		switch (matchcode) {
5900 		case MATCH_EXACT:
5901 			DBGPRN(DBG_CDI)(errfp, "Exact CDDB match\n");
5902 
5903 			DBGPRN(DBG_CDI)(errfp, "CddbControl_GetMatchedDisc: ");
5904 			ret = CddbControl_GetMatchedDisc(cp->ctrlp, &discp);
5905 			DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5906 
5907 			cdinfo_set_errstr(ret);
5908 
5909 			if (ret != Cddb_OK || discp == NULL) {
5910 				*retcode = READ_ERR;
5911 				return FALSE;
5912 			}
5913 			break;
5914 
5915 		case MATCH_MULTIPLE:
5916 			DBGPRN(DBG_CDI)(errfp, "Multiple CDDB matches\n");
5917 
5918 			/* Get the list of matching discs.
5919 			 * Each one is a partial disc
5920 			 */
5921 			DBGPRN(DBG_CDI)(errfp,
5922 				"CddbControl_GetMatchedDiscs: ");
5923 			ret = CddbControl_GetMatchedDiscs(cp->ctrlp, &discsp);
5924 			DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5925 
5926 			cdinfo_set_errstr(ret);
5927 
5928 			if (ret != Cddb_OK || discsp == NULL) {
5929 				*retcode = READ_ERR;
5930 				return FALSE;
5931 			}
5932 
5933 			/* Build matchlist */
5934 			if (!cdinfo_build_matchlist(discsp)) {
5935 				/* Failure */
5936 				CddbReleaseObject(discsp);
5937 				*retcode = READ_ERR;
5938 				return FALSE;
5939 			}
5940 
5941 			/* Save discs pointer - release later */
5942 			cdinfo_dbp->match_aux = (void *) discsp;
5943 			return TRUE;
5944 
5945 		case MATCH_NONE:
5946 			DBGPRN(DBG_CDI)(errfp, "No CDDB match\n");
5947 			return TRUE;
5948 
5949 		default:
5950 			DBGPRN(DBG_CDI)(errfp, "Unknown CDDB matchcode 0x%x\n",
5951 				matchcode);
5952 			*retcode = READ_ERR;
5953 			return FALSE;
5954 		}
5955 	}
5956 	else {
5957 		/* Query after fuzzy selection */
5958 
5959 		discsp = (CddbDiscsPtr) cdinfo_dbp->match_aux;
5960 
5961 		if (cdinfo_dbp->match_tag == 0) {
5962 			/* User chose "none of the above" */
5963 			CddbReleaseObject(discsp);
5964 			return TRUE;
5965 		}
5966 
5967 		DBGPRN(DBG_CDI)(errfp,
5968 			"CddbDiscs_GetDisc[%ld]: ", cdinfo_dbp->match_tag);
5969 		ret = CddbDiscs_GetDisc(discsp,
5970 			cdinfo_dbp->match_tag,
5971 			&discp2
5972 		);
5973 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5974 
5975 		cdinfo_set_errstr(ret);
5976 
5977 		if (ret != Cddb_OK || discp2 == NULL) {
5978 			CddbReleaseObject(discsp);
5979 			*retcode = READ_ERR;
5980 			return FALSE;
5981 		}
5982 
5983 		DBGPRN(DBG_CDI)(errfp, "CddbControl_GetFullDiscInfo: ");
5984 		ret = CddbControl_GetFullDiscInfo(
5985 			cp->ctrlp, discp2, 0, &discp
5986 		);
5987 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
5988 
5989 		cdinfo_set_errstr(ret);
5990 
5991 		if (ret != Cddb_OK) {
5992 			CddbReleaseObject(discp2);
5993 			CddbReleaseObject(discsp);
5994 			*retcode = READ_ERR;
5995 			return FALSE;
5996 		}
5997 
5998 		CddbReleaseObject(discp2);
5999 		CddbReleaseObject(discsp);
6000 	}
6001 
6002 	/* Query CDDB about the disc */
6003 	if (!cdinfo_discinfo_query(discp)) {
6004 		*retcode = READ_ERR;
6005 		return FALSE;
6006 	}
6007 
6008 	/* Query CDDB about the tracks */
6009 	if (!cdinfo_trackinfo_query(discp)) {
6010 		*retcode = READ_ERR;
6011 		return FALSE;
6012 	}
6013 
6014 	/* Query CDDB about the disc-related URLs */
6015 	if (!cdinfo_urls_query(cp, discp)) {
6016 		*retcode = READ_ERR;
6017 		return FALSE;
6018 	}
6019 
6020 	CddbReleaseObject(discp);
6021 
6022 	cdinfo_dbp->flags |= CDINFO_MATCH;
6023 	return TRUE;
6024 }
6025 
6026 
6027 /*
6028  * cdinfo_uregcddb
6029  *	Register the user with CDDB
6030  *
6031  * Args:
6032  *	cp - Pointer to the cdinfo_cddb_t structure returned from
6033  *	cdinfo_opencddb.
6034  *	retcode - return status code
6035  *
6036  * Return:
6037  *	TRUE - Success
6038  *	FALSE - Failure
6039  */
6040 bool_t
cdinfo_uregcddb(cdinfo_cddb_t * cp,cdinfo_ret_t * retcode)6041 cdinfo_uregcddb(cdinfo_cddb_t *cp, cdinfo_ret_t *retcode)
6042 {
6043 	CddbUserInfoPtr	uip = NULL;
6044 	CddbResult	ret;
6045 	CddbBoolean	registered = 0;
6046 
6047 	if (cdinfo_dbp->userreg.handle == NULL ||
6048 	    cdinfo_dbp->userreg.passwd == NULL) {
6049 		*retcode = REGI_ERR;
6050 		return FALSE;
6051 	}
6052 
6053 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetUserInfo: ");
6054 	ret = CddbControl_GetUserInfo(cp->ctrlp, &uip);
6055 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6056 
6057 	cdinfo_set_errstr(ret);
6058 
6059 	if (ret != Cddb_OK && uip == NULL) {
6060 		*retcode = REGI_ERR;
6061 		return FALSE;
6062 	}
6063 
6064 	(void) cdinfo_put_str("CddbUserInfo_PutUserHandle",
6065 		CddbUserInfo_PutUserHandle, uip,
6066 		cdinfo_dbp->userreg.handle
6067 	);
6068 	(void) cdinfo_put_str("CddbUserInfo_PutPassword",
6069 		CddbUserInfo_PutPassword, uip,
6070 		cdinfo_dbp->userreg.passwd
6071 	);
6072 	(void) cdinfo_put_str("CddbUserInfo_PutPasswordHint",
6073 		CddbUserInfo_PutPasswordHint, uip,
6074 		cdinfo_dbp->userreg.hint == NULL ?
6075 			"" : cdinfo_dbp->userreg.hint
6076 	);
6077 	(void) cdinfo_put_str("CddbUserInfo_PutEmailAddress",
6078 		CddbUserInfo_PutEmailAddress, uip,
6079 		cdinfo_dbp->userreg.email == NULL ?
6080 			"" : cdinfo_dbp->userreg.email
6081 	);
6082 	(void) cdinfo_put_str("CddbUserInfo_PutRegionId",
6083 		CddbUserInfo_PutRegionId, uip,
6084 		cdinfo_dbp->userreg.region == NULL ?
6085 			"" : cdinfo_dbp->userreg.region
6086 	);
6087 	(void) cdinfo_put_str("CddbUserInfo_PutPostalCode",
6088 		CddbUserInfo_PutPostalCode, uip,
6089 		cdinfo_dbp->userreg.postal == NULL ?
6090 			"" : cdinfo_dbp->userreg.postal
6091 	);
6092 	(void) cdinfo_put_str("CddbUserInfo_PutAge",
6093 		CddbUserInfo_PutAge, uip,
6094 		cdinfo_dbp->userreg.age == NULL ?
6095 			"" : cdinfo_dbp->userreg.age
6096 	);
6097 	(void) cdinfo_put_str("CddbUserInfo_PutSex",
6098 		CddbUserInfo_PutSex, uip,
6099 		cdinfo_dbp->userreg.gender == NULL ?
6100 			"" : cdinfo_dbp->userreg.gender
6101 	);
6102 
6103 	DBGPRN(DBG_CDI)(errfp, "CddbUserInfo_PutAllowEmail: ");
6104 	ret = CddbUserInfo_PutAllowEmail(uip,
6105 		(CddbBoolean) cdinfo_dbp->userreg.allowemail
6106 	);
6107 	DBGPRN(DBG_CDI)(errfp, "0x%lx %s\n", ret,
6108 		cdinfo_dbp->userreg.allowemail ? "Yes" : "No"
6109 	);
6110 
6111 	DBGPRN(DBG_CDI)(errfp, "CddbUserInfo_PutAllowStats: ");
6112 	ret = CddbUserInfo_PutAllowStats(uip,
6113 		(CddbBoolean) cdinfo_dbp->userreg.allowstats
6114 	);
6115 	DBGPRN(DBG_CDI)(errfp, "0x%lx %s\n", ret,
6116 		cdinfo_dbp->userreg.allowstats ? "Yes" : "No"
6117 	);
6118 
6119 	/* Set the registration info */
6120 	DBGPRN(DBG_CDI)(errfp, "CddbControl_SetUserInfo: ");
6121 	ret = CddbControl_SetUserInfo(cp->ctrlp, uip);
6122 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6123 
6124 	CddbReleaseObject(uip);
6125 
6126 	switch ((unsigned int) ret) {
6127 	case Cddb_OK:
6128 		/* Success: check if user is now registered */
6129 		DBGPRN(DBG_CDI)(errfp, "CddbControl_IsRegistered: ");
6130 		ret = CddbControl_IsRegistered(cp->ctrlp, 0, &registered);
6131 		DBGPRN(DBG_CDI)(errfp,
6132 			"0x%lx %s\n", ret, registered ? "Yes" : "No");
6133 
6134 		if (!registered)
6135 			*retcode = REGI_ERR;
6136 
6137 		DBGPRN(DBG_CDI)(errfp,
6138 			"User \"%s\" is %s registered with CDDB.\n",
6139 			cdinfo_dbp->userreg.handle,
6140 			registered ? "now" : "NOT");
6141 
6142 		return ((bool_t) registered);
6143 
6144 	case (unsigned int) CDDBSVCHandleUsed:
6145 		/* Incorrect password or handle taken */
6146 		*retcode = NAME_ERR;
6147 		return FALSE;
6148 
6149 	default:
6150 		/* Other error */
6151 		*retcode = REGI_ERR;
6152 		return FALSE;
6153 	}
6154 	/*NOTREACHED*/
6155 }
6156 
6157 
6158 /*
6159  * cdinfo_passhintcddb
6160  *	Request CDDB to e-mail the password hint.
6161  *
6162  * Args:
6163  *	cp - Pointer to the cdinfo_cddb_t structure returned from
6164  *	cdinfo_opencddb.
6165  *	retcode - return status code
6166  *
6167  * Return:
6168  *	TRUE - Success
6169  *	FALSE - Failure
6170  */
6171 bool_t
cdinfo_passhintcddb(cdinfo_cddb_t * cp,cdinfo_ret_t * retcode)6172 cdinfo_passhintcddb(cdinfo_cddb_t *cp, cdinfo_ret_t *retcode)
6173 {
6174 	CddbUserInfoPtr	uip = NULL;
6175 	CddbResult	ret;
6176 
6177 	if (cdinfo_dbp->userreg.handle == NULL) {
6178 		*retcode = REGI_ERR;
6179 		return FALSE;
6180 	}
6181 
6182 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetUserInfo: ");
6183 	ret = CddbControl_GetUserInfo(cp->ctrlp, &uip);
6184 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6185 
6186 	cdinfo_set_errstr(ret);
6187 
6188 	if (ret != Cddb_OK && uip == NULL) {
6189 		*retcode = REGI_ERR;
6190 		return FALSE;
6191 	}
6192 
6193 	(void) cdinfo_put_str("CddbUserInfo_PutUserHandle",
6194 		CddbUserInfo_PutUserHandle, uip,
6195 		cdinfo_dbp->userreg.handle
6196 	);
6197 
6198 	/* Set the registration info - request CDDB to mail password hint */
6199 	DBGPRN(DBG_CDI)(errfp, "CddbControl_SetUserInfo: ");
6200 	ret = CddbControl_SetUserInfo(cp->ctrlp, uip);
6201 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6202 
6203 	cdinfo_set_errstr(ret);
6204 
6205 	CddbReleaseObject(uip);
6206 
6207 	switch ((unsigned int) ret) {
6208 	case Cddb_OK:
6209 		/* Success */
6210 		return TRUE;
6211 
6212 	case (unsigned int) CDDBSVCUnknownHandle:
6213 		/* Unknown handle */
6214 		*retcode = NAME_ERR;
6215 		return FALSE;
6216 
6217 	case (unsigned int) CDDBSVCNoHint:
6218 		/* No hint registered */
6219 		*retcode = HINT_ERR;
6220 		return FALSE;
6221 
6222 	case (unsigned int) CDDBSVCNoEmail:
6223 		/* No e-mail address registered */
6224 		*retcode = MAIL_ERR;
6225 		return FALSE;
6226 
6227 	default:
6228 		/* Other error */
6229 		*retcode = REGI_ERR;
6230 		return FALSE;
6231 	}
6232 	/*NOTREACHED*/
6233 }
6234 
6235 
6236 /*
6237  * cdinfo_submitcddb
6238  *	Submit current CD info to CDDB
6239  *
6240  * Args:
6241  *	cp - Pointer to the cdinfo_cddb_t structure returned from
6242  *	     cdinfo_opencddb.
6243  *	s - Pointer to the curstat_t structure
6244  *	retcode - Return pointer of status code
6245  *
6246  * Return:
6247  *	TRUE - Success
6248  *	FALSE - Failure
6249  */
6250 bool_t
cdinfo_submitcddb(cdinfo_cddb_t * cp,curstat_t * s,cdinfo_ret_t * retcode)6251 cdinfo_submitcddb(cdinfo_cddb_t *cp, curstat_t *s, cdinfo_ret_t *retcode)
6252 {
6253 	CddbDiscPtr		discp = NULL;
6254 	CddbTrackPtr		trkp = NULL;
6255 	CddbCreditPtr		credp = NULL;
6256 	CddbSegmentPtr		segp = NULL;
6257 	CddbResult		ret;
6258 	long			ntrks,
6259 				pval;
6260 	int			i;
6261 	CddbStr			tocstr;
6262 	cdinfo_credit_t		*p;
6263 	cdinfo_segment_t	*q;
6264 
6265 	if (!cdinfo_initcddb(cp, retcode))
6266 		return FALSE;
6267 
6268 	if ((cdinfo_dbp->flags & CDINFO_NEEDREG) != 0)
6269 		return TRUE;
6270 
6271 	tocstr = (CddbStr) cdinfo_tocstr(s);
6272 
6273 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetSubmitDisc: ");
6274 	ret = CddbControl_GetSubmitDisc(
6275 		cp->ctrlp,
6276 		tocstr,
6277 		cdinfo_dbp->disc.mediaid,
6278 		cdinfo_dbp->disc.muiid,
6279 		&discp
6280 	);
6281 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6282 
6283 	cdinfo_set_errstr(ret);
6284 
6285 	if (ret != Cddb_OK || discp == NULL) {
6286 		if (discp != NULL)
6287 			CddbReleaseObject(discp);
6288 		*retcode = SUBMIT_ERR;
6289 		return FALSE;
6290 	}
6291 
6292 	/*
6293 	 * Fill in disc information
6294 	 */
6295 	(void) cdinfo_put_str("CddbDisc_PutToc",
6296 		CddbDisc_PutToc, discp, tocstr
6297 	);
6298 
6299 	DBGPRN(DBG_CDI)(errfp, "CddbDisc_PutCompilation: ");
6300 	ret = CddbDisc_PutCompilation(discp,
6301 		(CddbBoolean) cdinfo_dbp->disc.compilation
6302 	);
6303 	DBGPRN(DBG_CDI)(errfp, "0x%lx %s\n", ret,
6304 		cdinfo_dbp->disc.compilation ? "Yes" : "No"
6305 	);
6306 
6307 	(void) cdinfo_put_str("CddbDisc_PutArtist",
6308 		CddbDisc_PutArtist, discp, cdinfo_dbp->disc.artist
6309 	);
6310 	(void) cdinfo_put_str("CddbDisc_PutTitle",
6311 		CddbDisc_PutTitle, discp, cdinfo_dbp->disc.title
6312 	);
6313 	(void) cdinfo_put_str("CddbDisc_PutTitleSort",
6314 		CddbDisc_PutTitleSort, discp, cdinfo_dbp->disc.sorttitle
6315 	);
6316 	(void) cdinfo_put_str("CddbDisc_PutTitleThe",
6317 		CddbDisc_PutTitleThe, discp, cdinfo_dbp->disc.title_the
6318 	);
6319 	(void) cdinfo_put_str("CddbDisc_PutYear",
6320 		CddbDisc_PutYear, discp, cdinfo_dbp->disc.year
6321 	);
6322 	(void) cdinfo_put_str("CddbDisc_PutLabel",
6323 		CddbDisc_PutLabel, discp, cdinfo_dbp->disc.label
6324 	);
6325 	(void) cdinfo_put_str("CddbDisc_PutGenreId",
6326 		CddbDisc_PutGenreId, discp, cdinfo_dbp->disc.genre
6327 	);
6328 	(void) cdinfo_put_str("CddbDisc_PutSecondaryGenreId",
6329 		CddbDisc_PutSecondaryGenreId, discp, cdinfo_dbp->disc.genre2
6330 	);
6331 	(void) cdinfo_put_str("CddbDisc_PutNumberInSet",
6332 		CddbDisc_PutNumberInSet, discp, cdinfo_dbp->disc.dnum
6333 	);
6334 	(void) cdinfo_put_str("CddbDisc_PutTotalInSet",
6335 		CddbDisc_PutTotalInSet, discp, cdinfo_dbp->disc.tnum
6336 	);
6337 	(void) cdinfo_put_str("CddbDisc_PutRegionId",
6338 		CddbDisc_PutRegionId, discp, cdinfo_dbp->disc.region
6339 	);
6340 	(void) cdinfo_put_str("CddbDisc_PutLanguageId",
6341 		CddbDisc_PutLanguageId, discp, cdinfo_dbp->disc.lang
6342 	);
6343 	(void) cdinfo_put_str("CddbDisc_PutNotes",
6344 		CddbDisc_PutNotes, discp, cdinfo_dbp->disc.notes
6345 	);
6346 	(void) cdinfo_put_str("CddbDisc_PutRevision",
6347 		CddbDisc_PutRevision, discp, cdinfo_dbp->disc.revision
6348 	);
6349 	(void) cdinfo_put_str("CddbDisc_PutRevisionTag",
6350 		CddbDisc_PutRevisionTag, discp, cdinfo_dbp->disc.revtag
6351 	);
6352 
6353 	(void) cdinfo_put_fullname("CddbDisc_PutArtistFullName",
6354 		CddbDisc_PutArtistFullName, discp,
6355 		cdinfo_dbp->disc.artistfname.dispname,
6356 		cdinfo_dbp->disc.artistfname.lastname,
6357 		cdinfo_dbp->disc.artistfname.firstname,
6358 		cdinfo_dbp->disc.artistfname.the
6359 	);
6360 
6361 	/* Disc credits */
6362 	for (p = cdinfo_dbp->disc.credit_list; p != NULL; p = p->next) {
6363 		DBGPRN(DBG_CDI)(errfp, "CddbDisc_AddCredit: ");
6364 		ret = CddbDisc_AddCredit(discp,
6365 				p->crinfo.role->id,
6366 				p->crinfo.name,
6367 				&credp);
6368 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6369 
6370 		if (ret != Cddb_OK || credp == NULL)
6371 			continue;
6372 
6373 		(void) cdinfo_put_fullname("  CddbCredit_PutFullName",
6374 			CddbCredit_PutFullName, credp,
6375 			p->crinfo.fullname.dispname,
6376 			p->crinfo.fullname.lastname,
6377 			p->crinfo.fullname.firstname,
6378 			p->crinfo.fullname.the
6379 		);
6380 
6381 		(void) cdinfo_put_str("  CddbCredit_PutNotes",
6382 			CddbCredit_PutNotes, credp,
6383 			p->notes
6384 		);
6385 
6386 		CddbReleaseObject(credp);
6387 	}
6388 
6389 	/* Segments */
6390 	for (q = cdinfo_dbp->disc.segment_list; q != NULL; q = q->next) {
6391 		DBGPRN(DBG_CDI)(errfp, "CddbDisc_AddSegment: ");
6392 		ret = CddbDisc_AddSegment(discp, q->name, &segp);
6393 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6394 
6395 		if (ret != Cddb_OK || segp == NULL)
6396 			continue;
6397 
6398 		(void) cdinfo_put_str("  CddbSegment_PutNotes",
6399 			CddbSegment_PutNotes, segp,
6400 			q->notes
6401 		);
6402 		(void) cdinfo_put_str("  CddbSegment_PutStartTrack",
6403 			CddbSegment_PutStartTrack, segp,
6404 			q->start_track
6405 		);
6406 		(void) cdinfo_put_str("  CddbSegment_PutStartFrame",
6407 			CddbSegment_PutStartFrame, segp,
6408 			q->start_frame
6409 		);
6410 		(void) cdinfo_put_str("  CddbSegment_PutEndTrack",
6411 			CddbSegment_PutEndTrack, segp,
6412 			q->end_track
6413 		);
6414 		(void) cdinfo_put_str("  CddbSegment_PutEndFrame",
6415 			CddbSegment_PutEndFrame, segp,
6416 			q->end_frame
6417 		);
6418 
6419 		/* Segment Credits */
6420 		for (p = q->credit_list; p != NULL; p = p->next) {
6421 			DBGPRN(DBG_CDI)(errfp, "    CddbSegment_AddCredit: ");
6422 			ret = CddbSegment_AddCredit(segp,
6423 					p->crinfo.role->id,
6424 					p->crinfo.name,
6425 					&credp);
6426 			DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6427 
6428 			if (ret != Cddb_OK || credp == NULL)
6429 				continue;
6430 
6431 			(void) cdinfo_put_fullname(
6432 				"    CddbCredit_PutFullName",
6433 				CddbCredit_PutFullName, credp,
6434 				p->crinfo.fullname.dispname,
6435 				p->crinfo.fullname.lastname,
6436 				p->crinfo.fullname.firstname,
6437 				p->crinfo.fullname.the
6438 			);
6439 
6440 			(void) cdinfo_put_str("    CddbCredit_PutNotes",
6441 				CddbCredit_PutNotes, credp,
6442 				p->notes
6443 			);
6444 
6445 			CddbReleaseObject(credp);
6446 		}
6447 
6448 		CddbReleaseObject(segp);
6449 	}
6450 
6451 	/*
6452 	 * Fill in track information
6453 	 */
6454 	DBGPRN(DBG_CDI)(errfp, "CddbDisc_GetNumTracks: ");
6455 	ret = CddbDisc_GetNumTracks(discp, &ntrks);
6456 	DBGPRN(DBG_CDI)(errfp, "0x%lx %ld tracks\n", ret, ntrks);
6457 
6458 	for (i = 0; i < (int) ntrks; i++) {
6459 		DBGPRN(DBG_CDI)(errfp, "CddbDisc_GetTrack[%02d]: ", i+1);
6460 		ret = CddbDisc_GetTrack(discp, (long) (i+1), &trkp);
6461 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6462 
6463 		if (ret != Cddb_OK || trkp == NULL)
6464 			continue;
6465 
6466 		(void) cdinfo_put_str("  CddbTrack_PutArtist",
6467 			CddbTrack_PutArtist, trkp,
6468 			cdinfo_dbp->track[i].artist
6469 		);
6470 		(void) cdinfo_put_str("  CddbTrack_PutTitle",
6471 			CddbTrack_PutTitle, trkp,
6472 			cdinfo_dbp->track[i].title
6473 		);
6474 		(void) cdinfo_put_str("  CddbTrack_PutTitleSort",
6475 			CddbTrack_PutTitleSort, trkp,
6476 			cdinfo_dbp->track[i].sorttitle
6477 		);
6478 		(void) cdinfo_put_str("  CddbTrack_PutTitleThe",
6479 			CddbTrack_PutTitleThe, trkp,
6480 			cdinfo_dbp->track[i].title_the
6481 		);
6482 		(void) cdinfo_put_str("  CddbTrack_PutYear",
6483 			CddbTrack_PutYear, trkp,
6484 			cdinfo_dbp->track[i].year
6485 		);
6486 		(void) cdinfo_put_str("  CddbTrack_PutLabel",
6487 			CddbTrack_PutLabel, trkp,
6488 			cdinfo_dbp->track[i].label
6489 		);
6490 		(void) cdinfo_put_str("  CddbTrack_PutGenreId",
6491 			CddbTrack_PutGenreId, trkp,
6492 			cdinfo_dbp->track[i].genre
6493 		);
6494 		(void) cdinfo_put_str("  CddbTrack_PutSecondaryGenreId",
6495 			CddbTrack_PutSecondaryGenreId, trkp,
6496 			cdinfo_dbp->track[i].genre2
6497 		);
6498 		(void) cdinfo_put_str("  CddbTrack_PutBeatsPerMinute",
6499 			CddbTrack_PutBeatsPerMinute, trkp,
6500 			cdinfo_dbp->track[i].bpm
6501 		);
6502 		(void) cdinfo_put_str("  CddbTrack_PutNotes",
6503 			CddbTrack_PutNotes, trkp,
6504 			cdinfo_dbp->track[i].notes
6505 		);
6506 		(void) cdinfo_put_str("  CddbTrack_PutISRC",
6507 			CddbTrack_PutISRC, trkp,
6508 			cdinfo_dbp->track[i].isrc
6509 		);
6510 
6511 		(void) cdinfo_put_fullname("  CddbTrack_PutArtistFullName",
6512 			CddbTrack_PutArtistFullName, trkp,
6513 			cdinfo_dbp->track[i].artistfname.dispname,
6514 			cdinfo_dbp->track[i].artistfname.lastname,
6515 			cdinfo_dbp->track[i].artistfname.firstname,
6516 			cdinfo_dbp->track[i].artistfname.the
6517 		);
6518 
6519 		for (p = cdinfo_dbp->track[i].credit_list; p != NULL;
6520 		     p = p->next) {
6521 			DBGPRN(DBG_CDI)(errfp, "  CddbTrack_AddCredit: ");
6522 			ret = CddbTrack_AddCredit(trkp,
6523 					p->crinfo.role->id,
6524 					p->crinfo.name,
6525 					&credp);
6526 			DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6527 
6528 			if (ret != Cddb_OK || credp == NULL)
6529 				continue;
6530 
6531 			(void) cdinfo_put_fullname(
6532 				"  CddbCredit_PutFullName",
6533 				CddbCredit_PutFullName, credp,
6534 				p->crinfo.fullname.dispname,
6535 				p->crinfo.fullname.lastname,
6536 				p->crinfo.fullname.firstname,
6537 				p->crinfo.fullname.the
6538 			);
6539 
6540 			(void) cdinfo_put_str("  CddbCredit_PutNotes",
6541 				CddbCredit_PutNotes, credp,
6542 				p->notes
6543 			);
6544 
6545 			CddbReleaseObject(credp);
6546 		}
6547 
6548 		CddbReleaseObject(trkp);
6549 	}
6550 
6551 	/* Submit the disc info */
6552 	DBGPRN(DBG_CDI)(errfp, "CddbControl_SubmitDisc: ");
6553 	ret = CddbControl_SubmitDisc(cp->ctrlp, discp, 0, &pval);
6554 	DBGPRN(DBG_CDI)(errfp, "0x%lx pval=%lx\n", ret, pval);
6555 
6556 	cdinfo_set_errstr(ret);
6557 
6558 	CddbReleaseObject(discp);
6559 
6560 	*retcode = (ret == Cddb_OK) ? 0 : SUBMIT_ERR;
6561 	util_delayms(1000);
6562 	return (ret == Cddb_OK);
6563 }
6564 
6565 
6566 /*
6567  * cdinfo_submiturlcddb
6568  *	Submit to CDDB a URL pertaining to the current CD
6569  *
6570  * Args:
6571  *	cp - Pointer to the cdinfo_cddb_t structure returned from
6572  *	     cdinfo_opencddb.
6573  *	up - Pointer to the cdinfo_url_t structure
6574  *	retcode - Return pointer of status code
6575  *
6576  * Return:
6577  *	TRUE - Success
6578  *	FALSE - Failure
6579  */
6580 bool_t
cdinfo_submiturlcddb(cdinfo_cddb_t * cp,cdinfo_url_t * up,cdinfo_ret_t * retcode)6581 cdinfo_submiturlcddb(cdinfo_cddb_t *cp, cdinfo_url_t *up,
6582 		     cdinfo_ret_t *retcode)
6583 {
6584 	CddbDiscPtr		discp = NULL;
6585 	CddbDiscsPtr		discsp = NULL;
6586 	CddbURLManagerPtr	urlmgrp = NULL;
6587 	CddbURLPtr		urlp = NULL;
6588 	CddbResult		ret;
6589 
6590 	if (!cdinfo_initcddb(cp, retcode))
6591 		return FALSE;
6592 
6593 	if ((cdinfo_dbp->flags & CDINFO_NEEDREG) != 0)
6594 		return TRUE;
6595 
6596 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetDiscInfo: ");
6597 	ret = CddbControl_GetDiscInfo(
6598 		cp->ctrlp,
6599 		cdinfo_dbp->disc.mediaid,
6600 		cdinfo_dbp->disc.muiid,
6601 		NULL, NULL, 0,
6602 		&discp, &discsp
6603 	);
6604 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6605 
6606 	cdinfo_set_errstr(ret);
6607 
6608 	if (ret != Cddb_OK || discp == NULL) {
6609 		if (discp != NULL)
6610 			CddbReleaseObject(discp);
6611 		if (discsp != NULL)
6612 			CddbReleaseObject(discsp);
6613 		*retcode = SUBMIT_ERR;
6614 		return FALSE;
6615 	}
6616 
6617 	if (discsp != NULL)
6618 		CddbReleaseObject(discsp);
6619 
6620 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetURLManager: ");
6621 	ret = CddbControl_GetURLManager(cp->ctrlp, &urlmgrp);
6622 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6623 
6624 	cdinfo_set_errstr(ret);
6625 
6626 	if (ret != Cddb_OK || urlmgrp == NULL) {
6627 		CddbReleaseObject(discp);
6628 		*retcode = SUBMIT_ERR;
6629 		return FALSE;
6630 	}
6631 
6632 	urlp = (CddbURLPtr) CddbCreateObject(CddbURLType);
6633 
6634 	(void) cdinfo_put_str("CddbURL_PutType",
6635 		CddbURL_PutType, urlp, up->type
6636 	);
6637 	(void) cdinfo_put_str("CddbURL_PutHref",
6638 		CddbURL_PutHref, urlp, up->href
6639 	);
6640 	(void) cdinfo_put_str("CddbURL_PutDisplayLink",
6641 		CddbURL_PutDisplayLink, urlp, up->displink
6642 	);
6643 	(void) cdinfo_put_str("CddbURL_PutDisplayText",
6644 		CddbURL_PutDisplayText, urlp, up->disptext
6645 	);
6646 	(void) cdinfo_put_str("CddbURL_PutCategory",
6647 		CddbURL_PutCategory, urlp, up->categ
6648 	);
6649 	(void) cdinfo_put_str("CddbURL_PutDescription",
6650 		CddbURL_PutDescription, urlp, up->desc
6651 	);
6652 	(void) cdinfo_put_str("CddbURL_PutSize",
6653 		CddbURL_PutSize, urlp, up->size
6654 	);
6655 	(void) cdinfo_put_str("CddbURL_PutWeight",
6656 		CddbURL_PutWeight, urlp, up->weight
6657 	);
6658 
6659 	DBGPRN(DBG_CDI)(errfp, "CddbURLManager_SubmitURL: ");
6660 	ret = CddbURLManager_SubmitURL(urlmgrp, discp, urlp);
6661 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6662 
6663 	cdinfo_set_errstr(ret);
6664 
6665 	CddbReleaseObject(urlp);
6666 	CddbReleaseObject(urlmgrp);
6667 	CddbReleaseObject(discp);
6668 
6669 	util_delayms(1000);
6670 	return (ret == Cddb_OK);
6671 }
6672 
6673 
6674 /*
6675  * cdinfo_flushcddb
6676  *	Flush local CDDB cache.
6677  *
6678  * Args:
6679  *	cp - Pointer to the cdinfo_cddb_t structure returned from
6680  *	cdinfo_opencddb.
6681  *
6682  * Return:
6683  *	TRUE - Success
6684  *	FALSE - Failure
6685  */
6686 /*ARGSUSED*/
6687 bool_t
cdinfo_flushcddb(cdinfo_cddb_t * cp)6688 cdinfo_flushcddb(cdinfo_cddb_t *cp)
6689 {
6690 	CddbResult	ret;
6691 
6692 	DBGPRN(DBG_CDI)(errfp, "CddbControl_FlushLocalCache: ");
6693 	ret = CddbControl_FlushLocalCache(cp->ctrlp, FLUSH_DEFAULT);
6694 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6695 
6696 	cdinfo_set_errstr(ret);
6697 
6698 	util_delayms(1000);
6699 	return (ret == Cddb_OK ? TRUE : FALSE);
6700 }
6701 
6702 
6703 /*
6704  * cdinfo_infobrowsercddb
6705  *	Invoke CDDB info browser for the current disc
6706  *
6707  * Args:
6708  *	cp - Pointer to the cdinfo_cddb_t structure returned from
6709  *	cdinfo_opencddb.
6710  *
6711  * Return:
6712  *	TRUE - Success
6713  *	FALSE - Failure
6714  */
6715 bool_t
cdinfo_infobrowsercddb(cdinfo_cddb_t * cp)6716 cdinfo_infobrowsercddb(cdinfo_cddb_t *cp)
6717 {
6718 	CddbDiscPtr	discp = NULL;
6719 	CddbDiscsPtr	discsp = NULL;
6720 	CddbResult	ret;
6721 	int		retcode;
6722 
6723 	if (!cdinfo_initcddb(cp, &retcode))
6724 		return FALSE;
6725 
6726 	if ((cdinfo_dbp->flags & CDINFO_NEEDREG) != 0)
6727 		return TRUE;
6728 
6729 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetDiscInfo: ");
6730 	ret = CddbControl_GetDiscInfo(
6731 		cp->ctrlp,
6732 		cdinfo_dbp->disc.mediaid,
6733 		cdinfo_dbp->disc.muiid,
6734 		NULL, NULL, 0,
6735 		&discp, &discsp
6736 	);
6737 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6738 
6739 	cdinfo_set_errstr(ret);
6740 
6741 	if (ret != Cddb_OK || discp == NULL) {
6742 		if (discp != NULL)
6743 			CddbReleaseObject(discp);
6744 		if (discsp != NULL)
6745 			CddbReleaseObject(discsp);
6746 		return FALSE;
6747 	}
6748 
6749 	if (discsp != NULL)
6750 		CddbReleaseObject(discsp);
6751 
6752 	DBGPRN(DBG_CDI)(errfp, "CddbControl_InvokeInfoBrowser: ");
6753 	ret = CddbControl_InvokeInfoBrowser(cp->ctrlp, discp, 0, UI_NONE);
6754 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6755 
6756 	cdinfo_set_errstr(ret);
6757 
6758 	CddbReleaseObject(discp);
6759 
6760 	return (ret == Cddb_OK);
6761 }
6762 
6763 
6764 /*
6765  * cdinfo_urlcddb
6766  *	Go to a CDDB-supplied URL
6767  *
6768  * Args:
6769  *	cp - Pointer to the cdinfo_cddb_t structure returned from
6770  *	cdinfo_opencddb.
6771  *	wtype - WTYPE_GEN or WTYPE_ALBUM
6772  *	idx - index number into the URL list
6773  *
6774  * Return:
6775  *	TRUE - Success
6776  *	FALSE - Failure
6777  */
6778 bool_t
cdinfo_urlcddb(cdinfo_cddb_t * cp,int wtype,int idx)6779 cdinfo_urlcddb(cdinfo_cddb_t *cp, int wtype, int idx)
6780 {
6781 	CddbDiscPtr		discp = NULL;
6782 	CddbDiscsPtr		discsp = NULL;
6783 	CddbURLManagerPtr	urlmgrp = NULL;
6784 	CddbURLListPtr		urllistp = NULL;
6785 	CddbURLPtr		urlp = NULL;
6786 	CddbResult		ret;
6787 	int			retcode;
6788 
6789 	if (!cdinfo_initcddb(cp, &retcode))
6790 		return FALSE;
6791 
6792 	if ((cdinfo_dbp->flags & CDINFO_NEEDREG) != 0)
6793 		return TRUE;
6794 
6795 	if (wtype == WTYPE_ALBUM) {
6796 		DBGPRN(DBG_CDI)(errfp, "CddbControl_GetDiscInfo: ");
6797 		ret = CddbControl_GetDiscInfo(
6798 			cp->ctrlp,
6799 			cdinfo_dbp->disc.mediaid,
6800 			cdinfo_dbp->disc.muiid,
6801 			NULL, NULL, 0,
6802 			&discp, &discsp
6803 		);
6804 		DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6805 
6806 		cdinfo_set_errstr(ret);
6807 
6808 		if (ret != Cddb_OK || discp == NULL) {
6809 			if (discp != NULL)
6810 				CddbReleaseObject(discp);
6811 			if (discsp != NULL)
6812 				CddbReleaseObject(discsp);
6813 			return FALSE;
6814 		}
6815 	}
6816 
6817 	if (discsp != NULL)
6818 		CddbReleaseObject(discsp);
6819 
6820 	DBGPRN(DBG_CDI)(errfp, "CddbControl_GetURLManager: ");
6821 	ret = CddbControl_GetURLManager(cp->ctrlp, &urlmgrp);
6822 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6823 
6824 	cdinfo_set_errstr(ret);
6825 
6826 	if (ret != Cddb_OK || urlmgrp == NULL) {
6827 		if (discp != NULL)
6828 			CddbReleaseObject(discp);
6829 		return FALSE;
6830 	}
6831 
6832 	/* Get the appropriate URL list */
6833 	DBGPRN(DBG_CDI)(errfp, "CddbURLManager_GetMenuURLs: ");
6834 	ret = CddbURLManager_GetMenuURLs(urlmgrp, discp, &urllistp);
6835 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6836 
6837 	cdinfo_set_errstr(ret);
6838 
6839 	if (ret != Cddb_OK || urllistp == NULL) {
6840 		CddbReleaseObject(urlmgrp);
6841 		if (discp != NULL)
6842 			CddbReleaseObject(discp);
6843 		return FALSE;
6844 	}
6845 
6846 	/* Get the appropriate URL */
6847 	DBGPRN(DBG_CDI)(errfp, "CddbURLList_GetURL: ");
6848 	ret = CddbURLList_GetURL(urllistp, (long) idx, &urlp);
6849 	DBGPRN(DBG_CDI)(errfp, "0x%lx idx=%d\n", ret, idx);
6850 
6851 	cdinfo_set_errstr(ret);
6852 
6853 	if (ret != Cddb_OK || urlp == NULL) {
6854 		CddbReleaseObject(urllistp);
6855 		CddbReleaseObject(urlmgrp);
6856 		if (discp != NULL)
6857 			CddbReleaseObject(discp);
6858 		return FALSE;
6859 	}
6860 
6861 	/* Go to the URL */
6862 	DBGPRN(DBG_CDI)(errfp, "CddbURLManager_GotoURL: ");
6863 	ret = CddbURLManager_GotoURL(urlmgrp, urlp, 0);
6864 	DBGPRN(DBG_CDI)(errfp, "0x%lx\n", ret);
6865 
6866 	cdinfo_set_errstr(ret);
6867 
6868 	CddbReleaseObject(urlp);
6869 	CddbReleaseObject(urllistp);
6870 	CddbReleaseObject(urlmgrp);
6871 	if (discp != NULL)
6872 		CddbReleaseObject(discp);
6873 
6874 	return (ret == Cddb_OK);
6875 }
6876 
6877 
6878 /*
6879  * cdinfo_free_matchlist
6880  *	Deallocate the match list.
6881  *
6882  * Args:
6883  *	None.
6884  *
6885  * Return:
6886  *	Nothing.
6887  */
6888 void
cdinfo_free_matchlist(void)6889 cdinfo_free_matchlist(void)
6890 {
6891 	cdinfo_match_t	*p,
6892 			*q;
6893 
6894 	for (p = q = cdinfo_dbp->matchlist; p != NULL; p = q) {
6895 		q = p->next;
6896 		if (p->artist != NULL)
6897 			MEM_FREE(p->artist);
6898 		if (p->title != NULL)
6899 			MEM_FREE(p->title);
6900 		if (p->genre != NULL)
6901 			MEM_FREE(p->genre);
6902 		MEM_FREE(p);
6903 	}
6904 
6905 	cdinfo_dbp->matchlist = NULL;
6906 	cdinfo_dbp->match_aux = NULL;
6907 	cdinfo_dbp->match_tag = -1;
6908 	cdinfo_dbp->sav_cddbp = NULL;
6909 	cdinfo_dbp->sav_rpp = cdinfo_dbp->sav_spp = NULL;
6910 }
6911 
6912 
6913 /*
6914  * cdinfo_skip_whitespace
6915  *	Given a string, return a pointer to the first non-whitespace
6916  *	character in it.
6917  *
6918  * Args:
6919  *	str - String pointer
6920  *
6921  * Return:
6922  *	Pointer to first non-whitespace character in the string
6923  */
6924 char *
cdinfo_skip_whitespace(char * str)6925 cdinfo_skip_whitespace(char *str)
6926 {
6927 	for (; *str != '\0' && (*str == ' ' || *str == '\t'); str++)
6928 		;
6929 
6930 	return (str);
6931 }
6932 
6933 
6934 /*
6935  * cdinfo_skip_nowhitespace
6936  *	Given a string, return a pointer to the first whitespace
6937  *	character in it.
6938  *
6939  * Args:
6940  *	str - String pointer
6941  *
6942  * Return:
6943  *	Pointer to first whitespace character in the string
6944  */
6945 char *
cdinfo_skip_nowhitespace(char * str)6946 cdinfo_skip_nowhitespace(char *str)
6947 {
6948 	for (; *str != '\0' && (*str != ' ' && *str != '\t'); str++)
6949 		;
6950 
6951 	return (str);
6952 }
6953 
6954 
6955 /*
6956  * cdinfo_fgetline
6957  *	Read a line from the file stream fp, and allocate a dynamic
6958  *	buffer to hold it.  If a line is terminated with a '\' character,
6959  *	that is considered a "continuation" marker, and another line
6960  *	is read and contactenated.  The caller should use MEM_FREE to
6961  *	deallocate the buffer that is returned when it's done using it.
6962  *
6963  * Args:
6964  *	fp - The stdio file stream
6965  *
6966  * Return:
6967  *	Allocated buffer containing the line read from stream.
6968  */
6969 char *
cdinfo_fgetline(FILE * fp)6970 cdinfo_fgetline(FILE *fp)
6971 {
6972 	size_t		n;
6973 	char		*buf;
6974 	static char	rbuf[2048];
6975 
6976 	buf = NULL;
6977 	for (;;) {
6978 		if (fgets(rbuf, sizeof(rbuf), fp) == NULL)
6979 			break;
6980 
6981 		if ((n = strlen(rbuf)) == 0)
6982 			break;
6983 
6984 		if (buf == NULL) {
6985 			buf = (char *) MEM_ALLOC("fgetline_buf", n + 1);
6986 			if (buf != NULL)
6987 				buf[0] = '\0';
6988 		}
6989 		else {
6990 			buf = (char *) MEM_REALLOC("fgetline_buf",
6991 				buf, strlen(buf) + n + 1
6992 			);
6993 		}
6994 
6995 		if (buf == NULL) {
6996 			CDINFO_FATAL(app_data.str_nomemory);
6997 			return NULL;
6998 		}
6999 
7000 		if (rbuf[n-1] == '\n') {
7001 			if (n > 1 && rbuf[n-2] == '\\') {
7002 				rbuf[n-2] = '\0';
7003 				(void) strcat(buf, rbuf);
7004 			}
7005 			else {
7006 				rbuf[n-1] = '\0';
7007 				(void) strcat(buf, rbuf);
7008 				break;
7009 			}
7010 		}
7011 		else
7012 			(void) strcat(buf, rbuf);
7013 	}
7014 
7015 	return (buf);
7016 }
7017 
7018 
7019 /*
7020  * cdinfo_wwwchk_cleanup
7021  *	Clean up the check list created in cdinfo_wwwmenu_chk.
7022  *
7023  * Args:
7024  *	None.
7025  *
7026  * Return:
7027  *	Nothing.
7028  */
7029 void
cdinfo_wwwchk_cleanup(void)7030 cdinfo_wwwchk_cleanup(void)
7031 {
7032 	w_entchk_t	*c,
7033 			*c1;
7034 
7035 	/* Clean up check list */
7036 	for (c = c1 = cdinfo_wentchk_head; c != NULL; c = c1) {
7037 		c1 = c->next;
7038 		MEM_FREE(c);
7039 	}
7040 	cdinfo_wentchk_head = NULL;
7041 }
7042 
7043 
7044 /*
7045  * cdinfo_wwwmenu_chk
7046  *	Given a wwwwarp menu, traverse all its submenus and make sure
7047  *	there are no circular menu links.
7048  *
7049  * Args:
7050  *	menu - The first entry of a menu
7051  *	topmenu - boolean indicating whether this is called from the
7052  *		  top level menu.
7053  */
7054 bool_t
cdinfo_wwwmenu_chk(w_ent_t * menu,bool_t topmenu)7055 cdinfo_wwwmenu_chk(w_ent_t *menu, bool_t topmenu)
7056 {
7057 	bool_t			ret;
7058 	w_ent_t			*p;
7059 	w_entchk_t		*c,
7060 				*c1;
7061 	static w_entchk_t	*c2;
7062 
7063 	ret = TRUE;
7064 
7065 	for (p = menu; p != NULL; p = p->nextent) {
7066 		if (p->type != WTYPE_SUBMENU)
7067 			continue;
7068 
7069 		/* Check to see if this submenu points to an ancester menu */
7070 		for (c1 = cdinfo_wentchk_head; c1 != NULL; c1 = c1->next) {
7071 			if (strcmp(c1->ent->name, p->submenu->name) == 0) {
7072 				p->type = WTYPE_NULL;
7073 				p->submenu = NULL;
7074 				ret = FALSE;
7075 				break;
7076 			}
7077 		}
7078 		if (!ret)
7079 			break;
7080 
7081 		/* Add this submenu to link */
7082 		c = (w_entchk_t *)(void *) MEM_ALLOC(
7083 			"w_entchk_t", sizeof(w_entchk_t)
7084 		);
7085 		if (c == NULL) {
7086 			CDINFO_FATAL(app_data.str_nomemory);
7087 			ret = FALSE;
7088 			break;
7089 		}
7090 		c->ent = p->submenu;
7091 		c->next = NULL;
7092 
7093 		if (cdinfo_wentchk_head == NULL)
7094 			cdinfo_wentchk_head = c2 = c;
7095 		else {
7096 			c2->next = c;
7097 			c2 = c;
7098 		}
7099 
7100 		/* Recurse to the next level */
7101 		if (!cdinfo_wwwmenu_chk(p->submenu, FALSE)) {
7102 			ret = FALSE;
7103 			break;
7104 		}
7105 
7106 		if (topmenu)
7107 			cdinfo_wwwchk_cleanup();
7108 	}
7109 
7110 	if (topmenu)
7111 		cdinfo_wwwchk_cleanup();
7112 	return (ret);
7113 }
7114 
7115 
7116 /*
7117  * cdinfo_scan_url_attrib
7118  *	Scan a URL template string and record its attributes.
7119  *
7120  * Args:
7121  *	url - The URL template string
7122  *
7123  * Return:
7124  *	Nothing.
7125  */
7126 void
cdinfo_scan_url_attrib(char * url,url_attrib_t * up)7127 cdinfo_scan_url_attrib(char *url, url_attrib_t *up)
7128 {
7129 	char	*cp;
7130 
7131 	/* Scan URL string to get a count of the number of
7132 	 * substitutions needed.
7133 	 */
7134 	up->xcnt = up->vcnt = 0;
7135 	up->ncnt = up->hcnt = 0;
7136 	up->lcnt = up->ccnt = 0;
7137 	up->icnt = up->acnt = 0;
7138 	up->dcnt = up->tcnt = 0;
7139 	up->rcnt = up->pcnt = 0;
7140 	for (cp = url; *cp != '\0'; cp++) {
7141 		if (*cp == '%') {
7142 			switch ((int) *(++cp)) {
7143 			case 'X':
7144 				up->xcnt++;
7145 				break;
7146 			case 'V':
7147 				up->vcnt++;
7148 				break;
7149 			case 'N':
7150 				up->ncnt++;
7151 				break;
7152 			case 'H':
7153 				up->hcnt++;
7154 				break;
7155 			case 'L':
7156 				up->lcnt++;
7157 				break;
7158 			case 'C':
7159 				up->ccnt++;
7160 				break;
7161 			case 'I':
7162 				up->icnt++;
7163 				break;
7164 			case 'A':
7165 			case 'a':
7166 				up->acnt++;
7167 				break;
7168 			case 'D':
7169 			case 'd':
7170 				up->dcnt++;
7171 				break;
7172 			case 'R':
7173 			case 'r':
7174 				up->rcnt++;
7175 				break;
7176 			case 'T':
7177 			case 't':
7178 				up->tcnt++;
7179 				break;
7180 			case 'B':
7181 			case 'b':
7182 				up->acnt++;
7183 				up->dcnt++;
7184 				break;
7185 			case '#':
7186 				up->pcnt++;
7187 				break;
7188 			default:
7189 				break;
7190 			}
7191 		}
7192 	}
7193 }
7194 
7195 
7196 /*
7197  * cdinfo_add_pathent
7198  *	Add a cdinfo path list component.
7199  *
7200  * Args:
7201  *	path - The path component string
7202  *
7203  * Return:
7204  *	TRUE - success
7205  *	FALSE - failure
7206  */
7207 bool_t
cdinfo_add_pathent(char * path)7208 cdinfo_add_pathent(char *path)
7209 {
7210 	int			n;
7211 	char			*cp,
7212 				*cp2;
7213 	cdinfo_path_t		*pp;
7214 	STATIC cdinfo_path_t	*pp2 = NULL;
7215 
7216 	if (*path == '\0' || *path == '\n')
7217 		return TRUE;
7218 	if (strncmp(path, "cddbp://", 8) == 0 ||
7219 	    strncmp(path, "http://", 7) == 0) {
7220 		(void) fprintf(errfp,
7221 			"NOTICE: Skipped unsupported item in cdinfoPath: %s\n",
7222 			path);
7223 		return TRUE;
7224 	}
7225 
7226 	pp = (cdinfo_path_t *)(void *) MEM_ALLOC(
7227 		"cdinfo_path_t",
7228 		sizeof(cdinfo_path_t)
7229 	);
7230 	if (pp == NULL) {
7231 		CDINFO_FATAL(app_data.str_nomemory);
7232 		return FALSE;
7233 	}
7234 	(void) memset(pp, 0, sizeof(cdinfo_path_t));
7235 
7236 	if (cdinfo_dbp->pathlist == NULL) {
7237 		cdinfo_dbp->pathlist = pp2 = pp;
7238 	}
7239 	else {
7240 		pp2->next = pp;
7241 		pp2 = pp;
7242 	}
7243 
7244 	/* Determine path type */
7245 	if (strcmp(path, "CDDB") == 0) {
7246 		/* CDDB service */
7247 		pp->type = CDINFO_RMT;
7248 	}
7249 	else if (strcmp(path, "CDTEXT") == 0) {
7250 		/* CD-TEXT from the disc */
7251 		pp->type = CDINFO_CDTEXT;
7252 	}
7253 	else if (strncmp(path, "file://", 7) == 0) {
7254 		/* Syntax: file://dirpath */
7255 		pp->type = CDINFO_LOC;
7256 		path += 7;
7257 	}
7258 	else {
7259 		/* Syntax: dirpath */
7260 		pp->type = CDINFO_LOC;
7261 	}
7262 
7263 	/* Parse the rest of the line */
7264 	switch (pp->type) {
7265 	case CDINFO_RMT:
7266 	case CDINFO_CDTEXT:
7267 		/* Do nothing here */
7268 		break;
7269 
7270 	case CDINFO_LOC:
7271 		n = strlen(path);
7272 		if (path[0] == '/') {
7273 			/* Absolute local path name */
7274 			if (!util_newstr(&pp->path, path)) {
7275 				CDINFO_FATAL(app_data.str_nomemory);
7276 				return FALSE;
7277 			}
7278 		}
7279 		else if (path[0] == '~') {
7280 			/* Perform tilde expansion a la [ck]sh */
7281 			if (path[1] == '/') {
7282 				cp2 = util_homedir(util_get_ouid());
7283 
7284 				pp->path = (char *) MEM_ALLOC(
7285 					"pp->path",
7286 					n + strlen(cp2)
7287 				);
7288 				if (pp->path == NULL) {
7289 					CDINFO_FATAL(app_data.str_nomemory);
7290 					return FALSE;
7291 				}
7292 
7293 				(void) sprintf(pp->path, "%s%s",
7294 					       cp2, &path[1]);
7295 			}
7296 			else if (path[1] == '\0') {
7297 				cp2 = util_homedir(util_get_ouid());
7298 
7299 				if (!util_newstr(&pp->path, cp2)) {
7300 					CDINFO_FATAL(app_data.str_nomemory);
7301 					return FALSE;
7302 				}
7303 			}
7304 			else {
7305 				cp = strchr(path, '/');
7306 				if (cp == NULL) {
7307 					cp2 = util_uhomedir(&path[1]);
7308 					if (!util_newstr(&pp->path, cp2)) {
7309 						CDINFO_FATAL(
7310 							app_data.str_nomemory
7311 						);
7312 						return FALSE;
7313 					}
7314 				}
7315 				else {
7316 					*cp = '\0';
7317 					cp2 = util_uhomedir(&path[1]);
7318 					pp->path = (char *) MEM_ALLOC(
7319 						"pp->path",
7320 						n + strlen(cp2)
7321 					);
7322 					if (pp->path == NULL) {
7323 						CDINFO_FATAL(
7324 							app_data.str_nomemory
7325 						);
7326 						return FALSE;
7327 					}
7328 
7329 					(void) sprintf(pp->path, CONCAT_PATH,
7330 						       cp2, cp+1);
7331 				}
7332 			}
7333 		}
7334 		else {
7335 			/* Relative local path name */
7336 			pp->path = (char *) MEM_ALLOC(
7337 				"pp->path",
7338 				n + strlen(app_data.libdir) +
7339 					strlen(REL_DBDIR_PATH)
7340 			);
7341 			if (pp->path == NULL) {
7342 				CDINFO_FATAL(app_data.str_nomemory);
7343 				return FALSE;
7344 			}
7345 
7346 			(void) sprintf(pp->path, REL_DBDIR_PATH,
7347 				       app_data.libdir, path);
7348 
7349 		}
7350 
7351 		/* Set category name for CDDB1 to CDDB2 genre mapping */
7352 		cp = util_basename(pp->path);
7353 		if (cp != NULL && !util_newstr(&pp->categ, cp)) {
7354 			MEM_FREE(cp);
7355 			CDINFO_FATAL(app_data.str_nomemory);
7356 			return FALSE;
7357 		}
7358 		MEM_FREE(cp);
7359 
7360 		/* Make sure that the whole path name + discid can
7361 		 * fit in a FILE_PATH_SZ buffer.  Also, make sure the
7362 		 * category name is less than FILE_BASE_SZ.
7363 		 */
7364 		if ((int) strlen(pp->path) >= (FILE_PATH_SZ - 12)) {
7365 			CDINFO_FATAL(app_data.str_longpatherr);
7366 			return FALSE;
7367 		}
7368 
7369 		if ((cp = util_basename(pp->path)) == NULL) {
7370 			CDINFO_FATAL("cdinfoPath component error");
7371 			return FALSE;
7372 		}
7373 
7374 		if ((int) strlen(cp) >= FILE_BASE_SZ) {
7375 			MEM_FREE(cp);
7376 			CDINFO_FATAL(app_data.str_longpatherr);
7377 			return FALSE;
7378 		}
7379 		MEM_FREE(cp);
7380 
7381 		break;
7382 	}
7383 
7384 	return TRUE;
7385 }
7386 
7387 
7388 /*
7389  * cdinfo_load_locdb
7390  *	Attempt to load CD information from the specified local CD info file.
7391  *
7392  * Args:
7393  *	path - File path
7394  *	categ - CDDB1 category string
7395  *	s - Pointer to the curstat_t structure
7396  *	retcode - Return status code
7397  *
7398  * Return:
7399  *	TRUE - success
7400  *	FALSE - failure
7401  */
7402 /*ARGSUSED*/
7403 bool_t
cdinfo_load_locdb(char * path,char * categ,curstat_t * s,int * retcode)7404 cdinfo_load_locdb(char *path, char *categ, curstat_t *s, int *retcode)
7405 {
7406 	int	i,
7407 		pos,
7408 		bufsz = STR_BUF_SZ * 3;
7409 	char	*buf,
7410 		*tmpbuf;
7411 	FILE	*fp;
7412 
7413 	errno = 0;
7414 	*retcode = 0;
7415 
7416 	if ((fp = fopen(path, "r")) == NULL) {
7417 		/* File not found */
7418 		*retcode = 0;
7419 		DBGPRN(DBG_CDI)(errfp, "\n");
7420 		return TRUE;
7421 	}
7422 
7423 	if ((buf = (char *) MEM_ALLOC("read_buf", bufsz)) == NULL) {
7424 		*retcode = MEM_ERR;
7425 		DBGPRN(DBG_CDI)(errfp, "\n");
7426 		(void) fclose(fp);
7427 		CDINFO_FATAL(app_data.str_nomemory);
7428 		return FALSE;
7429 	}
7430 
7431 	if ((tmpbuf = (char *) MEM_ALLOC("read_tmpbuf", bufsz)) == NULL) {
7432 		*retcode = MEM_ERR;
7433 		DBGPRN(DBG_CDI)(errfp, "\n");
7434 		MEM_FREE(buf);
7435 		(void) fclose(fp);
7436 		CDINFO_FATAL(app_data.str_nomemory);
7437 		return FALSE;
7438 	}
7439 
7440 	/* Read first line of database entry */
7441 	if (fgets(buf, bufsz, fp) == NULL) {
7442 		/* Can't read file */
7443 		DBGPRN(DBG_CDI)(errfp, "\n");
7444 		MEM_FREE(buf);
7445 		MEM_FREE(tmpbuf);
7446 		(void) fclose(fp);
7447 		return TRUE;
7448 	}
7449 
7450 	/* Database file signature check */
7451 	if (strncmp(buf, "# xmcd", 6) != 0) {
7452 		/* Not a supported database file */
7453 		DBGPRN(DBG_CDI)(errfp, "\n");
7454 		MEM_FREE(buf);
7455 		MEM_FREE(tmpbuf);
7456 		(void) fclose(fp);
7457 		return TRUE;
7458 	}
7459 
7460 	/* Read the rest of the database entry */
7461 	while (fgets(buf, bufsz, fp) != NULL) {
7462 		/* Comment line */
7463 		if (buf[0] == '#') {
7464 			/* Concatenated cdinfo file */
7465 			if (strncmp(buf, "# xmcd", 6) == 0)
7466 				break;
7467 
7468 			continue;
7469 		}
7470 
7471 		buf[strlen(buf)-1] = '\n';
7472 
7473 		/* Disc IDs */
7474 		if (sscanf(buf, "DISCID=%[^\n]\n", tmpbuf) > 0) {
7475 			/* Do nothing for this line */
7476 			continue;
7477 		}
7478 
7479 		/* Disk title */
7480 		if (sscanf(buf, "DTITLE=%[^\n]\n", tmpbuf) > 0) {
7481 			cdinfo_disc_t	*dp;
7482 			char		*cp;
7483 
7484 			cdinfo_line_filter(tmpbuf);
7485 
7486 			dp = &cdinfo_dbp->disc;
7487 
7488 			/* This assumes that artist and title are separated
7489 			 * " / " (may not be true in all cases; shrug)
7490 			 */
7491 			if ((cp = strchr(tmpbuf, '/')) != NULL &&
7492 			     cp > (tmpbuf + 3) &&
7493 			     *(cp-1) == ' ' && *(cp+1) == ' ') {
7494 				char	*cp2;
7495 
7496 				cp2 = cp - 1;
7497 				*cp2 = '\0';
7498 				if (!cdinfo_concatstr(
7499 						    &dp->artistfname.dispname,
7500 						    tmpbuf)) {
7501 					CDINFO_FATAL(app_data.str_nomemory);
7502 					break;
7503 				}
7504 				if (!cdinfo_concatstr(&dp->artist,
7505 						      tmpbuf)) {
7506 					CDINFO_FATAL(app_data.str_nomemory);
7507 					break;
7508 				}
7509 
7510 				cp2 = cp + 2;
7511 				if (!cdinfo_concatstr(&dp->title, cp2)) {
7512 					CDINFO_FATAL(app_data.str_nomemory);
7513 					break;
7514 				}
7515 			}
7516 			else if (!cdinfo_concatstr(&dp->title, tmpbuf)) {
7517 				CDINFO_FATAL(app_data.str_nomemory);
7518 				break;
7519 			}
7520 			continue;
7521 		}
7522 
7523 		/* Track titles */
7524 		if (sscanf(buf, "TTITLE%u=%[^\n]\n", &pos, tmpbuf) >= 2) {
7525 			cdinfo_track_t	*tp;
7526 
7527 			if (pos >= (int) (cdinfo_dbp->discid & 0xff))
7528 				continue;
7529 
7530 			cdinfo_line_filter(tmpbuf);
7531 
7532 			tp = &cdinfo_dbp->track[pos];
7533 
7534 			if (!cdinfo_concatstr(&tp->title, tmpbuf)) {
7535 				CDINFO_FATAL(app_data.str_nomemory);
7536 				break;
7537 			}
7538 			continue;
7539 		}
7540 
7541 		/* Disk notes */
7542 		if (sscanf(buf, "EXTD=%[^\n]\n", tmpbuf) > 0) {
7543 			cdinfo_disc_t	*dp;
7544 
7545 			dp = &cdinfo_dbp->disc;
7546 
7547 			if (!cdinfo_concatstr(&dp->notes, tmpbuf)) {
7548 				CDINFO_FATAL(app_data.str_nomemory);
7549 				break;
7550 			}
7551 			continue;
7552 		}
7553 
7554 		/* Track extended info */
7555 		if (sscanf(buf, "EXTT%u=%[^\n]\n", &pos, tmpbuf) >= 2) {
7556 			cdinfo_track_t	*tp;
7557 
7558 			if (pos >= (int) (cdinfo_dbp->discid & 0xff))
7559 				continue;
7560 
7561 			tp = &cdinfo_dbp->track[pos];
7562 
7563 			if (!cdinfo_concatstr(&tp->notes, tmpbuf)) {
7564 				CDINFO_FATAL(app_data.str_nomemory);
7565 				break;
7566 			}
7567 			continue;
7568 		}
7569 
7570 #ifdef USE_XMCD2_PLAYORDER
7571 		/* Play order - this is deprecated */
7572 		if (sscanf(buf, "PLAYORDER=%[^\n]\n", tmpbuf) > 0) {
7573 			if (s->program || s->shuffle)
7574 				/* Play program or shuffle already in
7575 				 * progress, do not override it.
7576 				 */
7577 				continue;
7578 
7579 			if (!cdinfo_concatstr(&cdinfo_dbp->playorder, tmpbuf)){
7580 				CDINFO_FATAL(app_data.str_nomemory);
7581 				break;
7582 			}
7583 			continue;
7584 		}
7585 #endif
7586 	}
7587 
7588 	MEM_FREE(buf);
7589 	MEM_FREE(tmpbuf);
7590 
7591 	(void) fclose(fp);
7592 
7593 	/* Do CDDB1 -> CDDB2 genre mapping if possible */
7594 	for (i = 0; cdinfo_genre_map[i].cddb1_genre != NULL; i++) {
7595 		if (categ != NULL &&
7596 		    strcmp(categ, cdinfo_genre_map[i].cddb1_genre) == 0) {
7597 			if (!util_newstr(&cdinfo_dbp->disc.genre,
7598 					 cdinfo_genre_map[i].cddb2_genre)) {
7599 				CDINFO_FATAL(app_data.str_nomemory);
7600 			}
7601 			break;
7602 		}
7603 	}
7604 
7605 	/* Set the match bit */
7606 	cdinfo_dbp->flags |= (CDINFO_MATCH | CDINFO_FROMLOC);
7607 
7608 	DBGPRN(DBG_CDI)(errfp, ": Loaded.\n");
7609 	return TRUE;
7610 }
7611 
7612 
7613 /*
7614  * cdinfo_out_discog
7615  *	Output local discography HTML content for the currently loaded CD
7616  *
7617  * Args:
7618  *	path - File path to the local discography file
7619  *	s - Pointer to the curstat_t structure
7620  *	baseurl - The URL to the output file
7621  *
7622  * Return:
7623  *	TRUE - success
7624  *	FALSE - failure
7625  */
7626 bool_t
cdinfo_out_discog(char * path,curstat_t * s,char * baseurl)7627 cdinfo_out_discog(char *path, curstat_t *s, char *baseurl)
7628 {
7629 	int		i,
7630 			fmt,
7631 			ncreds,
7632 			nrows,
7633 			ntrkrows;
7634 	unsigned int	dmode,
7635 			fmode;
7636 	char		*p,
7637 			*q,
7638 			*tblparms1,
7639 			*tblparms2,
7640 			*tdparms1,
7641 			*tdparms2,
7642 			*tdparms3,
7643 			*srchact,
7644 			*gname,
7645 			*gpath,
7646 			*dhome,
7647 			*relpath,
7648 			*cmd,
7649 			outdir[FILE_PATH_SZ],
7650 			filepath[FILE_PATH_SZ + 40],
7651 			plspath[FILE_PATH_SZ + 480];
7652 	FILE		*fp,
7653 			*pls_fp;
7654 	DIR		*dp;
7655 	struct dirent	*de;
7656 	cdinfo_credit_t	*cp;
7657 	playls_t	*lheads[MAX_FILEFMTS],
7658 			*sp;
7659 	filefmt_t	*fmp;
7660 	struct stat	stbuf;
7661 	bool_t		first,
7662 			newdiscog;
7663 
7664 	(void) sscanf(app_data.cdinfo_filemode, "%o", &fmode);
7665 	/* Make sure file is at least accessible by user */
7666 	fmode |= S_IRUSR | S_IWUSR;
7667 	fmode &= ~(S_ISUID | S_ISGID);
7668 
7669 	/* Set directory perm based on file perm */
7670 	dmode = (fmode | S_IXUSR);
7671 	if (fmode & S_IRGRP)
7672 		dmode |= (S_IRGRP | S_IXGRP);
7673 	if (fmode & S_IWGRP)
7674 		dmode |= (S_IWGRP | S_IXGRP);
7675 	if (fmode & S_IROTH)
7676 		dmode |= (S_IROTH | S_IXOTH);
7677 	if (fmode & S_IWOTH)
7678 		dmode |= (S_IWOTH | S_IXOTH);
7679 
7680 	if ((p = util_dirname(path)) == NULL) {
7681 		DBGPRN(DBG_CDI)(errfp, "Directory path error: %s\n", path);
7682 		return FALSE;
7683 	}
7684 	(void) strcpy(outdir, p);
7685 	MEM_FREE(p);
7686 
7687 	newdiscog = FALSE;
7688 	if (util_dirstat(outdir, &stbuf, FALSE) < 0) {
7689 		if (errno == ENOENT)
7690 			newdiscog = TRUE;
7691 		else {
7692 			DBGPRN(DBG_CDI)(errfp, "Cannot stat %s\n", outdir);
7693 			return FALSE;
7694 		}
7695 	}
7696 
7697 	/* Make directories and fix perms */
7698 	if (!util_mkdir(outdir, (mode_t) dmode)) {
7699 		DBGPRN(DBG_CDI)(errfp, "Cannot create directory %s\n", outdir);
7700 		return FALSE;
7701 	}
7702 
7703 	/* Remove original file */
7704 	if (UNLINK(path) < 0 && errno != ENOENT) {
7705 		DBGPRN(DBG_CDI)(errfp, "Cannot unlink old %s\n", path);
7706 		return FALSE;
7707 	}
7708 
7709 	/* Write new file */
7710 	if ((fp = fopen(path, "w")) == NULL) {
7711 		DBGPRN(DBG_CDI)(errfp,
7712 			"Cannot open file for writing: %s\n", path);
7713 		return FALSE;
7714 	}
7715 	(void) chmod(path, (mode_t) fmode);
7716 
7717 	DBGPRN(DBG_CDI)(errfp, "\nWriting local Discography: %s\n", path);
7718 
7719 	/* Set up the CDDB search URL string */
7720 	srchact = NULL;
7721 	if (cdinfo_scddb != NULL && cdinfo_scddb->arg != NULL) {
7722 		if (!util_newstr(&srchact, cdinfo_scddb->arg)) {
7723 			CDINFO_FATAL(app_data.str_nomemory);
7724 			return FALSE;
7725 		}
7726 		if ((p = strrchr(srchact, '%')) != NULL)
7727 			*p = '\0';
7728 		else {
7729 			MEM_FREE(srchact);
7730 			srchact = NULL;
7731 		}
7732 	}
7733 
7734 	/* Get genre name and path */
7735 	gname = cdinfo_genre_name(cdinfo_dbp->disc.genre);
7736 	if (util_strstr(gname, " -> ") != NULL)
7737 		dhome = "../../..";
7738 	else
7739 		dhome = "../..";
7740 
7741 	/* Start HTML output */
7742 	tblparms1 = "CELLSPACING=\"0\" CELLPADDING=\"1\" BORDER=\"0\"";
7743 	tblparms2 = "CELLSPACING=\"0\" CELLPADDING=\"3\" BORDER=\"1\"";
7744 	tdparms1 = "ALIGN=\"center\"";
7745 	tdparms2 = "ALIGN=\"left\"";
7746 	tdparms3 = "ALIGN=\"left\" VALIGN=\"top\"";
7747 
7748 	/* Comments */
7749 	(void) fprintf(fp, "<!-- xmcd Local Discography\n");
7750 	(void) fprintf(fp, "     DO NOT EDIT: Generated by %s %s.%s.%s\n",
7751 		cdinfo_clinfo->prog, VERSION_MAJ, VERSION_MIN, VERSION_TEENY);
7752 	(void) fprintf(fp, "     %s\n     URL: %s E-mail: %s -->\n",
7753 		COPYRIGHT, XMCD_URL, EMAIL);
7754 	(void) fputs("<!-- tItLe: ", fp);
7755 
7756 	/* Album artist and title info in comments, for sorting by genidx */
7757 	if (cdinfo_dbp->disc.artistfname.lastname != NULL ||
7758 	    cdinfo_dbp->disc.artistfname.firstname != NULL) {
7759 		/* Use sorted artist name if possible */
7760 		if (cdinfo_dbp->disc.artistfname.lastname != NULL) {
7761 			util_html_fputs(cdinfo_dbp->disc.artistfname.lastname,
7762 					fp, FALSE, NULL, 0);
7763 			(void) fputs(", ", fp);
7764 		}
7765 		if (cdinfo_dbp->disc.artistfname.firstname != NULL) {
7766 			util_html_fputs(cdinfo_dbp->disc.artistfname.firstname,
7767 					fp, FALSE, NULL, 0);
7768 		}
7769 		if (cdinfo_dbp->disc.artistfname.the != NULL) {
7770 			(void) fputs(", ", fp);
7771 			util_html_fputs(cdinfo_dbp->disc.artistfname.the,
7772 					fp, FALSE, NULL, 0);
7773 		}
7774 	}
7775 	else if (cdinfo_dbp->disc.artist != NULL) {
7776 		/* Use display name */
7777 		util_html_fputs(cdinfo_dbp->disc.artist, fp, FALSE, NULL, 0);
7778 	}
7779 	else {
7780 		(void) fputs(app_data.str_unknartist, fp);
7781 	}
7782 
7783 	if (cdinfo_dbp->disc.sorttitle != NULL) {
7784 		/* Use sort title if possible */
7785 		(void) fputs(" / ", fp);
7786 		util_html_fputs(cdinfo_dbp->disc.sorttitle,
7787 				fp, FALSE, NULL, 0);
7788 		if (cdinfo_dbp->disc.title_the != NULL) {
7789 			(void) fputs(", ", fp);
7790 			util_html_fputs(cdinfo_dbp->disc.title_the,
7791 					fp, FALSE, NULL, 0);
7792 		}
7793 	}
7794 	else if (cdinfo_dbp->disc.title != NULL) {
7795 		/* Use display title */
7796 		(void) fputs(" / ", fp);
7797 		util_html_fputs(cdinfo_dbp->disc.title, fp, FALSE, NULL, 0);
7798 	}
7799 	else {
7800 		(void) fputs(" / ", fp);
7801 		(void) fputs(app_data.str_unkndisc, fp);
7802 	}
7803 	(void) fputs(" -->\n", fp);
7804 
7805 	(void) fputs("<HTML>\n<HEAD>\n", fp);
7806 
7807 	/* All in-core CD information is encoded in UTF-8 */
7808 	(void) fputs("<META HTTP-EQUIV=\"Content-type\" "
7809 		     "CONTENT=\"text/html; charset=utf-8\">\n", fp);
7810 
7811 	(void) fputs("<TITLE>\nxmcd: ", fp);
7812 
7813 	if (cdinfo_dbp->disc.artist != NULL)
7814 		util_html_fputs(cdinfo_dbp->disc.artist, fp, FALSE, NULL, 0);
7815 	else
7816 		(void) fputs(app_data.str_unknartist, fp);
7817 
7818 	(void) fputs(" / ", fp);
7819 
7820 	if (cdinfo_dbp->disc.title != NULL)
7821 		util_html_fputs(cdinfo_dbp->disc.title, fp, FALSE, NULL, 0);
7822 	else
7823 		(void) fputs(app_data.str_unkndisc, fp);
7824 
7825 	(void) fputs("\n</TITLE>\n", fp);
7826 
7827 #ifdef __VMS
7828 	(void) sprintf(filepath, "%s.discog]bkgnd.gif", app_data.libdir);
7829 	if ((p = util_vms_urlconv(filepath, VMS_2_UNIX)) != NULL) {
7830 		(void) strncpy(filepath, p, sizeof(filepath)-1);
7831 		filepath[sizeof(filepath)-1] = '\0';
7832 		MEM_FREE(p);
7833 	}
7834 #else
7835 	(void) sprintf(filepath, "%s/bkgnd.gif", dhome);
7836 #endif
7837 	(void) fprintf(fp,
7838 		"</HEAD>\n<BODY BGCOLOR=\"%s\" BACKGROUND=\"%s\">\n",
7839 		"#FFFFFF",		/* Background color */
7840 		filepath
7841 	);
7842 
7843 	(void) fputs("<DIV ALIGN=\"center\">\n", fp);
7844 
7845 	/* xmcd logo */
7846 	(void) fprintf(fp, "<A HREF=\"%s\">\n", XMCD_URL);
7847 #ifdef __VMS
7848 	(void) sprintf(filepath, "%s.discog]xmcdlogo.gif", app_data.libdir);
7849 	if ((p = util_vms_urlconv(filepath, VMS_2_UNIX)) != NULL) {
7850 		(void) strncpy(filepath, p, sizeof(filepath)-1);
7851 		filepath[sizeof(filepath)-1] = '\0';
7852 		MEM_FREE(p);
7853 	}
7854 #else
7855 	(void) sprintf(filepath, "%s/xmcdlogo.gif", dhome);
7856 #endif
7857 	(void) fprintf(fp, "<IMG SRC=\"%s\" ALT=\"xmcd\" BORDER=\"0\">",
7858 			filepath);
7859 	(void) fprintf(fp, "</A><P>\n<H4>Local Discography</H4><P>\n");
7860 
7861 	/* Disc artist / title */
7862 	(void) fputs("<H3>\n", fp);
7863 	if (cdinfo_dbp->disc.artist == NULL)
7864 		(void) fprintf(fp, "(%s)", app_data.str_unknartist);
7865 	else {
7866 		if (srchact != NULL) {
7867 			p = cdinfo_txtreduce(cdinfo_dbp->disc.artist, TRUE);
7868 			(void) fprintf(fp, "<A HREF=\"%s%s\">", srchact, p);
7869 			MEM_FREE(p);
7870 		}
7871 		util_html_fputs(cdinfo_dbp->disc.artist, fp, FALSE, NULL, 0);
7872 		if (srchact != NULL)
7873 			(void) fputs("</A>\n", fp);
7874 	}
7875 
7876 	(void) fputs(" / ", fp);
7877 
7878 	if (cdinfo_dbp->disc.title == NULL)
7879 		(void) fprintf(fp, "(%s)", app_data.str_unkndisc);
7880 	else {
7881 		if (srchact != NULL) {
7882 			p = cdinfo_txtreduce(cdinfo_dbp->disc.title, TRUE);
7883 			(void) fprintf(fp, "<A HREF=\"%s%s\">", srchact, p);
7884 			MEM_FREE(p);
7885 		}
7886 		util_html_fputs(cdinfo_dbp->disc.title, fp, FALSE, NULL, 0);
7887 		if (srchact != NULL)
7888 			(void) fputs("</A>\n", fp);
7889 	}
7890 	(void) fputs("</H3>\n", fp);
7891 
7892 	/* Album information */
7893 	(void) fprintf(fp, "<P>\n<TABLE %s>\n", tblparms1);
7894 	(void) fprintf(fp, "<TR><TH %s>Total time:</TH><TD %s>&nbsp;%02d:%02d"
7895 		"</TD></TR>\n",
7896 		tdparms2, tdparms2,
7897 		s->discpos_tot.min, s->discpos_tot.sec
7898 	);
7899 	(void) fprintf(fp, "<TR><TH %s>Primary genre:</TH><TD %s>&nbsp;",
7900 		tdparms2, tdparms2
7901 	);
7902 	util_html_fputs(gname, fp, FALSE, NULL, 0);
7903 	(void) fputs("</TD></TR>\n", fp);
7904 	(void) fprintf(fp, "<TR><TH %s>Secondary genre:</TH><TD %s>&nbsp;",
7905 		tdparms2, tdparms2
7906 	);
7907 	util_html_fputs(cdinfo_genre_name(cdinfo_dbp->disc.genre2),
7908 			fp, FALSE, NULL, 0);
7909 	(void) fputs("</TD></TR>\n", fp);
7910 	(void) fprintf(fp,
7911 		"<TR><TH %s>Xmcd disc ID:</TH><TD %s>&nbsp;%08x</TD></TR>\n",
7912 		tdparms2, tdparms2, cdinfo_dbp->discid
7913 	);
7914 	(void) fprintf(fp, "<TR><TH %s>Artist full name:</TH><TD %s>&nbsp;",
7915 		tdparms2, tdparms2
7916 	);
7917 	if (cdinfo_dbp->disc.artistfname.lastname != NULL) {
7918 		util_html_fputs(cdinfo_dbp->disc.artistfname.lastname,
7919 				fp, FALSE, NULL, 0);
7920 		(void) fputs(", ", fp);
7921 	}
7922 	if (cdinfo_dbp->disc.artistfname.firstname != NULL) {
7923 		util_html_fputs(cdinfo_dbp->disc.artistfname.firstname,
7924 				fp, FALSE, NULL, 0);
7925 	}
7926 	if (cdinfo_dbp->disc.artistfname.the != NULL) {
7927 		(void) fputs(", ", fp);
7928 		util_html_fputs(cdinfo_dbp->disc.artistfname.the,
7929 				fp, FALSE, NULL, 0);
7930 	}
7931 	(void) fputs("</TD></TR>\n", fp);
7932 	(void) fprintf(fp, "<TR><TH %s>Sort title:</TH><TD %s>&nbsp;",
7933 		tdparms2, tdparms2
7934 	);
7935 	if (cdinfo_dbp->disc.sorttitle != NULL) {
7936 		util_html_fputs(cdinfo_dbp->disc.sorttitle,
7937 				fp, FALSE, NULL, 0);
7938 	}
7939 	if (cdinfo_dbp->disc.title_the != NULL) {
7940 		(void) fputs(", ", fp);
7941 		util_html_fputs(cdinfo_dbp->disc.title_the,
7942 				fp, FALSE, NULL, 0);
7943 	}
7944 	(void) fputs("</TD></TR>\n", fp);
7945 	(void) fprintf(fp, "<TR><TH %s>Year:</TH><TD %s>&nbsp;%s</TD></TR>\n",
7946 		tdparms2, tdparms2,
7947 		cdinfo_dbp->disc.year == NULL ? "" : cdinfo_dbp->disc.year
7948 	);
7949 	(void) fprintf(fp, "<TR><TH %s>Record label:</TH><TD %s>&nbsp;",
7950 		tdparms2, tdparms2
7951 	);
7952 	if (cdinfo_dbp->disc.label != NULL)
7953 		util_html_fputs(cdinfo_dbp->disc.label, fp, FALSE, NULL, 0);
7954 	(void) fputs("</TD></TR>\n", fp);
7955 	(void) fprintf(fp,
7956 		"<TR><TH %s>Compilation:</TH><TD %s>&nbsp;%s</TD></TR>\n",
7957 		tdparms2, tdparms2,
7958 		cdinfo_dbp->disc.compilation ? "Yes" : "No"
7959 	);
7960 	(void) fprintf(fp,
7961 		"<TR><TH %s>Disc:</TH><TD %s>&nbsp;%s of %s</TD></TR>\n",
7962 		tdparms2, tdparms2,
7963 		cdinfo_dbp->disc.dnum == NULL ? "?" : cdinfo_dbp->disc.dnum,
7964 		cdinfo_dbp->disc.tnum == NULL ? "?" : cdinfo_dbp->disc.tnum
7965 	);
7966 	(void) fprintf(fp, "<TR><TH %s>Region:</TH><TD %s>&nbsp;",
7967 		tdparms2, tdparms2
7968 	);
7969 	util_html_fputs(cdinfo_region_name(cdinfo_dbp->disc.region),
7970 			fp, FALSE, NULL, 0);
7971 	(void) fputs("</TD></TR>\n", fp);
7972 	(void) fprintf(fp, "<TR><TH %s>Language:</TH><TD %s>&nbsp;",
7973 		tdparms2, tdparms2
7974 	);
7975 	util_html_fputs(cdinfo_lang_name(cdinfo_dbp->disc.lang),
7976 			fp, FALSE, NULL, 0);
7977 	(void) fputs("</TD></TR>\n", fp);
7978 	(void) fputs("</TABLE>\n", fp);
7979 
7980 	/* Big info table */
7981 	(void) fprintf(fp, "<P>\n<TABLE %s>\n", tblparms2);
7982 	(void) fputs("<TR>\n", fp);
7983 	(void) fprintf(fp, "<TH %s>Track</TH>\n", tdparms1);
7984 	(void) fprintf(fp, "<TH %s>Start</TH>\n", tdparms1);
7985 	(void) fprintf(fp, "<TH %s>Length</TH>\n", tdparms1);
7986 	(void) fprintf(fp, "<TH %s>Artist</TH>\n", tdparms1);
7987 	(void) fprintf(fp, "<TH %s>Title</TH>\n", tdparms1);
7988 	(void) fprintf(fp, "<TH %s>Pri genre</TH>\n", tdparms1);
7989 	(void) fprintf(fp, "<TH %s>Sec genre</TH>\n", tdparms1);
7990 	(void) fprintf(fp, "<TH %s>BPM</TH>\n", tdparms1);
7991 	(void) fprintf(fp, "<TH %s>Year</TH>\n", tdparms1);
7992 	(void) fprintf(fp, "<TH %s>Record label</TH>\n", tdparms1);
7993 	(void) fputs("</TR>\n", fp);
7994 
7995 	ntrkrows = 0;
7996 	for (i = 0; i < (int) s->tot_trks; i++) {
7997 		int	min,
7998 			sec,
7999 			secs;
8000 
8001 		secs = ((s->trkinfo[i+1].min * 60 + s->trkinfo[i+1].sec) -
8002 			(s->trkinfo[i].min * 60 + s->trkinfo[i].sec));
8003 		min = (byte_t) (secs / 60);
8004 		sec = (byte_t) (secs % 60);
8005 
8006 		(void) fprintf(fp, "<TR>\n<TD %s>%d</TD>\n",
8007 			tdparms1,
8008 			s->trkinfo[i].trkno
8009 		);
8010 		(void) fprintf(fp, "<TD %s>%02d:%02d</TD>\n",
8011 			tdparms1, s->trkinfo[i].min, s->trkinfo[i].sec);
8012 		(void) fprintf(fp, "<TD %s>%02d:%02d</TD>\n",
8013 			tdparms1, min, sec);
8014 
8015 		if (cdinfo_dbp->track[i].artist == NULL) {
8016 			(void) fprintf(fp, "<TD %s><B>&nbsp;</B></TD>\n",
8017 				tdparms2
8018 			);
8019 		}
8020 		else {
8021 			(void) fprintf(fp, "<TD %s><B>", tdparms2);
8022 			if (srchact != NULL) {
8023 				p = cdinfo_txtreduce(
8024 					cdinfo_dbp->track[i].artist,
8025 					TRUE
8026 				);
8027 				(void) fprintf(fp, "<A HREF=\"%s%s\">",
8028 					srchact, p
8029 				);
8030 				MEM_FREE(p);
8031 			}
8032 			util_html_fputs(
8033 				cdinfo_dbp->track[i].artist,
8034 				fp,
8035 				FALSE,
8036 				NULL,
8037 				0
8038 			);
8039 			if (srchact != NULL)
8040 				(void) fputs("</A>", fp);
8041 			(void) fputs("</B></TD>\n", fp);
8042 		}
8043 
8044 		if (cdinfo_dbp->track[i].title == NULL) {
8045 			(void) fprintf(fp, "<TD %s><B>(%s)</B></TD>\n",
8046 				tdparms2,
8047 				app_data.str_unkntrk
8048 			);
8049 		}
8050 		else {
8051 			(void) fprintf(fp, "<TD %s><B>", tdparms2);
8052 			if (srchact != NULL) {
8053 				p = cdinfo_txtreduce(
8054 					cdinfo_dbp->track[i].title,
8055 					TRUE
8056 				);
8057 				(void) fprintf(fp, "<A HREF=\"%s%s\">",
8058 					srchact, p
8059 				);
8060 				MEM_FREE(p);
8061 			}
8062 			util_html_fputs(
8063 				cdinfo_dbp->track[i].title,
8064 				fp,
8065 				FALSE,
8066 				NULL,
8067 				0
8068 			);
8069 			if (srchact != NULL)
8070 				(void) fputs("</A>", fp);
8071 			(void) fputs("</B></TD>\n", fp);
8072 		}
8073 
8074 		(void) fprintf(fp, "<TD %s>", tdparms2);
8075 		util_html_fputs(cdinfo_genre_name(cdinfo_dbp->track[i].genre),
8076 				fp, FALSE, NULL, 0);
8077 		fputs("&nbsp;</TD>\n", fp);
8078 
8079 		(void) fprintf(fp, "<TD %s>", tdparms2);
8080 		util_html_fputs(cdinfo_genre_name(cdinfo_dbp->track[i].genre2),
8081 				fp, FALSE, NULL, 0);
8082 		fputs("&nbsp;</TD>\n", fp);
8083 
8084 		(void) fprintf(fp, "<TD %s>%s</TD>\n",
8085 			tdparms2,
8086 			cdinfo_dbp->track[i].bpm == NULL ? "&nbsp;" :
8087 				cdinfo_dbp->track[i].bpm);
8088 
8089 		(void) fprintf(fp, "<TD %s>%s</TD>\n",
8090 			tdparms2,
8091 			cdinfo_dbp->track[i].year == NULL ? "&nbsp;" :
8092 				cdinfo_dbp->track[i].year);
8093 
8094 		(void) fprintf(fp, "<TD %s>", tdparms2);
8095 		if (cdinfo_dbp->track[i].label != NULL)
8096 			util_html_fputs(cdinfo_dbp->track[i].label,
8097 					fp, FALSE, NULL, 0);
8098 		else
8099 			(void) fputs("&nbsp;", fp);
8100 		(void) fputs("</TD>\n</TR>\n", fp);
8101 
8102 		/* Count the number of rows needed for track credits and
8103 		 * track notes
8104 		 */
8105 		for (cp = cdinfo_dbp->track[i].credit_list; cp != NULL;
8106 		     cp = cp->next)
8107 			ntrkrows++;
8108 		if (cdinfo_dbp->track[i].notes != NULL)
8109 			ntrkrows++;
8110 	}
8111 	(void) fputs("<TR><TD COLSPAN=\"10\">&nbsp;</TD></TR>\n", fp);
8112 
8113 	/* Album credits and notes */
8114 	ncreds = 0;
8115 	for (cp = cdinfo_dbp->disc.credit_list; cp != NULL; cp = cp->next)
8116 		ncreds++;
8117 
8118 	nrows = ncreds + (cdinfo_dbp->disc.notes == NULL ? 0 : 1);
8119 	if (nrows > 0) {
8120 		first = TRUE;
8121 		(void) fprintf(fp,
8122 			"<TR>\n<TH %s ROWSPAN=\"%d\">Album<BR>"
8123 			"Credits<BR>&amp; Notes</TH>\n",
8124 			tdparms3, nrows
8125 		);
8126 
8127 		/* credits */
8128 		for (cp = cdinfo_dbp->disc.credit_list; cp != NULL;
8129 		     cp = cp->next) {
8130 			if (first)
8131 				first = FALSE;
8132 			else
8133 				(void) fputs("<TR>\n", fp);
8134 
8135 			(void) fprintf(fp, "<TD %s COLSPAN=\"4\">", tdparms2);
8136 			if (cp->crinfo.name != NULL) {
8137 				if (srchact != NULL) {
8138 					p = cdinfo_txtreduce(cp->crinfo.name,
8139 							     TRUE);
8140 					(void) fprintf(fp, "<A HREF=\"%s%s\">",
8141 						srchact, p
8142 					);
8143 					MEM_FREE(p);
8144 				}
8145 				(void) fputs(cp->crinfo.name, fp);
8146 				if (srchact != NULL)
8147 					(void) fputs("</A>", fp);
8148 			}
8149 			else
8150 				(void) fputs("unknown", fp);
8151 
8152 			(void) fputs(" (", fp);
8153 			if (cp->crinfo.role != NULL)
8154 				util_html_fputs(cp->crinfo.role->name,
8155 						fp, FALSE, NULL, 0);
8156 			else
8157 				fputs("unknown", fp);
8158 			(void) fputs(")</TD>\n", fp);
8159 
8160 			(void) fprintf(fp, "<TD %s COLSPAN=\"5\">", tdparms2);
8161 			if (cp->notes != NULL)
8162 				util_html_fputs(cp->notes, fp, TRUE,
8163 						"courier", -1);
8164 			else
8165 				(void) fputs("&nbsp;", fp);
8166 			(void) fputs("</TD>\n</TR>\n", fp);
8167 		}
8168 
8169 		/* notes */
8170 		if (cdinfo_dbp->disc.notes != NULL) {
8171 			if (!first)
8172 				(void) fputs("<TR>\n", fp);
8173 			(void) fprintf(fp, "<TD %s COLSPAN=\"9\">", tdparms2);
8174 			util_html_fputs(cdinfo_dbp->disc.notes,
8175 					fp, TRUE, "courier", -1);
8176 			(void) fputs("</TD>\n</TR>\n", fp);
8177 		}
8178 	}
8179 
8180 	/* Track credits and notes */
8181 	if (ntrkrows > 0) {
8182 		(void) fprintf(fp,
8183 			    "<TH %s ROWSPAN=\"%d\">"
8184 			    "Track<BR>Credits<BR>&amp; Notes</TH>\n",
8185 			    tdparms3, ntrkrows);
8186 
8187 		for (i = 0; i < (int) s->tot_trks; i++) {
8188 			if (cdinfo_dbp->track[i].credit_list == NULL &&
8189 			    cdinfo_dbp->track[i].notes == NULL)
8190 				continue;
8191 
8192 			ncreds = 0;
8193 			for (cp = cdinfo_dbp->track[i].credit_list; cp != NULL;
8194 			     cp = cp->next)
8195 				ncreds++;
8196 
8197 			nrows = ncreds + (cdinfo_dbp->track[i].notes == NULL ?
8198 					  0 : 1);
8199 
8200 			(void) fprintf(fp,
8201 				    "<TD %s ROWSPAN=\"%d\">Track %d</TD>\n",
8202 				    tdparms3,
8203 				    nrows,
8204 				    (int) s->trkinfo[i].trkno);
8205 
8206 			first = TRUE;
8207 			/* credits */
8208 			for (cp = cdinfo_dbp->track[i].credit_list; cp != NULL;
8209 			     cp = cp->next) {
8210 				if (first)
8211 					first = FALSE;
8212 				else
8213 					(void) fputs("<TR>\n", fp);
8214 
8215 				(void) fprintf(fp, "<TD %s COLSPAN=\"3\">",
8216 						tdparms2);
8217 
8218 				if (cp->crinfo.name != NULL) {
8219 					if (srchact != NULL) {
8220 						p = cdinfo_txtreduce(
8221 							cp->crinfo.name,
8222 							TRUE
8223 						);
8224 						(void) fprintf(fp,
8225 							"<A HREF=\"%s%s\">",
8226 							srchact, p
8227 						);
8228 						MEM_FREE(p);
8229 					}
8230 					(void) fputs(cp->crinfo.name, fp);
8231 					if (srchact != NULL)
8232 						(void) fputs("</A>", fp);
8233 				}
8234 				else
8235 					(void) fputs("unknown", fp);
8236 
8237 				(void) fputs(" (", fp);
8238 				if (cp->crinfo.role != NULL)
8239 					util_html_fputs(cp->crinfo.role->name,
8240 							fp, TRUE, NULL, 0);
8241 				else
8242 					(void) fputs("unknown", fp);
8243 				(void) fputs(")</TD>\n", fp);
8244 
8245 				(void) fprintf(fp, "<TD %s COLSPAN=\"5\">",
8246 						tdparms2);
8247 				if (cp->notes == NULL)
8248 					(void) fputs("&nbsp;", fp);
8249 				else
8250 					util_html_fputs(cp->notes, fp, TRUE,
8251 							"courier", -1);
8252 				(void) fputs("</TD>\n</TR>\n", fp);
8253 			}
8254 
8255 			/* notes */
8256 			if (cdinfo_dbp->track[i].notes != NULL) {
8257 				if (!first)
8258 					(void) fputs("<TR>\n", fp);
8259 
8260 				(void) fprintf(fp, "<TD %s COLSPAN=\"8\">",
8261 						tdparms2);
8262 				util_html_fputs(cdinfo_dbp->track[i].notes,
8263 						fp, TRUE,
8264 						"courier", -1);
8265 				(void) fputs("</TD>\n</TR>\n", fp);
8266 			}
8267 		}
8268 	}
8269 
8270 	(void) fputs("</TABLE>\n", fp);
8271 
8272 	/* end of <DIV ALIGN="center"> */
8273 	(void) fputs("</DIV>\n<P>\n", fp);
8274 
8275 	/* Local discography */
8276 	(void) fputs("<H4>Local Discography</H4>\n<P>\n<UL>\n", fp);
8277 
8278 	/* Initialize list heads */
8279 	for (i = 0; i < MAX_FILEFMTS; i++)
8280 		lheads[i] = NULL;
8281 
8282 	/* Check directory and add links to files */
8283 	if (((util_urlchk(baseurl, &p, &i) & IS_REMOTE_URL) == 0) &&
8284 	    (dp = OPENDIR(outdir)) != NULL) {
8285 		while ((de = READDIR(dp)) != NULL) {
8286 			if (strcmp(de->d_name, ".") == 0 ||
8287 			    strcmp(de->d_name, "..") == 0)
8288 				/* Skip . and .. */
8289 				continue;
8290 
8291 #ifdef __VMS
8292 			/* Discard version number */
8293 			if ((p = strrchr(de->d_name, ';')) != NULL)
8294 				*p = '\0';
8295 
8296 			p = util_vms_urlconv(outdir, VMS_2_UNIX);
8297 			if (p != NULL) {
8298 				(void) strncpy(filepath, p,
8299 					       sizeof(filepath)-1);
8300 				filepath[sizeof(filepath)-1] = '\0';
8301 				MEM_FREE(p);
8302 			}
8303 #else
8304 			filepath[0] = '\0';
8305 #endif
8306 
8307 			if (util_strcasecmp(de->d_name, "index.html") == 0)
8308 				/* Skip index.html which we're generating */
8309 				continue;
8310 
8311 			fmt = -1;
8312 			if ((p = strrchr(de->d_name, '.')) != NULL) {
8313 				if (util_strcasecmp(p, ".m3u") == 0 ||
8314 				    util_strcasecmp(p, ".pls") == 0)
8315 					/* Skip playlist files */
8316 					continue;
8317 
8318 				/* Check if the file is an audio track */
8319 				for (i = 0; i < MAX_FILEFMTS; i++) {
8320 					if ((fmp = cdda_filefmt(i)) == NULL)
8321 						continue;
8322 
8323 					if (util_strcasecmp(p, fmp->suf) == 0)
8324 						fmt = fmp->fmt;
8325 				}
8326 			}
8327 
8328 			if (fmt >= 0) {
8329 				playls_t	**hp;
8330 
8331 				/* An audio track: Add to appropriate list */
8332 
8333 				hp = &lheads[fmt];
8334 
8335 				sp = (playls_t *) MEM_ALLOC(
8336 					"playls_t",
8337 					sizeof(playls_t)
8338 				);
8339 				if (sp != NULL) {
8340 					sp->prev = sp->next = NULL;
8341 					sp->prev2 = sp->next2 = NULL;
8342 					sp->path = NULL;
8343 
8344 					if (!util_newstr(&sp->path,
8345 							de->d_name)) {
8346 						MEM_FREE(sp);
8347 					}
8348 					else {
8349 						/* Add to list */
8350 						if (*hp != NULL)
8351 							(*hp)->prev = sp;
8352 						sp->next = *hp;
8353 						*hp = sp;
8354 					}
8355 				}
8356 			}
8357 			else {
8358 				/* Not an audio track */
8359 				(void) fprintf(fp,
8360 				    "<LI><A HREF=\"%s%s\">%s: %s</A></LI>\n",
8361 				    filepath, de->d_name, "File", de->d_name
8362 				);
8363 			}
8364 		}
8365 
8366 		(void) CLOSEDIR(dp);
8367 	}
8368 
8369 #ifdef __VMS
8370 	p = util_vms_urlconv(outdir, VMS_2_UNIX);
8371 	if (p != NULL) {
8372 		(void) strncpy(filepath, p, sizeof(filepath)-1);
8373 		filepath[sizeof(filepath)-1] = '\0';
8374 		MEM_FREE(p);
8375 	}
8376 #else
8377 	filepath[0] = '\0';
8378 #endif
8379 
8380 	relpath = NULL;
8381 	if (app_data.discog_url_pfx != NULL &&
8382 	    (p = util_basename(app_data.discog_url_pfx)) != NULL) {
8383 		if ((q = util_strstr(outdir, p)) != NULL)
8384 			q += strlen(p);
8385 		else
8386 			q = NULL;
8387 
8388 		MEM_FREE(p);
8389 
8390 		if (q != NULL) {
8391 			if (!util_newstr(&relpath, q)) {
8392 				CDINFO_FATAL(app_data.str_nomemory);
8393 				return FALSE;
8394 			}
8395 #ifdef __VMS
8396 			/* Convert VMS file path name separators into
8397 			 * URL path separators
8398 			 */
8399 			for (p = relpath; *p != '\0'; p++) {
8400 				if (*p == '.')
8401 					*p = '/';
8402 				else if (*p == ']')
8403 					*p = '\0';
8404 			}
8405 #endif
8406 		}
8407 	}
8408 
8409 	/* For each file format, generate audio track playlists */
8410 	for (i = 0; i < MAX_FILEFMTS; i++) {
8411 		playls_t	*shead;
8412 
8413 		if (lheads[i] == NULL || (fmp = cdda_filefmt(i)) == NULL)
8414 			continue;
8415 
8416 #ifdef __VMS
8417 		(void) sprintf(plspath, "%s%s.m3u", outdir, fmp->name);
8418 #else
8419 		(void) sprintf(plspath, "%s%c%s.m3u",
8420 				outdir, DIR_END, fmp->name);
8421 #endif
8422 		(void) UNLINK(plspath);
8423 
8424 		/* Sort the track list */
8425 		shead = cdinfo_sort_playlist(lheads[i]);
8426 
8427 		/* Write audio track list in discography file */
8428 		(void) fprintf(fp, "<LI>%s audio tracks:</LI>\n", fmp->name);
8429 		(void) fputs("<UL>\n", fp);
8430 
8431 		/* Write .m3u format playlist file */
8432 		if ((pls_fp = fopen(plspath, "w")) == NULL) {
8433 			DBGPRN(DBG_CDI)(errfp,
8434 				"Cannot open %s for writing.\n", plspath);
8435 		}
8436 		else {
8437 			(void) chmod(plspath, (mode_t) fmode);
8438 
8439 			for (sp = shead; sp != NULL; sp = sp->next2) {
8440 				if (relpath == NULL) {
8441 					(void) fprintf(pls_fp, "%s\n",
8442 						sp->path
8443 					);
8444 				}
8445 				else {
8446 					p = (char *) MEM_ALLOC("plsurl",
8447 					    strlen(relpath) +
8448 					    strlen(sp->path) + 4
8449 					);
8450 					if (p != NULL) {
8451 					    /* This is a URL, so use '/'
8452 					     * even for VMS.
8453 					     */
8454 					    (void) sprintf(p, "%s/%s",
8455 						relpath,
8456 						sp->path
8457 					    );
8458 
8459 					    q = util_urlencode(p);
8460 					    if (q != NULL) {
8461 						(void) fprintf(
8462 						    pls_fp, "%s%s\n",
8463 						    app_data.discog_url_pfx,
8464 						    q
8465 						);
8466 						MEM_FREE(q);
8467 					    }
8468 
8469 					    MEM_FREE(p);
8470 					}
8471 				}
8472 			}
8473 
8474 			(void) fclose(pls_fp);
8475 
8476 			/* Add playlist file entry to local discography */
8477 			(void) fprintf(fp,
8478 				"<LI><A HREF=\"%s%s.m3u\">"
8479 				"Playlist</A> (.m3u format)</LI>\n",
8480 				filepath, fmp->name
8481 			);
8482 		}
8483 
8484 #ifdef __VMS
8485 		(void) sprintf(plspath, "%s%s.pls", outdir, fmp->name);
8486 #else
8487 		(void) sprintf(plspath, "%s%c%s.pls",
8488 				outdir, DIR_END, fmp->name);
8489 #endif
8490 		(void) UNLINK(plspath);
8491 
8492 		/* Write .pls format playlist file */
8493 		if ((pls_fp = fopen(plspath, "w")) == NULL) {
8494 			DBGPRN(DBG_CDI)(errfp,
8495 				"Cannot open %s for writing.\n", plspath);
8496 		}
8497 		else {
8498 			int	n;
8499 
8500 			(void) chmod(plspath, (mode_t) fmode);
8501 			(void) fprintf(pls_fp, "[playlist]\n");
8502 
8503 			n = 1;
8504 			for (sp = shead; sp != NULL; sp = sp->next2) {
8505 				char	*cp,
8506 					*cp2;
8507 				int	len;
8508 
8509 				(void) sprintf(plspath, "%s%c%s",
8510 					       outdir, DIR_END, sp->path);
8511 				if (stat(plspath, &stbuf) < 0 ||
8512 				    !S_ISREG(stbuf.st_mode))
8513 					len = -1;
8514 				else
8515 					len = (int) stbuf.st_size;
8516 
8517 				if (relpath == NULL) {
8518 					(void) fprintf(pls_fp, "File%d=%s\n",
8519 						n, sp->path
8520 					);
8521 				}
8522 				else {
8523 					p = (char *) MEM_ALLOC("plsurl",
8524 					    strlen(relpath) +
8525 					    strlen(sp->path) + 4
8526 					);
8527 					/* This is a URL, so use '/'
8528 					 * even for VMS.
8529 					 */
8530 					if (p != NULL) {
8531 					    (void) sprintf(p, "%s/%s",
8532 						relpath,
8533 						sp->path
8534 					    );
8535 
8536 					    q = util_urlencode(p);
8537 					    if (q != NULL) {
8538 						(void) fprintf(
8539 						    pls_fp, "File%d=%s%s\n",
8540 						    n,
8541 						    app_data.discog_url_pfx,
8542 						    q
8543 						);
8544 						MEM_FREE(q);
8545 					    }
8546 
8547 					    MEM_FREE(p);
8548 					}
8549 				}
8550 
8551 				cp = NULL;
8552 				if (!util_newstr(&cp, sp->path)) {
8553 				    cp = sp->path;
8554 				}
8555 				else for (cp2 = cp; *cp2 != '\0'; cp2++) {
8556 				    if (util_strcasecmp(cp2, fmp->suf) == 0) {
8557 					*cp2 = '\0';
8558 					break;
8559 				    }
8560 				    else if (*cp2 == '_' || *cp2 == '-')
8561 					*cp2 = ' ';
8562 				}
8563 
8564 				(void) fprintf(pls_fp, "Title%d=%s\n",
8565 						n, cp);
8566 				(void) fprintf(pls_fp, "Length%d=%d\n",
8567 						n, len);
8568 
8569 				if (cp != sp->path)
8570 					MEM_FREE(cp);
8571 				n++;
8572 			}
8573 
8574 			(void) fprintf(pls_fp, "NumberOfEntries=%d\n", n - 1);
8575 			(void) fprintf(pls_fp, "Version=2\n");
8576 			(void) fclose(pls_fp);
8577 
8578 			/* Add playlist file entry to local discography */
8579 			(void) fprintf(fp,
8580 				"<LI><A HREF=\"%s%s.pls\">"
8581 				"Playlist</A> (.pls format)</LI>\n",
8582 				filepath, fmp->name
8583 			);
8584 		}
8585 
8586 		/* Add audio track files to local discography */
8587 		for (sp = shead; sp != NULL; sp = sp->next2) {
8588 			(void) fprintf(fp,
8589 				"<LI><A HREF=\"%s%s\">Track: %s</A></LI>\n",
8590 				filepath, sp->path, sp->path
8591 			);
8592 		}
8593 		(void) fputs("</UL>\n", fp);
8594 
8595 		/* Deallocate the playlist for the file format */
8596 		sp = lheads[i];
8597 		while (sp != NULL) {
8598 			playls_t	*sp2;
8599 
8600 			sp2 = sp->next;
8601 			if (sp->path != NULL)
8602 				MEM_FREE(sp->path);
8603 			MEM_FREE(sp);
8604 			sp = sp2;
8605 		}
8606 		lheads[i] = NULL;
8607 	}
8608 
8609 	if (relpath != NULL)
8610 		MEM_FREE(relpath);
8611 
8612 #ifdef __VMS
8613 	(void) sprintf(filepath, "%s.discog]index.html", app_data.libdir);
8614 	if ((p = util_vms_urlconv(filepath, VMS_2_UNIX)) != NULL) {
8615 		(void) strncpy(filepath, p, sizeof(filepath)-1);
8616 		filepath[sizeof(filepath)-1] = '\0';
8617 		MEM_FREE(p);
8618 	}
8619 #else
8620 	(void) sprintf(filepath, "%s/index.html", dhome);
8621 #endif
8622 	(void) fprintf(fp, "<LI><A HREF=\"%s\">Main index</A></LI>\n",
8623 			filepath);
8624 
8625 #ifdef __VMS
8626 	if ((p = util_dirname(outdir)) == NULL) {
8627 		(void) sprintf(filepath, "index.html");
8628 	}
8629 	else {
8630 		(void) sprintf(filepath, "%sindex.html", p);
8631 		MEM_FREE(p);
8632 	}
8633 
8634 	if ((p = util_vms_urlconv(filepath, VMS_2_UNIX)) != NULL) {
8635 		(void) strncpy(filepath, p, sizeof(filepath)-1);
8636 		filepath[sizeof(filepath)-1] = '\0';
8637 		MEM_FREE(p);
8638 	}
8639 #else
8640 	(void) sprintf(filepath, "../index.html");
8641 #endif
8642 	if (cdinfo_dbp->disc.genre != NULL) {
8643 		(void) fprintf(fp, "<LI><A HREF=\"%s\">", filepath);
8644 		util_html_fputs(
8645 			cdinfo_genre_name(cdinfo_dbp->disc.genre),
8646 			fp, TRUE, NULL, 0
8647 		);
8648 		(void) fputs(" index</A></LI>\n", fp);
8649 	}
8650 
8651 	if (cdinfo_dbp->disc.genre2 != NULL) {
8652 		gpath = cdinfo_genre_path(cdinfo_dbp->disc.genre2);
8653 #ifdef __VMS
8654 		(void) sprintf(filepath, "%s.discog.%s]index.html",
8655 			       app_data.libdir, gpath);
8656 		if ((p = util_vms_urlconv(filepath, VMS_2_UNIX)) != NULL) {
8657 			(void) strncpy(filepath, p, sizeof(filepath)-1);
8658 			filepath[sizeof(filepath)-1] = '\0';
8659 			MEM_FREE(p);
8660 		}
8661 #else
8662 		(void) sprintf(filepath, "%s/%s/index.html", dhome, gpath);
8663 #endif
8664 		(void) fprintf(fp, "<LI><A HREF=\"%s\">", filepath);
8665 		util_html_fputs(
8666 			cdinfo_genre_name(cdinfo_dbp->disc.genre2),
8667 			fp, TRUE, NULL, 0
8668 		);
8669 		(void) fputs(" index</A></LI>\n", fp);
8670 	}
8671 
8672 #ifdef __VMS
8673 	(void) sprintf(filepath, "%s.discog]discog.html", app_data.libdir);
8674 	if ((p = util_vms_urlconv(filepath, VMS_2_UNIX)) != NULL) {
8675 		(void) strncpy(filepath, p, sizeof(filepath)-1);
8676 		filepath[sizeof(filepath)-1] = '\0';
8677 		MEM_FREE(p);
8678 	}
8679 #else
8680 	(void) sprintf(filepath, "%s/discog.html", dhome);
8681 #endif
8682 	(void) fprintf(fp, "<LI><A HREF=\"%s\">%s</A></LI>\n",
8683 			filepath, "How to use Local Discography");
8684 
8685 	(void) fputs("</UL>\n<P>\n", fp);
8686 
8687 	/* Directory info */
8688 	(void) fprintf(fp, "<HR>\nThis directory: <B>%s</B><BR>\n", outdir);
8689 	(void) fputs("</BODY>\n</HTML>\n", fp);
8690 
8691 	if (srchact != NULL)
8692 		MEM_FREE(srchact);
8693 
8694 	(void) fclose(fp);
8695 
8696 	if (newdiscog) {
8697 		/* Generate local discography index for the primary genre */
8698 
8699 		gpath = cdinfo_genre_path(cdinfo_dbp->disc.genre);
8700 		cmd = (char *) MEM_ALLOC("genidx_cmd",
8701 			strlen(gpath) + STR_BUF_SZ
8702 		);
8703 		if (cmd == NULL) {
8704 			CDINFO_FATAL(app_data.str_nomemory);
8705 			return FALSE;
8706 		}
8707 #ifdef __VMS
8708 		(void) sprintf(cmd, "genidx %s", gpath);
8709 #else
8710 		(void) sprintf(cmd, "genidx %s >/dev/null 2>&1 &", gpath);
8711 #endif
8712 
8713 		DBGPRN(DBG_CDI)(errfp,
8714 			"\nGenerating local discography index for %s\n",
8715 			gpath);
8716 
8717 		(void) util_runcmd(cmd, cdinfo_clinfo->workproc,
8718 				   cdinfo_clinfo->arg);
8719 		MEM_FREE(cmd);
8720 	}
8721 
8722 	if (cdinfo_dbp->disc.genre2 != NULL) {
8723 		gpath = cdinfo_genre_path(cdinfo_dbp->disc.genre2);
8724 #ifdef __VMS
8725 		(void) sprintf(filepath, "%s.discog.%s]index.html",
8726 			       app_data.libdir, gpath);
8727 		if ((p = util_vms_urlconv(filepath, VMS_2_UNIX)) != NULL) {
8728 			(void) strncpy(filepath, p, sizeof(filepath)-1);
8729 			filepath[sizeof(filepath)-1] = '\0';
8730 			MEM_FREE(p);
8731 		}
8732 #else
8733 		(void) sprintf(filepath, "%s/%s/%s/index.html",
8734 			       outdir, dhome, gpath);
8735 #endif
8736 		if (stat(filepath, &stbuf) < 0 && errno == ENOENT) {
8737 			/* Generate local discography index for the
8738 		 	 * secondary genre, if applicable
8739 			 */
8740 			cmd = (char *) MEM_ALLOC("genidx_cmd",
8741 				strlen(gpath) + STR_BUF_SZ
8742 			);
8743 			if (cmd == NULL) {
8744 				CDINFO_FATAL(app_data.str_nomemory);
8745 				return FALSE;
8746 			}
8747 #ifdef __VMS
8748 			(void) sprintf(cmd, "genidx %s", gpath);
8749 #else
8750 			(void) sprintf(cmd, "genidx %s >/dev/null 2>&1 &",
8751 				       gpath);
8752 #endif
8753 
8754 			DBGPRN(DBG_CDI)(errfp,
8755 			    "\nGenerating local discography index for %s\n",
8756 			    gpath);
8757 
8758 			(void) util_runcmd(cmd, cdinfo_clinfo->workproc,
8759 					   cdinfo_clinfo->arg);
8760 			MEM_FREE(cmd);
8761 		}
8762 	}
8763 
8764 	return TRUE;
8765 }
8766 
8767 
8768 /*
8769  * cdinfo_map_cdtext
8770  *	Move CD-TEXT data to the incore CD information main structure.
8771  *
8772  * Args:
8773  *	s   - Pointer to the curstat_t structure.
8774  *	cdt - Pointer to the di_cdtext_t structure.
8775  *
8776  * Return:
8777  *	Nothing.
8778  */
8779 void
cdinfo_map_cdtext(curstat_t * s,di_cdtext_t * cdt)8780 cdinfo_map_cdtext(curstat_t *s, di_cdtext_t *cdt)
8781 {
8782 	int	i;
8783 	char	*cp = NULL;
8784 
8785 	if (cdinfo_dbp == NULL || cdt == NULL)
8786 		return;
8787 
8788 	/* Disc artist and title */
8789 	cdinfo_dbp->disc.artist = cdt->disc.performer;
8790 	cdinfo_dbp->disc.title = cdt->disc.title;
8791 	cdt->disc.performer = NULL;
8792 	cdt->disc.title = NULL;
8793 
8794 	/* Media catalog number (UPC/MCN) */
8795 	(void) strncpy(s->mcn, cdt->disc.catno, sizeof(s->mcn) - 1);
8796 	s->mcn[sizeof(s->mcn) - 1] = '\0';
8797 	MEM_FREE(cdt->disc.catno);
8798 	cdt->disc.catno = NULL;
8799 
8800 	/* Disc identification, songwriter, composer, composer and message:
8801 	 * put in the notes field
8802 	 */
8803 	if (cdt->ident != NULL) {
8804 		cp = (char *) MEM_ALLOC("ident",
8805 			strlen(cdt->ident) + 16
8806 		);
8807 		if (cp == NULL) {
8808 			CDINFO_FATAL(app_data.str_nomemory);
8809 			return;
8810 		}
8811 		(void) sprintf(cp, "Identification:\t%s\n", cdt->ident);
8812 		MEM_FREE(cdt->ident);
8813 		cdt->ident = NULL;
8814 	}
8815 	if (cdt->disc.songwriter != NULL) {
8816 		if (cp == NULL) {
8817 			cp = (char *) MEM_ALLOC("songwriter",
8818 				strlen(cdt->disc.songwriter) + 16
8819 			);
8820 			if (cp == NULL) {
8821 				CDINFO_FATAL(app_data.str_nomemory);
8822 				return;
8823 			}
8824 			(void) sprintf(cp, "Songwriter:\t%s\n",
8825 					cdt->disc.songwriter);
8826 		}
8827 		else {
8828 			cp = (char *) MEM_REALLOC("songwriter", cp,
8829 				strlen(cp) + strlen(cdt->disc.songwriter) + 16
8830 			);
8831 			if (cp == NULL) {
8832 				CDINFO_FATAL(app_data.str_nomemory);
8833 				return;
8834 			}
8835 			(void) sprintf(cp, "%sSongwriter:\t%s\n",
8836 					cp, cdt->disc.songwriter);
8837 		}
8838 		MEM_FREE(cdt->disc.songwriter);
8839 		cdt->disc.songwriter = NULL;
8840 	}
8841 	if (cdt->disc.composer != NULL) {
8842 		if (cp == NULL) {
8843 			cp = (char *) MEM_ALLOC("composer",
8844 				strlen(cdt->disc.composer) + 16
8845 			);
8846 			if (cp == NULL) {
8847 				CDINFO_FATAL(app_data.str_nomemory);
8848 				return;
8849 			}
8850 			(void) sprintf(cp, "Composer:\t%s\n",
8851 					cdt->disc.composer);
8852 		}
8853 		else {
8854 			cp = (char *) MEM_REALLOC("composer", cp,
8855 				strlen(cp) + strlen(cdt->disc.composer) + 16
8856 			);
8857 			if (cp == NULL) {
8858 				CDINFO_FATAL(app_data.str_nomemory);
8859 				return;
8860 			}
8861 			(void) sprintf(cp, "%sComposer:\t%s\n",
8862 					cp, cdt->disc.composer);
8863 		}
8864 		MEM_FREE(cdt->disc.composer);
8865 		cdt->disc.composer = NULL;
8866 	}
8867 	if (cdt->disc.arranger != NULL) {
8868 		if (cp == NULL) {
8869 			cp = (char *) MEM_ALLOC("arranger",
8870 				strlen(cdt->disc.arranger) + 16
8871 			);
8872 			if (cp == NULL) {
8873 				CDINFO_FATAL(app_data.str_nomemory);
8874 				return;
8875 			}
8876 			(void) sprintf(cp, "Composer:\t%s\n",
8877 					cdt->disc.arranger);
8878 		}
8879 		else {
8880 			cp = (char *) MEM_REALLOC("arranger", cp,
8881 				strlen(cp) + strlen(cdt->disc.arranger) + 16
8882 			);
8883 			if (cp == NULL) {
8884 				CDINFO_FATAL(app_data.str_nomemory);
8885 				return;
8886 			}
8887 			(void) sprintf(cp, "%sArranger:\t\t%s\n",
8888 					cp, cdt->disc.arranger);
8889 		}
8890 		MEM_FREE(cdt->disc.arranger);
8891 		cdt->disc.arranger = NULL;
8892 	}
8893 	if (cdt->disc.message != NULL) {
8894 		if (cp == NULL) {
8895 			cp = (char *) MEM_ALLOC("message",
8896 				strlen(cdt->disc.message) + 16
8897 			);
8898 			if (cp == NULL) {
8899 				CDINFO_FATAL(app_data.str_nomemory);
8900 				return;
8901 			}
8902 			(void) sprintf(cp, "Composer:\t%s\n",
8903 					cdt->disc.message);
8904 		}
8905 		else {
8906 			cp = (char *) MEM_REALLOC("message", cp,
8907 				strlen(cp) + strlen(cdt->disc.message) + 16
8908 			);
8909 			if (cp == NULL) {
8910 				CDINFO_FATAL(app_data.str_nomemory);
8911 				return;
8912 			}
8913 			(void) sprintf(cp, "%s\n%s\n",
8914 					cp, cdt->disc.message);
8915 		}
8916 		MEM_FREE(cdt->disc.message);
8917 		cdt->disc.message = NULL;
8918 	}
8919 
8920 	cdinfo_dbp->disc.notes = cp;
8921 
8922 	for (i = 0; i < (int) s->tot_trks; i++) {
8923 		/* Track artist, title and ISRC */
8924 		cdinfo_dbp->track[i].artist = cdt->track[i].performer;
8925 		cdinfo_dbp->track[i].title = cdt->track[i].title;
8926 		cdinfo_dbp->track[i].isrc = cdt->track[i].catno;
8927 
8928 		cdt->track[i].performer = NULL;
8929 		cdt->track[i].title = NULL;
8930 		cdt->track[i].catno = NULL;
8931 
8932 		/* Track songwriter, composer, arranger and message:
8933 		 * put in the notes section.
8934 		 */
8935 		cp = NULL;
8936 
8937 		if (cdt->track[i].songwriter != NULL) {
8938 			cp = (char *) MEM_ALLOC("songwriter",
8939 				strlen(cdt->track[i].songwriter) + 16
8940 			);
8941 			if (cp == NULL) {
8942 				CDINFO_FATAL(app_data.str_nomemory);
8943 				return;
8944 			}
8945 			(void) sprintf(cp, "Songwriter:\t%s\n",
8946 					cdt->track[i].songwriter);
8947 			MEM_FREE(cdt->track[i].songwriter);
8948 			cdt->track[i].songwriter = NULL;
8949 		}
8950 		if (cdt->track[i].composer != NULL) {
8951 			if (cp == NULL) {
8952 				cp = (char *) MEM_ALLOC("composer",
8953 					strlen(cdt->track[i].composer) + 16
8954 				);
8955 				if (cp == NULL) {
8956 					CDINFO_FATAL(app_data.str_nomemory);
8957 					return;
8958 				}
8959 				(void) sprintf(cp, "Composer:\t%s\n",
8960 						cdt->track[i].composer);
8961 			}
8962 			else {
8963 				cp = (char *) MEM_REALLOC("composer", cp,
8964 					strlen(cp) +
8965 					strlen(cdt->track[i].composer) + 16
8966 				);
8967 				if (cp == NULL) {
8968 					CDINFO_FATAL(app_data.str_nomemory);
8969 					return;
8970 				}
8971 				(void) sprintf(cp, "%sComposer:\t%s\n",
8972 						cp, cdt->track[i].composer);
8973 			}
8974 			MEM_FREE(cdt->track[i].composer);
8975 			cdt->track[i].composer = NULL;
8976 		}
8977 		if (cdt->track[i].arranger != NULL) {
8978 			if (cp == NULL) {
8979 				cp = (char *) MEM_ALLOC("arranger",
8980 					strlen(cdt->track[i].arranger) + 16
8981 				);
8982 				if (cp == NULL) {
8983 					CDINFO_FATAL(app_data.str_nomemory);
8984 					return;
8985 				}
8986 				(void) sprintf(cp, "Composer:\t%s\n",
8987 						cdt->track[i].arranger);
8988 			}
8989 			else {
8990 				cp = (char *) MEM_REALLOC("arranger", cp,
8991 					strlen(cp) +
8992 					strlen(cdt->track[i].arranger) + 16
8993 				);
8994 				if (cp == NULL) {
8995 					CDINFO_FATAL(app_data.str_nomemory);
8996 					return;
8997 				}
8998 				(void) sprintf(cp, "%sArranger:\t%s\n",
8999 						cp, cdt->track[i].arranger);
9000 			}
9001 			MEM_FREE(cdt->track[i].arranger);
9002 			cdt->track[i].arranger = NULL;
9003 		}
9004 		if (cdt->track[i].message != NULL) {
9005 			if (cp == NULL) {
9006 				cp = (char *) MEM_ALLOC("message",
9007 					strlen(cdt->track[i].message) + 16
9008 				);
9009 				if (cp == NULL) {
9010 					CDINFO_FATAL(app_data.str_nomemory);
9011 					return;
9012 				}
9013 				(void) sprintf(cp, "Composer:\t%s\n",
9014 						cdt->track[i].message);
9015 			}
9016 			else {
9017 				cp = (char *) MEM_REALLOC("message", cp,
9018 					strlen(cp) +
9019 					strlen(cdt->track[i].message) + 16
9020 				);
9021 				if (cp == NULL) {
9022 					CDINFO_FATAL(app_data.str_nomemory);
9023 					return;
9024 				}
9025 				(void) sprintf(cp, "%s\n%s\n",
9026 						cp, cdt->track[i].message);
9027 			}
9028 			MEM_FREE(cdt->track[i].message);
9029 			cdt->track[i].message = NULL;
9030 		}
9031 
9032 		cdinfo_dbp->track[i].notes = cp;
9033 	}
9034 }
9035 
9036 
9037