#include "lib/lib.h"
#include "lib/mempool.h"
-#include "lib/stkstring.h"
#include "sherlock/object.h"
#include "sherlock/objread.h"
-#include <sys/stat.h>
-
#include "submitd.h"
+/*** REQUESTS AND REPLIES ***/
+
static void NONRET
read_error_cb(struct obj_read_state *st UNUSED, byte *msg)
{
static void
write_reply(struct conn *c)
{
+ if (!obj_find_attr(c->reply, '-') && !obj_find_attr(c->reply, '+'))
+ obj_set_attr(c->reply, '+', "OK");
if (trace_commands)
{
byte *msg;
else
log(L_DEBUG, ">> ???");
}
- put_attr_set_type(BUCKET_TYPE_PLAIN);
- bput_object(&c->tx_fb, c->reply);
+ obj_write(&c->tx_fb, c->reply, BUCKET_TYPE_PLAIN);
bputc(&c->tx_fb, '\n');
bflush(&c->tx_fb);
}
+static void
+err(struct conn *c, byte *msg)
+{
+ obj_set_attr(c->reply, '-', msg);
+}
+
+/*** SUBMIT ***/
+
+static struct fastbuf *
+read_attachment(struct conn *c)
+{
+ uns size = obj_find_anum(c->request, 'S', 0);
+ if (size > max_attachment_size)
+ {
+ err(c, "Submission too large");
+ return NULL;
+ }
+ obj_set_attr(c->reply, '+', "Go on");
+ write_reply(c);
+ obj_set_attr(c->reply, '+', NULL);
+
+ // This is less efficient than bbcopy(), but we want our own error handling.
+ struct fastbuf *fb = bopen_tmp(4096);
+ byte buf[4096];
+ uns remains = size;
+ while (remains)
+ {
+ uns cnt = bread(&c->rx_fb, buf, MIN(remains, (uns)sizeof(buf)));
+ if (!cnt)
+ {
+ bclose(fb);
+ client_error("Truncated attachment");
+ }
+ bwrite(fb, buf, cnt);
+ remains -= cnt;
+ }
+ brewind(fb);
+ return fb;
+}
+
+static void
+cmd_submit(struct conn *c)
+{
+ byte *tname = obj_find_aval(c->request, 'T');
+ if (!tname)
+ {
+ err(c, "No task specified");
+ return;
+ }
+ struct task *task = task_find(tname);
+ if (!task)
+ {
+ err(c, "No such task");
+ return;
+ }
+ struct fastbuf *fb = read_attachment(c);
+ if (!fb)
+ return;
+
+ // FIXME: Check contest time
+ // FIXME: Keep history of submitted tasks
+ // FIXME: File names
+
+ task_lock_status(c);
+ struct odes *o = task_status_find_task(c, task);
+ task_submit(c, task, fb, task->name);
+ log(L_INFO, "User %s submitted task %s", c->user, task->name);
+ task_unlock_status(c, 1);
+}
+
+/*** COMMAND MUX ***/
+
static void
execute_command(struct conn *c)
{
byte *cmd = obj_find_aval(c->request, '!');
if (!cmd)
{
- obj_set_attr(c->reply, '-', "Missing command");
+ err(c, "Missing command");
return;
}
if (trace_commands)
log(L_DEBUG, "<< %s", cmd);
- obj_set_attr(c->reply, '-', "Unknown command");
+ if (!strcasecmp(cmd, "SUBMIT"))
+ cmd_submit(c);
+ else
+ err(c, "Unknown command");
}
int
return 1;
}
-static int
-user_exists_p(byte *user)
-{
- byte *fn = stk_printf("solutions/%s/status", user);
- struct stat st;
- return !stat(fn, &st) && S_ISREG(st.st_mode);
-}
+/*** INITIAL HANDSHAKE ***/
static void
execute_init(struct conn *c)
byte *user = obj_find_aval(c->request, 'U');
if (!user)
{
- obj_set_attr(c->reply, '-', "Missing user");
+ err(c, "Missing user");
return;
}
if (!c->cert_name ||
{
if (!user_exists_p(user))
{
- obj_set_attr(c->reply, '-', "Unknown user");
+ err(c, "Unknown user");
return;
}
log(L_INFO, "Logged in %s", user);
}
else
{
- obj_set_attr(c->reply, '-', "Permission denied");
+ err(c, "Permission denied");
log(L_ERROR, "Unauthorized attempt to log in as %s", user);
return;
}
- obj_set_attr(c->reply, '+', "OK");
c->user = xstrdup(user);
}
return 0;
execute_init(c);
write_reply(c);
- return !!obj_find_attr(c->reply, '+');
+ return !obj_find_attr(c->reply, '-');
}