void execcmd(const char * cmd, char * reply) { char arg[1024], * ptr; unsigned ncmd; const char * known [] = { "play", "love", "ban", "skip", "quit", "info", "pause", "discovery", "tag-artist", "tag-album", "tag-track", "artist-tags", "album-tags", "track-tags", "stop", }; memset(arg, 0, sizeof(arg)); memset(reply, 0, REPLYBUFSIZE); for(ncmd = 0; ncmd < (sizeof(known) / sizeof(char *)); ++ncmd) { if(!strncmp(known[ncmd], cmd, strlen(known[ncmd]))) break; } switch(ncmd) { case (sizeof(known) / sizeof(char *)): strncpy(reply, "ERROR", REPLYBUFSIZE); break; case 0: if(sscanf(cmd, "play %128[a-zA-Z0-9:/_ %,*.-]", arg) == 1) { char * url; decode(arg, & url); station(url); free(url); } break; case 1: rate("L"); break; case 2: rate("B"); break; case 3: rate("S"); break; case 4: quit(); case 5: if(* (cmd + 5)) strncpy(reply, meta(cmd + 5, 0, & track), REPLYBUFSIZE); else if(haskey(& rc, "np-file-format")) strncpy( reply, meta(value(& rc, "np-file-format"), 0, & track), REPLYBUFSIZE ); break; case 6: if(playfork) { if(pausetime) { kill(playfork, SIGCONT); } else { time(& pausetime); kill(playfork, SIGSTOP); } } break; case 7: toggle(DISCOVERY); break; case 8: if(sscanf(cmd, "tag-artist %128s", arg) == 1) sendtag('a', arg, track); break; case 9: if(sscanf(cmd, "tag-album %128s", arg) == 1) sendtag('l', arg, track); break; case 10: if(sscanf(cmd, "tag-track %128s", arg) == 1) sendtag('t', arg, track); break; case 11: if((ptr = oldtags('a', track)) != NULL) { strncpy(reply, ptr, REPLYBUFSIZE); free(ptr); ptr = NULL; } break; case 12: if((ptr = oldtags('l', track)) != NULL) { strncpy(reply, ptr, REPLYBUFSIZE); free(ptr); ptr = NULL; } break; case 13: if((ptr = oldtags('t', track)) != NULL) { strncpy(reply, ptr, REPLYBUFSIZE); free(ptr); ptr = NULL; } break; case 14: if(playfork) { enable(STOPPED); kill(playfork, SIGUSR1); } break; } }
void tag(struct hash data) { char key, * tagstring; struct prompt setup = { .prompt = "Tags (comma separated): ", .line = NULL, .history = NULL, .callback = tagcomplete, }; if(!data.content) return; fputs("Tag (a)rtist, a(l)bum, (t)rack or (c)ancel?\n", stderr); while(!strchr("altc", (key = fetchkey(2)))); if(key == 'c') return; popular = merge(toptags(key, data), usertags(value(& rc, "username")), 0); setup.line = oldtags(key, data); assert((tagstring = strdup(readline(& setup))) != NULL); if(setup.line) { free(setup.line); setup.line = NULL; } purge(popular); popular = NULL; sendtag(key, tagstring, data); free(tagstring); } char * oldtags(char key, struct hash track) { unsigned length, x; char * tags = NULL, * url = calloc(512, sizeof(char)), * user = NULL, * artist = NULL, * arg = NULL, * file = NULL, ** resp; assert(url != NULL); switch(key) { case 'a': file = "artisttags.xml"; break; case 'l': file = "albumtags.xml"; break; case 't': default: file = "tracktags.xml"; } encode(value(& track, "creator"), & artist); stripslashes(artist); encode(value(& rc, "username"), & user); length = snprintf( url, 512, "http://ws.audioscrobbler.com/1.0/user/%s/%s?artist=%s", user, file, artist); free(user); free(artist); if(key == 'l') { encode(value(& track, "album"), & arg); stripslashes(arg); length += snprintf(url + length, 512 - length, "&album=%s", arg); } else if(key == 't') { encode(value(& track, "title"), & arg); stripslashes(arg); length += snprintf(url + length, 512 - length, "&track=%s", arg); } if(arg) free(arg); resp = fetch(url, NULL, NULL, NULL); free(url); if(!resp) return NULL; for(x = 0, length = 0; resp[x]; ++x) { char * pbeg = strstr(resp[x], "<name>"), * pend; if(pbeg) { pbeg += 6; pend = strstr(pbeg, "</name>"); if(pend) { char * thistag = strndup(pbeg, pend - pbeg); unsigned nlength = strlen(thistag) + length; assert(thistag != NULL); if(length) ++nlength; tags = realloc(tags, nlength + 1); assert(tags != NULL); sprintf(tags + length, "%s%s", length ? "," : "", thistag); free(thistag); length = nlength; } } } purge(resp); return tags; }
int execcmd(const char * cmd, char * reply) { char arg[1024], * ptr; unsigned ncmd; const char * known [] = { "play", "love", "ban", "skip", "quit", "info", "pause", "discovery", "tag-artist", "tag-album", "tag-track", "artist-tags", "album-tags", "track-tags", "stop", "volume-up", "volume-down", "volume", "rtp", "status", "unlove", "detach" }; memset(arg, 0, sizeof(arg)); memset(reply, 0, BUFSIZE); for(ncmd = 0; ncmd < (sizeof(known) / sizeof(char *)); ++ncmd) { if(!strncmp(known[ncmd], cmd, strlen(known[ncmd]))) break; } switch(ncmd) { case (sizeof(known) / sizeof(char *)): strncpy(reply, "ERROR", BUFSIZE); break; /* "play lastfm://station" */ case 0: if(sscanf(cmd, "play %128[a-zA-Z0-9:/_ %,*.+-]", arg) == 1) { char * url; decode(arg, & url); station(url); free(url); } break; /* Love currently played track. */ case 1: rate("L"); break; /* Ban currently played track. */ case 2: rate("B"); break; /* Skip track. */ case 3: rate("S"); break; /* Kill Shell.FM. */ case 4: quit(); /* "info FORMAT" - returns the format string with the meta data filled in. */ case 5: if(* (cmd + 5)) strncpy(reply, meta(cmd + 5, 0, & track), BUFSIZE); else if(haskey(& rc, "np-file-format")) strncpy( reply, meta(value(& rc, "np-file-format"), 0, & track), BUFSIZE ); break; /* Pause playback. */ case 6: if(playfork) { if(pausetime) { kill(playfork, SIGCONT); } else { time(& pausetime); kill(playfork, SIGSTOP); } } break; /* Toggle discovery mode. Returns "DISCOVERY <ON|OFF>" */ case 7: toggle(DISCOVERY); snprintf( reply, BUFSIZE, "DISCOVERY %s", enabled(DISCOVERY) ? "ON" : "OFF" ); break; /* "tag-artist tag1,tag2,..." - tag the artist of the current track. */ case 8: if(sscanf(cmd, "tag-artist %128s", arg) == 1) sendtag('a', arg, track); break; /* "tag-album tag1,tag2,..." - tag the album of the current track. */ case 9: if(sscanf(cmd, "tag-album %128s", arg) == 1) sendtag('l', arg, track); break; /* "tag-track tag1,tag2,..." - tag the current track. */ case 10: if(sscanf(cmd, "tag-track %128s", arg) == 1) sendtag('t', arg, track); break; /* Return comma-separated list of the current artists tags. */ case 11: if((ptr = oldtags('a', track)) != NULL) { strncpy(reply, ptr, BUFSIZE); free(ptr); ptr = NULL; } break; /* Return comma-separated list of the current albums tags. */ case 12: if((ptr = oldtags('l', track)) != NULL) { strncpy(reply, ptr, BUFSIZE); free(ptr); ptr = NULL; } break; /* Return comma-separated list of the current tracks tags. */ case 13: if((ptr = oldtags('t', track)) != NULL) { strncpy(reply, ptr, BUFSIZE); free(ptr); ptr = NULL; } break; /* Stop playback. */ case 14: if(playfork) { enable(STOPPED); kill(playfork, SIGUSR1); } break; /* Increase absolute volume (0-64) by 1. */ case 15: volume_up(); break; /* Decrease absolute volume (0-64) by 1. */ case 16: volume_down(); break; /* Set volume. "volume 32" - set absolute volume (0-64) to 32 (50%). "volume %50" - same, but using percentual volume. "volume +1" - same as "volume_up". "volume -1" - same as "volume_down". Returns absolute volume ("VOLUME 32"). */ case 17: parse_volume(cmd); snprintf(reply, BUFSIZE, "VOLUME %d", volume); break; /* Toggle RTP (report to profile, "scrobbling"). Returns "RTP <ON|OFF>". */ case 18: /* RTP on/off */ toggle(RTP); snprintf(reply, BUFSIZE, "RTP %s", enabled(RTP) ? "ON" : "OFF"); break; /* Get current status. Returns on of "PAUSE", "PLAYING" and "STOPPED". */ case 19: strncpy(reply, PLAYBACK_STATUS, BUFSIZE); break; /* Unlove currently played track. */ case 20: rate("U"); break; /* Detach from network interface. */ case 21: return 1; } return 0; }