static int load_rules(struct userdata *u) { FILE *f; int n = 0; int ret = -1; char buf_name[256], buf_volume[256], buf_sink[256], buf_source[256]; char *ln = buf_name; f = u->table_file ? fopen(u->table_file, "r") : pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "r"); if (!f) { if (errno == ENOENT) { pa_log_info("starting with empty ruleset."); ret = 0; } else pa_log("failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); goto finish; } pa_lock_fd(fileno(f), 1); while (!feof(f)) { struct rule *rule; pa_cvolume v; pa_bool_t v_is_set; if (!fgets(ln, sizeof(buf_name), f)) break; n++; pa_strip_nl(ln); if (ln[0] == '#') continue; if (ln == buf_name) { ln = buf_volume; continue; } if (ln == buf_volume) { ln = buf_sink; continue; } if (ln == buf_sink) { ln = buf_source; continue; } pa_assert(ln == buf_source); if (buf_volume[0]) { if (!parse_volume(buf_volume, &v)) { pa_log("parse failure in %s:%u, stopping parsing", u->table_file, n); goto finish; } v_is_set = TRUE; } else v_is_set = FALSE; ln = buf_name; if (pa_hashmap_get(u->hashmap, buf_name)) { pa_log("double entry in %s:%u, ignoring", u->table_file, n); continue; } rule = pa_xnew(struct rule, 1); rule->name = pa_xstrdup(buf_name); if ((rule->volume_is_set = v_is_set)) rule->volume = v; rule->sink = buf_sink[0] ? pa_xstrdup(buf_sink) : NULL; rule->source = buf_source[0] ? pa_xstrdup(buf_source) : NULL; pa_hashmap_put(u->hashmap, rule->name, rule); } if (ln != buf_name) { pa_log("invalid number of lines in %s.", u->table_file); goto finish; } ret = 0; finish: if (f) { pa_lock_fd(fileno(f), 0); fclose(f); } return ret; }
static void parse_options(int argc, char **argv, struct cmdopt *cmdopt) { struct option options[] = { { "help" , no_argument , NULL, 'h' }, { "daemon" , no_argument , NULL, 'd' }, { "interactive" , no_argument , NULL, 'i' }, { "8kHz" , no_argument , NULL, '8' }, { "user" , required_argument, NULL, 'u' }, { "standard" , required_argument, NULL, 's' }, { "buflen" , required_argument, NULL, 'b' }, { "minreq" , required_argument, NULL, 'r' }, { "statistics" , no_argument , NULL, 'S' }, { "tag-dtmf" , required_argument, NULL, 'D' }, { "tag-indicator" , required_argument, NULL, 'I' }, { "tag-notif" , required_argument, NULL, 'N' }, { "volume-dtmf" , required_argument, NULL, '1' }, { "volume-indicator", required_argument, NULL, '2' }, { "volume-notif" , required_argument, NULL, '3' }, #define OPTS "du:s:b:r:hi8SD:I:N:" { NULL , 0 , NULL, 0 } }; int option; struct passwd *pwd; long int t; char *e; while ((option = getopt_long(argc, argv, OPTS, options, NULL)) != -1) { switch (option) { case 'h': usage(argc, argv, 0); break; case 'd': cmdopt->daemon = 1; break; case 'i': cmdopt->interactive = 1; break; case '8': cmdopt->sample_rate = 8000; break; case 'u': if (!optarg && !*optarg) usage(argc, argv, EINVAL); cmdopt->uid = -1; while ((pwd = getpwent()) != NULL) { if (!strcmp(optarg, pwd->pw_name)) { cmdopt->uid = pwd->pw_uid; break; } } if (cmdopt->uid < 0) { printf("invalid username: %s\n", optarg); usage(argc, argv, EINVAL); } break; case 's': if (!strcmp(optarg, "cept")) cmdopt->standard = STD_CEPT; else if (!strcmp(optarg, "ansi")) cmdopt->standard = STD_ANSI; else if (!strcmp(optarg, "japan")) cmdopt->standard = STD_JAPAN; else if (!strcmp(optarg, "atnt")) cmdopt->standard = STD_ATNT; else { printf("invalid standard '%s'\n", optarg); usage(argc, argv, EINVAL); } break; case 'b': t = strtol(optarg, &e, 10); if (*e == '\0' && t > 0 && t <= 10000) cmdopt->buflen = t; else { printf("invalid buffer length '%s' msec\n", optarg); usage(argc, argv, EINVAL); } break; case 'r': t = strtol(optarg, &e, 10); if (*e == '\0' && t > 0 && t <= 1000) cmdopt->minreq = t; else { printf("invalid min.request length '%s' msec\n", optarg); usage(argc, argv, EINVAL); } break; case 'S': cmdopt->statistics = 1; break; case 'D': cmdopt->dtmf_tags = optarg; break; case 'I': cmdopt->ind_tags = optarg; break; case 'N': cmdopt->notif_tags = optarg; break; case '1': cmdopt->dtmf_volume = parse_volume(optarg); break; case '2': cmdopt->ind_volume = parse_volume(optarg); break; case '3': cmdopt->notif_volume = parse_volume(optarg); break; default: usage(argc, argv, EINVAL); break; } } if (!cmdopt->daemon && cmdopt->uid > 0) { printf("Warning: -d is not present; ignoring -u option\n"); } }
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; }