chiark / gitweb /
act_playing
[disorder] / server / actions.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2004-2008 Richard Kettlewell
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20
21 #include <config.h>
22 #include "types.h"
23
24 #include "actions.h"
25 #include "lookups.h"
26
27 /** @brief Login cookie */
28 char *login_cookie;
29
30 /* 'playing' and 'manage' just add a Refresh: header */
31 static void act_playing(void) {
32   long refresh = config->refresh;
33   long length;
34   time_t now, fin;
35   char *url;
36
37   lookups(DC_PLAYING|DC_QUEUE|DC_ENABLED|DC_RANDOM_ENABLED);
38   if(playing
39      && playing->state == playing_started /* i.e. not paused */
40      && !disorder_length(client, playing->track, &length)
41      && length
42      && playing->sofar >= 0) {
43     /* Try to put the next refresh at the start of the next track. */
44     time(&now);
45     fin = now + length - playing->sofar + config->gap;
46     if(now + refresh > fin)
47       refresh = fin - now;
48   }
49   if(queue && queue->state == playing_isscratch) {
50     /* next track is a scratch, don't leave more than the inter-track gap */
51     if(refresh > config->gap)
52       refresh = config->gap;
53   }
54   if(!playing
55      && ((queue
56           && queue->state != playing_random)
57          || random_enabled)
58      && enabled) {
59     /* no track playing but playing is enabled and there is something coming
60      * up, must be in a gap */
61     if(refresh > config->gap)
62       refresh = config->gap;
63   }
64   if((action = cgi_get("action")))
65     url = cgi_makeurl(config->url, "action", action, (char *)0);
66   else
67     url = config->url;
68   if(printf("Content-Type: text/html\n"
69             "Refresh: %ld;url=%s\n"
70             /* TODO cookie */
71             "\n",
72             refresh, url) < 0)
73     fatal(errno, "error writing to stdout");
74   disorder_cgi_expand(action ? action : "playing");
75 }
76
77 /** @brief Table of actions */
78 static const struct action {
79   /** @brief Action name */
80   const char *name;
81   /** @brief Action handler */
82   void (*handler)(void);
83 } actions[] = {
84   { "confirm", act_confirm },
85   { "disable", act_disable },
86   { "edituser", act_edituser },
87   { "enable", act_enable },
88   { "login", act_login },
89   { "logout", act_logout },
90   { "manage", act_playing },
91   { "move", act_move },
92   { "pause", act_pause },
93   { "play", act_play },
94   { "playing", act_playing },
95   { "prefs", act_prefs },
96   { "random-disable", act_random_disable },
97   { "random-enable", act_random_enable },
98   { "register", act_register },
99   { "reminder", act_reminder },
100   { "remove", act_remove },
101   { "resume", act_resume },
102   { "scratch", act_scratch },
103   { "volume", act_volume },
104 };
105
106 /** @brief Expand a template
107  * @param name Base name of template, or NULL to consult CGI args
108  */
109 void disorder_cgi_expand(const char *name) {
110   const char *p;
111   
112   /* For unknown actions check that they aren't evil */
113   for(p = name; *p && isalnum((unsigned char)*p); ++p)
114     ;
115   if(*p)
116     fatal(0, "invalid action name '%s'", action);
117   byte_xasprintf((char **)&p, "%s.tmpl", action);
118   if(mx_expand_file(p, sink_stdio(stdout), 0) == -1
119      || fflush(stdout) < 0)
120     fatal(errno, "error writing to stdout");
121 }
122
123 /** @brief Execute a web action
124  * @param action Action to perform, or NULL to consult CGI args
125  *
126  * If no recognized action is specified then 'playing' is assumed.
127  */
128 void disorder_cgi_action(const char *action) {
129   int n;
130   char *s;
131
132   /* Consult CGI args if caller had no view */
133   if(!action)
134     action = cgi_get("action");
135   /* Pick a default if nobody cares at all */
136   if(!action) {
137     /* We allow URLs which are just c=... in order to keep confirmation URLs,
138      * which are user-facing, as short as possible.  Actually we could lose the
139      * c= for this... */
140     if(cgi_get("c"))
141       action = "confirm";
142     else
143       action = "playing";
144   }
145   if((n = TABLE_FIND(actions, struct action, name, action)) >= 0)
146     /* Its a known action */
147     actions[n].handler();
148   else {
149     /* Just expand the template */
150     if(printf("Content-Type: text/html\n"
151               /* TODO cookie */
152               "\n") < 0)
153       fatal(errno, "error writing to stdout");
154     disorder_cgi_expand(action);
155   }
156 }
157
158 /** @brief Generate an error page */
159 void disorder_cgi_error(const char *msg, ...) {
160   va_list ap;
161
162   va_start(ap, msg);
163   byte_xvasprintf(&error_string, msg, ap);
164   va_end(ap);
165   disorder_cgi_expand("error");
166 }
167
168 /** @brief Log in as the current user or guest if none */
169 void disorder_cgi_login(dcgi_state *ds, struct sink *output) {
170   /* Junk old data */
171   disorder_macros_reset();
172   /* Reconnect */
173   if(disorder_connect_cookie(client, login_cookie)) {
174     disorder_cgi_error("Cannot connect to server");
175     exit(0);
176   }
177   /* If there was a cookie but it went bad, we forget it */
178   if(login_cookie && !strcmp(disorder_user(>client), "guest"))
179     login_cookie = 0;
180 }
181
182 /*
183 Local Variables:
184 c-basic-offset:2
185 comment-column:40
186 fill-column:79
187 indent-tabs-mode:nil
188 End:
189 */