+/*** STATUS ***/
+
+static void
+copy_attrs(struct odes *dest, struct odes *src)
+{
+ for (struct oattr *a = src->attrs ; a; a=a->next)
+ if (a->attr < OBJ_ATTR_SON)
+ for (struct oattr *aa = a; aa; aa=aa->same)
+ obj_add_attr(dest, aa->attr, aa->val);
+}
+
+static void
+cmd_status(struct conn *c)
+{
+ uns verbose = obj_find_anum(c->request, 'V', 0);
+ task_load_status(c);
+
+ CLIST_FOR_EACH(struct task *, t, task_list)
+ {
+ struct odes *to = task_status_find_task(c, t, 1);
+ struct odes *tr = obj_add_son(c->reply, 'T' + OBJ_ATTR_SON);
+ copy_attrs(tr, to);
+ CLIST_FOR_EACH(simp_node *, x, *t->extensions)
+ obj_add_attr(tr, 'A', x->s);
+ CLIST_FOR_EACH(simp_node *, p, t->parts)
+ {
+ struct odes *po = task_status_find_part(to, p->s, 1);
+ struct odes *pr = obj_add_son(tr, 'P' + OBJ_ATTR_SON);
+ copy_attrs(pr, po);
+ uns current_ver = obj_find_anum(po, 'V', 0);
+ for (struct oattr *v = obj_find_attr(po, 'V' + OBJ_ATTR_SON); v; v=v->same)
+ {
+ struct odes *vo = v->son;
+ uns ver = obj_find_anum(vo, 'V', 0);
+ if (ver == current_ver || verbose)
+ obj_add_son_ref(pr, 'V' + OBJ_ATTR_SON, vo);
+ }
+ }
+ }
+}
+
+/*** Contest timeout checks ***/
+
+static int
+load_time_limit(char *name)
+{
+ struct fastbuf *f = bopen_try(name, O_RDONLY, 1024);
+ if (!f)
+ return -1;
+ char buf[256];
+ int h, m;
+ if (bgets_nodie(f, buf, sizeof(buf)) < 0 ||
+ sscanf(buf, "%d:%d", &h, &m) != 2 ||
+ h < 0 || h > 23 || m < 0 || m > 59)
+ {
+ msg(L_ERROR, "Invalid timeout in %s", name);
+ bclose(f);
+ return -1;
+ }
+ bclose(f);
+ return 100*h + m;
+}
+
+static int
+contest_over(struct conn *c)
+{
+ time_t now = time(NULL);
+ struct tm *tm = localtime(&now);
+ int tstamp = tm->tm_hour*100 + tm->tm_min;
+ int local_limit = load_time_limit(stk_printf("solutions/%s/TIMEOUT", c->user));
+ int global_limit = load_time_limit("solutions/TIMEOUT");
+ if (trace_commands > 1)
+ msg(L_DEBUG, "Time check: current %d, global limit %d, user limit %d", tstamp, global_limit, local_limit);
+ if (local_limit >= 0)
+ return (tstamp >= local_limit);
+ return (global_limit >= 0 && tstamp >= global_limit);
+}
+