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