X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/10921eba21e8e74d086854e1e361c381e4661eda..c12575c6cea802f894df6ca8b04c1b3656496592:/cgi/actions.c diff --git a/cgi/actions.c b/cgi/actions.c index a139eaf..584da76 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,19 +75,19 @@ 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); + xtime(&now); fin = now + length - dcgi_playing->sofar + config->gap; if(now + refresh > fin) refresh = fin - now; } - if(dcgi_queue && dcgi_queue->state == playing_isscratch) { + if(dcgi_queue && dcgi_queue->origin == origin_scratch) { /* next track is a scratch, don't leave more than the inter-track gap */ if(refresh > config->gap) refresh = config->gap; } 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 @@ -95,17 +95,21 @@ static void act_playing(void) { if(refresh > config->gap) refresh = config->gap; } + /* 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 +119,7 @@ static void act_disable(void) { redirect(0); } -/*! enable +/*$ enable * * Enables play. */ @@ -125,7 +129,7 @@ static void act_enable(void) { redirect(0); } -/*! random-disable +/*$ random-disable * * Disables random play. */ @@ -135,7 +139,7 @@ static void act_random_disable(void) { redirect(0); } -/*! random-enable +/*$ random-enable * * Enables random play. */ @@ -145,7 +149,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 +159,7 @@ static void act_pause(void) { redirect(0); } -/*! resume +/*$ resume * * Resumes the current track (if there is one and it's paused). */ @@ -165,7 +169,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 +180,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 +212,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. @@ -240,24 +239,18 @@ static void act_play(void) { const char *track, *dir; char **tracks; int ntracks, n; - struct dcgi_entry *e; + 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; - /* TODO use tracksort_init */ - e = xmalloc(ntracks * sizeof (struct dcgi_entry)); - for(n = 0; n < ntracks; ++n) { - e[n].track = tracks[n]; - e[n].sort = trackname_transform("track", tracks[n], "sort"); - e[n].display = trackname_transform("track", tracks[n], "display"); - } - qsort(e, ntracks, sizeof (struct dcgi_entry), dcgi_compare_entry); + tsd = tracksort_init(ntracks, tracks, "track"); for(n = 0; n < ntracks; ++n) - disorder_play(dcgi_client, e[n].track); + disorder_play(dcgi_client, tsd[n].track, &id); } } redirect(0); @@ -271,7 +264,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). @@ -333,7 +326,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, @@ -368,7 +361,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. @@ -393,7 +386,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 @@ -435,8 +428,7 @@ static void act_register(void) { } /* We could well do better address validation but for now we'll just do the * minimum */ - /* TODO use email_valid() */ - if(!strchr(email, '@')) { + if(!email_valid(email)) { login_error("bademail"); return; } @@ -451,7 +443,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", @@ -461,7 +453,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 @@ -497,7 +489,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 @@ -525,8 +517,7 @@ static void act_edituser(void) { } } else password = password2 = 0; - /* TODO use email_valid() */ - if(email && !strchr(email, '@')) { + if(email && !email_valid(email)) { login_error("bademail"); return; } @@ -559,7 +550,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 @@ -622,7 +613,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"); @@ -641,7 +632,7 @@ static int process_prefs(int numfile) { return 0; } -/*! prefs +/*$ prefs * * Set preferences on a number of tracks. * @@ -740,19 +731,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