1 /*
2  *   xmcd - Motif(R) CD Audio Player/Ripper
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 *_wwwwarp_c_ident_ = "@(#)wwwwarp.c	7.68 04/04/20";
24 #endif
25 
26 #include "common_d/appenv.h"
27 #include "common_d/util.h"
28 #include "libdi_d/libdi.h"
29 #include "xmcd_d/xmcd.h"
30 #include "xmcd_d/widget.h"
31 #include "cdinfo_d/cdinfo.h"
32 #include "cdinfo_d/motd.h"
33 #include "xmcd_d/callback.h"
34 #include "xmcd_d/cdfunc.h"
35 #include "xmcd_d/dbprog.h"
36 #include "xmcd_d/hotkey.h"
37 #include "xmcd_d/geom.h"
38 #include "xmcd_d/userreg.h"
39 #include "xmcd_d/wwwwarp.h"
40 
41 
42 extern widgets_t	widgets;
43 extern appdata_t	app_data;
44 extern char		*cdisplay;
45 extern FILE		*errfp;
46 
47 STATIC w_ent_t		*wwwwarp_menu = NULL;	 /* Ptr to head of menu */
48 STATIC bool_t		wwwwarp_initted = FALSE; /* Initialization done */
49 
50 
51 /***********************
52  *  internal routines  *
53  ***********************/
54 
55 
56 /*
57  * wwwwarp_menu_setup
58  *	Function to set up the initial wwwwarp popup menu, based on
59  *	the definition in the wwwwarp.cfg file, parsed in libcdinfo.
60  *	This function is recursively called to build submenu levels.
61  *
62  * Args:
63  *	parentw - The parent menu widget
64  *	menu - The menu entries list as defined by w_ent_t *
65  *	s - Pointer to the curstat_t structure
66  *
67  * Return:
68  *	TRUE - Success
69  *	FALSE - Failure
70  */
71 STATIC bool_t
wwwwarp_menu_setup(Widget parentw,w_ent_t * menu,curstat_t * s)72 wwwwarp_menu_setup(Widget parentw, w_ent_t *menu, curstat_t *s)
73 {
74 	w_ent_t		*p;
75 	char		*cp;
76 	Widget		w,
77 			w1;
78 	int		i;
79 	Arg		arg[10];
80 
81 	for (p = menu; p != NULL; p = p->nextent) {
82 		cp = p->desc == NULL ? "" : p->desc;
83 
84 		/* Set up common resources */
85 		i = 0;
86 		XtSetArg(arg[i], XmNinitialResourcesPersistent, False); i++;
87 		XtSetArg(arg[i], XmNshadowThickness, 2); i++;
88 		if (p->modifier != NULL && p->keyname != NULL &&
89 		    hotkey_ckkey(p->modifier, p->keyname)) {
90 			char	acc[STR_BUF_SZ];
91 
92 			(void) sprintf(acc, "%s<Key>%s",
93 					p->modifier, p->keyname);
94 
95 			XtSetArg(arg[i], XmNaccelerator, acc); i++;
96 			XtSetArg(arg[i], XmNmnemonic,
97 				 XStringToKeysym(p->keyname)); i++;
98 		}
99 
100 		switch (p->type) {
101 		case WTYPE_TITLE:
102 			w = XmCreateLabel(parentw, cp, NULL, 0);
103 			XtManageChild(w);
104 			p->aux = (void *) w;
105 			break;
106 
107 		case WTYPE_SEP:
108 			XtSetArg(arg[i], XmNseparatorType,
109 				 XmSHADOW_ETCHED_IN); i++;
110 			w = XmCreateSeparator(parentw, "separator", arg, i);
111 			XtManageChild(w);
112 			p->aux = (void *) w;
113 			break;
114 
115 		case WTYPE_SEP2:
116 			XtSetArg(arg[i], XmNseparatorType, XmDOUBLE_LINE); i++;
117 			w = XmCreateSeparator(parentw, "separator2", arg, i);
118 			XtManageChild(w);
119 			p->aux = (void *) w;
120 			break;
121 
122 		case WTYPE_SUBMENU:
123 			w1 = XmCreatePulldownMenu(parentw, cp, arg, i);
124 
125 			XtSetArg(arg[i], XmNsubMenuId, w1); i++;
126 			w = XmCreateCascadeButton(parentw, cp, arg, i);
127 			XtManageChild(w);
128 			p->aux = (void *) w;
129 
130 			/* Recurse into submenu */
131 			if (!wwwwarp_menu_setup(w1, p->submenu, s))
132 				return FALSE;
133 			break;
134 
135 		case WTYPE_GOTO:
136 		case WTYPE_DISCOG:
137 			w = XmCreatePushButton(parentw, cp, arg, i);
138 			XtManageChild(w);
139 			p->aux = (void *) w;
140 
141 			register_activate_cb(w, wwwwarp_go_url, p);
142 			break;
143 
144 		case WTYPE_ABOUT:
145 			w = XmCreatePushButton(parentw, cp, arg, i);
146 			XtManageChild(w);
147 			p->aux = (void *) w;
148 
149 			register_activate_cb(w, cd_about, s);
150 			break;
151 
152 		case WTYPE_HELP:
153 			w = XmCreatePushButton(parentw, cp, arg, i);
154 			XtManageChild(w);
155 			p->aux = (void *) w;
156 
157 			register_activate_cb(w, cd_help_popup, s);
158 			break;
159 
160 		case WTYPE_MOTD:
161 			w = XmCreatePushButton(parentw, cp, arg, i);
162 			XtManageChild(w);
163 			p->aux = (void *) w;
164 
165 			register_activate_cb(w, wwwwarp_motd, s);
166 			break;
167 
168 		case WTYPE_BROWSER:
169 			w = XmCreatePushButton(parentw, cp, arg, i);
170 			XtManageChild(w);
171 			p->aux = (void *) w;
172 
173 			register_activate_cb(w, wwwwarp_go_musicbrowser, p);
174 			break;
175 
176 		case WTYPE_GEN:
177 			XtSetArg(arg[i], XmNsubMenuId,
178 				 widgets.wwwwarp.genurls_menu); i++;
179 			w = XmCreateCascadeButton(parentw, cp, arg, i);
180 			XtManageChild(w);
181 			p->aux = (void *) w;
182 			break;
183 
184 		case WTYPE_ALBUM:
185 			XtSetArg(arg[i], XmNsubMenuId,
186 				 widgets.wwwwarp.discurls_menu); i++;
187 			w = XmCreateCascadeButton(parentw, cp, arg, i);
188 			XtManageChild(w);
189 			p->aux = (void *) w;
190 			break;
191 
192 		case WTYPE_SUBMITURL:
193 			w = XmCreatePushButton(parentw, cp, arg, i);
194 			XtManageChild(w);
195 			p->aux = (void *) w;
196 
197 			register_activate_cb(w, wwwwarp_submit_url, s);
198 			break;
199 
200 		case WTYPE_NULL:
201 		default:
202 			/* Do nothing */
203 			break;
204 		}
205 	}
206 	return TRUE;
207 }
208 
209 
210 /*
211  * wwwwarp_url_ckkey
212  *	Check a shortcut key string against existing shortcut key strings
213  *	in the provided URL list to see if it's been used.
214  *
215  * Args:
216  *	list - The URL list
217  *	keyname - The key name string
218  *
219  * Return:
220  *	FALSE - The key name string has been used
221  *	TRUE -  The key string has not been used
222  */
223 STATIC bool_t
wwwwarp_url_ckkey(cdinfo_url_t * list,char * keyname)224 wwwwarp_url_ckkey(cdinfo_url_t *list, char *keyname)
225 {
226 	cdinfo_url_t	*up;
227 
228 	for (up = list; up != NULL; up = up->next) {
229 		if (up->keyname != NULL &&
230 		    util_strcasecmp(up->keyname, keyname) == 0)
231 			return FALSE;
232 	}
233 	return TRUE;
234 }
235 
236 
237 /*
238  * wwwwarp_set_shortcut
239  *	Auto-generate a unique shortcut key if possible, based on the
240  *	menu entry's description string.
241  *
242  * Args:
243  *	ulist - The cdinfo_url_list list head
244  *	dbp - Pointer to the cdinfo_incore_t structure
245  *
246  * Return:
247  *	Nothing.
248  */
249 STATIC void
wwwwarp_set_shortcut(cdinfo_url_t * up,cdinfo_incore_t * dbp)250 wwwwarp_set_shortcut(cdinfo_url_t *up, cdinfo_incore_t *dbp)
251 {
252 	char		*modifier,
253 			c,
254 			keystr[2];
255 	int		i;
256 
257 	if (up->disptext[0] == '\0')
258 		return;	/* No description */
259 
260 	if (up->keyname != NULL)
261 		return;	/* A shortcut is already assigned */
262 
263 	/* Pick a unique shortcut character */
264 	modifier = NULL;
265 	c = '\0';
266 	for (i = 0; up->disptext[i] != '\0'; i++) {
267 		if (!isalnum((int) up->disptext[i]))
268 			continue;
269 
270 		keystr[0] = up->disptext[i];
271 		keystr[1] = '\0';
272 		modifier = isupper((int) keystr[0]) ? "Shift" : "Alt";
273 
274 		/* Match against existing wwwWarp menu entries and
275 		 * main window hotkeys
276 		 */
277 		if (cdinfo_wwwwarp_ckkey(keystr) &&
278 		    hotkey_ckkey(modifier, keystr) &&
279 		    wwwwarp_url_ckkey(dbp->gen_url_list, keystr) &&
280 		    wwwwarp_url_ckkey(dbp->disc_url_list, keystr)) {
281 			c = keystr[0];
282 			break;
283 		}
284 	}
285 
286 	/* Set the shortcut */
287 	if (c != '\0') {
288 		if (!util_newstr(&up->modifier, modifier)) {
289 			CD_FATAL(app_data.str_nomemory);
290 			return;
291 		}
292 		if (!util_newstr(&up->keyname, keystr)) {
293 			CD_FATAL(app_data.str_nomemory);
294 			return;
295 		}
296 	}
297 }
298 
299 
300 
301 /*
302  * wwwwarp_sel_cfg_menu
303  *	Set the sensitivity of the wwwWarp menu entries
304  *
305  * Args:
306  *	menu - Pointer to the menu entry list being configured
307  *	dbp - Pointer to the incore cdinfo structure
308  *	s - Pointer to the curstat_t structure
309  *
310  * Return:
311  *	Nothing.
312  */
313 void
wwwwarp_sel_cfg_menu(w_ent_t * menu,cdinfo_incore_t * dbp,curstat_t * s)314 wwwwarp_sel_cfg_menu(w_ent_t *menu, cdinfo_incore_t *dbp, curstat_t *s)
315 {
316 	cdinfo_url_t	*u,
317 			*l;
318 	w_ent_t		*p;
319 	char		*cp;
320 	Widget		w;
321 	int		i,
322 			len;
323 	Arg		arg[10];
324 	Boolean		sens;
325 
326 	for (p = menu; p != NULL; p = p->nextent) {
327 		if (p->type == WTYPE_NULL  || p->type == WTYPE_HELP ||
328 		    p->type == WTYPE_TITLE || p->type == WTYPE_SEP  ||
329 		    p->type == WTYPE_SEP2)
330 			continue;
331 
332 		sens = True;
333 
334 		if (p->attrib.acnt > 0 && dbp->disc.artist == NULL &&
335 		    p->attrib.dcnt == 0)
336 			sens = False;
337 
338 		if (p->attrib.dcnt > 0 && dbp->disc.title == NULL &&
339 		    p->attrib.acnt == 0)
340 			sens = False;
341 
342 		if (p->attrib.acnt > 0 && dbp->disc.artist == NULL &&
343 		    p->attrib.dcnt > 0 && dbp->disc.title == NULL)
344 			sens = False;
345 
346 		if (p->attrib.tcnt > 0 && dbp->disc.title == NULL)
347 			sens = False;
348 
349 		if (p->attrib.ccnt > 0 && dbp->disc.genre == NULL)
350 			sens = False;
351 
352 		if (p->attrib.icnt > 0 &&
353 		    (s->mode == MOD_NODISC || s->mode == MOD_BUSY))
354 			sens = False;
355 
356 		if (p->type == WTYPE_GOTO &&
357 		    app_data.cdinfo_inetoffln && p->arg != NULL &&
358 		    (util_urlchk(p->arg, &cp, &len) & IS_REMOTE_URL))
359 			sens = False;
360 
361 		if (p->type == WTYPE_BROWSER) {
362 			if (cdinfo_cddb_ver() != 2 ||
363 			    s->qmode != QMODE_MATCH ||
364 			    app_data.cdinfo_inetoffln)
365 				sens = False;
366 			else if (app_data.auto_musicbrowser) {
367 				/* Auto-launch the Music Browser */
368 				wwwwarp_go_musicbrowser(
369 					(Widget) p->aux,
370 					(XtPointer) p,
371 					NULL
372 				);
373 			}
374 		}
375 
376 		if (p->type == WTYPE_GEN || p->type == WTYPE_ALBUM) {
377 			l = (p->type == WTYPE_GEN) ?
378 				dbp->gen_url_list : dbp->disc_url_list;
379 
380 			if (l == NULL || app_data.cdinfo_inetoffln)
381 				sens = False;
382 			else for (u = l; u != NULL; u = u->next) {
383 				char	*title;
384 				int	categ_len,
385 					disptext_len;
386 
387 				if (u->aux != NULL)
388 					/* Menu entry already exists */
389 					continue;
390 
391 				/* Create menu entry */
392 
393 				categ_len = (u->categ == NULL) ?
394 					0 : strlen(u->categ);
395 				disptext_len = (u->disptext == NULL) ?
396 					0 : strlen(u->disptext);
397 
398 				/* Change "Sites" to "Site" if applicable */
399 				if (categ_len > 0 &&
400 				    (strcmp(u->categ + categ_len - 5,
401 					    "Sites") == 0 ||
402 				     strcmp(u->categ + categ_len - 5,
403 					    "sites") == 0))
404 					*(u->categ + categ_len - 1) = '\0';
405 
406 				title = (char *) MEM_ALLOC("wwwwarp_cddbent",
407 					categ_len + disptext_len + 4
408 				);
409 				if (title == NULL) {
410 					CD_FATAL(app_data.str_nomemory);
411 					return;
412 				}
413 				(void) sprintf(title, "%s%s%s%s",
414 					u->disptext == NULL ? "" : u->disptext,
415 					u->categ == NULL ? "" : " (",
416 					u->categ == NULL ? "" : u->categ,
417 					u->categ == NULL ? "" : ")"
418 				);
419 
420 				wwwwarp_set_shortcut(u, dbp);
421 
422 				i = 0;
423 				XtSetArg(arg[i], XmNinitialResourcesPersistent,
424 					 False); i++;
425 				XtSetArg(arg[i], XmNshadowThickness, 2); i++;
426 				if (u->modifier != NULL && u->keyname != NULL){
427 				    char acc[STR_BUF_SZ];
428 
429 				    (void) sprintf(acc, "%s<Key>%s",
430 						   u->modifier, u->keyname);
431 
432 				    XtSetArg(arg[i], XmNaccelerator, acc); i++;
433 				    XtSetArg(arg[i], XmNmnemonic,
434 					 XStringToKeysym(u->keyname)); i++;
435 				}
436 				w = XmCreatePushButton(
437 					(p->type == WTYPE_GEN) ?
438 						widgets.wwwwarp.genurls_menu :
439 						widgets.wwwwarp.discurls_menu,
440 					title,
441 					arg,
442 					i
443 				);
444 				XtManageChild(w);
445 				u->aux = (void *) w;
446 
447 				MEM_FREE(title);
448 
449 				register_activate_cb(w, wwwwarp_go_cddburl, u);
450 			}
451 		}
452 
453 		if (p->type == WTYPE_SUBMITURL) {
454 			if (cdinfo_cddb_ver() != 2 ||
455 			    s->qmode != QMODE_MATCH ||
456 			    app_data.cdinfo_inetoffln)
457 				sens = False;
458 		}
459 
460 		XtSetSensitive((Widget) p->aux, sens);
461 
462 		if (p->submenu != NULL)
463 			/* Recurse into submenu */
464 			wwwwarp_sel_cfg_menu(p->submenu, dbp, s);
465 	}
466 }
467 
468 
469 /***********************
470  *   public routines   *
471  ***********************/
472 
473 
474 /*
475  * wwwwarp_init
476  *	Initialize the wwwWarp subsystem.
477  *
478  * Args:
479  *	s - Pointer to the curstat_t structure.
480  *
481  * Return:
482  *	Nothing.
483  */
484 /*ARGSUSED*/
485 void
wwwwarp_init(curstat_t * s)486 wwwwarp_init(curstat_t *s)
487 {
488 	cdinfo_incore_t	*dbp;
489 	w_ent_t		*p;
490 	int		i;
491 	Arg		arg[10];
492 
493 	/* Set up wwwWarp menu basic structure */
494 	cdinfo_wwwwarp_parmload();
495 
496 	dbp = dbprog_curdb(s);
497 
498 	/* Find the root wwwWarp menu */
499 	for (p = dbp->wwwwarp_list; p != NULL; p = p->nextmenu) {
500 		if (strcmp(p->name, "wwwWarp") == 0) {
501 			wwwwarp_menu = p;
502 			break;
503 		}
504 	}
505 
506 	if (wwwwarp_menu == NULL) {
507 		DBGPRN(DBG_GEN)(errfp, "No wwwWarp menu defined in %s.\n",
508 			WWWWARP_CFG);
509 		return;
510 	}
511 
512 	/* Create pulldown menu widget for the top level wwwWarp selector */
513 	i = 0;
514 	XtSetArg(arg[i], XmNshadowThickness, 2); i++;
515 	widgets.wwwwarp.menu = XmCreatePulldownMenu(
516 		widgets.main.wwwwarp_btn,
517 		"wwwWarpMenu",
518 		arg,
519 		i
520 	);
521 
522 	XtVaSetValues(widgets.main.wwwwarp_btn,
523 		XmNsubMenuId, widgets.wwwwarp.menu,
524 		NULL
525 	);
526 
527 	/* Create general sites menu */
528 	i = 0;
529 	XtSetArg(arg[i], XmNshadowThickness, 2); i++;
530 	widgets.wwwwarp.genurls_menu = XmCreatePulldownMenu(
531 		widgets.main.dbmode_ind,
532 		"genUrlsMenu",
533 		arg,
534 		i
535 	);
536 
537 	/* Create album-specific sites menu */
538 	i = 0;
539 	XtSetArg(arg[i], XmNshadowThickness, 2); i++;
540 	widgets.wwwwarp.discurls_menu = XmCreatePulldownMenu(
541 		widgets.main.dbmode_ind,
542 		"discUrlsMenu",
543 		arg,
544 		i
545 	);
546 
547 	/* Set up the menu entries */
548 	if (!wwwwarp_menu_setup(widgets.wwwwarp.menu, p, s))
549 		return;
550 
551 	wwwwarp_initted = TRUE;
552 
553 	/* Configure the wwwWarp menu entries */
554 	wwwwarp_sel_cfg(s);
555 }
556 
557 
558 /*
559  * wwwwarp_sel_cfg
560  *	Configure the wwwwarp menu
561  *
562  * Args:
563  *	s - Pointer to the curstat_t structure.
564  *
565  * Return:
566  *	Nothing.
567  */
568 void
wwwwarp_sel_cfg(curstat_t * s)569 wwwwarp_sel_cfg(curstat_t *s)
570 {
571 	cdinfo_incore_t	*dbp;
572 	cdinfo_ret_t	ret;
573 
574 	if (!wwwwarp_initted)
575 		return;
576 
577 	dbp = dbprog_curdb(s);
578 
579 	/* Pop down wwwWarp menu if necessary */
580 	if (XtIsManaged(widgets.wwwwarp.menu))
581 		XtUnmanageChild(widgets.wwwwarp.menu);
582 
583 	/* Configure the menu items' sensitivity */
584 	wwwwarp_sel_cfg_menu(wwwwarp_menu, dbp, s);
585 
586 	if (s->qmode == QMODE_MATCH &&
587 	    (app_data.discog_mode & DISCOG_GEN_CDINFO)) {
588 		/* New disc inserted and a CD info query is successful:
589 		 * generate new discography
590 		 */
591 		if ((ret = cdinfo_gen_discog(s)) != 0) {
592 			DBGPRN(DBG_CDI)(errfp,
593 				"cdinfo_gen_discog: status=%d arg=%d\n",
594 				CDINFO_GET_STAT(ret), CDINFO_GET_ARG(ret));
595 		}
596 	}
597 }
598 
599 
600 /*
601  * wwwwarp_disc_url_clear
602  *	Clear out album-specific URLs menu entries.  Used when ejecting
603  *	the CD, changing CDs, or re-loading the CD info.
604  *
605  * Args:
606  *	s - Pointer to the curstat_t structure.
607  *
608  * Return:
609  *	Nothing.
610  */
611 void
wwwwarp_disc_url_clear(curstat_t * s)612 wwwwarp_disc_url_clear(curstat_t *s)
613 {
614 	cdinfo_incore_t	*dbp;
615 	cdinfo_url_t	*p;
616 
617 	if (!wwwwarp_initted)
618 		return;
619 
620 	dbp = dbprog_curdb(s);
621 
622 	/* Pop down wwwWarp menu if necessary */
623 	if (XtIsManaged(widgets.wwwwarp.menu))
624 		XtUnmanageChild(widgets.wwwwarp.menu);
625 
626 	for (p = dbp->disc_url_list; p != NULL; p = p->next) {
627 		if (p->aux == NULL)
628 			continue;
629 
630 		XtUnmanageChild((Widget) p->aux);
631 		XtDestroyWidget((Widget) p->aux);
632 		p->aux = NULL;
633 	}
634 }
635 
636 
637 /**************** vv Callback routines vv ****************/
638 
639 
640 /*
641  * wwwwarp_motd
642  *	Message of the day menu button callback function
643  */
644 /*ARGSUSED*/
645 void
wwwwarp_motd(Widget w,XtPointer client_data,XtPointer call_data)646 wwwwarp_motd(Widget w, XtPointer client_data, XtPointer call_data)
647 {
648 	/* Change to busy cursor */
649 	cd_busycurs(TRUE, CURS_ALL);
650 
651 	/* Get MOTD */
652 	motd_get((byte_t *) 1);
653 
654 	/* Change to normal cursor */
655 	cd_busycurs(FALSE, CURS_ALL);
656 }
657 
658 
659 /*
660  * wwwwarp_go_musicbrowser
661  *	Music Browser menu button callback function
662  */
663 /*ARGSUSED*/
664 void
wwwwarp_go_musicbrowser(Widget w,XtPointer client_data,XtPointer call_data)665 wwwwarp_go_musicbrowser(Widget w, XtPointer client_data, XtPointer call_data)
666 {
667 	w_ent_t		*p = (w_ent_t *)(void *) client_data;
668 	curstat_t	*s = curstat_addr();
669 	char		*errmsg;
670 	cdinfo_incore_t	*dbp;
671 	cdinfo_ret_t	ret;
672 	int		msglen;
673 
674 	/* Change to busy cursor */
675 	cd_busycurs(TRUE, CURS_ALL);
676 
677 	/* Load CD informtion */
678 	if ((ret = cdinfo_go_musicbrowser(s)) != 0) {
679 		DBGPRN(DBG_CDI)(errfp,
680 			"cdinfo_go_musicbrowser: status=%d arg=%d\n",
681 			CDINFO_GET_STAT(ret), CDINFO_GET_ARG(ret));
682 	}
683 
684 	/* Change to normal cursor */
685 	cd_busycurs(FALSE, CURS_ALL);
686 
687 	if (ret == 0) {
688 		dbp = dbprog_curdb(s);
689 
690 		if ((dbp->flags & CDINFO_NEEDREG) != 0) {
691 			/* User not registered with CDDB:
692                          * Pop up CDDB user registration dialog
693 			 */
694                         userreg_do_popup(s, TRUE);
695                 }
696 	}
697 	else {
698 		msglen = strlen(app_data.str_cannotinvoke) +
699 			 strlen(p->desc) + 4;
700 
701 		if ((errmsg = (char *) MEM_ALLOC("errmsg", msglen)) == NULL) {
702 			CD_FATAL(app_data.str_nomemory);
703 			return;
704 		}
705 
706 		(void) sprintf(errmsg, app_data.str_cannotinvoke, p->desc);
707 
708 		/* Pop up info message dialog */
709 		CD_INFO(errmsg);
710 
711 		MEM_FREE(errmsg);
712 	}
713 }
714 
715 
716 /*
717  * wwwwarp_go_url
718  *	Goto URL menu button callback function
719  */
720 /*ARGSUSED*/
721 void
wwwwarp_go_url(Widget w,XtPointer client_data,XtPointer call_data)722 wwwwarp_go_url(Widget w, XtPointer client_data, XtPointer call_data)
723 {
724 	w_ent_t		*menu = (w_ent_t *)(void *) client_data;
725 	char		*url,
726 			*errmsg;
727 	curstat_t	*s = curstat_addr();
728 	cdinfo_ret_t	ret;
729 	int		n,
730 			trkpos,
731 			sel_pos,
732 			msglen;
733 
734 	if (menu == NULL)
735 		return;
736 
737 	/* Change to busy cursor */
738 	cd_busycurs(TRUE, CURS_ALL);
739 
740 	if (menu->type == WTYPE_DISCOG &&
741 	    (app_data.discog_mode & DISCOG_GEN_WWWWARP)) {
742 		/* Generate new discography */
743 		if ((ret = cdinfo_gen_discog(s)) != 0) {
744 			DBGPRN(DBG_CDI)(errfp,
745 				"cdinfo_gen_discog: status=%d arg=%d\n",
746 				CDINFO_GET_STAT(ret), CDINFO_GET_ARG(ret));
747 		}
748 	}
749 
750 	/* Do template to URL conversion */
751 	sel_pos = dbprog_curseltrk(s);
752 
753 	if (sel_pos > 0)
754 		/* A track is selected: use it for the track title */
755 		trkpos = sel_pos - 1;
756 	else
757 		/* Use current playing track for the track title, if playing */
758 		trkpos = di_curtrk_pos(s);
759 
760 	n = cdinfo_url_len(menu->arg, &menu->attrib, &trkpos);
761 
762 	if ((url = (char *) MEM_ALLOC("wwwwarp_go_url", n)) == NULL) {
763 		CD_FATAL(app_data.str_nomemory);
764 		return;
765 	}
766 
767 	/* Make the URL from template */
768 	cdinfo_tmpl_to_url(s, menu->arg, url, trkpos);
769 
770 	/* Load CD informtion */
771 	if ((ret = cdinfo_go_url(url)) != 0) {
772 		DBGPRN(DBG_CDI)(errfp, "cdinfo_go_url: status=%d arg=%d\n",
773 			CDINFO_GET_STAT(ret), CDINFO_GET_ARG(ret));
774 	}
775 
776 	MEM_FREE(url);
777 
778 	/* Change to normal cursor */
779 	cd_busycurs(FALSE, CURS_ALL);
780 
781 	if (ret != 0) {
782 		msglen = strlen(app_data.str_cannotinvoke) +
783 			 strlen(menu->desc) + 4;
784 
785 		if ((errmsg = (char *) MEM_ALLOC("errmsg", msglen)) == NULL) {
786 			CD_FATAL(app_data.str_nomemory);
787 			return;
788 		}
789 
790 		(void) sprintf(errmsg, app_data.str_cannotinvoke, menu->desc);
791 
792 		/* Pop up info message dialog */
793 		CD_INFO(errmsg);
794 
795 		MEM_FREE(errmsg);
796 	}
797 }
798 
799 
800 /*
801  * wwwwarp_go_cddburl
802  *	CDDB URL menu button callback function
803  */
804 /*ARGSUSED*/
805 void
wwwwarp_go_cddburl(Widget w,XtPointer client_data,XtPointer call_data)806 wwwwarp_go_cddburl(Widget w, XtPointer client_data, XtPointer call_data)
807 {
808 	curstat_t	*s = curstat_addr();
809 	cdinfo_incore_t	*dbp;
810 	cdinfo_url_t	*p;
811 	cdinfo_ret_t	ret;
812 	char		*errmsg;
813 	int		i;
814 	int		msglen;
815 
816 	dbp = dbprog_curdb(s);
817 
818 	/* Try the general URLs list */
819 	for (i = 1, p = dbp->gen_url_list; p != NULL; p = p->next, i++) {
820 		if (p == (cdinfo_url_t *)(void *) client_data)
821 			break;
822 	}
823 	if (p == NULL) {
824 		/* Try the album-specific URLs list */
825 		for (i = 1, p = dbp->disc_url_list; p != NULL;
826 		     p = p->next, i++) {
827 			if (p == (cdinfo_url_t *)(void *) client_data)
828 				break;
829 		}
830 	}
831 
832 	if (p == NULL)
833 		/* This shouldn't happen */
834 		return;
835 
836 	/* Change to busy cursor */
837 	cd_busycurs(TRUE, CURS_ALL);
838 
839 	/* Load CD informtion */
840 	if ((ret = cdinfo_go_cddburl(s, p->wtype, i)) != 0) {
841 		DBGPRN(DBG_CDI)(errfp, "cdinfo_go_cddburl: status=%d arg=%d\n",
842 			CDINFO_GET_STAT(ret), CDINFO_GET_ARG(ret));
843 	}
844 
845 	/* Change to normal cursor */
846 	cd_busycurs(FALSE, CURS_ALL);
847 
848 	if (ret == 0) {
849 		if ((dbp->flags & CDINFO_NEEDREG) != 0) {
850 			/* User not registered with CDDB:
851                          * Pop up CDDB user registration dialog
852 			 */
853                         userreg_do_popup(s, TRUE);
854                 }
855 	}
856 	else {
857 		msglen = strlen(app_data.str_cannotinvoke) +
858 			 strlen(p->disptext) + 4;
859 
860 		if ((errmsg = (char *) MEM_ALLOC("errmsg", msglen)) == NULL) {
861 			CD_FATAL(app_data.str_nomemory);
862 			return;
863 		}
864 
865 		(void) sprintf(errmsg, app_data.str_cannotinvoke, p->disptext);
866 
867 		/* Pop up info message dialog */
868 		CD_INFO(errmsg);
869 
870 		MEM_FREE(errmsg);
871 	}
872 }
873 
874 
875 /*
876  * wwwwarp_submit_url
877  *	CDDB Submit URL menu button callback.
878  */
879 /*ARGSUSED*/
880 void
wwwwarp_submit_url(Widget w,XtPointer client_data,XtPointer call_data)881 wwwwarp_submit_url(Widget w, XtPointer client_data, XtPointer call_data)
882 {
883 	static bool_t	first = TRUE;
884 
885 	if (XtIsManaged(widgets.submiturl.form))
886 		/* Already popped up */
887 		return;
888 
889 	set_text_string(widgets.submiturl.categ_txt, "Fan Site", FALSE);
890 	set_text_string(widgets.submiturl.name_txt, "", FALSE);
891 	set_text_string(widgets.submiturl.url_txt, "http://", FALSE);
892 	XmTextSetInsertionPosition(widgets.submiturl.url_txt, 7);
893 	set_text_string(widgets.submiturl.desc_txt, "", FALSE);
894 	XtSetSensitive(widgets.submiturl.submit_btn, False);
895 
896 	XtManageChild(widgets.submiturl.form);
897 
898 	if (first) {
899 		first = FALSE;
900 
901 		/* Set up dialog box position */
902 		cd_dialog_setpos(XtParent(widgets.submiturl.form));
903 	}
904 
905 	XtMapWidget(XtParent(widgets.submiturl.form));
906 
907 	/* Put focus on category text */
908 	XmProcessTraversal(widgets.submiturl.categ_txt, XmTRAVERSE_CURRENT);
909 }
910 
911 
912 /*
913  * wwwwarp_submit_url_chg
914  *	Text field change callback for submit URL window
915  */
916 /*ARGSUSED*/
917 void
wwwwarp_submit_url_chg(Widget w,XtPointer client_data,XtPointer call_data)918 wwwwarp_submit_url_chg(Widget w, XtPointer client_data, XtPointer call_data)
919 {
920 	XtSetSensitive(widgets.submiturl.submit_btn, True);
921 }
922 
923 
924 /*
925  * wwwwarp_submit_url_ok
926  *	CDDB Submit URL window Submit button callback.
927  */
928 /*ARGSUSED*/
929 void
wwwwarp_submit_url_submit(Widget w,XtPointer client_data,XtPointer call_data)930 wwwwarp_submit_url_submit(Widget w, XtPointer client_data, XtPointer call_data)
931 {
932 	curstat_t		*s = (curstat_t *)(void *) client_data;
933 	cdinfo_url_t		*up;
934 	char			*categ,
935 				*name,
936 				*url,
937 				*desc,
938 				*p;
939 	cdinfo_ret_t		ret;
940 	int			len;
941 
942 	/* Get category and do some checking */
943 	categ = get_text_string(widgets.submiturl.categ_txt, TRUE);
944 	if (categ == NULL || *categ == '\0') {
945 		CD_INFO(app_data.str_nocateg);
946 
947 		XmProcessTraversal(
948 			widgets.submiturl.categ_txt, XmTRAVERSE_CURRENT
949 		);
950 		return;
951 	}
952 
953 	/* Get name and do some checking */
954 	name = get_text_string(widgets.submiturl.name_txt, TRUE);
955 	if (name == NULL || *name == '\0') {
956 		CD_INFO(app_data.str_noname);
957 
958 		XmProcessTraversal(
959 			widgets.submiturl.name_txt, XmTRAVERSE_CURRENT
960 		);
961 		return;
962 	}
963 
964 	/* Get URL and do some checking */
965 	url = get_text_string(widgets.submiturl.url_txt, TRUE);
966 	if (url == NULL || *url == '\0' ||
967 	    ((ret = util_urlchk(url, &p, &len) & IS_REMOTE_URL) == 0)) {
968 		CD_INFO(app_data.str_invalurl);
969 
970 		XmProcessTraversal(
971 			widgets.submiturl.url_txt, XmTRAVERSE_CURRENT
972 		);
973 		return;
974 	}
975 
976 	/* Get description.  This field is optional */
977 	desc = get_text_string(widgets.submiturl.desc_txt, TRUE);
978 
979 	/* Allocate a submiturl structure */
980 	up = (cdinfo_url_t *)(void *) MEM_ALLOC(
981 		"cdinfo_submiturl_t", sizeof(cdinfo_url_t)
982 	);
983 	if (up == NULL) {
984 		CD_FATAL(app_data.str_nomemory);
985 		return;
986 	}
987 	(void) memset(up, 0, sizeof(cdinfo_url_t));
988 
989 	/* Fill with data */
990 	if (!util_newstr(&up->categ, categ)) {
991 		CD_FATAL(app_data.str_nomemory);
992 		return;
993 	}
994 	MEM_FREE(categ);
995 
996 	if (!util_newstr(&up->disptext, name)) {
997 		CD_FATAL(app_data.str_nomemory);
998 		return;
999 	}
1000 	MEM_FREE(name);
1001 
1002 	if (ret & NEED_PREPEND_HTTP) {
1003 		p = (char *) MEM_ALLOC("url", strlen(url) + 8);
1004 		if (p == NULL) {
1005 			CD_FATAL(app_data.str_nomemory);
1006 			return;
1007 		}
1008 		(void) sprintf(p, "http://%s", url);
1009 		up->href = p;
1010 		set_text_string(widgets.submiturl.url_txt, p, TRUE);
1011 	}
1012 	else if (ret & NEED_PREPEND_FTP) {
1013 		p = (char *) MEM_ALLOC("url", strlen(url) + 7);
1014 		if (p == NULL) {
1015 			CD_FATAL(app_data.str_nomemory);
1016 			return;
1017 		}
1018 		(void) sprintf(p, "ftp://%s", url);
1019 		up->href = p;
1020 		set_text_string(widgets.submiturl.url_txt, p, TRUE);
1021 	}
1022 	else if (ret & NEED_PREPEND_MAILTO) {
1023 		p = (char *) MEM_ALLOC("url", strlen(url) + 8);
1024 		if (p == NULL) {
1025 			CD_FATAL(app_data.str_nomemory);
1026 			return;
1027 		}
1028 		(void) sprintf(p, "mailto:%s", url);
1029 		up->href = p;
1030 		set_text_string(widgets.submiturl.url_txt, p, TRUE);
1031 	}
1032 	else if (!util_newstr(&up->href, url)) {
1033 		CD_FATAL(app_data.str_nomemory);
1034 		return;
1035 	}
1036 	MEM_FREE(url);
1037 
1038 	if (!util_newstr(&up->disptext, desc)) {
1039 		CD_FATAL(app_data.str_nomemory);
1040 		return;
1041 	}
1042 	if (desc != NULL)
1043 		MEM_FREE(desc);
1044 
1045 	up->type = "menu";
1046 
1047 	/* Change to watch cursor */
1048 	cd_busycurs(TRUE, CURS_ALL);
1049 
1050 	/* Submit the URL */
1051 	if ((ret = cdinfo_submit_url(s, up)) != 0) {
1052 		DBGPRN(DBG_CDI)(errfp,
1053 			"cdinfo_submit_url: status=%d arg=%d\n",
1054 			CDINFO_GET_STAT(ret), CDINFO_GET_ARG(ret));
1055 
1056 		CD_INFO(app_data.str_submiterr);
1057 
1058 		/* Put focus on OK button */
1059 		XmProcessTraversal(
1060 			widgets.submiturl.ok_btn, XmTRAVERSE_CURRENT
1061 		);
1062 	}
1063 	else
1064 		CD_INFO_AUTO(app_data.str_submitok);
1065 
1066 	cd_busycurs(FALSE, CURS_ALL);
1067 
1068 	/* Free data structure */
1069 	MEM_FREE(up->categ);
1070 	MEM_FREE(up->disptext);
1071 	MEM_FREE(up->href);
1072 	if (up->desc != NULL)
1073 		MEM_FREE(up->desc);
1074 	MEM_FREE(up);
1075 
1076 	if (ret == 0) {
1077 		/* Revert to default */
1078 		set_text_string(
1079 			widgets.submiturl.categ_txt, "Fan Site", FALSE
1080 		);
1081 		set_text_string(
1082 			widgets.submiturl.name_txt, "", FALSE
1083 		);
1084 		set_text_string(
1085 			widgets.submiturl.url_txt, "http://", FALSE
1086 		);
1087 		XmTextSetInsertionPosition(widgets.submiturl.url_txt, 7);
1088 		set_text_string(widgets.submiturl.desc_txt, "", FALSE);
1089 		XtSetSensitive(widgets.submiturl.submit_btn, False);
1090 
1091 		/* Put focus on categ text */
1092 		XmProcessTraversal(
1093 			widgets.submiturl.categ_txt, XmTRAVERSE_CURRENT
1094 		);
1095 	}
1096 }
1097 
1098 
1099 /*
1100  * wwwwarp_submit_url_ok
1101  *	CDDB Submit URL window OK button callback.
1102  */
1103 /*ARGSUSED*/
1104 void
wwwwarp_submit_url_ok(Widget w,XtPointer client_data,XtPointer call_data)1105 wwwwarp_submit_url_ok(Widget w, XtPointer client_data, XtPointer call_data)
1106 {
1107 	XtUnmapWidget(XtParent(widgets.submiturl.form));
1108 	XtUnmanageChild(widgets.submiturl.form);
1109 }
1110 
1111 
1112 /*
1113  * wwwwarp_focus_next
1114  *	Change focus to the next widget on done
1115  */
1116 /*ARGSUSED*/
1117 void
wwwwarp_focus_next(Widget w,XtPointer client_data,XtPointer call_data)1118 wwwwarp_focus_next(Widget w, XtPointer client_data, XtPointer call_data)
1119 {
1120 	Widget	nextw;
1121 
1122 	if (w == widgets.submiturl.categ_txt)
1123 		nextw = widgets.submiturl.name_txt;
1124 	else if (w == widgets.submiturl.name_txt)
1125 		nextw = widgets.submiturl.url_txt;
1126 	else if (w == widgets.submiturl.url_txt)
1127 		nextw = widgets.submiturl.desc_txt;
1128 	else
1129 		return;
1130 
1131 	/* Put the input focus on the next widget */
1132 	XmProcessTraversal(nextw, XmTRAVERSE_CURRENT);
1133 }
1134 
1135 
1136 /**************** ^^ Callback routines ^^ ****************/
1137 
1138