X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/763d5e6ad88ef3ba1cd1d7742d060e4f1e54c6b8..a55c70c74f75d7b745d3560c862dac69b45ec367:/clients/disorder.c diff --git a/clients/disorder.c b/clients/disorder.c index f7b4130..1491b2e 100644 --- a/clients/disorder.c +++ b/clients/disorder.c @@ -1,6 +1,6 @@ /* * This file is part of DisOrder. - * Copyright (C) 2004, 2005, 2006 Richard Kettlewell + * Copyright (C) 2004, 2005, 2006, 2007 Richard Kettlewell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include "configuration.h" #include "syscalls.h" @@ -59,7 +61,11 @@ static const struct option options[] = { { "version", no_argument, 0, 'V' }, { "config", required_argument, 0, 'c' }, { "debug", no_argument, 0, 'd' }, + { "local", no_argument, 0, 'l' }, + { "no-per-user-config", no_argument, 0, 'N' }, { "help-commands", no_argument, 0, 'H' }, + { "user", required_argument, 0, 'u' }, + { "password", required_argument, 0, 'p' }, { 0, 0, 0, 0 } }; @@ -72,6 +78,7 @@ static void help(void) { " --help-commands, -H List commands\n" " --version, -V Display version number\n" " --config PATH, -c PATH Set configuration file\n" + " --local, -l Force connection to local server\n" " --debug, -d Turn on debugging\n"); xfclose(stdout); exit(0); @@ -79,7 +86,7 @@ static void help(void) { /* display version number and terminate */ static void version(void) { - xprintf("disorder version %s\n", disorder_version_string); + xprintf("%s", disorder_version_string); xfclose(stdout); exit(0); } @@ -148,6 +155,8 @@ static void cf_shutdown(disorder_client *c, static void cf_reconfigure(disorder_client *c, char attribute((unused)) **argv) { + /* Re-check configuration for server */ + if(config_read(1)) fatal(0, "cannot read configuration"); if(disorder_reconfigure(c)) exit(EXIT_FAILURE); } @@ -327,9 +336,9 @@ static int isarg_filename(const char *s) { return s[0] == '/'; } -static void cf_authorize(disorder_client attribute((unused)) *c, +static void cf_authorize(disorder_client *c, char **argv) { - if(!authorize(argv[0])) + if(!authorize(c, argv[0])) auto_reconfigure = 1; } @@ -360,6 +369,15 @@ static void cf_tags(disorder_client *c, xprintf("%s\n", nullcheck(utf82mb(*vec++))); } +static void cf_users(disorder_client *c, + char attribute((unused)) **argv) { + char **vec; + + if(disorder_users(c, &vec, 0)) exit(EXIT_FAILURE); + while(*vec) + xprintf("%s\n", nullcheck(utf82mb(*vec++))); +} + static void cf_get_global(disorder_client *c, char **argv) { char *value; @@ -375,6 +393,60 @@ static void cf_unset_global(disorder_client *c, char **argv) { if(disorder_unset_global(c, argv[0])) exit(EXIT_FAILURE); } +static int isarg_integer(const char *s) { + if(!*s) return 0; + while(*s) { + if(!isdigit((unsigned char)*s)) + return 0; + ++s; + } + return 1; +} + +static void cf_new(disorder_client *c, + char **argv) { + char **vec; + + if(disorder_new_tracks(c, &vec, 0, argv[0] ? atoi(argv[0]) : 0)) + exit(EXIT_FAILURE); + while(*vec) + xprintf("%s\n", nullcheck(utf82mb(*vec++))); +} + +static void cf_rtp_address(disorder_client *c, + char attribute((unused)) **argv) { + char *address, *port; + + if(disorder_rtp_address(c, &address, &port)) exit(EXIT_FAILURE); + xprintf("address: %s\nport: %s\n", address, port); +} + +static void cf_adduser(disorder_client *c, + char **argv) { + if(disorder_adduser(c, argv[0], argv[1])) + exit(EXIT_FAILURE); +} + +static void cf_deluser(disorder_client *c, + char **argv) { + if(disorder_deluser(c, argv[0])) + exit(EXIT_FAILURE); +} + +static void cf_edituser(disorder_client *c, + char **argv) { + if(disorder_edituser(c, argv[0], argv[1], argv[2])) + exit(EXIT_FAILURE); +} + +static void cf_userinfo(disorder_client *c, char **argv) { + char *s; + + if(disorder_userinfo(c, argv[0], argv[1], &s)) + exit(EXIT_FAILURE); + xprintf("%s\n", nullcheck(utf82mb(s))); +} + static const struct command { const char *name; int min, max; @@ -382,18 +454,24 @@ static const struct command { int (*isarg)(const char *); const char *argstr, *desc; } commands[] = { + { "adduser", 2, 2, cf_adduser, 0, "USER PASSWORD", + "Create a new user" }, { "allfiles", 1, 2, cf_allfiles, isarg_regexp, "DIR [~REGEXP]", "List all files and directories in DIR" }, { "authorize", 1, 1, cf_authorize, 0, "USER", "Authorize USER to connect to the server" }, { "become", 1, 1, cf_become, 0, "USER", "Become user USER" }, + { "deluser", 1, 1, cf_deluser, 0, "USER", + "Delete a user" }, { "dirs", 1, 2, cf_dirs, isarg_regexp, "DIR [~REGEXP]", "List directories in DIR" }, { "disable", 0, 0, cf_disable, 0, "", "Disable play" }, { "disable-random", 0, 0, cf_random_disable, 0, "", "Disable random play" }, + { "edituser", 3, 3, cf_edituser, 0, "USER PROPERTY VALUE", + "Set a property of a user" }, { "enable", 0, 0, cf_enable, 0, "", "Enable play" }, { "enable-random", 0, 0, cf_random_enable, 0, "", @@ -412,6 +490,8 @@ static const struct command { "Copy event log to stdout" }, { "move", 2, 2, cf_move, 0, "TRACK DELTA", "Move a track in the queue" }, + { "new", 0, 1, cf_new, isarg_integer, "[MAX]", + "Get the most recently added MAX tracks" }, { "part", 3, 3, cf_part, 0, "TRACK CONTEXT PART", "Find a track name part" }, { "pause", 0, 0, cf_pause, 0, "", @@ -441,6 +521,8 @@ static const struct command { "Resolve alias for TRACK" }, { "resume", 0, 0, cf_resume, 0, "", "Resume after a pause" }, + { "rtp-address", 0, 0, cf_rtp_address, 0, "", + "Report server's broadcast address" }, { "scratch", 0, 0, cf_scratch, 0, "", "Scratch the currently playing track" }, { "scratch-id", 1, 1, cf_scratch, 0, "ID", @@ -463,6 +545,10 @@ static const struct command { "Unset a preference" }, { "unset-global", 1, 1, cf_unset_global, 0, "NAME", "Unset a global preference" }, + { "userinfo", 2, 2, cf_userinfo, 0, "USER PROPERTY", + "Get a property of as user" }, + { "users", 0, 0, cf_users, 0, "", + "List all users" }, { "version", 0, 0, cf_version, 0, "", "Display the server version" }, }; @@ -495,27 +581,41 @@ static void help_commands(void) { } int main(int argc, char **argv) { - int n, i, j; + int n, i, j, local = 0; disorder_client *c = 0; - const char *s; int status = 0; struct vector args; + const char *user = 0, *password = 0; - mem_init(1); + mem_init(); + /* garbage-collect PCRE's memory */ + pcre_malloc = xmalloc; + pcre_free = xfree; if(!setlocale(LC_CTYPE, "")) fatal(errno, "error calling setlocale"); - while((n = getopt_long(argc, argv, "hVc:dHL", options, 0)) >= 0) { + while((n = getopt_long(argc, argv, "hVc:dHlNu:p:", options, 0)) >= 0) { switch(n) { case 'h': help(); case 'H': help_commands(); case 'V': version(); case 'c': configfile = optarg; break; case 'd': debugging = 1; break; + case 'l': local = 1; break; + case 'N': config_per_user = 0; break; + case 'u': user = optarg; break; + case 'p': password = optarg; break; default: fatal(0, "invalid option"); } } - if(config_read()) fatal(0, "cannot read configuration"); + if(config_read(0)) fatal(0, "cannot read configuration"); + if(user) { + config->username = user; + config->password = 0; + } + if(password) + config->password = password; + if(local) + config->connect.n = 0; if(!(c = disorder_new(1))) exit(EXIT_FAILURE); - s = config_get_file("socket"); if(disorder_connect(c)) exit(EXIT_FAILURE); n = optind; /* accumulate command args */