X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/bdd2a99650780a1ef4a9e788eaabbc5e810cc39c..ff92debd29cab62e0f824ca3e40914f64e0bcb05:/cgi/actions.c diff --git a/cgi/actions.c b/cgi/actions.c index 4728503..6f094cb 100644 --- a/cgi/actions.c +++ b/cgi/actions.c @@ -2,28 +2,28 @@ * This file is part of DisOrder. * Copyright (C) 2004-2008 Richard Kettlewell * - * This program is free software; you can redistribute it and/or modify + * 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 - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. If not, see . */ -/** @file server/actions.c +/** @file cgi/actions.c * @brief DisOrder web actions * * Actions are anything that the web interface does beyond passive template * expansion and inspection of state recieved from the server. This means * playing tracks, editing prefs etc but also setting extra headers e.g. to * auto-refresh the playing list. + * + * See @ref lib/macros-builtin.c for docstring syntax. */ #include "disorder-cgi.h" @@ -44,17 +44,17 @@ static void redirect(const char *url) { if(printf("Location: %s\n" "%s\n" "\n", url, dcgi_cookie_header()) < 0) - fatal(errno, "error writing to stdout"); + disorder_fatal(errno, "error writing to stdout"); } -/*! playing +/*$ playing * * Expands \fIplaying.tmpl\fR as if there was no special 'playing' action, but * adds a Refresh: field to the HTTP header. The maximum refresh interval is * defined by \fBrefresh\fR (see \fBdisorder_config\fR(5)) but may be less if * the end of the track is near. */ -/*! manage +/*$ manage * * Expands \fIplaying.tmpl\fR (NB not \fImanage.tmpl\fR) as if there was no * special 'playing' action, and adds a Refresh: field to the HTTP header. The @@ -75,37 +75,39 @@ static void act_playing(void) { && length && dcgi_playing->sofar >= 0) { /* Try to put the next refresh at the start of the next track. */ - time(&now); - fin = now + length - dcgi_playing->sofar + config->gap; + xtime(&now); + fin = now + length - dcgi_playing->sofar; if(now + refresh > fin) refresh = fin - now; } - if(dcgi_queue && dcgi_queue->state == playing_isscratch) { - /* next track is a scratch, don't leave more than the inter-track gap */ - if(refresh > config->gap) - refresh = config->gap; + if(dcgi_queue && dcgi_queue->origin == origin_scratch) { + /* next track is a scratch, refresh immediately */ + refresh = 0; } if(!dcgi_playing && ((dcgi_queue - && dcgi_queue->state != playing_random) + && dcgi_queue->origin != origin_random) || dcgi_random_enabled) && dcgi_enabled) { /* no track playing but playing is enabled and there is something coming - * up, must be in a gap */ - if(refresh > config->gap) - refresh = config->gap; + * up, so refresh immediately */ + refresh = 0; } + /* Bound the refresh interval below as a back-stop against the above + * calculations coming up with a stupid answer */ + if(refresh < config->refresh_min) + refresh = config->refresh_min; if((action = cgi_get("action"))) url = cgi_makeurl(config->url, "action", action, (char *)0); else url = config->url; if(printf("Refresh: %ld;url=%s\n", refresh, url) < 0) - fatal(errno, "error writing to stdout"); + disorder_fatal(errno, "error writing to stdout"); dcgi_expand("playing", 1); } -/*! disable +/*$ disable * * Disables play. */ @@ -115,7 +117,7 @@ static void act_disable(void) { redirect(0); } -/*! enable +/*$ enable * * Enables play. */ @@ -125,7 +127,7 @@ static void act_enable(void) { redirect(0); } -/*! random-disable +/*$ random-disable * * Disables random play. */ @@ -135,7 +137,7 @@ static void act_random_disable(void) { redirect(0); } -/*! random-enable +/*$ random-enable * * Enables random play. */ @@ -145,7 +147,7 @@ static void act_random_enable(void) { redirect(0); } -/*! pause +/*$ pause * * Pauses the current track (if there is one and it's not paused already). */ @@ -155,7 +157,7 @@ static void act_pause(void) { redirect(0); } -/*! resume +/*$ resume * * Resumes the current track (if there is one and it's paused). */ @@ -165,7 +167,7 @@ static void act_resume(void) { redirect(0); } -/*! remove +/*$ remove * * Removes the track given by the \fBid\fR argument. If this is the currently * playing track then it is scratched. @@ -176,32 +178,27 @@ static void act_remove(void) { if(dcgi_client) { if(!(id = cgi_get("id"))) - error(0, "missing 'id' argument"); + disorder_error(0, "missing 'id' argument"); else if(!(q = dcgi_findtrack(id))) - error(0, "unknown queue id %s", id); - else switch(q->state) { - case playing_isscratch: - case playing_failed: - case playing_no_player: - case playing_ok: - case playing_quitting: - case playing_scratched: - error(0, "does not make sense to scratch %s", id); - break; - case playing_paused: /* started but paused */ - case playing_started: /* started to play */ + disorder_error(0, "unknown queue id %s", id); + else if(q->origin == origin_scratch) + /* can't scratch scratches */ + disorder_error(0, "does not make sense to scratch or remove %s", id); + else if(q->state == playing_paused + || q->state == playing_started) + /* removing the playing track = scratching */ disorder_scratch(dcgi_client, id); - break; - case playing_random: /* unplayed randomly chosen track */ - case playing_unplayed: /* haven't played this track yet */ + else if(q->state == playing_unplayed) + /* otherwise it must be in the queue */ disorder_remove(dcgi_client, id); - break; - } + else + /* various error states */ + disorder_error(0, "does not make sense to scratch or remove %s", id); } redirect(0); } -/*! move +/*$ move * * Moves the track given by the \fBid\fR argument the distance given by the * \fBdelta\fR argument. If this is positive the track is moved earlier in the @@ -213,25 +210,25 @@ static void act_move(void) { if(dcgi_client) { if(!(id = cgi_get("id"))) - error(0, "missing 'id' argument"); + disorder_error(0, "missing 'id' argument"); else if(!(delta = cgi_get("delta"))) - error(0, "missing 'delta' argument"); + disorder_error(0, "missing 'delta' argument"); else if(!(q = dcgi_findtrack(id))) - error(0, "unknown queue id %s", id); + disorder_error(0, "unknown queue id %s", id); else switch(q->state) { case playing_random: /* unplayed randomly chosen track */ case playing_unplayed: /* haven't played this track yet */ disorder_move(dcgi_client, id, atol(delta)); break; default: - error(0, "does not make sense to scratch %s", id); + disorder_error(0, "does not make sense to scratch %s", id); break; } } redirect(0); } -/*! play +/*$ play * * Play the track given by the \fBtrack\fR argument, or if that is not set all * the tracks in the directory given by the \fBdir\fR argument. @@ -241,16 +238,17 @@ static void act_play(void) { char **tracks; int ntracks, n; struct tracksort_data *tsd; + char *id; if(dcgi_client) { if((track = cgi_get("track"))) { - disorder_play(dcgi_client, track); + disorder_play(dcgi_client, track, &id); } else if((dir = cgi_get("dir"))) { if(disorder_files(dcgi_client, dir, 0, &tracks, &ntracks)) ntracks = 0; tsd = tracksort_init(ntracks, tracks, "track"); for(n = 0; n < ntracks; ++n) - disorder_play(dcgi_client, tsd[n].track); + disorder_play(dcgi_client, tsd[n].track, &id); } } redirect(0); @@ -264,7 +262,7 @@ static int clamp(int n, int min, int max) { return n; } -/*! volume +/*$ volume * * If the \fBdelta\fR argument is set: adjust both channels by that amount (up * if positive, down if negative). @@ -309,8 +307,12 @@ static int login_as(const char *username, const char *password) { if(dcgi_cookie && dcgi_client) disorder_revoke(dcgi_client); - /* We'll need a new connection as we are going to stop being guest */ + /* We'll need a new connection as we are going to stop being guest. + * Make sure it's unprivileged, so that the server actually bothers checking + * the password we supply. + */ c = disorder_new(0); + disorder_force_unpriv(c); if(disorder_connect_user(c, username, password)) { login_error("loginfailed"); return -1; @@ -326,7 +328,7 @@ static int login_as(const char *username, const char *password) { return 0; /* OK */ } -/*! login +/*$ login * * If \fBusername\fR and \fBpassword\fR are set (and the username isn't * "guest") then attempt to log in using those credentials. On success, @@ -361,7 +363,7 @@ static void act_login(void) { } } -/*! logout +/*$ logout * * Logs out the current user and expands \fIlogin.tmpl\fR with \fBstatus\fR or * \fB@error\fR set according to the result. @@ -386,7 +388,7 @@ static void act_logout(void) { dcgi_expand("login", 1); } -/*! register +/*$ register * * Register a new user using \fBusername\fR, \fBpassword1\fR, \fBpassword2\fR * and \fBemail\fR and expands \fIlogin.tmpl\fR with \fBstatus\fR or @@ -443,7 +445,7 @@ static void act_register(void) { "\n" "%s?c=%s\n", config->url, urlencodestring(confirm)); if(!(text = mime_encode_text(text, &charset, &encoding))) - fatal(0, "cannot encode email"); + disorder_fatal(0, "cannot encode email"); byte_xasprintf(&content_type, "text/plain;charset=%s", quote822(charset, 0)); sendmail("", config->mail_sender, email, "Welcome to DisOrder", @@ -453,7 +455,7 @@ static void act_register(void) { dcgi_expand("login", 1); } -/*! confirm +/*$ confirm * * Confirm a user registration using the nonce supplied in \fBc\fR and expands * \fIlogin.tmpl\fR with \fBstatus\fR or \fB@error\fR set according to the @@ -489,7 +491,7 @@ static void act_confirm(void) { dcgi_expand("login", 1); } -/*! edituser +/*$ edituser * * Edit user details using \fBusername\fR, \fBchangepassword1\fR, * \fBchangepassword2\fR and \fBemail\fR and expands \fIlogin.tmpl\fR with @@ -550,7 +552,7 @@ static void act_edituser(void) { dcgi_expand("login", 1); } -/*! reminder +/*$ reminder * * Issue an email password reminder to \fBusername\fR and expands * \fIlogin.tmpl\fR with \fBstatus\fR or \fB@error\fR set according to the @@ -613,7 +615,7 @@ static int process_prefs(int numfile) { byte_xasprintf((char **)&name, "trackname_%s_%s", context, part); disorder_set(dcgi_client, file, name, value); } - if((value = numbered_arg("random", numfile))) + if(numbered_arg("random", numfile)) disorder_unset(dcgi_client, file, "pick_at_random"); else disorder_set(dcgi_client, file, "pick_at_random", "0"); @@ -632,7 +634,7 @@ static int process_prefs(int numfile) { return 0; } -/*! prefs +/*$ prefs * * Set preferences on a number of tracks. * @@ -731,19 +733,19 @@ void dcgi_expand(const char *name, int header) { mx_expand_file(found, sink_discard(), 0); /* For unknown actions check that they aren't evil */ if(!dcgi_valid_action(name)) - fatal(0, "invalid action name '%s'", name); + disorder_fatal(0, "invalid action name '%s'", name); byte_xasprintf((char **)&p, "%s.tmpl", name); if(!(found = mx_find(p, 0/*report*/))) - fatal(errno, "cannot find %s", p); + disorder_fatal(errno, "cannot find %s", p); if(header) { if(printf("Content-Type: text/html; charset=UTF-8\n" "%s\n" "\n", dcgi_cookie_header()) < 0) - fatal(errno, "error writing to stdout"); + disorder_fatal(errno, "error writing to stdout"); } if(mx_expand_file(found, sink_stdio("stdout", stdout), 0) == -1 || fflush(stdout) < 0) - fatal(errno, "error writing to stdout"); + disorder_fatal(errno, "error writing to stdout"); } /** @brief Execute a web action