5 #include <sys/socket.h>
19 #include "server-cgi.h"
21 #include "configuration.h"
32 #include "trackname.h"
46 static int compare_entry(const void *a
, const void *b
) {
47 const struct entry
*ea
= a
, *eb
= b
;
49 return compare_tracks(ea
->sort
, eb
->sort
,
50 ea
->display
, eb
->display
,
54 static const char *front_url(void) {
58 /* preserve management interface visibility */
59 if((mgmt
= cgi_get("mgmt")) && !strcmp(mgmt
, "true")) {
60 byte_xasprintf(&url
, "%s?mgmt=true", config
->url
);
66 static void redirect(struct sink
*output
) {
69 back
= cgi_get("back");
70 cgi_header(output
, "Location", back
&& *back ? back
: front_url());
71 header_cookie(output
);
75 static void expand_template(dcgi_state
*ds
, cgi_sink
*output
,
77 cgi_header(output
->sink
, "Content-Type", "text/html");
78 header_cookie(output
->sink
);
79 cgi_body(output
->sink
);
80 expand(output
, action
, ds
);
83 /* actions ********************************************************************/
85 static void act_prefs_errors(const char *msg
,
86 void attribute((unused
)) *u
) {
87 fatal(0, "error splitting parts list: %s", msg
);
90 static const char *numbered_arg(const char *argname
, int numfile
) {
93 byte_xasprintf(&fullname
, "%d_%s", numfile
, argname
);
94 return cgi_get(fullname
);
97 static void process_prefs(dcgi_state
*ds
, int numfile
) {
98 const char *file
, *name
, *value
, *part
, *parts
, *current
, *context
;
101 if(!(file
= numbered_arg("file", numfile
)))
102 /* The first file doesn't need numbering. */
103 if(numfile
> 0 || !(file
= cgi_get("file")))
105 if((parts
= numbered_arg("parts", numfile
))
106 || (parts
= cgi_get("parts"))) {
107 /* Default context is display. Other contexts not actually tested. */
108 if(!(context
= numbered_arg("context", numfile
))) context
= "display";
109 partslist
= split(parts
, 0, 0, act_prefs_errors
, 0);
110 while((part
= *partslist
++)) {
111 if(!(value
= numbered_arg(part
, numfile
)))
113 /* If it's already right (whether regexps or db) don't change anything,
114 * so we don't fill the database up with rubbish. */
115 if(disorder_part(ds
->g
->client
, (char **)¤t
,
116 file
, context
, part
))
117 fatal(0, "disorder_part() failed");
118 if(!strcmp(current
, value
))
120 byte_xasprintf((char **)&name
, "trackname_%s_%s", context
, part
);
121 disorder_set(ds
->g
->client
, file
, name
, value
);
123 if((value
= numbered_arg("random", numfile
)))
124 disorder_unset(ds
->g
->client
, file
, "pick_at_random");
126 disorder_set(ds
->g
->client
, file
, "pick_at_random", "0");
127 if((value
= numbered_arg("tags", numfile
))) {
129 disorder_unset(ds
->g
->client
, file
, "tags");
131 disorder_set(ds
->g
->client
, file
, "tags", value
);
133 if((value
= numbered_arg("weight", numfile
))) {
134 if(!*value
|| !strcmp(value
, "90000"))
135 disorder_unset(ds
->g
->client
, file
, "weight");
137 disorder_set(ds
->g
->client
, file
, "weight", value
);
139 } else if((name
= cgi_get("name"))) {
140 /* Raw preferences. Not well supported in the templates at the moment. */
141 value
= cgi_get("value");
143 disorder_set(ds
->g
->client
, file
, name
, value
);
145 disorder_unset(ds
->g
->client
, file
, name
);
149 static void act_prefs(cgi_sink
*output
, dcgi_state
*ds
) {
153 if((files
= cgi_get("files"))) nfiles
= atoi(files
);
155 for(numfile
= 0; numfile
< nfiles
; ++numfile
)
156 process_prefs(ds
, numfile
);
157 cgi_header(output
->sink
, "Content-Type", "text/html");
158 header_cookie(output
->sink
);
159 cgi_body(output
->sink
);
160 expand(output
, "prefs", ds
);
163 static void act_login(cgi_sink
*output
,
165 const char *username
, *password
, *back
;
168 username
= cgi_get("username");
169 password
= cgi_get("password");
170 if(!username
|| !password
171 || !strcmp(username
, "guest")/*bodge to avoid guest cookies*/) {
172 /* We're just visiting the login page */
173 expand_template(ds
, output
, "login");
176 /* We'll need a new connection as we are going to stop being guest */
178 if(disorder_connect_user(c
, username
, password
)) {
179 cgi_set_option("error", "loginfailed");
180 expand_template(ds
, output
, "login");
183 if(disorder_make_cookie(c
, &login_cookie
)) {
184 cgi_set_option("error", "cookiefailed");
185 expand_template(ds
, output
, "login");
188 /* Use the new connection henceforth */
191 /* We have a new cookie */
192 header_cookie(output
->sink
);
193 cgi_set_option("status", "loginok");
194 if((back
= cgi_get("back")) && *back
)
195 /* Redirect back to somewhere or other */
196 redirect(output
->sink
);
198 /* Stick to the login page */
199 expand_template(ds
, output
, "login");
202 static void act_logout(cgi_sink
*output
,
204 disorder_revoke(ds
->g
->client
);
206 /* Reconnect as guest */
207 disorder_cgi_login(ds
, output
);
208 /* Back to the login page */
209 cgi_set_option("status", "logoutok");
210 expand_template(ds
, output
, "login");
213 static void act_register(cgi_sink
*output
,
215 const char *username
, *password
, *password2
, *email
;
216 char *confirm
, *content_type
;
217 const char *text
, *encoding
, *charset
;
219 username
= cgi_get("username");
220 password
= cgi_get("password1");
221 password2
= cgi_get("password2");
222 email
= cgi_get("email");
224 if(!username
|| !*username
) {
225 cgi_set_option("error", "nousername");
226 expand_template(ds
, output
, "login");
229 if(!password
|| !*password
) {
230 cgi_set_option("error", "nopassword");
231 expand_template(ds
, output
, "login");
234 if(!password2
|| !*password2
|| strcmp(password
, password2
)) {
235 cgi_set_option("error", "passwordmismatch");
236 expand_template(ds
, output
, "login");
239 if(!email
|| !*email
) {
240 cgi_set_option("error", "noemail");
241 expand_template(ds
, output
, "login");
244 /* We could well do better address validation but for now we'll just do the
246 if(!strchr(email
, '@')) {
247 cgi_set_option("error", "bademail");
248 expand_template(ds
, output
, "login");
251 if(disorder_register(ds
->g
->client
, username
, password
, email
, &confirm
)) {
252 cgi_set_option("error", "cannotregister");
253 expand_template(ds
, output
, "login");
256 /* Send the user a mail */
257 /* TODO templatize this */
258 byte_xasprintf((char **)&text
,
259 "Welcome to DisOrder. To active your login, please visit this URL:\n"
261 "%s?c=%s\n", config
->url
, urlencodestring(confirm
));
262 if(!(text
= mime_encode_text(text
, &charset
, &encoding
)))
263 fatal(0, "cannot encode email");
264 byte_xasprintf(&content_type
, "text/plain;charset=%s",
265 quote822(charset
, 0));
266 sendmail("", config
->mail_sender
, email
, "Welcome to DisOrder",
267 encoding
, content_type
, text
); /* TODO error checking */
268 /* We'll go back to the login page with a suitable message */
269 cgi_set_option("status", "registered");
270 expand_template(ds
, output
, "login");
273 static void act_confirm(cgi_sink
*output
,
275 const char *confirmation
;
277 if(!(confirmation
= cgi_get("c"))) {
278 cgi_set_option("error", "noconfirm");
279 expand_template(ds
, output
, "login");
281 /* Confirm our registration */
282 if(disorder_confirm(ds
->g
->client
, confirmation
)) {
283 cgi_set_option("error", "badconfirm");
284 expand_template(ds
, output
, "login");
287 if(disorder_make_cookie(ds
->g
->client
, &login_cookie
)) {
288 cgi_set_option("error", "cookiefailed");
289 expand_template(ds
, output
, "login");
292 /* Discard any cached data JIC */
294 /* We have a new cookie */
295 header_cookie(output
->sink
);
296 cgi_set_option("status", "confirmed");
297 expand_template(ds
, output
, "login");
300 static void act_edituser(cgi_sink
*output
,
302 const char *email
= cgi_get("email"), *password
= cgi_get("changepassword1");
303 const char *password2
= cgi_get("changepassword2");
307 if((password
&& *password
) || (password
&& *password2
)) {
308 if(!password
|| !password2
|| strcmp(password
, password2
)) {
309 cgi_set_option("error", "passwordmismatch");
310 expand_template(ds
, output
, "login");
314 password
= password2
= 0;
317 if(disorder_edituser(ds
->g
->client
, disorder_user(ds
->g
->client
),
319 cgi_set_option("error", "badedit");
320 expand_template(ds
, output
, "login");
325 if(disorder_edituser(ds
->g
->client
, disorder_user(ds
->g
->client
),
326 "password", password
)) {
327 cgi_set_option("error", "badedit");
328 expand_template(ds
, output
, "login");
334 login_cookie
= 0; /* it'll be invalid now */
335 /* This is a bit duplicative of act_login() */
337 if(disorder_connect_user(c
, disorder_user(ds
->g
->client
), password
)) {
338 cgi_set_option("error", "loginfailed");
339 expand_template(ds
, output
, "login");
342 if(disorder_make_cookie(c
, &login_cookie
)) {
343 cgi_set_option("error", "cookiefailed");
344 expand_template(ds
, output
, "login");
347 /* Use the new connection henceforth */
350 /* We have a new cookie */
351 header_cookie(output
->sink
);
353 cgi_set_option("status", "edited");
354 expand_template(ds
, output
, "login");
357 static void act_reminder(cgi_sink
*output
,
359 const char *const username
= cgi_get("username");
361 if(!username
|| !*username
) {
362 cgi_set_option("error", "nousername");
363 expand_template(ds
, output
, "login");
366 if(disorder_reminder(ds
->g
->client
, username
)) {
367 cgi_set_option("error", "reminderfailed");
368 expand_template(ds
, output
, "login");
371 cgi_set_option("status", "reminded");
372 expand_template(ds
, output
, "login");
375 /* expansions *****************************************************************/
377 static void exp_label(int attribute((unused
)) nargs
,
380 void attribute((unused
)) *u
) {
381 cgi_output(output
, "%s", cgi_label(args
[0]));
384 struct trackinfo_state
{
386 const struct queue_entry
*q
;
396 static int compare_result(const void *a
, const void *b
) {
397 const struct result
*ra
= a
, *rb
= b
;
400 if(!(c
= strcmp(ra
->sort
, rb
->sort
)))
401 c
= strcmp(ra
->track
, rb
->track
);
405 static void exp_stats(int attribute((unused
)) nargs
,
406 char attribute((unused
)) **args
,
412 cgi_opentag(output
->sink
, "pre", "class", "stats", (char *)0);
413 if(!disorder_stats(ds
->g
->client
, &v
, 0)) {
415 cgi_output(output
, "%s\n", *v
++);
417 cgi_closetag(output
->sink
, "pre");
420 static char *expandarg(const char *arg
, dcgi_state
*ds
) {
426 output
.sink
= sink_dynstr(&d
);
427 expandstring(&output
, arg
, ds
);
428 dynstr_terminate(&d
);
432 static void exp_navigate(int attribute((unused
)) nargs
,
438 const char *path
= expandarg(args
[0], ds
);
443 memset(&substate
, 0, sizeof substate
);
445 ptr
= path
+ 1; /* skip root */
447 substate
.nav_path
= path
;
450 while(*ptr
&& *ptr
!= '/')
452 substate
.last
= !*ptr
;
453 substate
.nav_len
= ptr
- path
;
454 substate
.nav_dirlen
= dirlen
;
455 expandstring(output
, args
[1], &substate
);
456 dirlen
= substate
.nav_len
;
463 static void exp_fullname(int attribute((unused
)) nargs
,
464 char attribute((unused
)) **args
,
468 cgi_output(output
, "%.*s", ds
->nav_len
, ds
->nav_path
);