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_x_c_ident_ = "@(#)cdinfo_x.c 7.176 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
32 #include "common_d/appenv.h"
33 #include "common_d/version.h"
34 #include "common_d/util.h"
35 #include "libdi_d/libdi.h"
36 #include "cdinfo_d/cdinfo.h"
37
38
39 #define MAX_ENV_LEN (STR_BUF_SZ * 16)
40
41 extern appdata_t app_data;
42 extern FILE *errfp;
43 extern cdinfo_client_t *cdinfo_clinfo; /* Client info */
44 extern cdinfo_incore_t *cdinfo_dbp; /* Incore CD info structure */
45 extern cdinfo_cddb_t *cdinfo_cddbp; /* Opened CDDB handle */
46 extern w_ent_t *cdinfo_discog, /* Local discog menu ptr */
47 *cdinfo_scddb; /* Search CDDB menu ptr */
48 extern void *cdinfo_lconv_desc; /* Charset conv descriptor */
49 extern bool_t cdinfo_ischild; /* Is a child process */
50
51 STATIC pid_t child_pid = 0; /* Child pid */
52 STATIC char curfile[FILE_PATH_SZ] = { '\0' };
53 /* Current disc info file */
54
55
56 /***********************
57 * private routines *
58 ***********************/
59
60
61 /*
62 * cdinfo_mkpath
63 * Convert a string to replace all occurrences of non-alpha and
64 * non-digit characters with an underscore. Multiple such characters
65 * are only substituted with one underscore. This is used to create
66 * names suitable for use as a path name. This function allocates
67 * memory which must be freed by the caller via MEM_FREE when done.
68 *
69 * Args:
70 * str - Input string
71 * len - Max output string length including terminating null character
72 *
73 * Return:
74 * Converted string, or NULL on failure.
75 */
76 STATIC char *
cdinfo_mkpath(char * str,int len)77 cdinfo_mkpath(char *str, int len)
78 {
79 int i;
80 char *buf,
81 *cp,
82 *cp2;
83
84 if ((buf = (char *) MEM_ALLOC("cdinfo_mkpath", len)) == NULL)
85 return NULL;
86
87 cp = buf;
88 cp2 = str;
89 for (i = 0; *cp2 != '\0' && i < (len - 1); i++) {
90 /* Replace non-alpha and non-digit chars with an underscore */
91
92 if (isalnum((int) *cp2))
93 *cp++ = *cp2;
94 else if (cp > buf && *(cp-1) != '_')
95 *cp++ = '_';
96 else
97 i--;
98
99 cp2++;
100 }
101 *cp = '\0';
102
103 return (buf);
104 }
105
106
107 /*
108 * cdinfo_forkwait
109 * Function that forks a child and sets the uid and gid to the original
110 * invoking user. The parent then waits for the child to do some
111 * work and exit, and return an exit code in the location pointed to
112 * by retcode. The caller can check the return of this function to
113 * determine whether it's the parent or child. If SYNCHRONOUS is
114 * defined, this function always returns FALSE and no child is forked.
115 *
116 * Args:
117 * retcode - Location that the parent is to return an status code of
118 * the child.
119 *
120 * Return:
121 * TRUE - Parent process: child has exited and the status code is
122 * returned in retcode.
123 * FALSE - Child process: Now running with original uid/gid.
124 */
125 bool_t
cdinfo_forkwait(cdinfo_ret_t * retcode)126 cdinfo_forkwait(cdinfo_ret_t *retcode)
127 {
128 #ifdef SYNCHRONOUS
129 *retcode = 0;
130 return FALSE;
131 #else
132 int ret;
133 pid_t cpid;
134 waitret_t wstat;
135
136 /* Fork child and make child do actual work */
137 switch (cpid = FORK()) {
138 case 0:
139 /* Child process */
140 cdinfo_ischild = TRUE;
141
142 (void) util_signal(SIGTERM, cdinfo_onterm);
143 (void) util_signal(SIGPIPE, SIG_IGN);
144
145 /* Force uid and gid to original setting */
146 if (!util_set_ougid())
147 _exit(SETUID_ERR);
148
149 return FALSE;
150
151 case -1:
152 *retcode = CDINFO_SET_CODE(FORK_ERR, errno);
153 return TRUE;
154
155 default:
156 /* Parent process: wait for child to exit */
157 child_pid = cpid;
158
159 ret = util_waitchild(cpid, app_data.srv_timeout + 5,
160 cdinfo_clinfo->workproc,
161 cdinfo_clinfo->arg,
162 TRUE, &wstat);
163 child_pid = 0;
164
165 if (ret < 0) {
166 *retcode = CDINFO_SET_CODE(WAIT_ERR, errno);
167 }
168 else if (WIFEXITED(wstat)) {
169 if (WEXITSTATUS(wstat) == 0)
170 *retcode = 0;
171 else
172 *retcode = CDINFO_SET_CODE(
173 WEXITSTATUS(wstat), 0
174 );
175 }
176 else if (WIFSIGNALED(wstat)) {
177 *retcode = CDINFO_SET_CODE(
178 KILLED_ERR, WTERMSIG(wstat)
179 );
180 }
181 else
182 *retcode = 0;
183
184 return TRUE;
185 }
186
187 /*NOTREACHED*/
188 #endif /* SYNCHRONOUS */
189 }
190
191
192 /***********************
193 * public routines *
194 ***********************/
195
196
197 /*
198 * cdinfo_addr
199 * Return a pointer to the incore CD information structure.
200 *
201 * Args:
202 * None.
203 *
204 * Return:
205 * Pointer to the incore CD info structure.
206 */
207 cdinfo_incore_t *
cdinfo_addr(void)208 cdinfo_addr(void)
209 {
210 return (cdinfo_dbp);
211 }
212
213
214 /*
215 * cdinfo_discid
216 * Compute a quasi-unique integer disc identifier based on the
217 * number of tracks, the length of each track, and a checksum of
218 * the string that represents the offset of each track.
219 *
220 * Args:
221 * s - Pointer to the curstat_t structure.
222 *
223 * Return:
224 * The integer disc ID.
225 */
226 word32_t
cdinfo_discid(curstat_t * s)227 cdinfo_discid(curstat_t *s)
228 {
229 int i,
230 a,
231 t = 0,
232 n = 0;
233
234 /* For backward compatibility this algorithm must not change */
235 a = (int) s->tot_trks;
236
237 for (i = 0; i < a; i++)
238 n += cdinfo_sum((s->trkinfo[i].min * 60) + s->trkinfo[i].sec);
239
240 t = ((s->trkinfo[a].min * 60) + s->trkinfo[a].sec) -
241 ((s->trkinfo[0].min * 60) + s->trkinfo[0].sec);
242
243 return ((n % 0xff) << 24 | t << 8 | s->tot_trks);
244 }
245
246
247 /*
248 * cdinfo_txtreduce
249 * Transform a text string into a CGI search string
250 *
251 * Args:
252 * text - Input text string
253 * reduce - Whether to reduce text (remove punctuations,
254 * exclude words from the excludeWords list).
255 *
256 * Return:
257 * Output string. The storage is internally allocated per call,
258 * and should be freed by the caller with MEM_FREE() after the
259 * buffer is no longer needed. If there is no sufficient memory
260 * to allocate the buffer, NULL is returned.
261 */
262 char *
cdinfo_txtreduce(char * text,bool_t reduce)263 cdinfo_txtreduce(char *text, bool_t reduce)
264 {
265 char *p,
266 *q;
267
268 if (reduce) {
269 if ((p = util_text_reduce(text)) == NULL)
270 return NULL;
271 }
272 else
273 p = text;
274
275 if ((q = util_cgi_xlate(p)) == NULL)
276 return NULL;
277
278 if (reduce)
279 MEM_FREE(p);
280
281 return (q);
282 }
283
284
285 /*
286 * cdinfo_tmpl_to_url
287 * Make a URL string from a template.
288 *
289 * Args:
290 * s - Pointer to the curstat_t structure
291 * tmpl - Template string
292 * url - Buffer to store resultant URL string
293 * trkpos - The track position for %T or %t
294 *
295 * Return:
296 * Nothing.
297 */
298 void
cdinfo_tmpl_to_url(curstat_t * s,char * tmpl,char * url,int trkpos)299 cdinfo_tmpl_to_url(curstat_t *s, char *tmpl, char *url, int trkpos)
300 {
301 char *q,
302 *r,
303 *a;
304 char dtitle[(STR_BUF_SZ * 4) + 4];
305
306 r = url;
307 for (a = tmpl; *a != '\0'; a++) {
308 switch (*a) {
309 case '%':
310 switch (*(++a)) {
311 case 'X':
312 (void) strcpy(r, cdinfo_clinfo->prog);
313 r += strlen(cdinfo_clinfo->prog);
314 break;
315
316 case 'V':
317 (void) sprintf(r, "%s.%s",
318 VERSION_MAJ, VERSION_MIN);
319 r += (strlen(VERSION_MAJ) +
320 strlen(VERSION_MIN) + 1);
321 break;
322
323 case 'N':
324 q = util_loginname();
325 (void) strcpy(r, q);
326 r += strlen(q);
327 break;
328
329 case '~':
330 q = util_homedir(util_get_ouid());
331 (void) strcpy(r, q);
332 r += strlen(q);
333 break;
334
335 case 'H':
336 (void) strcpy(r, cdinfo_clinfo->host);
337 r += strlen(cdinfo_clinfo->host);
338 break;
339
340 case 'L':
341 (void) strcpy(r, app_data.libdir);
342 r += strlen(app_data.libdir);
343 break;
344
345 case 'S':
346 (void) strcpy(r, app_data.libdir);
347 #ifdef __VMS
348 (void) strcat(r, ".discog");
349 #else
350 (void) strcat(r, "/discog");
351 #endif
352 r += strlen(app_data.libdir) +
353 strlen("discog") + 1;
354 break;
355
356 case 'C':
357 q = cdinfo_genre_path(cdinfo_dbp->disc.genre);
358 (void) strcpy(r, q);
359 r += strlen(q);
360 break;
361
362 case 'I':
363 (void) sprintf(r, "%08x", cdinfo_dbp->discid);
364 r += 8;
365 break;
366
367 case 'A':
368 case 'a':
369 /* Translate disk artist into a
370 * keyword string in CGI form
371 */
372 if (cdinfo_dbp->disc.artist == NULL)
373 break;
374
375 q = cdinfo_txtreduce(
376 cdinfo_dbp->disc.artist,
377 (bool_t) (*a == 'a')
378 );
379 if (q == NULL) {
380 CDINFO_FATAL(app_data.str_nomemory);
381 return;
382 }
383
384 (void) strcpy(r, q);
385 r += strlen(q);
386 MEM_FREE(q);
387 break;
388
389 case 'R':
390 case 'r':
391 /* Translate track artist into a
392 * keyword string in CGI form
393 */
394 if (trkpos >= 0 &&
395 cdinfo_dbp->track[trkpos].artist != NULL) {
396 q = cdinfo_txtreduce(
397 cdinfo_dbp->track[trkpos].artist,
398 (bool_t) (*a == 'r')
399 );
400 if (q == NULL) {
401 CDINFO_FATAL(
402 app_data.str_nomemory
403 );
404 return;
405 }
406 strcpy(r, q);
407 r += strlen(q);
408 MEM_FREE(q);
409 break;
410 }
411
412 if (cdinfo_dbp->disc.artist == NULL)
413 break;
414
415 /* Can't do track, Use disc artist instead */
416 q = cdinfo_txtreduce(cdinfo_dbp->disc.artist,
417 (bool_t) (*a == 'r'));
418 if (q == NULL) {
419 CDINFO_FATAL(app_data.str_nomemory);
420 return;
421 }
422
423 (void) strcpy(r, q);
424 r += strlen(q);
425 MEM_FREE(q);
426 break;
427
428 case 'T':
429 case 't':
430 /* Translate track title into a
431 * keyword string in CGI form
432 */
433 if (trkpos >= 0 &&
434 cdinfo_dbp->track[trkpos].title != NULL) {
435 q = cdinfo_txtreduce(
436 cdinfo_dbp->track[trkpos].title,
437 (bool_t) (*a == 't')
438 );
439 if (q == NULL) {
440 CDINFO_FATAL(
441 app_data.str_nomemory
442 );
443 return;
444 }
445 strcpy(r, q);
446 r += strlen(q);
447 MEM_FREE(q);
448 break;
449 }
450
451 if (cdinfo_dbp->disc.title == NULL)
452 break;
453
454 /* Can't do track, Use disc title instead */
455 q = cdinfo_txtreduce(cdinfo_dbp->disc.title,
456 (bool_t) (*a == 't'));
457 if (q == NULL) {
458 CDINFO_FATAL(app_data.str_nomemory);
459 return;
460 }
461
462 (void) strcpy(r, q);
463 r += strlen(q);
464 MEM_FREE(q);
465 break;
466
467 case 'D':
468 case 'd':
469 /* Translate disc title into a
470 * keyword string in CGI form
471 */
472 if (cdinfo_dbp->disc.title == NULL)
473 break;
474
475 q = cdinfo_txtreduce(cdinfo_dbp->disc.title,
476 (bool_t) (*a == 'd'));
477 if (q == NULL) {
478 CDINFO_FATAL(app_data.str_nomemory);
479 return;
480 }
481
482 (void) strcpy(r, q);
483 r += strlen(q);
484 MEM_FREE(q);
485 break;
486
487 case 'B':
488 case 'b':
489 /* Translate artist and disc title into a
490 * keyword string in CGI form
491 */
492 if (cdinfo_dbp->disc.artist == NULL &&
493 cdinfo_dbp->disc.title == NULL)
494 break;
495
496 (void) sprintf(dtitle, "%.127s%s%.127s",
497 (cdinfo_dbp->disc.artist == NULL) ?
498 "" : cdinfo_dbp->disc.artist,
499 (cdinfo_dbp->disc.artist != NULL &&
500 cdinfo_dbp->disc.title != NULL) ?
501 " / " : "",
502 (cdinfo_dbp->disc.title == NULL) ?
503 "" : cdinfo_dbp->disc.title);
504
505 q = cdinfo_txtreduce(
506 dtitle,
507 (bool_t) (*a == 'b')
508 );
509 if (q == NULL) {
510 CDINFO_FATAL(app_data.str_nomemory);
511 return;
512 }
513
514 (void) strcpy(r, q);
515 r += strlen(q);
516 MEM_FREE(q);
517 break;
518
519 case '#':
520 if (trkpos >= 0) {
521 (void) sprintf(r, "%02d",
522 s->trkinfo[trkpos].trkno);
523 r += 2;
524 }
525 break;
526
527 case '%':
528 *r++ = '%';
529 break;
530
531 default:
532 *r++ = '%';
533 *r++ = *a;
534 break;
535 }
536 break;
537
538 default:
539 *r++ = *a;
540 break;
541 }
542 }
543 *r = '\0';
544 }
545
546
547 /*
548 * cdinfo_url_len
549 * Determine a string buffer size large enough to hold a
550 * URL after it is expanded from its template.
551 *
552 * Args:
553 * tmpl - Template string
554 * up - Pointer to the associated URL attributes structure
555 * trkpos - Pointer to the track position for %T or %t.
556 *
557 * Return:
558 * The buffer length.
559 */
560 int
cdinfo_url_len(char * tmpl,url_attrib_t * up,int * trkpos)561 cdinfo_url_len(char *tmpl, url_attrib_t *up, int *trkpos)
562 {
563 int n,
564 artist_len,
565 title_len,
566 dtitle_len;
567
568 artist_len = (cdinfo_dbp->disc.artist != NULL) ?
569 strlen(cdinfo_dbp->disc.artist) : STR_BUF_SZ;
570 title_len = (cdinfo_dbp->disc.title != NULL) ?
571 strlen(cdinfo_dbp->disc.title) : STR_BUF_SZ;
572 dtitle_len = artist_len + title_len;
573
574 n = 16 + strlen(tmpl) + ((up->acnt + up->dcnt) * dtitle_len);
575
576 if (*trkpos < 0 || cdinfo_dbp->track[*trkpos].title == NULL) {
577 *trkpos = -1;
578 n += ((up->rcnt * dtitle_len) + (up->tcnt * dtitle_len));
579 }
580 else {
581 n += (up->tcnt * strlen(cdinfo_dbp->track[*trkpos].title));
582
583 if (cdinfo_dbp->track[*trkpos].artist != NULL)
584 n += (up->rcnt * strlen(cdinfo_dbp->track[*trkpos].artist));
585 else
586 n += (up->rcnt * artist_len);
587 }
588
589 n += (up->xcnt * strlen(cdinfo_clinfo->prog));
590 n += (up->vcnt * (strlen(VERSION_MAJ) + strlen(VERSION_MIN) + 1));
591 n += (up->ncnt * STR_BUF_SZ);
592 n += (up->hcnt * HOST_NAM_SZ);
593 n += (up->lcnt * strlen(app_data.libdir));
594 n += (up->pcnt * 2);
595 if (cdinfo_dbp->disc.genre != NULL) {
596 n += (up->ccnt *
597 strlen(cdinfo_genre_path(cdinfo_dbp->disc.genre)));
598 }
599 n += (up->icnt * 8);
600 n++;
601
602 return (n);
603 }
604
605
606 /*
607 * cdinfo_init
608 * Initialize CD information management services
609 *
610 * Args:
611 * progname - The client program name string
612 * username - The client user login name string
613 *
614 * Return:
615 * Nothing.
616 */
617 void
cdinfo_init(cdinfo_client_t * clp)618 cdinfo_init(cdinfo_client_t *clp)
619 {
620 char *cp;
621
622 cdinfo_clinfo = (cdinfo_client_t *)(void *) MEM_ALLOC(
623 "cdinfo_client_t", sizeof(cdinfo_client_t)
624 );
625 if (cdinfo_clinfo == NULL) {
626 CDINFO_FATAL(app_data.str_nomemory);
627 return;
628 }
629 (void) memcpy(cdinfo_clinfo, clp, sizeof(cdinfo_client_t));
630
631 /* Sanity check */
632 if (clp->prog[0] == '\0')
633 (void) strcpy(clp->prog, "unknown");
634
635 /* Hard wire file modes in case these are missing from the
636 * common.cfg file
637 */
638 if (app_data.cdinfo_filemode == NULL)
639 app_data.cdinfo_filemode = "0666";
640 if (app_data.hist_filemode == NULL)
641 app_data.hist_filemode = "0644";
642
643 /* Load XMCD_CDINFOPATH environment variable, if specified */
644 if ((cp = (char *) getenv("XMCD_CDINFOPATH")) != NULL &&
645 !util_newstr(&app_data.cdinfo_path, cp)) {
646 CDINFO_FATAL(app_data.str_nomemory);
647 return;
648 }
649
650 if (app_data.cdinfo_path == NULL &&
651 !util_newstr(&app_data.cdinfo_path, "CDDB;CDTEXT")) {
652 CDINFO_FATAL(app_data.str_nomemory);
653 return;
654 }
655
656 if ((int) strlen(app_data.cdinfo_path) >= MAX_ENV_LEN) {
657 CDINFO_FATAL(app_data.str_longpatherr);
658 return;
659 }
660
661 /* Allocate CD info incore structure */
662 cdinfo_dbp = (cdinfo_incore_t *)(void *) MEM_ALLOC(
663 "cdinfo_incore_t",
664 sizeof(cdinfo_incore_t)
665 );
666 if (cdinfo_dbp == NULL) {
667 CDINFO_FATAL(app_data.str_nomemory);
668 return;
669 }
670 (void) memset(cdinfo_dbp, 0, sizeof(cdinfo_incore_t));
671
672 /* Set up CD info path list */
673 cdinfo_reinit();
674 }
675
676
677 /*
678 * cdinfo_reinit
679 * Re-initialize CD information management services.
680 *
681 * Args:
682 * None.
683 *
684 * Return:
685 * Nothing.
686 */
687 void
cdinfo_reinit(void)688 cdinfo_reinit(void)
689 {
690 char *cp,
691 *path;
692 cdinfo_path_t *pp,
693 *pp_next;
694
695 /* Deallocate CD info path list, if present */
696 pp = cdinfo_dbp->pathlist;
697 while (pp != NULL) {
698 pp_next = pp->next;
699
700 if (pp->categ != NULL)
701 MEM_FREE(pp->categ);
702 if (pp->path != NULL)
703 MEM_FREE(pp->path);
704 MEM_FREE(pp);
705
706 pp = pp_next;
707 }
708 cdinfo_dbp->pathlist = NULL;
709
710 /* Create new CD info path list */
711 path = app_data.cdinfo_path;
712 while ((cp = strchr(path, CDINFOPATH_SEPCHAR)) != NULL) {
713 *cp = '\0';
714
715 if (!cdinfo_add_pathent(path))
716 return;
717
718 *cp = CDINFOPATH_SEPCHAR;
719 path = cp + 1;
720 }
721 (void) cdinfo_add_pathent(path);
722 }
723
724
725 /*
726 * cdinfo_halt
727 * Shut down cdinfo subsystem.
728 *
729 * Args:
730 * s - Pointer to the curstat_t structure
731 *
732 * Return:
733 * Nothing
734 */
735 void
cdinfo_halt(curstat_t * s)736 cdinfo_halt(curstat_t *s)
737 {
738 if (cdinfo_cddbp != NULL)
739 (void) cdinfo_closecddb(cdinfo_cddbp);
740
741 if (curfile[0] != '\0' && s->devlocked)
742 (void) UNLINK(curfile);
743 }
744
745
746 /*
747 * cdinfo_submit
748 * Submit current CD information to CDDB server
749 *
750 * Args:
751 * s - Pointer to the curstat_t structure
752 *
753 * Return:
754 * return code as defined by cdinfo_ret_t
755 */
756 /*ARGSUSED*/
757 cdinfo_ret_t
cdinfo_submit(curstat_t * s)758 cdinfo_submit(curstat_t *s)
759 {
760 cdinfo_cddb_t *cp;
761 cdinfo_ret_t retcode;
762
763 if (cdinfo_forkwait(&retcode))
764 return (retcode);
765
766 /* Open CDDB connection */
767 if ((cp = cdinfo_opencddb(s, FALSE, &retcode)) == NULL) {
768 /* CDDB service failure */
769 CH_RET(retcode);
770 }
771
772 /* Submit disc info to CDDB */
773 if (!cdinfo_submitcddb(cp, s, &retcode)) {
774 /* Submit failed */
775 (void) cdinfo_closecddb(cp);
776 CH_RET(retcode);
777 }
778
779 /* Close CDDB connection */
780 (void) cdinfo_closecddb(cp);
781
782 /* Child exits here */
783 CH_RET(0);
784 /*NOTREACHED*/
785 }
786
787
788 /*
789 * cdinfo_submit_url
790 * Submit to CDDB a URL pertaining to the current CD
791 *
792 * Args:
793 * s - Pointer to the curstat_t structure
794 * up - Pointer to the cdinfo_url_t structure
795 *
796 * Return:
797 * return code as defined by cdinfo_ret_t
798 */
799 /*ARGSUSED*/
800 cdinfo_ret_t
cdinfo_submit_url(curstat_t * s,cdinfo_url_t * up)801 cdinfo_submit_url(curstat_t *s, cdinfo_url_t *up)
802 {
803 cdinfo_cddb_t *cp;
804 cdinfo_ret_t retcode;
805
806 if (up == NULL ||
807 up->categ == NULL || up->href == NULL || up->disptext == NULL)
808 return CDINFO_SET_CODE(ARG_ERR, 0);
809
810 if (cdinfo_forkwait(&retcode))
811 return (retcode);
812
813 /* Open CDDB connection */
814 if ((cp = cdinfo_opencddb(s, FALSE, &retcode)) == NULL) {
815 /* CDDB service failure */
816 CH_RET(retcode);
817 }
818
819 /* Submit disc info to CDDB */
820 if (!cdinfo_submiturlcddb(cp, up, &retcode)) {
821 /* Submit failed */
822 (void) cdinfo_closecddb(cp);
823 CH_RET(retcode);
824 }
825
826 /* Close CDDB connection */
827 (void) cdinfo_closecddb(cp);
828
829 /* Child exits here */
830 CH_RET(0);
831 /*NOTREACHED*/
832 }
833
834
835 /*
836 * cdinfo_flush
837 * Flush CD information cache
838 *
839 * Args:
840 * s - Pointer to the curstat_t structure
841 *
842 * Return:
843 * return code as defined by cdinfo_ret_t
844 */
845 /*ARGSUSED*/
846 cdinfo_ret_t
cdinfo_flush(curstat_t * s)847 cdinfo_flush(curstat_t *s)
848 {
849 cdinfo_cddb_t *cp;
850 cdinfo_ret_t retcode;
851
852 if (cdinfo_forkwait(&retcode))
853 return (retcode);
854
855 /* Open CDDB connection */
856 if ((cp = cdinfo_opencddb(s, FALSE, &retcode)) == NULL) {
857 /* CDDB service failure */
858 CH_RET(retcode);
859 }
860
861 /* Flush CDDB local cache */
862 if (!cdinfo_flushcddb(cp)) {
863 /* Cache flush failed */
864 (void) cdinfo_closecddb(cp);
865 CH_RET(FLUSH_ERR);
866 }
867
868 /* Close CDDB connection */
869 (void) cdinfo_closecddb(cp);
870
871 /* Child exits here */
872 CH_RET(0);
873 /*NOTREACHED*/
874 }
875
876
877 /*
878 * cdinfo_offline
879 * Set the offline mode to what is specified by app_data.cdinfo_inetoffln
880 *
881 * Args:
882 * s - Pointer to the curstat_t structure
883 *
884 * Return:
885 * return code as defined by cdinfo_ret_t
886 */
887 /*ARGSUSED*/
888 cdinfo_ret_t
cdinfo_offline(curstat_t * s)889 cdinfo_offline(curstat_t *s)
890 {
891 cdinfo_cddb_t *cp;
892 cdinfo_ret_t retcode;
893
894 if (cdinfo_forkwait(&retcode))
895 return (retcode);
896
897 /* Open CDDB connection */
898 if ((cp = cdinfo_opencddb(s, FALSE, &retcode)) == NULL) {
899 /* CDDB service failure */
900 CH_RET(retcode);
901 }
902
903 /* The cdinfo_opencddb call implicitly does the work, so
904 * we don't need to do anything else here.
905 */
906
907 /* Close CDDB connection */
908 (void) cdinfo_closecddb(cp);
909
910 /* Child exits here */
911 CH_RET(0);
912 /*NOTREACHED*/
913 }
914
915
916 /*
917 * cdinfo_load
918 * Load CD database entry for the currently inserted CD.
919 *
920 * Args:
921 * s - Pointer to the curstat_t structure
922 *
923 * Return:
924 * Return value will be 0 for a successful connection, and
925 * a successful query will cause the CDINFO_MATCH bit to be
926 * set in the flags field of the cdinfo_incore_t structure.
927 * If an error occurred, then the return code is as defined
928 * by cdinfo_ret_t.
929 */
930 cdinfo_ret_t
cdinfo_load(curstat_t * s)931 cdinfo_load(curstat_t *s)
932 {
933 #ifdef SYNCHRONOUS
934 cdinfo_path_t *pp;
935 cdinfo_cddb_t *cp;
936 cdinfo_credit_t *p;
937 cdinfo_segment_t *q;
938 di_cdtext_t *cdt;
939 char *path;
940 int i,
941 retcode;
942
943 cdinfo_dbp->flags &= ~(CDINFO_MATCH | CDINFO_FROMLOC | CDINFO_FROMCDT);
944
945 if ((cdinfo_dbp->discid = cdinfo_discid(s)) == 0)
946 return CDINFO_SET_CODE(ARG_ERR, 0);
947
948 if (cdinfo_cddb_iscfg() &&
949 (cdinfo_dbp->regionlist == NULL ||
950 cdinfo_dbp->langlist == NULL ||
951 cdinfo_dbp->rolelist == NULL ||
952 cdinfo_dbp->genrelist == NULL)) {
953 DBGPRN(DBG_CDI)(errfp, "Initializing CDDB service...\n");
954
955 /* Open CDDB connection */
956 if ((cp = cdinfo_opencddb(s, TRUE, &retcode)) != NULL) {
957 /* Check user registration, set up region, lang, role
958 * and genre lists
959 */
960 (void) cdinfo_initcddb(cp, &retcode);
961 (void) cdinfo_closecddb(cp);
962 }
963 else if (retcode == AUTH_ERR) {
964 /* Special case handling for proxy auth error */
965 return CDINFO_SET_CODE(retcode, 0);
966 }
967 }
968
969 for (pp = cdinfo_dbp->pathlist; pp != NULL; pp = pp->next) {
970 DBGPRN(DBG_CDI)(errfp, "*** CD info query: ");
971 retcode = 0;
972
973 switch (pp->type) {
974 case CDINFO_CDTEXT:
975 /* Use CD-TEXT information from the CD */
976 DBGPRN(DBG_CDI)(errfp, "Trying CD-TEXT...\n");
977 cdt = &cdinfo_dbp->cdtext;
978 di_load_cdtext(s, cdt);
979
980 if (cdt->cdtext_valid) {
981 cdinfo_map_cdtext(s, cdt);
982 cdinfo_dbp->flags |=
983 (CDINFO_MATCH | CDINFO_FROMCDT);
984 }
985 break;
986
987 case CDINFO_RMT:
988 /* Remote: Use CDDB service */
989 DBGPRN(DBG_CDI)(errfp, "Trying CDDB service...\n");
990
991 /* Open CDDB connection */
992 if ((cp = cdinfo_opencddb(s, TRUE, &retcode)) == NULL)
993 {
994 /* CDDB service failure */
995 if (retcode == AUTH_ERR) {
996 /* Special case handling for
997 * proxy auth error
998 */
999 return CDINFO_SET_CODE(retcode, 0);
1000 }
1001 break;
1002 }
1003
1004 /* Read CD information into incore structure */
1005 if (!cdinfo_querycddb(cp, s, &retcode)) {
1006 /* Query failed */
1007 (void) cdinfo_closecddb(cp);
1008 if (retcode == AUTH_ERR) {
1009 /* Special case handling for
1010 * proxy auth error
1011 */
1012 return CDINFO_SET_CODE(retcode, 0);
1013 }
1014 break;
1015 }
1016
1017 if (cdinfo_dbp->matchlist != NULL) {
1018 /* Inexact "fuzzy matches" found.
1019 * Query user to choose one
1020 */
1021 cdinfo_dbp->match_tag = 0;
1022
1023 /* Don't close CDDB connection here,
1024 * but save pointer.
1025 */
1026 cdinfo_dbp->sav_cddbp = cp;
1027
1028 /* We return here, and continue to
1029 * service this query via the callback
1030 * cdinfo_load_matchsel().
1031 */
1032 return 0;
1033 }
1034
1035 /* Close CDDB connection */
1036 (void) cdinfo_closecddb(cp);
1037
1038 break;
1039
1040 case CDINFO_LOC:
1041 /* Local: Open local CD info file */
1042
1043 path = (char *) MEM_ALLOC(
1044 "path", strlen(pp->path) + 12
1045 );
1046 if (path == NULL)
1047 return CDINFO_SET_CODE(MEM_ERR, errno);;
1048
1049 (void) sprintf(path, CDINFOFILE_PATH,
1050 pp->path, cdinfo_dbp->discid);
1051
1052 DBGPRN(DBG_CDI)(errfp, "Trying %s", path);
1053 (void) cdinfo_load_locdb(path, pp->categ, s, &retcode);
1054
1055 MEM_FREE(path);
1056 break;
1057 }
1058
1059 if ((cdinfo_dbp->flags & CDINFO_MATCH) != 0 ||
1060 (cdinfo_dbp->flags & CDINFO_NEEDREG) != 0) {
1061 /* Found a match or need user registration */
1062 break;
1063 }
1064 }
1065
1066 /* If the display name field of the fullname structures are
1067 * NULL, * fill them with the appropriate text. Conversely,
1068 * if the display name field is non NULL and the matching
1069 * name fields are NULL, back fill the data.
1070 */
1071
1072 if (cdinfo_dbp->disc.artistfname.dispname == NULL &&
1073 cdinfo_dbp->disc.artist != NULL &&
1074 !util_newstr(&cdinfo_dbp->disc.artistfname.dispname,
1075 cdinfo_dbp->disc.artist)) {
1076 return CDINFO_SET_CODE(MEM_ERR, 0);
1077 }
1078 else if (cdinfo_dbp->disc.artist == NULL &&
1079 cdinfo_dbp->disc.artistfname.dispname != NULL &&
1080 !util_newstr(&cdinfo_dbp->disc.artist,
1081 cdinfo_dbp->disc.artistfname.dispname)) {
1082 return CDINFO_SET_CODE(MEM_ERR, 0);
1083 }
1084
1085 for (p = cdinfo_dbp->disc.credit_list; p != NULL; p = p->next) {
1086 if (p->crinfo.fullname.dispname == NULL &&
1087 p->crinfo.name != NULL &&
1088 !util_newstr(&p->crinfo.fullname.dispname,
1089 p->crinfo.name)) {
1090 return CDINFO_SET_CODE(MEM_ERR, 0);
1091 }
1092 else if (p->crinfo.name == NULL &&
1093 p->crinfo.fullname.dispname != NULL &&
1094 !util_newstr(&p->crinfo.name,
1095 p->crinfo.fullname.dispname)) {
1096 return CDINFO_SET_CODE(MEM_ERR, 0);
1097 }
1098 }
1099
1100 for (q = cdinfo_dbp->disc.segment_list; q != NULL; q = q->next) {
1101 for (p = q->credit_list; p != NULL; p = p->next) {
1102 if (p->crinfo.fullname.dispname == NULL &&
1103 p->crinfo.name != NULL &&
1104 !util_newstr(&p->crinfo.fullname.dispname,
1105 p->crinfo.name)) {
1106 return CDINFO_SET_CODE(MEM_ERR, 0);
1107 }
1108 else if (p->crinfo.name == NULL &&
1109 p->crinfo.fullname.dispname != NULL &&
1110 !util_newstr(&p->crinfo.name,
1111 p->crinfo.fullname.dispname)) {
1112 return CDINFO_SET_CODE(MEM_ERR, 0);
1113 }
1114 }
1115 }
1116
1117 for (i = 0; i < (int) s->tot_trks; i++) {
1118 if (cdinfo_dbp->track[i].artistfname.dispname == NULL &&
1119 cdinfo_dbp->track[i].artist != NULL &&
1120 !util_newstr(&cdinfo_dbp->track[i].artistfname.dispname,
1121 cdinfo_dbp->track[i].artist)) {
1122 return CDINFO_SET_CODE(MEM_ERR, 0);
1123 }
1124 else if (cdinfo_dbp->track[i].artist == NULL &&
1125 cdinfo_dbp->track[i].artistfname.dispname != NULL &&
1126 !util_newstr(&cdinfo_dbp->track[i].artist,
1127 cdinfo_dbp->track[i].artistfname.dispname)) {
1128 return CDINFO_SET_CODE(MEM_ERR, 0);
1129 }
1130
1131 for (p = cdinfo_dbp->track[i].credit_list; p != NULL;
1132 p = p->next){
1133 if (p->crinfo.fullname.dispname == NULL &&
1134 p->crinfo.name != NULL &&
1135 !util_newstr(&p->crinfo.fullname.dispname,
1136 p->crinfo.name)) {
1137 return CDINFO_SET_CODE(MEM_ERR, 0);
1138 }
1139 else if (p->crinfo.name == NULL &&
1140 p->crinfo.fullname.dispname != NULL &&
1141 !util_newstr(&p->crinfo.name,
1142 p->crinfo.fullname.dispname)) {
1143 return CDINFO_SET_CODE(MEM_ERR, 0);
1144 }
1145 }
1146
1147 /* If we have ISRC data that was read from the CD itself,
1148 * use these instead of the ones from CDDB.
1149 */
1150 if (s->trkinfo[i].isrc[0] != 0 &&
1151 !util_newstr(&cdinfo_dbp->track[i].isrc,
1152 s->trkinfo[i].isrc)) {
1153 return CDINFO_SET_CODE(MEM_ERR, 0);
1154 }
1155 }
1156
1157 return 0;
1158
1159 #else /* SYNCHRONOUS */
1160 int i,
1161 ret,
1162 retcode;
1163 pid_t cpid;
1164 waitret_t wstat;
1165 cdinfo_path_t *pp;
1166 cdinfo_cddb_t *cp;
1167 cdinfo_credit_t *p;
1168 cdinfo_segment_t *q;
1169 cdinfo_pipe_t *spp,
1170 *rpp;
1171 di_cdtext_t *cdt;
1172 char *path;
1173 bool_t done;
1174
1175 cdinfo_dbp->flags &= ~(CDINFO_MATCH | CDINFO_FROMLOC | CDINFO_FROMCDT);
1176
1177 if ((cdinfo_dbp->discid = cdinfo_discid(s)) == 0)
1178 return CDINFO_SET_CODE(ARG_ERR, 0);
1179
1180 /* Open pipes for IPC */
1181 if ((rpp = cdinfo_openpipe(CDINFO_DATAIN)) == NULL)
1182 return CDINFO_SET_CODE(OPEN_ERR, errno);
1183 if ((spp = cdinfo_openpipe(CDINFO_DATAOUT)) == NULL) {
1184 (void) cdinfo_closepipe(rpp);
1185 return CDINFO_SET_CODE(OPEN_ERR, errno);
1186 }
1187
1188 /* Fork child to performs actual I/O */
1189 switch (cpid = FORK()) {
1190 case 0:
1191 /* Child process */
1192 cdinfo_ischild = TRUE;
1193
1194 (void) util_signal(SIGTERM, cdinfo_onterm);
1195 (void) util_signal(SIGPIPE, SIG_IGN);
1196
1197 /* Close unneeded descriptors */
1198 (void) close(rpp->r.fd);
1199 (void) close(spp->w.fd);
1200 rpp->r.fd = spp->w.fd = -1;
1201
1202 /* Force uid and gid to original setting */
1203 if (!util_set_ougid()) {
1204 (void) cdinfo_closepipe(rpp);
1205 (void) cdinfo_closepipe(spp);
1206 CH_RET(SETUID_ERR);
1207 }
1208
1209 break;
1210
1211 case -1:
1212 (void) cdinfo_closepipe(rpp);
1213 (void) cdinfo_closepipe(spp);
1214 return CDINFO_SET_CODE(FORK_ERR, errno);
1215
1216 default:
1217 /* Parent process */
1218 child_pid = cpid;
1219
1220 /* Close unneeded descriptors */
1221 (void) close(rpp->w.fd);
1222 (void) close(spp->r.fd);
1223 rpp->w.fd = spp->r.fd = -1;
1224
1225 /* Read CD info content from pipe into in-core structure */
1226 (void) cdinfo_read_datapipe(rpp);
1227
1228 if (cdinfo_dbp->matchlist != NULL) {
1229 /* Inexact "fuzzy matches" found. Query user
1230 * to choose one.
1231 */
1232 cdinfo_dbp->match_tag = 0;
1233
1234 /* Don't close pipes here, but save pointer */
1235 cdinfo_dbp->sav_rpp = rpp;
1236 cdinfo_dbp->sav_spp = spp;
1237
1238 /* We return with child process still running,
1239 * and continue to service this query via
1240 * the callback cdinfo_load_matchsel().
1241 */
1242 return 0;
1243 }
1244
1245 /* Close pipes */
1246 (void) cdinfo_closepipe(rpp);
1247 (void) cdinfo_closepipe(spp);
1248
1249 /* Parent process: wait for child to exit */
1250 ret = util_waitchild(cpid, app_data.srv_timeout + 5,
1251 cdinfo_clinfo->workproc,
1252 cdinfo_clinfo->arg,
1253 TRUE, &wstat);
1254 child_pid = 0;
1255
1256 if (ret < 0) {
1257 return CDINFO_SET_CODE(WAIT_ERR, errno);
1258 }
1259 if (WIFEXITED(wstat)) {
1260 if (WEXITSTATUS(wstat) == 0)
1261 return 0;
1262 else
1263 return CDINFO_SET_CODE(WEXITSTATUS(wstat), 0);
1264 }
1265 else if (WIFSIGNALED(wstat)) {
1266 return CDINFO_SET_CODE(KILLED_ERR, WTERMSIG(wstat));
1267 }
1268 else
1269 return 0;
1270
1271 /*NOTREACHED*/
1272 }
1273
1274 if (cdinfo_cddb_iscfg() &&
1275 (cdinfo_dbp->regionlist == NULL ||
1276 cdinfo_dbp->langlist == NULL ||
1277 cdinfo_dbp->rolelist == NULL ||
1278 cdinfo_dbp->genrelist == NULL)) {
1279 DBGPRN(DBG_CDI)(errfp, "Initializing CDDB service...\n");
1280
1281 /* Open CDDB connection */
1282 if ((cp = cdinfo_opencddb(s, TRUE, &retcode)) != NULL) {
1283 /* Check user registration, set up region, lang, role
1284 * and genre lists
1285 */
1286 (void) cdinfo_initcddb(cp, &retcode);
1287 (void) cdinfo_closecddb(cp);
1288 }
1289 else if (retcode == AUTH_ERR) {
1290 /* Special case handling for proxy auth error */
1291 (void) cdinfo_closepipe(rpp);
1292 (void) cdinfo_closepipe(spp);
1293 CH_RET(retcode);
1294 }
1295 }
1296
1297 done = FALSE;
1298 for (pp = cdinfo_dbp->pathlist; pp != NULL; pp = pp->next) {
1299 DBGPRN(DBG_CDI)(errfp, "*** CD info query: ");
1300 retcode = 0;
1301
1302 switch (pp->type) {
1303 case CDINFO_CDTEXT:
1304 /* Use CD-TEXT information from the CD */
1305 DBGPRN(DBG_CDI)(errfp, "Trying CD-TEXT...\n");
1306 cdt = &cdinfo_dbp->cdtext;
1307 di_load_cdtext(s, cdt);
1308
1309 if (cdt->cdtext_valid) {
1310 cdinfo_map_cdtext(s, cdt);
1311 cdinfo_dbp->flags |=
1312 (CDINFO_MATCH | CDINFO_FROMCDT);
1313 done = TRUE;
1314 }
1315 break;
1316
1317 case CDINFO_RMT:
1318 /* Remote: Use CDDB service */
1319 DBGPRN(DBG_CDI)(errfp, "Trying CDDB service...\n");
1320
1321 /* Open CDDB connection */
1322 if ((cp = cdinfo_opencddb(s, TRUE, &retcode)) == NULL)
1323 {
1324 /* CDDB service Failure */
1325 if (retcode == AUTH_ERR) {
1326 /* Special case handling for
1327 * proxy auth error
1328 */
1329 (void) cdinfo_closepipe(rpp);
1330 (void) cdinfo_closepipe(spp);
1331 CH_RET(retcode);
1332 }
1333 break;
1334 }
1335
1336 /* Read CD info content and update incore structures */
1337 if (!cdinfo_querycddb(cp, s, &retcode)) {
1338 /* Failure */
1339 (void) cdinfo_closecddb(cp);
1340 if (retcode == AUTH_ERR) {
1341 /* Special case handling for
1342 * proxy auth error
1343 */
1344 (void) cdinfo_closepipe(rpp);
1345 (void) cdinfo_closepipe(spp);
1346 CH_RET(retcode);
1347 }
1348 break;
1349 }
1350
1351 if (cdinfo_dbp->matchlist != NULL) {
1352 /* Inexact "fuzzy matches" found.
1353 * Transmit the list to parent process
1354 * for processing.
1355 */
1356 cdinfo_dbp->match_tag = 0;
1357
1358 if (!cdinfo_write_datapipe(rpp, s)) {
1359 /* Failure */
1360 (void) cdinfo_closecddb(cp);
1361 (void) cdinfo_closepipe(rpp);
1362 (void) cdinfo_closepipe(spp);
1363 cdinfo_free_matchlist();
1364 CH_RET(WRITE_ERR);
1365 }
1366
1367 util_delayms(2000);
1368
1369 /* Read user selection */
1370 if (!cdinfo_read_selpipe(spp)) {
1371 /* Failure */
1372 (void) cdinfo_closecddb(cp);
1373 (void) cdinfo_closepipe(rpp);
1374 (void) cdinfo_closepipe(spp);
1375 cdinfo_free_matchlist();
1376 CH_RET(READ_ERR);
1377 }
1378
1379 /* Read CD info content and update incore
1380 * structures
1381 */
1382 if (!cdinfo_querycddb(cp, s, &retcode)) {
1383 /* Failure */
1384 (void) cdinfo_closecddb(cp);
1385 if (retcode == AUTH_ERR) {
1386 /* Special case handling for
1387 * proxy auth error
1388 */
1389 (void) cdinfo_closepipe(rpp);
1390 (void) cdinfo_closepipe(spp);
1391 cdinfo_free_matchlist();
1392 CH_RET(retcode);
1393 }
1394 break;
1395 }
1396
1397 /* Deallocate the matchlist */
1398 cdinfo_free_matchlist();
1399 }
1400
1401 /* Close CDDB connection */
1402 (void) cdinfo_closecddb(cp);
1403
1404 if ((cdinfo_dbp->flags & CDINFO_MATCH) != 0 ||
1405 (cdinfo_dbp->flags & CDINFO_NEEDREG) != 0) {
1406 /* Found a match or needs user reg */
1407 done = TRUE;
1408 }
1409 break;
1410
1411 case CDINFO_LOC:
1412 /* Local: Open local CD info file */
1413 path = (char *) MEM_ALLOC(
1414 "path", strlen(pp->path) + 12
1415 );
1416 if (path == NULL) {
1417 (void) cdinfo_closepipe(rpp);
1418 (void) cdinfo_closepipe(spp);
1419 CH_RET(MEM_ERR);
1420 }
1421
1422 (void) sprintf(path, CDINFOFILE_PATH,
1423 pp->path, cdinfo_dbp->discid);
1424
1425 DBGPRN(DBG_CDI)(errfp, "Trying %s", path);
1426 (void) cdinfo_load_locdb(path, pp->categ, s, &retcode);
1427
1428 MEM_FREE(path);
1429
1430 if ((cdinfo_dbp->flags & CDINFO_MATCH) != 0) {
1431 /* Found a match */
1432 done = TRUE;
1433 }
1434 break;
1435 }
1436
1437 if (done)
1438 break;
1439 }
1440
1441 /* If the display name field of the fullname structures are
1442 * NULL, fill them with the appropriate text. Conversely,
1443 * if the display name field is non NULL and the matching
1444 * name fields are NULL, back fill the data.
1445 */
1446
1447 if (cdinfo_dbp->disc.artistfname.dispname == NULL &&
1448 cdinfo_dbp->disc.artist != NULL &&
1449 !util_newstr(&cdinfo_dbp->disc.artistfname.dispname,
1450 cdinfo_dbp->disc.artist)) {
1451 (void) cdinfo_closepipe(rpp);
1452 (void) cdinfo_closepipe(spp);
1453 CH_RET(MEM_ERR);
1454 }
1455 else if (cdinfo_dbp->disc.artist == NULL &&
1456 cdinfo_dbp->disc.artistfname.dispname != NULL &&
1457 !util_newstr(&cdinfo_dbp->disc.artist,
1458 cdinfo_dbp->disc.artistfname.dispname)) {
1459 (void) cdinfo_closepipe(rpp);
1460 (void) cdinfo_closepipe(spp);
1461 CH_RET(MEM_ERR);
1462 }
1463
1464 for (p = cdinfo_dbp->disc.credit_list; p != NULL; p = p->next) {
1465 if (p->crinfo.fullname.dispname == NULL &&
1466 p->crinfo.name != NULL &&
1467 !util_newstr(&p->crinfo.fullname.dispname,
1468 p->crinfo.name)) {
1469 (void) cdinfo_closepipe(rpp);
1470 (void) cdinfo_closepipe(spp);
1471 CH_RET(MEM_ERR);
1472 }
1473 else if (p->crinfo.name == NULL &&
1474 p->crinfo.fullname.dispname != NULL &&
1475 !util_newstr(&p->crinfo.name,
1476 p->crinfo.fullname.dispname)) {
1477 (void) cdinfo_closepipe(rpp);
1478 (void) cdinfo_closepipe(spp);
1479 CH_RET(MEM_ERR);
1480 }
1481 }
1482
1483 for (q = cdinfo_dbp->disc.segment_list; q != NULL; q = q->next) {
1484 for (p = q->credit_list; p != NULL; p = p->next) {
1485 if (p->crinfo.fullname.dispname == NULL &&
1486 p->crinfo.name != NULL &&
1487 !util_newstr(&p->crinfo.fullname.dispname,
1488 p->crinfo.name)) {
1489 (void) cdinfo_closepipe(rpp);
1490 (void) cdinfo_closepipe(spp);
1491 CH_RET(MEM_ERR);
1492 }
1493 else if (p->crinfo.name == NULL &&
1494 p->crinfo.fullname.dispname != NULL &&
1495 !util_newstr(&p->crinfo.name,
1496 p->crinfo.fullname.dispname)) {
1497 (void) cdinfo_closepipe(rpp);
1498 (void) cdinfo_closepipe(spp);
1499 CH_RET(MEM_ERR);
1500 }
1501 }
1502 }
1503
1504 for (i = 0; i < (int) s->tot_trks; i++) {
1505 if (cdinfo_dbp->track[i].artistfname.dispname == NULL &&
1506 cdinfo_dbp->track[i].artist != NULL &&
1507 !util_newstr(&cdinfo_dbp->track[i].artistfname.dispname,
1508 cdinfo_dbp->track[i].artist)) {
1509 CH_RET(MEM_ERR);
1510 }
1511 else if (cdinfo_dbp->track[i].artist == NULL &&
1512 cdinfo_dbp->track[i].artistfname.dispname != NULL &&
1513 !util_newstr(&cdinfo_dbp->track[i].artist,
1514 cdinfo_dbp->track[i].artistfname.dispname)) {
1515 (void) cdinfo_closepipe(rpp);
1516 (void) cdinfo_closepipe(spp);
1517 CH_RET(MEM_ERR);
1518 }
1519
1520 for (p = cdinfo_dbp->track[i].credit_list; p != NULL;
1521 p = p->next) {
1522 if (p->crinfo.fullname.dispname == NULL &&
1523 p->crinfo.name != NULL &&
1524 !util_newstr(&p->crinfo.fullname.dispname,
1525 p->crinfo.name)) {
1526 (void) cdinfo_closepipe(rpp);
1527 (void) cdinfo_closepipe(spp);
1528 CH_RET(MEM_ERR);
1529 }
1530 else if (p->crinfo.name == NULL &&
1531 p->crinfo.fullname.dispname != NULL &&
1532 !util_newstr(&p->crinfo.name,
1533 p->crinfo.fullname.dispname)) {
1534 (void) cdinfo_closepipe(rpp);
1535 (void) cdinfo_closepipe(spp);
1536 CH_RET(MEM_ERR);
1537 }
1538 }
1539
1540 /* If we have ISRC data that was read from the CD itself,
1541 * use these instead of the ones from CDDB.
1542 */
1543 if (s->trkinfo[i].isrc[0] != 0 &&
1544 !util_newstr(&cdinfo_dbp->track[i].isrc,
1545 s->trkinfo[i].isrc)) {
1546 (void) cdinfo_closepipe(rpp);
1547 (void) cdinfo_closepipe(spp);
1548 CH_RET(MEM_ERR);
1549 }
1550 }
1551
1552 /* Write incore CD info into pipe */
1553 if (!cdinfo_write_datapipe(rpp, s))
1554 retcode = WRITE_ERR;
1555 else
1556 retcode = 0;
1557
1558 (void) cdinfo_closepipe(rpp);
1559 (void) cdinfo_closepipe(spp);
1560 CH_RET(retcode);
1561
1562 /*NOTREACHED*/
1563 #endif /* SYNCHRONOUS */
1564 }
1565
1566
1567 /*
1568 * cdinfo_load_matchsel
1569 * Load CD database entry after user chooses a fuzzy match
1570 *
1571 * Args:
1572 * s - Pointer to the curstat_t structure
1573 *
1574 * Return:
1575 * Return value will be 0 for a successful connection, and
1576 * a successful query will cause the CDINFO_MATCH bit to be
1577 * set in the flags field of the cdinfo_incore_t structure.
1578 * If an error occurred, then the return code is as defined
1579 * by cdinfo_ret_t.
1580 */
1581 /*ARGSUSED*/
1582 cdinfo_ret_t
cdinfo_load_matchsel(curstat_t * s)1583 cdinfo_load_matchsel(curstat_t *s)
1584 {
1585 #ifdef SYNCHRONOUS
1586 cdinfo_cddb_t *cp;
1587 cdinfo_ret_t retcode;
1588
1589 cp = cdinfo_dbp->sav_cddbp;
1590 if (cp == NULL)
1591 return CDINFO_SET_CODE(READ_ERR, 0);
1592
1593 /* Read CD information into incore structure */
1594 if (!cdinfo_querycddb(cp, s, &retcode)) {
1595 /* Query failed */
1596 (void) cdinfo_closecddb(cp);
1597
1598 /* Deallocate the matchlist */
1599 cdinfo_free_matchlist();
1600
1601 return CDINFO_SET_CODE(retcode, 0);
1602 }
1603
1604 /* Close CDDB connection */
1605 (void) cdinfo_closecddb(cp);
1606
1607 /* Deallocate the matchlist */
1608 cdinfo_free_matchlist();
1609
1610 return 0;
1611
1612 #else /* SYNCHRONOUS */
1613 int ret;
1614 pid_t cpid;
1615 waitret_t wstat;
1616 cdinfo_pipe_t *spp,
1617 *rpp;
1618 void (*oh)(int);
1619
1620 /* Restore pointers */
1621 rpp = cdinfo_dbp->sav_rpp;
1622 spp = cdinfo_dbp->sav_spp;
1623
1624 /* Child pid */
1625 cpid = child_pid;
1626
1627 if (rpp == NULL || spp == NULL || cpid == 0) {
1628 /* Error */
1629 return CDINFO_SET_CODE(READ_ERR, 0);
1630 }
1631
1632 /* Child process should still be running. Communicate user
1633 * selection to it.
1634 */
1635 oh = util_signal(SIGPIPE, SIG_IGN);
1636 if (!cdinfo_write_selpipe(spp)) {
1637 /* Failure */
1638 (void) cdinfo_closepipe(rpp);
1639 (void) cdinfo_closepipe(spp);
1640 cdinfo_load_cancel();
1641 (void) util_signal(SIGPIPE, oh);
1642
1643 /* Deallocate the matchlist */
1644 cdinfo_free_matchlist();
1645
1646 return CDINFO_SET_CODE(READ_ERR, 0);
1647 }
1648 (void) util_signal(SIGPIPE, oh);
1649
1650 /* Deallocate the matchlist */
1651 cdinfo_free_matchlist();
1652
1653 /* Read CD info content from pipe into in-core structure */
1654 (void) cdinfo_read_datapipe(rpp);
1655
1656 /* Close pipes */
1657 (void) cdinfo_closepipe(rpp);
1658 (void) cdinfo_closepipe(spp);
1659
1660 /* Parent process: wait for child to exit */
1661 ret = util_waitchild(cpid, app_data.srv_timeout + 5,
1662 cdinfo_clinfo->workproc, cdinfo_clinfo->arg,
1663 TRUE, &wstat);
1664 child_pid = 0;
1665
1666 if (ret < 0) {
1667 return CDINFO_SET_CODE(WAIT_ERR, errno);
1668 }
1669 if (WIFEXITED(wstat)) {
1670 if (WEXITSTATUS(wstat) == 0)
1671 return 0;
1672 else
1673 return CDINFO_SET_CODE(WEXITSTATUS(wstat), 0);
1674 }
1675 else if (WIFSIGNALED(wstat)) {
1676 return CDINFO_SET_CODE(KILLED_ERR, WTERMSIG(wstat));
1677 }
1678 else
1679 return 0;
1680 #endif /* SYNCHRONOUS */
1681 }
1682
1683
1684 /*
1685 * cdinfo_load_prog
1686 * Load user-saved track program for the currently inserted CD.
1687 *
1688 * Args:
1689 * s - Pointer to the curstat_t structure
1690 *
1691 * Return:
1692 * Return value will be 0 for a successful load, or an error value
1693 * on failure.
1694 */
1695 cdinfo_ret_t
cdinfo_load_prog(curstat_t * s)1696 cdinfo_load_prog(curstat_t *s)
1697 {
1698 FILE *fp;
1699 char *homepath,
1700 trk[8],
1701 buf[STR_BUF_SZ * 2],
1702 junk[STR_BUF_SZ * 2],
1703 path[FILE_PATH_SZ];
1704 #ifndef SYNCHRONOUS
1705 pid_t cpid;
1706 waitret_t wstat;
1707 int ret,
1708 pfd[2];
1709
1710 if ((cdinfo_dbp->discid = cdinfo_discid(s)) == 0)
1711 return CDINFO_SET_CODE(ARG_ERR, 0);
1712
1713 if (s->program || s->shuffle)
1714 /* Program or shuffle already in progress */
1715 return CDINFO_SET_CODE(BUSY_ERR, 0);
1716
1717 if (PIPE(pfd) < 0) {
1718 DBGPRN(DBG_CDI)(errfp,
1719 "cdinfo_load_prog: pipe failed (errno=%d)\n", errno);
1720 return CDINFO_SET_CODE(OPEN_ERR, 0);
1721 }
1722
1723 switch (cpid = FORK()) {
1724 case 0:
1725 /* Child */
1726 cdinfo_ischild = TRUE;
1727
1728 (void) util_signal(SIGTERM, cdinfo_onterm);
1729 (void) util_signal(SIGPIPE, SIG_IGN);
1730
1731 /* Close un-needed pipe descriptor */
1732 (void) close(pfd[0]);
1733
1734 /* Force uid and gid to original setting */
1735 if (!util_set_ougid()) {
1736 (void) close(pfd[1]);
1737 _exit(SETUID_ERR);
1738 }
1739
1740 homepath = util_homedir(util_get_ouid());
1741
1742 (void) sprintf(path, USR_PROG_PATH, homepath);
1743 (void) sprintf(path, "%s%c%08x%s",
1744 path, DIR_END, cdinfo_dbp->discid,
1745 #ifdef __VMS
1746 "."
1747 #else
1748 ""
1749 #endif
1750 );
1751
1752 DBGPRN(DBG_CDI)(errfp, "Loading track program: %s\n", path);
1753
1754 if ((fp = fopen(path, "r")) == NULL) {
1755 (void) close(pfd[1]);
1756 _exit(OPEN_ERR);
1757 }
1758
1759 while (fgets(buf, sizeof(buf), fp) != NULL) {
1760 /* Skip comments */
1761 if (buf[0] == '#' || buf[0] == '!' || buf[0] == '\n')
1762 continue;
1763 (void) write(pfd[1], buf, strlen(buf));
1764 }
1765 (void) write(pfd[1], ".\n", 2);
1766
1767 (void) close(pfd[1]);
1768 (void) fclose(fp);
1769
1770 _exit(0);
1771 /*NOTREACHED*/
1772
1773 case -1:
1774 DBGPRN(DBG_CDI)(errfp,
1775 "cdinfo_load_prog: fork failed (errno=%d)\n", errno);
1776 (void) close(pfd[0]);
1777 (void) close(pfd[1]);
1778 return CDINFO_SET_CODE(FORK_ERR, 0);
1779 /*NOTREACHED*/
1780
1781 default:
1782 /* Parent */
1783 child_pid = cpid;
1784
1785 /* Close un-needed pipe descriptor */
1786 (void) close(pfd[1]);
1787
1788 if ((fp = fdopen(pfd[0], "r")) == NULL) {
1789 DBGPRN(DBG_CDI)(errfp,
1790 "cdinfo_load_prog: read pipe fdopen failed\n");
1791 return CDINFO_SET_CODE(READ_ERR, 0);
1792 }
1793 break;
1794 }
1795 #else
1796 if ((cdinfo_dbp->discid = cdinfo_discid(s)) == 0)
1797 return CDINFO_SET_CODE(ARG_ERR, 0);
1798
1799 if (s->program || s->shuffle)
1800 /* Program or shuffle already in progress */
1801 return CDINFO_SET_CODE(BUSY_ERR, 0);
1802
1803 homepath = util_homedir(util_get_ouid());
1804
1805 (void) sprintf(path, USR_PROG_PATH, homepath);
1806 (void) sprintf(path, "%s%c%08x%s",
1807 path, DIR_END, cdinfo_dbp->discid,
1808 #ifdef __VMS
1809 "."
1810 #else
1811 ""
1812 #endif
1813 );
1814
1815 DBGPRN(DBG_CDI)(errfp, "Loading track program: %s\n", path);
1816
1817 if ((fp = fopen(path, "r")) == NULL)
1818 return CDINFO_SET_CODE(OPEN_ERR, 0);
1819 #endif /* SYNCHRONOUS */
1820
1821 while (fgets(buf, sizeof(buf), fp) != NULL) {
1822 int n;
1823
1824 if (buf[0] == '.' && buf[1] == '\n')
1825 /* Done */
1826 break;
1827
1828 if (buf[0] == '#' || buf[0] == '!' || buf[0] == '\n')
1829 /* Skip comments */
1830 continue;
1831
1832 buf[strlen(buf)-1] = '\0'; /* Zap newline */
1833
1834 /* Parse the line and check for error */
1835 if (sscanf(buf, "%2s %80s", trk, junk) < 1 ||
1836 (n = atoi(trk)) <= 0)
1837 continue;
1838
1839 (void) sprintf(trk, "%d", n);
1840 if (cdinfo_dbp->playorder == NULL) {
1841 if (!util_newstr(&cdinfo_dbp->playorder, trk)) {
1842 (void) fclose(fp);
1843 return CDINFO_SET_CODE(MEM_ERR, errno);
1844 }
1845 }
1846 else {
1847 cdinfo_dbp->playorder = (char *) MEM_REALLOC(
1848 "playorder",
1849 cdinfo_dbp->playorder,
1850 strlen(cdinfo_dbp->playorder) + strlen(trk) + 2
1851 );
1852 if (cdinfo_dbp->playorder == NULL) {
1853 (void) fclose(fp);
1854 return CDINFO_SET_CODE(MEM_ERR, errno);
1855 }
1856 (void) sprintf(cdinfo_dbp->playorder, "%s,%s",
1857 cdinfo_dbp->playorder, trk);
1858 }
1859 }
1860
1861 (void) fclose(fp);
1862
1863 #ifndef SYNCHRONOUS
1864 /* Parent process: wait for child to exit */
1865 ret = util_waitchild(cpid, app_data.srv_timeout + 5,
1866 cdinfo_clinfo->workproc, cdinfo_clinfo->arg,
1867 TRUE, &wstat);
1868 child_pid = 0;
1869
1870 if (ret < 0) {
1871 return CDINFO_SET_CODE(WAIT_ERR, errno);
1872 }
1873 if (WIFEXITED(wstat)) {
1874 if (WEXITSTATUS(wstat) == 0)
1875 return 0;
1876 else
1877 return CDINFO_SET_CODE(WEXITSTATUS(wstat), 0);
1878 }
1879 else if (WIFSIGNALED(wstat)) {
1880 return CDINFO_SET_CODE(KILLED_ERR, WTERMSIG(wstat));
1881 }
1882 else
1883 return 0;
1884 #else
1885 return 0;
1886 #endif
1887 }
1888
1889
1890 /*
1891 * cdinfo_save_prog
1892 * Write user-defined track program into file for future retrieval
1893 *
1894 * Arg:
1895 * s - Pointer to the curstat_t structure
1896 *
1897 * Return:
1898 * Return value will be 0 for a successful write, or an error value
1899 * on failure.
1900 */
1901 cdinfo_ret_t
cdinfo_save_prog(curstat_t * s)1902 cdinfo_save_prog(curstat_t *s)
1903 {
1904 FILE *fp;
1905 char *p,
1906 *q,
1907 *tartist,
1908 *ttitle,
1909 *homepath,
1910 path[FILE_PATH_SZ];
1911 cdinfo_ret_t retcode;
1912 int i,
1913 err;
1914
1915 if (cdinfo_dbp->discid == 0 ||
1916 cdinfo_dbp->playorder == NULL ||
1917 !isdigit((int) cdinfo_dbp->playorder[0]))
1918 return (ARG_ERR);
1919
1920 if (cdinfo_forkwait(&retcode))
1921 return (retcode);
1922
1923 homepath = util_homedir(util_get_ouid());
1924
1925 (void) sprintf(path, USR_PROG_PATH, homepath);
1926 (void) sprintf(path, "%s%c%08x%s",
1927 path, DIR_END, cdinfo_dbp->discid,
1928 #ifdef __VMS
1929 "."
1930 #else
1931 ""
1932 #endif
1933 );
1934
1935 /* Remove original file */
1936 if (UNLINK(path) < 0 && errno != ENOENT) {
1937 err = errno;
1938 DBGPRN(DBG_CDI)(errfp, "Cannot unlink old %s\n", path);
1939 CH_RET(err);
1940 }
1941
1942 /* Write new file */
1943 if ((fp = fopen(path, "w")) == NULL) {
1944 err = errno;
1945 DBGPRN(DBG_CDI)(errfp,
1946 "Cannot open file for writing: %s\n", path);
1947 CH_RET(err);
1948 }
1949
1950 DBGPRN(DBG_CDI)(errfp, "Writing track program: %s\n", path);
1951
1952 (void) fprintf(fp, "# xmcd %s.%s track program file\n# %s\n#\n",
1953 VERSION_MAJ, VERSION_MIN, COPYRIGHT);
1954 (void) fprintf(fp, "# ID: %08x\n", cdinfo_dbp->discid);
1955 (void) fprintf(fp, "# Artist: %.65s\n",
1956 (cdinfo_dbp->disc.artist != NULL) ?
1957 cdinfo_dbp->disc.artist : "<unknown>");
1958 (void) fprintf(fp, "# Title: %.65s\n",
1959 (cdinfo_dbp->disc.title != NULL) ?
1960 cdinfo_dbp->disc.title : "<unknown>");
1961 (void) fprintf(fp, "# Genre: %.65s\n#\n",
1962 cdinfo_genre_name(cdinfo_dbp->disc.genre));
1963
1964 p = q = cdinfo_dbp->playorder;
1965 do {
1966 if ((q = strchr(p, ',')) != NULL)
1967 *q = '\0';
1968
1969 for (i = 0; i < (int) s->tot_trks; i++) {
1970 if (s->trkinfo[i].trkno == atoi(p))
1971 break;
1972 }
1973
1974 if (i < (int) s->tot_trks) {
1975 tartist = cdinfo_dbp->track[i].artist;
1976 ttitle = cdinfo_dbp->track[i].title;
1977
1978 (void) fprintf(fp, "%02d %.25s%s%.45s\n",
1979 s->trkinfo[i].trkno,
1980 (tartist == NULL) ? "" : tartist,
1981 (tartist != NULL && ttitle != NULL) ?
1982 " / " : "",
1983 (ttitle == NULL) ? "" : ttitle
1984 );
1985 }
1986
1987 if (q != NULL)
1988 *q = ',';
1989
1990 p = q + 1;
1991 } while (q != NULL);
1992
1993 (void) fclose(fp);
1994
1995 CH_RET(0);
1996 /*NOTREACHED*/
1997 }
1998
1999
2000 /*
2001 * cdinfo_del_prog
2002 * Delete the user-defined track program file for the loaded CD.
2003 *
2004 * Arg:
2005 * None
2006 *
2007 * Return:
2008 * Return value will be 0 for a successful delete, or an error value
2009 * on failure.
2010 */
2011 cdinfo_ret_t
cdinfo_del_prog(void)2012 cdinfo_del_prog(void)
2013 {
2014 char *homepath,
2015 path[FILE_PATH_SZ];
2016 cdinfo_ret_t retcode;
2017
2018 if (cdinfo_dbp->discid == 0)
2019 return (ARG_ERR);
2020
2021 if (cdinfo_forkwait(&retcode))
2022 return (retcode);
2023
2024 homepath = util_homedir(util_get_ouid());
2025
2026 (void) sprintf(path, USR_PROG_PATH, homepath);
2027 (void) sprintf(path, "%s%c%08x%s",
2028 path, DIR_END, cdinfo_dbp->discid,
2029 #ifdef __VMS
2030 "."
2031 #else
2032 ""
2033 #endif
2034 );
2035
2036 DBGPRN(DBG_CDI)(errfp, "Deleting track program: %s\n", path);
2037
2038 if (UNLINK(path) < 0)
2039 CH_RET(errno);
2040
2041 CH_RET(0);
2042 /*NOTREACHED*/
2043 }
2044
2045
2046 /*
2047 * cdinfo_reguser
2048 * Register the user with CDDB
2049 *
2050 * Args:
2051 * s - Pointer to the curstat_t structure.
2052 *
2053 * Return:
2054 * Return value will be 0 for a successful connection, otherwise
2055 * the return status will be as defined for cdinfo_ret_t.
2056 */
2057 cdinfo_ret_t
cdinfo_reguser(curstat_t * s)2058 cdinfo_reguser(curstat_t *s)
2059 {
2060 cdinfo_cddb_t *cp;
2061 cdinfo_ret_t retcode;
2062
2063 if (cdinfo_forkwait(&retcode)) {
2064 if (retcode == 0) {
2065 /* Clear flag */
2066 cdinfo_dbp->flags &= ~CDINFO_NEEDREG;
2067 }
2068 return (retcode);
2069 }
2070
2071 /* Open CDDB connection */
2072 if ((cp = cdinfo_opencddb(s, FALSE, &retcode)) == NULL)
2073 CH_RET(retcode);
2074
2075 /* Register user with CDDB */
2076 if (!cdinfo_uregcddb(cp, &retcode)) {
2077 (void) cdinfo_closecddb(cp);
2078 CH_RET(retcode);
2079 }
2080
2081 /* Close CDDB connection */
2082 (void) cdinfo_closecddb(cp);
2083
2084 /* Clear flag */
2085 cdinfo_dbp->flags &= ~CDINFO_NEEDREG;
2086
2087 /* Child exits here */
2088 CH_RET(0);
2089 /*NOTREACHED*/
2090 }
2091
2092
2093 /*
2094 * cdinfo_getpasshint
2095 * Request CDDB to send password hint via e-mail
2096 *
2097 * Args:
2098 * s - Pointer to the curstat_t structure.
2099 *
2100 * Return:
2101 * Return value will be 0 for a successful connection, otherwise
2102 * the return status will be as defined for cdinfo_ret_t.
2103 */
2104 cdinfo_ret_t
cdinfo_getpasshint(curstat_t * s)2105 cdinfo_getpasshint(curstat_t *s)
2106 {
2107 cdinfo_cddb_t *cp;
2108 cdinfo_ret_t retcode;
2109
2110 if (cdinfo_forkwait(&retcode))
2111 return (retcode);
2112
2113 /* Open CDDB connection */
2114 if ((cp = cdinfo_opencddb(s, FALSE, &retcode)) == NULL)
2115 CH_RET(retcode);
2116
2117 /* Ask CDDB to send password hint */
2118 if (!cdinfo_passhintcddb(cp, &retcode)) {
2119 (void) cdinfo_closecddb(cp);
2120 CH_RET(retcode);
2121 }
2122
2123 /* Close CDDB connection */
2124 (void) cdinfo_closecddb(cp);
2125
2126 /* Child exits here */
2127 CH_RET(0);
2128 /*NOTREACHED*/
2129 }
2130
2131
2132 /*
2133 * cdinfo_go_musicbrowser
2134 * Invoke CDDB music browser.
2135 *
2136 * Args:
2137 * s - Pointer to the curstat_t structure.
2138 *
2139 * Return:
2140 * Return value will be 0 for a successful connection, otherwise
2141 * the return status will be as defined for cdinfo_ret_t.
2142 */
2143 cdinfo_ret_t
cdinfo_go_musicbrowser(curstat_t * s)2144 cdinfo_go_musicbrowser(curstat_t *s)
2145 {
2146 cdinfo_ret_t retcode;
2147 cdinfo_cddb_t *cp;
2148
2149 if (cdinfo_forkwait(&retcode))
2150 return (retcode);
2151
2152 /* Open CDDB connection */
2153 if ((cp = cdinfo_opencddb(s, FALSE, &retcode)) == NULL) {
2154 /* Failure */
2155 CH_RET(retcode);
2156 }
2157
2158 /* Invoke CDDB info browser */
2159 if (!cdinfo_infobrowsercddb(cp)) {
2160 /* Failure */
2161 (void) cdinfo_closecddb(cp);
2162 CH_RET(CMD_ERR);
2163 }
2164
2165 /* Close CDDB connection */
2166 (void) cdinfo_closecddb(cp);
2167
2168 /* Child exits here */
2169 CH_RET(0);
2170 /*NOTREACHED*/
2171 }
2172
2173
2174 /*
2175 * cdinfo_go_url
2176 * Invoke web browser and go to the specified URL.
2177 *
2178 * Args:
2179 * url - The URL string.
2180 *
2181 * Return:
2182 * Return value will be 0 for a successful connection, otherwise
2183 * the return status will be as defined for cdinfo_ret_t.
2184 */
2185 cdinfo_ret_t
cdinfo_go_url(char * url)2186 cdinfo_go_url(char *url)
2187 {
2188 int ret;
2189 char *cmd;
2190
2191 if (url == NULL || url[0] == '\0')
2192 return CDINFO_SET_CODE(CMD_ERR, 0);
2193
2194 /* Invoke web browser to the specified URL */
2195 cmd = (char *) MEM_ALLOC("urlstr", strlen(url) + FILE_PATH_SZ + 4);
2196 if (cmd == NULL)
2197 return CDINFO_SET_CODE(MEM_ERR, 0);
2198
2199 (void) sprintf(cmd, "%s '%s'", CDINFO_GOBROWSER, url);
2200
2201 ret = util_runcmd(cmd, cdinfo_clinfo->workproc, cdinfo_clinfo->arg);
2202
2203 MEM_FREE(cmd);
2204
2205 #ifdef __VMS
2206 return CDINFO_SET_CODE(
2207 (ret == 0 || (ret & 0x1) == 1) ? 0 : CMD_ERR, 0
2208 );
2209 #else
2210 return CDINFO_SET_CODE((ret == 0) ? 0 : CMD_ERR, 0);
2211 #endif
2212 }
2213
2214
2215 /*
2216 * cdinfo_go_cddburl
2217 * Invoke web browser to go to a URL supplied by CDDB
2218 *
2219 * Args:
2220 * s - Pointer to the curstat_t structure.
2221 * type - WTYPE_GEN or WTYPE_ALBUM
2222 * idx - URL index as found in the cdinfo_dbp->gen_url_list
2223 *
2224 * Return:
2225 * Return value will be 0 for a successful connection, otherwise
2226 * the return status will be as defined for cdinfo_ret_t.
2227 */
2228 cdinfo_ret_t
cdinfo_go_cddburl(curstat_t * s,int type,int idx)2229 cdinfo_go_cddburl(curstat_t *s, int type, int idx)
2230 {
2231 cdinfo_cddb_t *cp;
2232 cdinfo_ret_t retcode;
2233
2234 if (type != WTYPE_GEN && type != WTYPE_ALBUM)
2235 return CDINFO_SET_CODE(ARG_ERR, 0);
2236
2237 if (cdinfo_forkwait(&retcode))
2238 return (retcode);
2239
2240 /* Open CDDB connection */
2241 if ((cp = cdinfo_opencddb(s, FALSE, &retcode)) == NULL) {
2242 /* Failure */
2243 CH_RET(retcode);
2244 }
2245
2246 /* Invoke web browser to go to the specified URL */
2247 if (!cdinfo_urlcddb(cp, type, idx)) {
2248 /* Failure */
2249 (void) cdinfo_closecddb(cp);
2250 CH_RET(CMD_ERR);
2251 }
2252
2253 /* Close CDDB connection */
2254 (void) cdinfo_closecddb(cp);
2255
2256 /* Child exits here */
2257 CH_RET(0);
2258 /*NOTREACHED*/
2259 }
2260
2261
2262 /*
2263 * cdinfo_gen_discog
2264 * Write out local discography file containing the currently loaded
2265 * CD information.
2266 *
2267 * Args:
2268 * s - Pointer to the curstat_t structure
2269 * baseurl - The URL to the output file
2270 *
2271 * Return:
2272 * Return value will be 0 for a successful connection, otherwise
2273 * the return status will be as defined for cdinfo_ret_t.
2274 */
2275 cdinfo_ret_t
cdinfo_gen_discog(curstat_t * s)2276 cdinfo_gen_discog(curstat_t *s)
2277 {
2278 int i,
2279 n;
2280 char *path,
2281 *url;
2282 bool_t err;
2283 cdinfo_ret_t retcode;
2284
2285 if (cdinfo_forkwait(&retcode))
2286 return (retcode);
2287
2288 if (cdinfo_discog == NULL) {
2289 /* Local discography not defined */
2290 DBGPRN(DBG_CDI)(errfp,
2291 "Local discography not defined in %s.\n", WWWWARP_CFG);
2292 CH_RET(ENOENT);
2293 }
2294
2295 i = -1;
2296 n = cdinfo_url_len(cdinfo_discog->arg, &cdinfo_discog->attrib, &i);
2297 if ((url = (char *) MEM_ALLOC("cdinfo_genurl", n)) == NULL) {
2298 DBGPRN(DBG_CDI)(errfp, "Out of memory.\n");
2299 CH_RET(ENOMEM);
2300 }
2301
2302 /* Make the URL from template */
2303 cdinfo_tmpl_to_url(s, cdinfo_discog->arg, url, i);
2304
2305 if (util_urlchk(url, &path, &n) & IS_REMOTE_URL) {
2306 /* Error: local discography cannot be remote */
2307 DBGPRN(DBG_CDI)(errfp,
2308 "Local discography URL error: %s\n", url);
2309 MEM_FREE(url);
2310 CH_RET(EINVAL);
2311 }
2312
2313 /* Generate local discography */
2314 err = !cdinfo_out_discog(path, s, url);
2315
2316 MEM_FREE(url);
2317 CH_RET(err ? EIO : 0);
2318 /*NOTREACHED*/
2319 }
2320
2321
2322 /*
2323 * cdinfo_clear
2324 * Clear the in-core cdinfo_incore_t structure
2325 *
2326 * Args:
2327 * reload - Whether this operation is due to a reload of the CD info
2328 * (We don't want to clear a play sequence in this case).
2329 *
2330 * Return:
2331 * Nothing
2332 */
2333 void
cdinfo_clear(bool_t reload)2334 cdinfo_clear(bool_t reload)
2335 {
2336 int i;
2337 cdinfo_url_t *u,
2338 *v;
2339 cdinfo_credit_t *p,
2340 *q;
2341 cdinfo_segment_t *r,
2342 *s;
2343
2344 if (cdinfo_dbp == NULL)
2345 return;
2346
2347 /* Clear CD-TEXT information */
2348 di_clear_cdtext(&cdinfo_dbp->cdtext);
2349
2350 /* Cancel pending queries */
2351 cdinfo_load_cancel();
2352
2353 /* Disc */
2354 cdinfo_dbp->disc.compilation = FALSE;
2355
2356 if (cdinfo_dbp->disc.artistfname.dispname != NULL) {
2357 MEM_FREE(cdinfo_dbp->disc.artistfname.dispname);
2358 cdinfo_dbp->disc.artistfname.dispname = NULL;
2359 }
2360 if (cdinfo_dbp->disc.artistfname.lastname != NULL) {
2361 MEM_FREE(cdinfo_dbp->disc.artistfname.lastname);
2362 cdinfo_dbp->disc.artistfname.lastname = NULL;
2363 }
2364 if (cdinfo_dbp->disc.artistfname.firstname != NULL) {
2365 MEM_FREE(cdinfo_dbp->disc.artistfname.firstname);
2366 cdinfo_dbp->disc.artistfname.firstname = NULL;
2367 }
2368 if (cdinfo_dbp->disc.artistfname.the != NULL) {
2369 MEM_FREE(cdinfo_dbp->disc.artistfname.the);
2370 cdinfo_dbp->disc.artistfname.the = NULL;
2371 }
2372 if (cdinfo_dbp->disc.artist != NULL) {
2373 MEM_FREE(cdinfo_dbp->disc.artist);
2374 cdinfo_dbp->disc.artist = NULL;
2375 }
2376 if (cdinfo_dbp->disc.title != NULL) {
2377 MEM_FREE(cdinfo_dbp->disc.title);
2378 cdinfo_dbp->disc.title = NULL;
2379 }
2380 if (cdinfo_dbp->disc.sorttitle != NULL) {
2381 MEM_FREE(cdinfo_dbp->disc.sorttitle);
2382 cdinfo_dbp->disc.sorttitle = NULL;
2383 }
2384 if (cdinfo_dbp->disc.title_the != NULL) {
2385 MEM_FREE(cdinfo_dbp->disc.title_the);
2386 cdinfo_dbp->disc.title_the = NULL;
2387 }
2388 if (cdinfo_dbp->disc.year != NULL) {
2389 MEM_FREE(cdinfo_dbp->disc.year);
2390 cdinfo_dbp->disc.year = NULL;
2391 }
2392 if (cdinfo_dbp->disc.label != NULL) {
2393 MEM_FREE(cdinfo_dbp->disc.label);
2394 cdinfo_dbp->disc.label = NULL;
2395 }
2396 if (cdinfo_dbp->disc.genre != NULL) {
2397 MEM_FREE(cdinfo_dbp->disc.genre);
2398 cdinfo_dbp->disc.genre = NULL;
2399 }
2400 if (cdinfo_dbp->disc.genre2 != NULL) {
2401 MEM_FREE(cdinfo_dbp->disc.genre2);
2402 cdinfo_dbp->disc.genre2 = NULL;
2403 }
2404 if (cdinfo_dbp->disc.dnum != NULL) {
2405 MEM_FREE(cdinfo_dbp->disc.dnum);
2406 cdinfo_dbp->disc.dnum = NULL;
2407 }
2408 if (cdinfo_dbp->disc.tnum != NULL) {
2409 MEM_FREE(cdinfo_dbp->disc.tnum);
2410 cdinfo_dbp->disc.tnum = NULL;
2411 }
2412 if (cdinfo_dbp->disc.region != NULL) {
2413 MEM_FREE(cdinfo_dbp->disc.region);
2414 cdinfo_dbp->disc.region = NULL;
2415 }
2416 if (cdinfo_dbp->disc.lang != NULL) {
2417 MEM_FREE(cdinfo_dbp->disc.lang);
2418 cdinfo_dbp->disc.lang = NULL;
2419 }
2420 if (cdinfo_dbp->disc.notes != NULL) {
2421 MEM_FREE(cdinfo_dbp->disc.notes);
2422 cdinfo_dbp->disc.notes = NULL;
2423 }
2424 if (cdinfo_dbp->disc.mediaid != NULL) {
2425 MEM_FREE(cdinfo_dbp->disc.mediaid);
2426 cdinfo_dbp->disc.mediaid = NULL;
2427 }
2428 if (cdinfo_dbp->disc.muiid != NULL) {
2429 MEM_FREE(cdinfo_dbp->disc.muiid);
2430 cdinfo_dbp->disc.muiid = NULL;
2431 }
2432 if (cdinfo_dbp->disc.titleuid != NULL) {
2433 MEM_FREE(cdinfo_dbp->disc.titleuid);
2434 cdinfo_dbp->disc.titleuid = NULL;
2435 }
2436 if (cdinfo_dbp->disc.revision != NULL) {
2437 MEM_FREE(cdinfo_dbp->disc.revision);
2438 cdinfo_dbp->disc.revision = NULL;
2439 }
2440 if (cdinfo_dbp->disc.revtag != NULL) {
2441 MEM_FREE(cdinfo_dbp->disc.revtag);
2442 cdinfo_dbp->disc.revtag = NULL;
2443 }
2444 if (cdinfo_dbp->disc.certifier != NULL) {
2445 MEM_FREE(cdinfo_dbp->disc.certifier);
2446 cdinfo_dbp->disc.certifier = NULL;
2447 }
2448 if (cdinfo_dbp->disc.lang != NULL) {
2449 MEM_FREE(cdinfo_dbp->disc.lang);
2450 cdinfo_dbp->disc.lang = NULL;
2451 }
2452 for (p = cdinfo_dbp->disc.credit_list; p != NULL; p = q) {
2453 q = p->next;
2454 if (p->crinfo.name != NULL)
2455 MEM_FREE(p->crinfo.name);
2456 if (p->crinfo.fullname.dispname != NULL)
2457 MEM_FREE(p->crinfo.fullname.dispname);
2458 if (p->crinfo.fullname.lastname != NULL)
2459 MEM_FREE(p->crinfo.fullname.lastname);
2460 if (p->crinfo.fullname.firstname != NULL)
2461 MEM_FREE(p->crinfo.fullname.firstname);
2462 if (p->crinfo.fullname.the != NULL)
2463 MEM_FREE(p->crinfo.fullname.the);
2464 if (p->notes != NULL)
2465 MEM_FREE(p->notes);
2466 MEM_FREE(p);
2467 }
2468 cdinfo_dbp->disc.credit_list = NULL;
2469
2470 for (r = cdinfo_dbp->disc.segment_list; r != NULL; r = s) {
2471 s = r->next;
2472 if (r->name != NULL)
2473 MEM_FREE(r->name);
2474 if (r->notes != NULL)
2475 MEM_FREE(r->notes);
2476 if (r->start_track != NULL)
2477 MEM_FREE(r->start_track);
2478 if (r->start_frame != NULL)
2479 MEM_FREE(r->start_frame);
2480 if (r->end_track != NULL)
2481 MEM_FREE(r->end_track);
2482 if (r->end_frame != NULL)
2483 MEM_FREE(r->end_frame);
2484 for (p = r->credit_list; p != NULL; p = q) {
2485 q = p->next;
2486 if (p->crinfo.name != NULL)
2487 MEM_FREE(p->crinfo.name);
2488 if (p->crinfo.fullname.dispname != NULL)
2489 MEM_FREE(p->crinfo.fullname.dispname);
2490 if (p->crinfo.fullname.lastname != NULL)
2491 MEM_FREE(p->crinfo.fullname.lastname);
2492 if (p->crinfo.fullname.firstname != NULL)
2493 MEM_FREE(p->crinfo.fullname.firstname);
2494 if (p->crinfo.fullname.the != NULL)
2495 MEM_FREE(p->crinfo.fullname.the);
2496 if (p->notes != NULL)
2497 MEM_FREE(p->notes);
2498 MEM_FREE(p);
2499 }
2500 MEM_FREE(r);
2501 }
2502 cdinfo_dbp->disc.segment_list = NULL;
2503
2504 /* Tracks */
2505 for (i = MAXTRACK-1; i >= 0; i--) {
2506 if (cdinfo_dbp->track[i].artistfname.dispname != NULL) {
2507 MEM_FREE(cdinfo_dbp->track[i].artistfname.dispname);
2508 cdinfo_dbp->track[i].artistfname.dispname = NULL;
2509 }
2510 if (cdinfo_dbp->track[i].artistfname.lastname != NULL) {
2511 MEM_FREE(cdinfo_dbp->track[i].artistfname.lastname);
2512 cdinfo_dbp->track[i].artistfname.lastname = NULL;
2513 }
2514 if (cdinfo_dbp->track[i].artistfname.firstname != NULL) {
2515 MEM_FREE(cdinfo_dbp->track[i].artistfname.firstname);
2516 cdinfo_dbp->track[i].artistfname.firstname = NULL;
2517 }
2518 if (cdinfo_dbp->track[i].artistfname.the != NULL) {
2519 MEM_FREE(cdinfo_dbp->track[i].artistfname.the);
2520 cdinfo_dbp->track[i].artistfname.the = NULL;
2521 }
2522 if (cdinfo_dbp->track[i].artist != NULL) {
2523 MEM_FREE(cdinfo_dbp->track[i].artist);
2524 cdinfo_dbp->track[i].artist = NULL;
2525 }
2526 if (cdinfo_dbp->track[i].title != NULL) {
2527 MEM_FREE(cdinfo_dbp->track[i].title);
2528 cdinfo_dbp->track[i].title = NULL;
2529 }
2530 if (cdinfo_dbp->track[i].sorttitle != NULL) {
2531 MEM_FREE(cdinfo_dbp->track[i].sorttitle);
2532 cdinfo_dbp->track[i].sorttitle = NULL;
2533 }
2534 if (cdinfo_dbp->track[i].title_the != NULL) {
2535 MEM_FREE(cdinfo_dbp->track[i].title_the);
2536 cdinfo_dbp->track[i].title_the = NULL;
2537 }
2538 if (cdinfo_dbp->track[i].year != NULL) {
2539 MEM_FREE(cdinfo_dbp->track[i].year);
2540 cdinfo_dbp->track[i].year = NULL;
2541 }
2542 if (cdinfo_dbp->track[i].label != NULL) {
2543 MEM_FREE(cdinfo_dbp->track[i].label);
2544 cdinfo_dbp->track[i].label = NULL;
2545 }
2546 if (cdinfo_dbp->track[i].genre != NULL) {
2547 MEM_FREE(cdinfo_dbp->track[i].genre);
2548 cdinfo_dbp->track[i].genre = NULL;
2549 }
2550 if (cdinfo_dbp->track[i].genre2 != NULL) {
2551 MEM_FREE(cdinfo_dbp->track[i].genre2);
2552 cdinfo_dbp->track[i].genre2 = NULL;
2553 }
2554 if (cdinfo_dbp->track[i].bpm != NULL) {
2555 MEM_FREE(cdinfo_dbp->track[i].bpm);
2556 cdinfo_dbp->track[i].bpm = NULL;
2557 }
2558 if (cdinfo_dbp->track[i].notes != NULL) {
2559 MEM_FREE(cdinfo_dbp->track[i].notes);
2560 cdinfo_dbp->track[i].notes = NULL;
2561 }
2562 if (cdinfo_dbp->track[i].isrc != NULL) {
2563 MEM_FREE(cdinfo_dbp->track[i].isrc);
2564 cdinfo_dbp->track[i].isrc = NULL;
2565 }
2566 for (p = cdinfo_dbp->track[i].credit_list; p != NULL; p = q) {
2567 q = p->next;
2568 if (p->crinfo.name != NULL)
2569 MEM_FREE(p->crinfo.name);
2570 if (p->crinfo.fullname.dispname != NULL)
2571 MEM_FREE(p->crinfo.fullname.dispname);
2572 if (p->crinfo.fullname.lastname != NULL)
2573 MEM_FREE(p->crinfo.fullname.lastname);
2574 if (p->crinfo.fullname.firstname != NULL)
2575 MEM_FREE(p->crinfo.fullname.firstname);
2576 if (p->crinfo.fullname.the != NULL)
2577 MEM_FREE(p->crinfo.fullname.the);
2578 if (p->notes != NULL)
2579 MEM_FREE(p->notes);
2580 MEM_FREE(p);
2581 }
2582 cdinfo_dbp->track[i].credit_list = NULL;
2583 }
2584
2585 /* Album-related URLs */
2586 for (u = v = cdinfo_dbp->disc_url_list; u != NULL; u = v) {
2587 v = u->next;
2588 if (u->disptext != NULL)
2589 MEM_FREE(u->disptext);
2590 if (u->modifier != NULL)
2591 MEM_FREE(u->modifier);
2592 if (u->keyname != NULL)
2593 MEM_FREE(u->keyname);
2594 MEM_FREE(u);
2595 }
2596 cdinfo_dbp->disc_url_list = NULL;
2597
2598 /* Misc */
2599 if (!reload && cdinfo_dbp->playorder != NULL) {
2600 MEM_FREE(cdinfo_dbp->playorder);
2601 cdinfo_dbp->playorder = NULL;
2602 }
2603
2604 cdinfo_dbp->discid = 0;
2605 cdinfo_dbp->flags = 0;
2606
2607 /* Deallocate the matchlist */
2608 cdinfo_free_matchlist();
2609 }
2610
2611
2612 /*
2613 * cdinfo_genre
2614 * Given a genre ID, return a pointer to the associated genre structure.
2615 *
2616 * Args:
2617 * id - The genre ID string.
2618 *
2619 * Return:
2620 * Pointer to the genre structure.
2621 */
2622 cdinfo_genre_t *
cdinfo_genre(char * id)2623 cdinfo_genre(char *id)
2624 {
2625 cdinfo_genre_t *gp,
2626 *sgp;
2627
2628 if (id == NULL)
2629 return NULL;
2630
2631 for (gp = cdinfo_dbp->genrelist; gp != NULL; gp = gp->next) {
2632 if (gp->id != NULL && strcmp(gp->id, id) == 0)
2633 return (gp);
2634
2635 for (sgp = gp->child; sgp != NULL; sgp = sgp->next) {
2636 if (sgp->id != NULL && strcmp(sgp->id, id) == 0)
2637 return (sgp);
2638 }
2639 }
2640
2641 /* Can't find genre entry */
2642 return NULL;
2643 }
2644
2645
2646 /*
2647 * cdinfo_genre_name
2648 * Given a genre ID, return the genre name string.
2649 *
2650 * Args:
2651 * id - The genre ID string.
2652 *
2653 * Return:
2654 * Pointer to the genre name string.
2655 */
2656 char *
cdinfo_genre_name(char * id)2657 cdinfo_genre_name(char *id)
2658 {
2659 cdinfo_genre_t *gp;
2660 static char name[STR_BUF_SZ * 2 + 8];
2661
2662 if (id == NULL)
2663 return ("");
2664
2665 if ((gp = cdinfo_genre(id)) == NULL) {
2666 /* If genre entry is not found, just use the ID */
2667 return (id);
2668 }
2669
2670 if (gp->parent == NULL) {
2671 /* Genre */
2672 (void) sprintf(name, "%.63s",
2673 gp->name == NULL ? id : gp->name);
2674 return (name);
2675 }
2676 else {
2677 /* Subgenre */
2678 (void) sprintf(name, "%.63s -> %.63s",
2679 gp->parent->name == NULL ?
2680 gp->parent->id : gp->parent->name,
2681 gp->name == NULL ? gp->id : gp->name);
2682 return (name);
2683 }
2684
2685 /*NOTREACHED*/
2686 }
2687
2688
2689 /*
2690 * cdinfo_genre_path
2691 * Return a relative file path name for a given genre ID.
2692 *
2693 * Args:
2694 * id - The genre ID string
2695 *
2696 * Return:
2697 * Pointer to the path name string.
2698 */
2699 char *
cdinfo_genre_path(char * id)2700 cdinfo_genre_path(char *id)
2701 {
2702 char *cp,
2703 *cp2;
2704 cdinfo_genre_t *gp;
2705 static char buf[STR_BUF_SZ * 2 + 2];
2706
2707 if (id == NULL)
2708 #ifdef __VMS
2709 return ("Unknown.Unknown");
2710 #else
2711 return ("Unknown/Unknown");
2712 #endif
2713
2714 if ((gp = cdinfo_genre(id)) == NULL) {
2715 /* If genre entry is not found, just use the ID */
2716 return (id);
2717 }
2718
2719 if (gp->parent == NULL) {
2720 /* Genre */
2721 cp = cdinfo_mkpath(
2722 gp->name == NULL ? gp->id : gp->name,
2723 STR_BUF_SZ * 2
2724 );
2725 if (cp == NULL) {
2726 CDINFO_FATAL(app_data.str_nomemory);
2727 return ("");
2728 }
2729
2730 (void) strcpy(buf, cp);
2731 MEM_FREE(cp);
2732
2733 return (buf);
2734 }
2735 else {
2736 /* Subgenre */
2737 cp = cdinfo_mkpath(
2738 gp->parent->name == NULL ?
2739 gp->parent->id : gp->parent->name,
2740 STR_BUF_SZ
2741 );
2742 cp2 = cdinfo_mkpath(
2743 gp->name == NULL ? gp->id : gp->name,
2744 STR_BUF_SZ
2745 );
2746 if (cp == NULL || cp2 == NULL) {
2747 CDINFO_FATAL(app_data.str_nomemory);
2748 return ("");
2749 }
2750
2751 (void) sprintf(buf, "%s%c%s", cp, DIR_SEP, cp2);
2752 MEM_FREE(cp);
2753 MEM_FREE(cp2);
2754
2755 return (buf);
2756 }
2757
2758 /*NOTREACHED*/
2759 }
2760
2761
2762 /*
2763 * cdinfo_region_name
2764 * Given a region ID, return the region name.
2765 *
2766 * Args:
2767 * id - The region ID string.
2768 *
2769 * Return:
2770 * Pointer to the region name string.
2771 */
2772 char *
cdinfo_region_name(char * id)2773 cdinfo_region_name(char *id)
2774 {
2775 cdinfo_region_t *rp;
2776
2777 if (id == NULL)
2778 return ("");
2779
2780 for (rp = cdinfo_dbp->regionlist; rp != NULL; rp = rp->next) {
2781 if (rp->id != NULL && strcmp(rp->id, id) == 0)
2782 return (rp->name);
2783 }
2784 return ("");
2785 }
2786
2787
2788 /*
2789 * cdinfo_lang_name
2790 * Given a language ID, return the language name.
2791 *
2792 * Args:
2793 * id - The language ID string.
2794 *
2795 * Return:
2796 * Pointer to the language name string.
2797 */
2798 char *
cdinfo_lang_name(char * id)2799 cdinfo_lang_name(char *id)
2800 {
2801 cdinfo_lang_t *lp;
2802
2803 if (id == NULL)
2804 return ("");
2805
2806 for (lp = cdinfo_dbp->langlist; lp != NULL; lp = lp->next) {
2807 if (lp->id != NULL && strcmp(lp->id, id) == 0)
2808 return (lp->name);
2809 }
2810 return ("");
2811 }
2812
2813
2814 /*
2815 * cdinfo_role
2816 * Given a role ID, return a pointer to the role list element.
2817 *
2818 * Args:
2819 * id - The role ID string.
2820 *
2821 * Return:
2822 * Pointer to the role list element.
2823 */
2824 cdinfo_role_t *
cdinfo_role(char * id)2825 cdinfo_role(char *id)
2826 {
2827 cdinfo_role_t *rp,
2828 *srp;
2829
2830 if (id == NULL)
2831 return NULL;
2832
2833 for (rp = cdinfo_dbp->rolelist; rp != NULL; rp = rp->next) {
2834 if (rp->id != NULL && strcmp(rp->id, id) == 0)
2835 return (rp);
2836
2837 for (srp = rp->child; srp != NULL; srp = srp->next) {
2838 if (srp->id != NULL && strcmp(srp->id, id) == 0)
2839 return (srp);
2840 }
2841 }
2842
2843 return NULL;
2844 }
2845
2846
2847 /*
2848 * cdinfo_role_name
2849 * Given a role ID, return the role name.
2850 *
2851 * Args:
2852 * id - The role ID string.
2853 *
2854 * Return:
2855 * Pointer to the role name string.
2856 */
2857 char *
cdinfo_role_name(char * id)2858 cdinfo_role_name(char *id)
2859 {
2860 cdinfo_role_t *rp;
2861
2862 if ((rp = cdinfo_role(id)) == NULL)
2863 return ("unknown role");
2864
2865 return (rp->name);
2866 }
2867
2868
2869 /*
2870 * cdinfo_load_cancel
2871 * Cancel asynchronous CD info load operation, if active.
2872 *
2873 * Args:
2874 * None.
2875 *
2876 * Return:
2877 * nothing.
2878 */
2879 void
cdinfo_load_cancel(void)2880 cdinfo_load_cancel(void)
2881 {
2882 if (child_pid > 0) {
2883 /* Kill child process */
2884 (void) kill(child_pid, SIGTERM);
2885 child_pid = 0;
2886 }
2887 }
2888
2889
2890 /*
2891 * cdinfo_cddb_ver
2892 * Returns the version string of the CDDB interface
2893 *
2894 * Args:
2895 * None.
2896 *
2897 * Return:
2898 * The CDDB interface version number
2899 */
2900 int
cdinfo_cddb_ver(void)2901 cdinfo_cddb_ver(void)
2902 {
2903 return (cddb_ifver());
2904 }
2905
2906
2907 /*
2908 * cdinfo_cddbctrl_ver
2909 * Returns the version string of the CDDB control
2910 *
2911 * Args:
2912 * None.
2913 *
2914 * Return:
2915 * The version string.
2916 */
2917 char *
cdinfo_cddbctrl_ver(void)2918 cdinfo_cddbctrl_ver(void)
2919 {
2920 static char buf[STR_BUF_SZ];
2921
2922 if (cdinfo_dbp->ctrl_ver == NULL)
2923 return ("");
2924
2925 (void) sprintf(buf, "%.63s\n", cdinfo_dbp->ctrl_ver);
2926 return (buf);
2927 }
2928
2929
2930 /*
2931 * cdinfo_cddb_iscfg
2932 * Returns whether CDDB is configured in the cdinfoPath parameter.
2933 *
2934 * Args:
2935 * None.
2936 *
2937 * Return:
2938 * TRUE - CDDB is configured
2939 * FALSE - CDDB not configured
2940 */
2941 bool_t
cdinfo_cddb_iscfg(void)2942 cdinfo_cddb_iscfg(void)
2943 {
2944 cdinfo_path_t *pp;
2945
2946 for (pp = cdinfo_dbp->pathlist; pp != NULL; pp = pp->next) {
2947 if (pp->type == CDINFO_RMT)
2948 return TRUE;
2949 }
2950 return FALSE;
2951 }
2952
2953
2954 /*
2955 * cdinfo_cdtext_iscfg
2956 * Returns whether CD-TEXT is configured in the cdinfoPath parameter.
2957 *
2958 * Args:
2959 * None.
2960 *
2961 * Return:
2962 * TRUE - CDDB is configured
2963 * FALSE - CDDB not configured
2964 */
2965 bool_t
cdinfo_cdtext_iscfg(void)2966 cdinfo_cdtext_iscfg(void)
2967 {
2968 cdinfo_path_t *pp;
2969
2970 for (pp = cdinfo_dbp->pathlist; pp != NULL; pp = pp->next) {
2971 if (pp->type == CDINFO_CDTEXT)
2972 return TRUE;
2973 }
2974 return FALSE;
2975 }
2976
2977
2978 /*
2979 * cdinfo_wwwwarp_parmload
2980 * Load the wwwwarp configuration file and initialize structures.
2981 *
2982 * Args:
2983 * None.
2984 *
2985 * Return:
2986 * Nothing.
2987 */
2988 void
cdinfo_wwwwarp_parmload(void)2989 cdinfo_wwwwarp_parmload(void)
2990 {
2991 FILE *fp;
2992 char *buf,
2993 *name,
2994 *p,
2995 *q,
2996 trypath[FILE_PATH_SZ];
2997 w_ent_t *wp,
2998 *wp1,
2999 *wp2,
3000 *wp3;
3001 bool_t newmenu;
3002 #ifndef SYNCHRONOUS
3003 pid_t cpid;
3004 waitret_t wstat;
3005 int ret,
3006 pfd[2];
3007
3008 if (PIPE(pfd) < 0) {
3009 DBGPRN(DBG_CDI)(errfp,
3010 "cdinfo_wwwwarp_parmload: pipe failed (errno=%d)\n",
3011 errno);
3012 return;
3013 }
3014
3015 switch (cpid = FORK()) {
3016 case 0:
3017 /* Child */
3018 cdinfo_ischild = TRUE;
3019
3020 (void) util_signal(SIGTERM, cdinfo_onterm);
3021 (void) util_signal(SIGPIPE, SIG_IGN);
3022
3023 /* Close un-needed pipe descriptor */
3024 (void) close(pfd[0]);
3025
3026 /* Force uid and gid to original setting */
3027 if (!util_set_ougid()) {
3028 (void) close(pfd[1]);
3029 _exit(1);
3030 }
3031
3032 /* Try the user's own wwwwarp.cfg, if it exists */
3033 (void) sprintf(trypath, USR_DSCFG_PATH,
3034 util_homedir(util_get_ouid()), WWWWARP_CFG);
3035 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3036 "Loading wwwwarp parameters: %s\n", trypath);
3037 fp = fopen(trypath, "r");
3038
3039 if (fp == NULL) {
3040 DBGPRN(DBG_GEN|DBG_CDI)(errfp, " Cannot open %s\n",
3041 trypath);
3042
3043 /* Try the system-wide wwwwarp.cfg, if it exists */
3044 (void) sprintf(trypath, SYS_DSCFG_PATH,
3045 app_data.libdir, WWWWARP_CFG);
3046 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3047 "Loading wwwwarp parameters: %s\n", trypath);
3048 fp = fopen(trypath, "r");
3049 }
3050
3051 if (fp == NULL) {
3052 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3053 " Cannot open %s\n", trypath);
3054
3055 (void) close(pfd[1]);
3056 _exit(0);
3057 }
3058
3059 while ((buf = cdinfo_fgetline(fp)) != NULL) {
3060 (void) write(pfd[1], buf, strlen(buf));
3061 (void) write(pfd[1], "\n", 1);
3062 MEM_FREE(buf);
3063 }
3064 (void) write(pfd[1], ".\n", 2);
3065
3066 (void) fclose(fp);
3067 (void) close(pfd[1]);
3068
3069 _exit(0);
3070 /*NOTREACHED*/
3071
3072 case -1:
3073 DBGPRN(DBG_CDI)(errfp,
3074 "cdinfo_wwwwarp_parmload: fork failed (errno=%d)\n",
3075 errno);
3076 (void) close(pfd[0]);
3077 (void) close(pfd[1]);
3078 return;
3079
3080 default:
3081 /* Parent */
3082 child_pid = cpid;
3083
3084 /* Close un-needed pipe descriptor */
3085 (void) close(pfd[1]);
3086
3087 if ((fp = fdopen(pfd[0], "r")) == NULL) {
3088 DBGPRN(DBG_CDI)(errfp,
3089 "cdinfo_common_parmload: read pipe fdopen failed\n");
3090 return;
3091 }
3092 break;
3093 }
3094 #else
3095 /* Try the user's own wwwwarp.cfg, if it exists */
3096 (void) sprintf(trypath, USR_DSCFG_PATH,
3097 util_homedir(util_get_ouid()), WWWWARP_CFG);
3098 DBGPRN(DBG_GEN|DBG_CDI)(errfp, "Loading wwwwarp parameters: %s\n",
3099 trypath);
3100 fp = fopen(trypath, "r");
3101
3102 if (fp == NULL) {
3103 DBGPRN(DBG_GEN|DBG_CDI)(errfp, " Cannot open %s\n",
3104 trypath);
3105
3106 /* Try the system-wide wwwwarp.cfg, if it exists */
3107 (void) sprintf(trypath, SYS_DSCFG_PATH,
3108 app_data.libdir, WWWWARP_CFG);
3109 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3110 "Loading wwwwarp parameters: %s\n",
3111 trypath);
3112 fp = fopen(trypath, "r");
3113 }
3114
3115 if (fp == NULL) {
3116 DBGPRN(DBG_GEN|DBG_CDI)(errfp, " Cannot open %s\n",
3117 trypath);
3118 return;
3119 }
3120
3121 #endif /* SYNCHRONOUS */
3122
3123 newmenu = FALSE;
3124 wp1 = wp2 = NULL;
3125 name = NULL;
3126
3127 /* Read in common parameters */
3128 while ((buf = cdinfo_fgetline(fp)) != NULL) {
3129 if (strcmp(buf, ".") == 0) {
3130 /* Done */
3131 MEM_FREE(buf);
3132 break;
3133 }
3134
3135 p = q = cdinfo_skip_whitespace(buf);
3136
3137 if (*p == '#' || *p == '!' || *p == '\0') {
3138 /* Skip comments and blank lines */
3139 MEM_FREE(buf);
3140 continue;
3141 }
3142
3143 if (*p == '{' || *p == '}') {
3144 /* Do nothing. These are only visual aids for
3145 * the user.
3146 */
3147 MEM_FREE(buf);
3148 continue;
3149 }
3150
3151 if (strncmp(p, "Menu", 4) == 0) {
3152 /* Start of new menu */
3153 p = cdinfo_skip_whitespace(p + 4);
3154 if (*p == '\0') {
3155 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3156 " Error in %s file:\nline: %s\n",
3157 WWWWARP_CFG, buf);
3158 MEM_FREE(buf);
3159 break;
3160 }
3161 p = cdinfo_skip_whitespace(p);
3162 q = cdinfo_skip_nowhitespace(p);
3163 *q = '\0';
3164
3165 if (!util_newstr(&name, p)) {
3166 CDINFO_FATAL(app_data.str_nomemory);
3167 return;
3168 }
3169
3170 newmenu = TRUE;
3171 }
3172 else {
3173 /* Menu entry */
3174 wp = (w_ent_t *)(void *) MEM_ALLOC(
3175 "w_ent_t", sizeof(w_ent_t)
3176 );
3177 if (wp == NULL) {
3178 CDINFO_FATAL(app_data.str_nomemory);
3179 return;
3180 }
3181 (void) memset(wp, 0, sizeof(w_ent_t));
3182
3183 if (newmenu) {
3184 if (cdinfo_dbp->wwwwarp_list == NULL)
3185 cdinfo_dbp->wwwwarp_list = wp1 = wp;
3186 else {
3187 wp1->nextmenu = wp;
3188 wp1 = wp;
3189 }
3190 }
3191 else if (wp2 == NULL) {
3192 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3193 " Error in %s file:\nline: %s\n",
3194 WWWWARP_CFG, buf);
3195 MEM_FREE(buf);
3196 break;
3197 }
3198 else
3199 wp2->nextent = wp;
3200
3201 wp2 = wp;
3202
3203 if (!util_newstr(&wp->name, name)) {
3204 CDINFO_FATAL(app_data.str_nomemory);
3205 return;
3206 }
3207
3208 /* Description */
3209 if (*p != '"') {
3210 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3211 " Error in %s file:\nline: %s\n",
3212 WWWWARP_CFG, buf);
3213 wp->type = WTYPE_NULL;
3214 MEM_FREE(buf);
3215 break;
3216 }
3217 p++;
3218
3219 if ((q = strchr(p, '"')) == NULL) {
3220 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3221 " Error in %s file:\nline: %s\n",
3222 WWWWARP_CFG, buf);
3223 wp->type = WTYPE_NULL;
3224 MEM_FREE(buf);
3225 break;
3226 }
3227 *q = '\0';
3228
3229 if (!util_newstr(&wp->desc, p)) {
3230 CDINFO_FATAL(app_data.str_nomemory);
3231 return;
3232 }
3233
3234 p = cdinfo_skip_whitespace(q+1);
3235
3236 /* Shortcut key */
3237 if (strncmp(p, "f.", 2) != 0) {
3238 char *cp;
3239
3240 q = cdinfo_skip_nowhitespace(p);
3241 if (*q == '\0') {
3242 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3243 " Error in %s file:\n"
3244 "line: %s\n",
3245 WWWWARP_CFG, buf);
3246 MEM_FREE(buf);
3247 break;
3248 }
3249 *q = '\0';
3250
3251 if ((cp = strchr(p, '-')) == NULL) {
3252 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3253 " Error in %s file:\n"
3254 "line: %s\n",
3255 WWWWARP_CFG, buf);
3256 MEM_FREE(buf);
3257 break;
3258 }
3259 *cp = '\0';
3260
3261 if (!util_newstr(&wp->modifier, p)) {
3262 CDINFO_FATAL(app_data.str_nomemory);
3263 return;
3264 }
3265 if (!util_newstr(&wp->keyname, cp+1)) {
3266 CDINFO_FATAL(app_data.str_nomemory);
3267 return;
3268 }
3269
3270 p = cdinfo_skip_whitespace(q+1);
3271 }
3272 else {
3273 wp->modifier = NULL;
3274 wp->keyname = NULL;
3275 }
3276
3277 /* Type */
3278 if (strncmp(p, "f.title", 7) == 0) {
3279 q = p + 7;
3280 wp->type = WTYPE_TITLE;
3281 }
3282 else if (strncmp(p, "f.separator2", 12) == 0) {
3283 q = p + 12;
3284 wp->type = WTYPE_SEP2;
3285 }
3286 else if (strncmp(p, "f.separator", 11) == 0) {
3287 q = p + 11;
3288 wp->type = WTYPE_SEP;
3289 }
3290 else if (strncmp(p, "f.about", 7) == 0) {
3291 q = p + 7;
3292 wp->type = WTYPE_ABOUT;
3293 }
3294 else if (strncmp(p, "f.help", 6) == 0) {
3295 q = p + 6;
3296 wp->type = WTYPE_HELP;
3297 }
3298 else if (strncmp(p, "f.motd", 6) == 0) {
3299 q = p + 6;
3300 wp->type = WTYPE_MOTD;
3301 }
3302 else if (strncmp(p, "f.goto", 6) == 0) {
3303 q = p + 6;
3304 wp->type = WTYPE_GOTO;
3305 }
3306 else if (strncmp(p, "f.menu", 6) == 0) {
3307 q = p + 6;
3308 wp->type = WTYPE_SUBMENU;
3309 }
3310 else if (strncmp(p, "f.infoBrowser", 13) == 0) {
3311 q = p + 13;
3312 wp->type = WTYPE_BROWSER;
3313 }
3314 else if (strncmp(p, "f.discog", 8) == 0) {
3315 q = p + 8;
3316 wp->type = WTYPE_DISCOG;
3317 }
3318 else if (strncmp(p, "f.generalSites", 14) == 0) {
3319 q = p + 14;
3320 wp->type = WTYPE_GEN;
3321 }
3322 else if (strncmp(p, "f.albumSites", 12) == 0) {
3323 q = p + 12;
3324 wp->type = WTYPE_ALBUM;
3325 }
3326 else if (strncmp(p, "f.submitURL", 11) == 0) {
3327 q = p + 11;
3328 wp->type = WTYPE_SUBMITURL;
3329 }
3330 else {
3331 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3332 " Error in %s file:\nline: %s\n",
3333 WWWWARP_CFG, buf);
3334 wp->type = WTYPE_NULL;
3335 MEM_FREE(buf);
3336 break;
3337 }
3338
3339 p = cdinfo_skip_whitespace(q);
3340
3341 /* Args */
3342 switch(wp->type) {
3343 case WTYPE_SUBMENU:
3344 q = cdinfo_skip_nowhitespace(p);
3345 *q = '\0';
3346
3347 if (!util_newstr(&wp->arg, p)) {
3348 CDINFO_FATAL(app_data.str_nomemory);
3349 return;
3350 }
3351 break;
3352
3353 case WTYPE_GOTO:
3354 case WTYPE_DISCOG:
3355 if (*p == '"')
3356 p++;
3357
3358 q = cdinfo_skip_nowhitespace(p);
3359 if (*(q-1) == '"')
3360 *(q-1) = '\0';
3361 else
3362 *q = '\0';
3363
3364 if (!util_newstr(&wp->arg, p)) {
3365 CDINFO_FATAL(app_data.str_nomemory);
3366 return;
3367 }
3368
3369 /* Scan URL and record its attributes */
3370 cdinfo_scan_url_attrib(wp->arg, &wp->attrib);
3371
3372 /* Save menu pointer for later use */
3373 if (wp->type == WTYPE_DISCOG)
3374 cdinfo_discog = wp;
3375 else if (strcmp(wp->name,
3376 "searchMenu") == 0 &&
3377 util_strncasecmp(wp->desc,
3378 "CDDB", 4) == 0) {
3379 cdinfo_scddb = wp;
3380 }
3381
3382 break;
3383
3384 case WTYPE_BROWSER:
3385 case WTYPE_ALBUM:
3386 wp->attrib.acnt++;
3387 wp->attrib.dcnt++;
3388 wp->attrib.tcnt++;
3389 wp->attrib.icnt++;
3390 wp->attrib.ccnt++;
3391 break;
3392
3393 default:
3394 break;
3395 }
3396
3397 newmenu = FALSE;
3398 }
3399
3400 MEM_FREE(buf);
3401 }
3402 if (name != NULL)
3403 MEM_FREE(name);
3404
3405 (void) fclose(fp);
3406
3407 /* Bind submenus */
3408 for (wp = cdinfo_dbp->wwwwarp_list; wp != NULL; wp = wp->nextmenu) {
3409 for (wp2 = wp; wp2 != NULL; wp2 = wp2->nextent) {
3410 if (wp2->type != WTYPE_SUBMENU)
3411 continue;
3412
3413 for (wp3 = cdinfo_dbp->wwwwarp_list; wp3 != NULL;
3414 wp3 = wp3->nextmenu) {
3415 if (strcmp(wp2->arg, wp3->name) == 0) {
3416 wp2->submenu = wp3;
3417 break;
3418 }
3419 }
3420 if (wp3 == NULL) {
3421 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3422 " Error in %s file: %s not found\n",
3423 WWWWARP_CFG, wp2->arg);
3424 }
3425 }
3426 }
3427
3428 /* Check for circular menu links */
3429 for (wp = cdinfo_dbp->wwwwarp_list; wp != NULL; wp = wp->nextmenu) {
3430 if (!cdinfo_wwwmenu_chk(wp, TRUE)) {
3431 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3432 "\n Error in %s file: "
3433 "circular menu link.\n",
3434 WWWWARP_CFG);
3435 }
3436 }
3437
3438 #ifndef SYNCHRONOUS
3439 ret = util_waitchild(cpid, app_data.srv_timeout + 5,
3440 NULL, 0, FALSE, &wstat);
3441 child_pid = 0;
3442 if (ret < 0) {
3443 DBGPRN(DBG_GEN|DBG_CDI)(errfp, "cdinfo_wwwwarp_parmload: "
3444 "waitpid failed (errno=%d)\n",
3445 errno);
3446 }
3447 else if (WIFEXITED(wstat)) {
3448 if (WEXITSTATUS(wstat) != 0) {
3449 DBGPRN(DBG_GEN|DBG_CDI)(errfp,
3450 "cdinfo_wwwwarp_parmload: "
3451 "child exited (status=%d)\n",
3452 WEXITSTATUS(wstat));
3453 }
3454 }
3455 else if (WIFSIGNALED(wstat)) {
3456 DBGPRN(DBG_GEN|DBG_CDI)(errfp, "cdinfo_wwwwarp_parmload: "
3457 "child killed (signal=%d)\n",
3458 WTERMSIG(wstat));
3459 }
3460 #endif
3461 }
3462
3463
3464 /*
3465 * cdinfo_wwwwarp_ckkey
3466 * Given a shortcut key, check to see if it is unique amongst
3467 * existing wwwwarp menu shortcuts.
3468 *
3469 * Args:
3470 * keyname - The key name to check
3471 *
3472 * Return:
3473 * TRUE - is unique
3474 * FALSE - not unique
3475 */
3476 bool_t
cdinfo_wwwwarp_ckkey(char * keyname)3477 cdinfo_wwwwarp_ckkey(char *keyname)
3478 {
3479 w_ent_t *p,
3480 *q;
3481
3482 if (keyname == NULL)
3483 return FALSE;
3484
3485 for (p = cdinfo_dbp->wwwwarp_list; p != NULL; p = p->nextmenu) {
3486 for (q = p; q != NULL; q = q->nextent) {
3487 if (q->keyname != NULL &&
3488 util_strcasecmp(q->keyname, keyname) == 0)
3489 return FALSE;
3490 }
3491 }
3492 return TRUE;
3493 }
3494
3495
3496 /*
3497 * cdinfo_curfileupd
3498 * Update the current disc info file.
3499 *
3500 * Args:
3501 * None.
3502 *
3503 * Return:
3504 * Nothing
3505 */
3506 void
cdinfo_curfileupd(void)3507 cdinfo_curfileupd(void)
3508 {
3509 #ifndef __VMS
3510 FILE *fp;
3511 struct stat stbuf;
3512 char *artist,
3513 *title,
3514 *ttitle,
3515 str[FILE_PATH_SZ * 3];
3516 static char prev[FILE_PATH_SZ * 3],
3517 prev_artist[STR_BUF_SZ],
3518 prev_title[STR_BUF_SZ],
3519 prev_ttitle[STR_BUF_SZ];
3520 curstat_t *s;
3521 bool_t playing,
3522 changed;
3523
3524 if (!app_data.write_curfile || /* disabled */
3525 strncmp(app_data.device, "(sim", 4) == 0) /* demo */
3526 return;
3527
3528 if (cdinfo_clinfo->curstat_addr == NULL)
3529 return;
3530
3531 s = cdinfo_clinfo->curstat_addr();
3532
3533 if (!s->devlocked)
3534 /* Don't write curfile if we don't own the device */
3535 return;
3536
3537 playing = FALSE;
3538 artist = title = ttitle = NULL;
3539
3540 if (s->mode != MOD_NODISC) {
3541 char modestr[24];
3542
3543 artist = cdinfo_dbp->disc.artist;
3544 title = cdinfo_dbp->disc.title;
3545
3546 switch (s->mode) {
3547 case MOD_PLAY:
3548 case MOD_PAUSE:
3549 case MOD_SAMPLE:
3550 playing = TRUE;
3551
3552 (void) sprintf(modestr, "Playing track %d",
3553 s->cur_trk);
3554
3555 if (s->cur_trk > 0) {
3556 int n;
3557
3558 n = (int) s->cur_trk - 1;
3559
3560 if (s->trkinfo[n].trkno != s->cur_trk) {
3561 for (n = 0; n < MAXTRACK; n++) {
3562 if (s->trkinfo[n].trkno ==
3563 s->cur_trk)
3564 break;
3565 }
3566 }
3567
3568 ttitle = cdinfo_dbp->track[n].title;
3569 }
3570 break;
3571
3572 case MOD_STOP:
3573 (void) strcpy(modestr, "Stopped");
3574 break;
3575
3576 default:
3577 modestr[0] = '\0';
3578 break;
3579 }
3580
3581 (void) sprintf(str,
3582 "%s\t\t%s\n%s\t\t%s\n%s\t\t%s\n",
3583 "Device:", s->curdev == NULL ? "-" : s->curdev,
3584 "Genre:",
3585 cdinfo_genre_name(cdinfo_dbp->disc.genre),
3586 "Status:", modestr);
3587 }
3588 else {
3589 (void) sprintf(str,
3590 "%s\t\t%s\n%s\t\t%s\n%s\t\t%s\n",
3591 "Device:", s->curdev == NULL ? "-" : s->curdev,
3592 "Genre:", "-",
3593 "Status:", "No_Disc");
3594 }
3595
3596 changed = FALSE;
3597
3598 if (playing) {
3599 if (ttitle == NULL && prev_ttitle[0] != '\0')
3600 changed = TRUE;
3601 else if (ttitle != NULL &&
3602 strncmp(ttitle, prev_ttitle, STR_BUF_SZ - 1) != 0)
3603 changed = TRUE;
3604 }
3605
3606 if (s->mode != MOD_NODISC) {
3607 if (artist == NULL && prev_artist[0] != '\0')
3608 changed = TRUE;
3609 else if (title == NULL && prev_title[0] != '\0')
3610 changed = TRUE;
3611 else if (artist != NULL &&
3612 strncmp(artist, prev_artist, STR_BUF_SZ - 1) != 0)
3613 changed = TRUE;
3614 else if (title != NULL &&
3615 strncmp(title, prev_title, STR_BUF_SZ - 1) != 0)
3616 changed = TRUE;
3617 }
3618
3619 if (strcmp(str, prev) != 0)
3620 changed = TRUE;
3621
3622 if (!changed)
3623 return;
3624
3625 /* Write to file */
3626 if (curfile[0] == '\0') {
3627 if (stat(app_data.device, &stbuf) < 0) {
3628 DBGPRN(DBG_CDI)(errfp,
3629 "\nCannot stat %s\n", app_data.device);
3630 return;
3631 }
3632
3633 (void) sprintf(curfile, "%s/curr.%x",
3634 TEMP_DIR, (int) stbuf.st_rdev);
3635 }
3636
3637 /* Remove original file */
3638 if (UNLINK(curfile) < 0 && errno != ENOENT) {
3639 DBGPRN(DBG_CDI)(errfp, "\nCannot unlink old %s\n", curfile);
3640 return;
3641 }
3642
3643 /* Write new file */
3644 if ((fp = fopen(curfile, "w")) == NULL) {
3645 DBGPRN(DBG_CDI)(errfp,
3646 "\nCannot open %s for writing\n", curfile);
3647 return;
3648 }
3649
3650 DBGPRN(DBG_CDI)(errfp,
3651 "\nWriting current disc info file: %s\n", curfile);
3652
3653 (void) fprintf(fp, "#\n# Xmcd current CD information\n#\n%s", str);
3654
3655 if (s->mode != MOD_NODISC) {
3656 (void) fprintf(fp, "Disc:\t\t%s / %s\n",
3657 artist == NULL ?
3658 "<unknown artist>" : artist,
3659 title == NULL ?
3660 "<unknown disc title>" : title);
3661 }
3662 else {
3663 (void) fprintf(fp, "Disc:\t\t-\n");
3664 }
3665
3666 if (playing) {
3667 (void) fprintf(fp, "Track:\t\t%s\n",
3668 ttitle == NULL ?
3669 "<unknown track title>" : ttitle);
3670 }
3671 else {
3672 (void) fprintf(fp, "Track:\t\t-\n");
3673 }
3674
3675 (void) fclose(fp);
3676 (void) chmod(curfile, 0644);
3677
3678 if (ttitle == NULL)
3679 prev_ttitle[0] = '\0';
3680 else {
3681 (void) strncpy(prev_ttitle, ttitle, STR_BUF_SZ - 1);
3682 prev_ttitle[STR_BUF_SZ - 1] = '\0';
3683 }
3684
3685 if (artist == NULL)
3686 prev_artist[0] = '\0';
3687 else {
3688 (void) strncpy(prev_artist, artist, STR_BUF_SZ - 1);
3689 prev_artist[STR_BUF_SZ - 1] = '\0';
3690 }
3691
3692 if (title == NULL)
3693 prev_title[0] = '\0';
3694 else {
3695 (void) strncpy(prev_title, title, STR_BUF_SZ - 1);
3696 prev_title[STR_BUF_SZ - 1] = '\0';
3697 }
3698
3699 (void) strcpy(prev, str);
3700 #endif /* __VMS */
3701 }
3702
3703
3704 /*
3705 * cdinfo_issync
3706 * Return a boolean value indicating whether we are running in
3707 * synchronous mode.
3708 *
3709 * Args:
3710 * None.
3711 *
3712 * Return:
3713 * TRUE - synchronous mode
3714 * FALSE - asynchronous mode
3715 */
3716 bool_t
cdinfo_issync(void)3717 cdinfo_issync(void)
3718 {
3719 #ifdef SYNCHRONOUS
3720 return TRUE;
3721 #else
3722 return FALSE;
3723 #endif
3724 }
3725
3726
3727 /*
3728 * cdinfo_dump_incore
3729 * Displays the contents of the cdinfo_incore_t structure.
3730 *
3731 * Args:
3732 * s - Pointer to the curstat_t structure.
3733 *
3734 * Returns:
3735 * Nothing.
3736 */
3737 void
cdinfo_dump_incore(curstat_t * s)3738 cdinfo_dump_incore(curstat_t *s)
3739 {
3740 int i,
3741 j;
3742
3743 if (cdinfo_dbp == NULL)
3744 return;
3745
3746 (void) fprintf(errfp,
3747 "\nDumping the cdinfo_incore_t structure at 0x%lx:\n",
3748 (unsigned long) cdinfo_dbp);
3749 (void) fprintf(errfp, "ctrl_ver=%s\n",
3750 cdinfo_dbp->ctrl_ver == NULL ?
3751 "NULL" : cdinfo_dbp->ctrl_ver);
3752 (void) fprintf(errfp, "discid=%08x flags=0x%x\n",
3753 cdinfo_dbp->discid, cdinfo_dbp->flags);
3754 (void) fprintf(errfp, "disc: ----------------------\n");
3755 (void) fprintf(errfp, " revision=%s revtag=%s region=%s lang=%s\n",
3756 cdinfo_dbp->disc.revision == NULL ?
3757 "NULL" : cdinfo_dbp->disc.revision,
3758 cdinfo_dbp->disc.revtag == NULL ?
3759 "NULL" : cdinfo_dbp->disc.revtag,
3760 cdinfo_dbp->disc.region == NULL ?
3761 "NULL" : cdinfo_dbp->disc.region,
3762 cdinfo_dbp->disc.lang == NULL ?
3763 "NULL" : cdinfo_dbp->disc.lang);
3764 (void) fprintf(errfp, " compilation=%d dnum=%s tnum=%s\n",
3765 (int) cdinfo_dbp->disc.compilation,
3766 cdinfo_dbp->disc.dnum == NULL ?
3767 "NULL" : cdinfo_dbp->disc.dnum,
3768 cdinfo_dbp->disc.tnum == NULL ?
3769 "NULL" : cdinfo_dbp->disc.tnum);
3770 (void) fprintf(errfp,
3771 " fullname: dispname=%s "
3772 "lastname=%s firstname=%s the=%s\n",
3773 cdinfo_dbp->disc.artistfname.dispname == NULL ?
3774 "NULL" : cdinfo_dbp->disc.artistfname.dispname,
3775 cdinfo_dbp->disc.artistfname.lastname == NULL ?
3776 "NULL" : cdinfo_dbp->disc.artistfname.lastname,
3777 cdinfo_dbp->disc.artistfname.firstname == NULL ?
3778 "NULL" : cdinfo_dbp->disc.artistfname.firstname,
3779 cdinfo_dbp->disc.artistfname.the == NULL ?
3780 "NULL" : cdinfo_dbp->disc.artistfname.the);
3781 (void) fprintf(errfp,
3782 " artist=%s title=%s\n sorttitle=%s title_the=%s\n",
3783 cdinfo_dbp->disc.artist == NULL ?
3784 "NULL" : cdinfo_dbp->disc.artist,
3785 cdinfo_dbp->disc.title == NULL ?
3786 "NULL" : cdinfo_dbp->disc.title,
3787 cdinfo_dbp->disc.sorttitle == NULL ?
3788 "NULL" : cdinfo_dbp->disc.sorttitle,
3789 cdinfo_dbp->disc.title_the == NULL ?
3790 "NULL" : cdinfo_dbp->disc.title_the);
3791 (void) fprintf(errfp, " year=%s label=%s genre=%s genre2=%s\n",
3792 cdinfo_dbp->disc.year == NULL ?
3793 "NULL" : cdinfo_dbp->disc.year,
3794 cdinfo_dbp->disc.label == NULL ?
3795 "NULL" : cdinfo_dbp->disc.label,
3796 cdinfo_dbp->disc.genre == NULL ?
3797 "NULL" : cdinfo_dbp->disc.genre,
3798 cdinfo_dbp->disc.genre2 == NULL ?
3799 "NULL" : cdinfo_dbp->disc.genre2);
3800 (void) fprintf(errfp, " mediaid=%s\n muiid=%s titleuid=%s\n",
3801 cdinfo_dbp->disc.mediaid == NULL ?
3802 "NULL" : cdinfo_dbp->disc.mediaid,
3803 cdinfo_dbp->disc.muiid == NULL ?
3804 "NULL" : cdinfo_dbp->disc.muiid,
3805 cdinfo_dbp->disc.titleuid == NULL ?
3806 "NULL" : cdinfo_dbp->disc.titleuid);
3807 (void) fprintf(errfp, " certifier=%s\n",
3808 cdinfo_dbp->disc.certifier == NULL ?
3809 "NULL" : cdinfo_dbp->disc.certifier);
3810 if (cdinfo_dbp->disc.notes == NULL)
3811 (void) fprintf(errfp, " notes=NULL\n");
3812 else
3813 (void) fprintf(errfp, " notes=\n%s\n", cdinfo_dbp->disc.notes);
3814
3815 if (cdinfo_dbp->disc.credit_list == NULL)
3816 (void) fprintf(errfp, " credit_list=NULL\n");
3817 else {
3818 cdinfo_credit_t *p;
3819
3820 (void) fprintf(errfp, "credit_list=\n");
3821 for (i = 0, p = cdinfo_dbp->disc.credit_list; p != NULL;
3822 p = p->next, i++) {
3823 (void) fprintf(errfp, " credit[%d]\n", i);
3824 (void) fprintf(errfp, " role=%s name=%s\n",
3825 p->crinfo.role == NULL ?
3826 "NULL" : p->crinfo.role->name,
3827 p->crinfo.name == NULL ?
3828 "NULL" : p->crinfo.name);
3829 (void) fprintf(errfp,
3830 " fullname: dispname=%s lastname=%s "
3831 "firstname=%s the=%s\n",
3832 p->crinfo.fullname.dispname == NULL ?
3833 "NULL" :
3834 p->crinfo.fullname.dispname,
3835 p->crinfo.fullname.lastname == NULL ?
3836 "NULL" :
3837 p->crinfo.fullname.lastname,
3838 p->crinfo.fullname.firstname == NULL ?
3839 "NULL" :
3840 p->crinfo.fullname.firstname,
3841 p->crinfo.fullname.the == NULL ?
3842 "NULL" :
3843 p->crinfo.fullname.the);
3844 if (p->notes == NULL)
3845 (void) fprintf(errfp,
3846 " notes=NULL\n");
3847 else
3848 (void) fprintf(errfp,
3849 " notes=\n%s\n", p->notes);
3850 }
3851 }
3852
3853 if (cdinfo_dbp->disc.segment_list == NULL)
3854 (void) fprintf(errfp, " segment_list=NULL\n");
3855 else {
3856 cdinfo_segment_t *q;
3857
3858 (void) fprintf(errfp, "segment_list=\n");
3859 for (i = 0, q = cdinfo_dbp->disc.segment_list; q != NULL;
3860 q = q->next, i++) {
3861 (void) fprintf(errfp, " segment[%d]\n", i);
3862 (void) fprintf(errfp, " name=%s start=%s/%s ",
3863 q->name == NULL ? "NULL" : q->name,
3864 q->start_track == NULL ?
3865 "?" : q->start_track,
3866 q->start_frame == NULL ?
3867 "?" : q->start_frame);
3868 (void) fprintf(errfp, "end=%s/%s\n",
3869 q->end_track == NULL ?
3870 "?" : q->end_track,
3871 q->end_frame == NULL ?
3872 "?" : q->end_frame);
3873 if (q->notes == NULL)
3874 (void) fprintf(errfp, " notes=NULL\n");
3875 else
3876 (void) fprintf(errfp,
3877 " notes=\n%s\n", q->notes);
3878
3879 if (q->credit_list == NULL)
3880 (void) fprintf(errfp, " credit_list=NULL\n");
3881 else {
3882 cdinfo_credit_t *p;
3883
3884 for (j = 0, p = q->credit_list; p != NULL;
3885 p = p->next, j++) {
3886 (void) fprintf(errfp, " credit[%d]\n", j);
3887 (void) fprintf(errfp,
3888 " role=%s name=%s\n",
3889 p->crinfo.role == NULL ?
3890 "NULL" : p->crinfo.role->name,
3891 p->crinfo.name == NULL ?
3892 "NULL" : p->crinfo.name);
3893 (void) fprintf(errfp,
3894 " fullname: dispname=%s "
3895 "lastname=%s firstname=%s the=%s\n",
3896 p->crinfo.fullname.dispname == NULL ?
3897 "NULL" :
3898 p->crinfo.fullname.dispname,
3899 p->crinfo.fullname.lastname == NULL ?
3900 "NULL" :
3901 p->crinfo.fullname.lastname,
3902 p->crinfo.fullname.firstname == NULL ?
3903 "NULL" :
3904 p->crinfo.fullname.firstname,
3905 p->crinfo.fullname.the == NULL ?
3906 "NULL" :
3907 p->crinfo.fullname.the);
3908 if (p->notes == NULL)
3909 (void) fprintf(errfp,
3910 " notes=NULL\n");
3911 else
3912 (void) fprintf(errfp,
3913 " notes=\n%s\n",
3914 p->notes);
3915 }
3916 }
3917 }
3918 }
3919
3920 for (i = 0; i < (int) s->tot_trks; i++) {
3921 (void) fprintf(errfp, "track[%d] ----------------------\n", i);
3922
3923 (void) fprintf(errfp,
3924 " fullname: dispname=%s lastname=%s "
3925 "firstname=%s the=%s\n",
3926 cdinfo_dbp->track[i].artistfname.dispname == NULL ?
3927 "NULL" :
3928 cdinfo_dbp->track[i].artistfname.dispname,
3929 cdinfo_dbp->track[i].artistfname.lastname == NULL ?
3930 "NULL" :
3931 cdinfo_dbp->track[i].artistfname.lastname,
3932 cdinfo_dbp->track[i].artistfname.firstname == NULL ?
3933 "NULL" :
3934 cdinfo_dbp->track[i].artistfname.firstname,
3935 cdinfo_dbp->track[i].artistfname.the == NULL ?
3936 "NULL" :
3937 cdinfo_dbp->track[i].artistfname.the);
3938 (void) fprintf(errfp, " artist=%s title=%s\n",
3939 cdinfo_dbp->track[i].artist == NULL ?
3940 "NULL" : cdinfo_dbp->track[i].artist,
3941 cdinfo_dbp->track[i].title == NULL ?
3942 "NULL" : cdinfo_dbp->track[i].title);
3943 (void) fprintf(errfp, " sorttitle=%s title_the=%s\n",
3944 cdinfo_dbp->track[i].sorttitle == NULL ?
3945 "NULL" :
3946 cdinfo_dbp->track[i].sorttitle,
3947 cdinfo_dbp->track[i].title_the == NULL ?
3948 "NULL" :
3949 cdinfo_dbp->track[i].title_the);
3950 (void) fprintf(errfp,
3951 " year=%s label=%s genre=%s genre2=%s\n",
3952 cdinfo_dbp->track[i].year == NULL ?
3953 "NULL" : cdinfo_dbp->track[i].year,
3954 cdinfo_dbp->track[i].label == NULL ?
3955 "NULL" : cdinfo_dbp->track[i].label,
3956 cdinfo_dbp->track[i].genre == NULL ?
3957 "NULL" : cdinfo_dbp->track[i].genre,
3958 cdinfo_dbp->track[i].genre2 == NULL ?
3959 "NULL" :
3960 cdinfo_dbp->track[i].genre2);
3961 (void) fprintf(errfp, " isrc=%s\n",
3962 cdinfo_dbp->track[i].isrc == NULL ?
3963 "NULL" : cdinfo_dbp->track[i].isrc);
3964 if (cdinfo_dbp->track[i].notes == NULL)
3965 (void) fprintf(errfp, " notes=NULL\n");
3966 else
3967 (void) fprintf(errfp, " notes=\n%s\n",
3968 cdinfo_dbp->track[i].notes);
3969
3970 if (cdinfo_dbp->track[i].credit_list == NULL)
3971 (void) fprintf(errfp, " credit_list=NULL\n");
3972 else {
3973 cdinfo_credit_t *p;
3974
3975 (void) fprintf(errfp, " credit_list=\n");
3976 for (j = 0, p = cdinfo_dbp->track[j].credit_list;
3977 p != NULL; p = p->next, j++) {
3978 (void) fprintf(errfp, " credit[%d]\n", j);
3979 (void) fprintf(errfp, " role=%s name=%s\n",
3980 p->crinfo.role == NULL ?
3981 "NULL" : p->crinfo.role->name,
3982 p->crinfo.name == NULL ?
3983 "NULL" : p->crinfo.name);
3984 (void) fprintf(errfp,
3985 " fullname: dispname=%s lastname=%s "
3986 "firstname=%s the=%s\n",
3987 p->crinfo.fullname.dispname == NULL ?
3988 "NULL" :
3989 p->crinfo.fullname.dispname,
3990 p->crinfo.fullname.lastname == NULL ?
3991 "NULL" :
3992 p->crinfo.fullname.lastname,
3993 p->crinfo.fullname.firstname == NULL ?
3994 "NULL" :
3995 p->crinfo.fullname.firstname,
3996 p->crinfo.fullname.the == NULL ?
3997 "NULL" :
3998 p->crinfo.fullname.the);
3999 if (p->notes == NULL)
4000 (void) fprintf(errfp,
4001 " notes=NULL\n");
4002 else
4003 (void) fprintf(errfp,
4004 " notes=\n%s\n", p->notes);
4005 }
4006 }
4007 }
4008
4009 (void) fprintf(errfp, "----------------------\n");
4010
4011 if (cdinfo_dbp->genrelist == NULL)
4012 (void) fprintf(errfp, "genrelist=NULL\n");
4013 else {
4014 cdinfo_genre_t *p,
4015 *q;
4016
4017 (void) fprintf(errfp, "genrelist:\n");
4018 for (p = cdinfo_dbp->genrelist, i = 0; p != NULL;
4019 p = p->next, i++) {
4020 (void) fprintf(errfp, "genre[%d]: %s (%s)\n",
4021 i, p->name, p->id);
4022
4023 for (q = p->child, j = 0; q != NULL; q = q->next, j++) {
4024 (void) fprintf(errfp, " subgenre[%d]: %s (%s)\n",
4025 j, q->name, q->id);
4026 }
4027 }
4028 }
4029
4030 if (cdinfo_dbp->regionlist == NULL)
4031 (void) fprintf(errfp, "regionlist=NULL\n");
4032 else {
4033 cdinfo_region_t *p;
4034
4035 (void) fprintf(errfp, "regionlist:\n");
4036 for (p = cdinfo_dbp->regionlist, i = 0; p != NULL;
4037 p = p->next, i++) {
4038 (void) fprintf(errfp, "region[%d]: %s (%s)\n",
4039 i, p->name, p->id);
4040 }
4041 }
4042
4043 if (cdinfo_dbp->langlist == NULL)
4044 (void) fprintf(errfp, "langlist=NULL\n");
4045 else {
4046 cdinfo_lang_t *p;
4047
4048 (void) fprintf(errfp, "langlist:\n");
4049 for (p = cdinfo_dbp->langlist, i = 0; p != NULL;
4050 p = p->next, i++) {
4051 (void) fprintf(errfp, "lang[%d]: %s (%s)\n",
4052 i, p->name, p->id);
4053 }
4054 }
4055
4056 if (cdinfo_dbp->rolelist == NULL)
4057 (void) fprintf(errfp, "rolelist=NULL\n");
4058 else {
4059 cdinfo_role_t *p,
4060 *q;
4061
4062 (void) fprintf(errfp, "rolelist:\n");
4063 for (p = cdinfo_dbp->rolelist, i = 0; p != NULL;
4064 p = p->next, i++) {
4065 (void) fprintf(errfp, "role[%d]: %s (%s)\n",
4066 i, p->name, p->id);
4067 for (q = p->child, j = 0; q != NULL; q = q->next, j++){
4068 (void) fprintf(errfp,
4069 " subrole[%d]: %s (%s)\n",
4070 j, q->name, q->id);
4071 }
4072 }
4073 }
4074
4075 if (cdinfo_dbp->matchlist == NULL)
4076 (void) fprintf(errfp, "matchlist=NULL\n");
4077 else {
4078 cdinfo_match_t *p;
4079
4080 for (p = cdinfo_dbp->matchlist, i = 0; p != NULL;
4081 p = p->next, i++) {
4082 (void) fprintf(errfp,
4083 "matchlist[%d] ptr=0x%lx genre=%s ",
4084 i, (unsigned long) p,
4085 p->genre == NULL ? "NULL" : p->genre);
4086 (void) fprintf(errfp, "artist=%s title=%s\n",
4087 p->artist == NULL ? "NULL" : p->artist,
4088 p->title == NULL ? "NULL" : p->title);
4089 }
4090 }
4091 if (cdinfo_dbp->match_aux == NULL)
4092 (void) fprintf(errfp, "match_aux=NULL\n");
4093 else
4094 (void) fprintf(errfp, "match_aux=0x%lx\n",
4095 (unsigned long) cdinfo_dbp->match_aux);
4096 (void) fprintf(errfp, "match_tag=%ld\n", cdinfo_dbp->match_tag);
4097
4098 if (cdinfo_dbp->gen_url_list == NULL)
4099 (void) fprintf(errfp, "gen_url_list=NULL\n");
4100 else {
4101 cdinfo_url_t *u;
4102
4103 for (u = cdinfo_dbp->gen_url_list, i = 0; u != NULL;
4104 u = u->next, i++) {
4105 (void) fprintf(errfp,
4106 "gen_url_list[%d] ptr=0x%lx key=%s-%s "
4107 "type=%s size=%s weight=%s categ=%s\n",
4108 i, (unsigned long) u,
4109 u->modifier == NULL ? "NULL" : u->modifier,
4110 u->keyname == NULL ? "NULL" : u->keyname,
4111 u->type == NULL ? "NULL" : u->type,
4112 u->size == NULL ? "NULL" : u->size,
4113 u->weight == NULL ? "NULL" : u->weight,
4114 u->categ == NULL ? "NULL" : u->categ);
4115
4116 (void) fprintf(errfp,
4117 " href=%s\n",
4118 u->href == NULL ? "NULL" : u->href);
4119 (void) fprintf(errfp,
4120 " displink=%s\n",
4121 u->displink == NULL ? "NULL" : u->displink);
4122 (void) fprintf(errfp,
4123 " disptext=%s\n",
4124 u->disptext == NULL ? "NULL" : u->disptext);
4125 }
4126 }
4127 if (cdinfo_dbp->disc_url_list == NULL)
4128 (void) fprintf(errfp, "disc_url_list=NULL\n");
4129 else {
4130 cdinfo_url_t *u;
4131
4132 for (u = cdinfo_dbp->disc_url_list, i = 0; u != NULL;
4133 u = u->next, i++) {
4134 (void) fprintf(errfp,
4135 "gen_disc_list[%d] ptr=0x%lx key=%s-%s "
4136 "type=%s size=%s weight=%s categ=%s\n",
4137 i, (unsigned long) u,
4138 u->modifier == NULL ? "NULL" : u->modifier,
4139 u->keyname == NULL ? "NULL" : u->keyname,
4140 u->type == NULL ? "NULL" : u->type,
4141 u->size == NULL ? "NULL" : u->size,
4142 u->weight == NULL ? "NULL" : u->weight,
4143 u->categ == NULL ? "NULL" : u->categ);
4144
4145 (void) fprintf(errfp,
4146 " href=%s\n",
4147 u->href == NULL ? "NULL" : u->href);
4148 (void) fprintf(errfp,
4149 " displink=%s\n",
4150 u->displink == NULL ? "NULL" : u->displink);
4151 (void) fprintf(errfp,
4152 " disptext=%s\n",
4153 u->disptext == NULL ? "NULL" : u->disptext);
4154 }
4155 }
4156
4157 (void) fprintf(errfp, "playorder=%s\n",
4158 cdinfo_dbp->playorder == NULL ?
4159 "NULL" : cdinfo_dbp->playorder);
4160 }
4161
4162
4163