341f881cbb33137959eb9518b32c49248d073ac5
2 * This file is part of DisOrder.
3 * Copyright (C) 2004-2008 Richard Kettlewell
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.
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.
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
42 #include "configuration.h"
47 #include "macros-disorder.h"
49 /** @brief Login cookie */
52 /** @brief Return a Cookie: header */
53 static char *cookie(void) {
58 memset(&u
, 0, sizeof u
);
60 parse_url(config
->url
, &u
);
62 dynstr_append_string(d
, "disorder=");
63 dynstr_append_string(d
, login_cookie
);
65 /* Force browser to discard cookie */
66 dynstr_append_string(d
, "disorder=none;Max-Age=0");
69 /* The default domain matches the request host, so we need not override
70 * that. But the default path only goes up to the rightmost /, which would
71 * cause the browser to expose the cookie to other CGI programs on the same
73 dynstr_append_string(d
, ";Version=1;Path=");
74 /* Formally we are supposed to quote the path, since it invariably has a
75 * slash in it. However Safari does not parse quoted paths correctly, so
76 * this won't work. Fortunately nothing else seems to care about proper
77 * quoting of paths, so in practice we get with it. (See also
78 * parse_cookie() where we are liberal about cookie paths on the way back
80 dynstr_append_string(d
, u
.path
);
83 byte_xasprintf(&s
, "Set-Cookie: %s", d
->vec
);
87 /** @brief Redirect to some other action or URL */
88 static void redirect(const char *url
) {
89 /* By default use the 'back' argument */
91 url
= cgi_get("back");
93 if(!strncmp(url
, "http", 4))
94 /* If the target is not a full URL assume it's the action */
95 url
= cgi_makeurl(config
->url
, "action", url
, (char *)0);
97 /* If back= is not set just go back to the front page */
100 if(printf("Location: %s\n"
102 "\n", url
, cookie()) < 0)
103 fatal(errno
, "error writing to stdout");
106 /* 'playing' and 'manage' just add a Refresh: header */
107 static void act_playing(void) {
108 long refresh
= config
->refresh
;
114 lookup(DC_PLAYING
|DC_QUEUE
|DC_ENABLED
|DC_RANDOM_ENABLED
);
116 && playing
->state
== playing_started
/* i.e. not paused */
117 && !disorder_length(client
, playing
->track
, &length
)
119 && playing
->sofar
>= 0) {
120 /* Try to put the next refresh at the start of the next track. */
122 fin
= now
+ length
- playing
->sofar
+ config
->gap
;
123 if(now
+ refresh
> fin
)
126 if(queue
&& queue
->state
== playing_isscratch
) {
127 /* next track is a scratch, don't leave more than the inter-track gap */
128 if(refresh
> config
->gap
)
129 refresh
= config
->gap
;
133 && queue
->state
!= playing_random
)
136 /* no track playing but playing is enabled and there is something coming
137 * up, must be in a gap */
138 if(refresh
> config
->gap
)
139 refresh
= config
->gap
;
141 if((action
= cgi_get("action")))
142 url
= cgi_makeurl(config
->url
, "action", action
, (char *)0);
145 if(printf("Content-Type: text/html\n"
146 "Refresh: %ld;url=%s\n"
149 refresh
, url
, cookie()) < 0)
150 fatal(errno
, "error writing to stdout");
151 disorder_cgi_expand(action ? action
: "playing");
154 /** @brief Table of actions */
155 static const struct action
{
156 /** @brief Action name */
158 /** @brief Action handler */
159 void (*handler
)(void);
162 { "confirm", act_confirm
},
163 { "disable", act_disable
},
164 { "edituser", act_edituser
},
165 { "enable", act_enable
},
166 { "login", act_login
},
167 { "logout", act_logout
},
168 { "manage", act_playing
},
169 { "move", act_move
},
170 { "pause", act_pause
},
171 { "play", act_play
},
173 { "playing", act_playing
},
175 { "prefs", act_prefs
},
176 { "random-disable", act_random_disable
},
177 { "random-enable", act_random_enable
},
178 { "register", act_register
},
179 { "reminder", act_reminder
},
180 { "remove", act_remove
},
181 { "resume", act_resume
},
182 { "scratch", act_scratch
},
183 { "volume", act_volume
},
187 /** @brief Expand a template
188 * @param name Base name of template, or NULL to consult CGI args
190 void disorder_cgi_expand(const char *name
) {
193 /* For unknown actions check that they aren't evil */
194 for(p
= name
; *p
&& isalnum((unsigned char)*p
); ++p
)
197 fatal(0, "invalid action name '%s'", name
);
198 byte_xasprintf((char **)&p
, "%s.tmpl", name
);
199 if(mx_expand_file(p
, sink_stdio("stdout", stdout
), 0) == -1
200 || fflush(stdout
) < 0)
201 fatal(errno
, "error writing to stdout");
204 /** @brief Execute a web action
205 * @param action Action to perform, or NULL to consult CGI args
207 * If no recognized action is specified then 'playing' is assumed.
209 void disorder_cgi_action(const char *action
) {
212 /* Consult CGI args if caller had no view */
214 action
= cgi_get("action");
215 /* Pick a default if nobody cares at all */
217 /* We allow URLs which are just c=... in order to keep confirmation URLs,
218 * which are user-facing, as short as possible. Actually we could lose the
224 /* Make sure 'action' is always set */
225 cgi_set("action", action
);
227 if((n
= TABLE_FIND(actions
, struct action
, name
, action
)) >= 0)
228 /* Its a known action */
229 actions
[n
].handler();
231 /* Just expand the template */
232 if(printf("Content-Type: text/html\n"
235 fatal(errno
, "error writing to stdout");
236 disorder_cgi_expand(action
);
240 /** @brief Generate an error page */
241 void disorder_cgi_error(const char *msg
, ...) {
245 byte_xvasprintf(&error_string
, msg
, ap
);
247 disorder_cgi_expand("error");
250 /** @brief Log in as the current user or guest if none */
251 void disorder_cgi_login(void) {
255 if(disorder_connect_cookie(client
, login_cookie
)) {
256 disorder_cgi_error("Cannot connect to server");
259 /* If there was a cookie but it went bad, we forget it */
260 if(login_cookie
&& !strcmp(disorder_user(client
), "guest"))