source: ogServer-Git/src/rest.c @ 216986e

Last change on this file since 216986e was 216986e, checked in by OpenGnSys Support Team <soporte-og@…>, 3 years ago

#915 consolidate WoL sender function

This patch aims simplifies the WoL sender routine.

A few related changes:

  • Replace goto err to continue if IP address is malformed
  • Use ret |= instead of ret &= to accumulate error code.
  • Property mode set to 100644
File size: 153.4 KB
Line 
1/*
2 * Copyright (C) 2020-2021 Soleta Networks <info@soleta.eu>
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Affero General Public License as published by the
6 * Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 */
9
10#include "ogAdmServer.h"
11#include "dbi.h"
12#include "utils.h"
13#include "list.h"
14#include "rest.h"
15#include "wol.h"
16#include "cfg.h"
17#include "schedule.h"
18#include "legacy.h"
19#include <ev.h>
20#include <syslog.h>
21#include <sys/ioctl.h>
22#include <ifaddrs.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <fcntl.h>
26#include <jansson.h>
27#include <dirent.h>
28#include <time.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <sys/wait.h>
32#include <sys/statvfs.h>
33
34struct ev_loop *og_loop;
35
36#define OG_REST_PARAM_ADDR                      (1UL << 0)
37#define OG_REST_PARAM_MAC                       (1UL << 1)
38#define OG_REST_PARAM_WOL_TYPE                  (1UL << 2)
39#define OG_REST_PARAM_RUN_CMD                   (1UL << 3)
40#define OG_REST_PARAM_DISK                      (1UL << 4)
41#define OG_REST_PARAM_PARTITION                 (1UL << 5)
42#define OG_REST_PARAM_REPO                      (1UL << 6)
43#define OG_REST_PARAM_NAME                      (1UL << 7)
44#define OG_REST_PARAM_ID                        (1UL << 8)
45#define OG_REST_PARAM_CODE                      (1UL << 9)
46#define OG_REST_PARAM_TYPE                      (1UL << 10)
47#define OG_REST_PARAM_PROFILE                   (1UL << 11)
48#define OG_REST_PARAM_CACHE                     (1UL << 12)
49#define OG_REST_PARAM_CACHE_SIZE                (1UL << 13)
50#define OG_REST_PARAM_PART_0                    (1UL << 14)
51#define OG_REST_PARAM_PART_1                    (1UL << 15)
52#define OG_REST_PARAM_PART_2                    (1UL << 16)
53#define OG_REST_PARAM_PART_3                    (1UL << 17)
54#define OG_REST_PARAM_SYNC_SYNC                 (1UL << 18)
55#define OG_REST_PARAM_SYNC_DIFF                 (1UL << 19)
56#define OG_REST_PARAM_SYNC_REMOVE               (1UL << 20)
57#define OG_REST_PARAM_SYNC_COMPRESS             (1UL << 21)
58#define OG_REST_PARAM_SYNC_CLEANUP              (1UL << 22)
59#define OG_REST_PARAM_SYNC_CACHE                (1UL << 23)
60#define OG_REST_PARAM_SYNC_CLEANUP_CACHE        (1UL << 24)
61#define OG_REST_PARAM_SYNC_REMOVE_DST           (1UL << 25)
62#define OG_REST_PARAM_SYNC_DIFF_ID              (1UL << 26)
63#define OG_REST_PARAM_SYNC_DIFF_NAME            (1UL << 27)
64#define OG_REST_PARAM_SYNC_PATH                 (1UL << 28)
65#define OG_REST_PARAM_SYNC_METHOD               (1UL << 29)
66#define OG_REST_PARAM_ECHO                      (1UL << 30)
67#define OG_REST_PARAM_TASK                      (1UL << 31)
68#define OG_REST_PARAM_TIME_YEARS                (1UL << 32)
69#define OG_REST_PARAM_TIME_MONTHS               (1UL << 33)
70#define OG_REST_PARAM_TIME_WEEKS                (1UL << 34)
71#define OG_REST_PARAM_TIME_WEEK_DAYS            (1UL << 35)
72#define OG_REST_PARAM_TIME_DAYS                 (1UL << 36)
73#define OG_REST_PARAM_TIME_HOURS                (1UL << 37)
74#define OG_REST_PARAM_TIME_AM_PM                (1UL << 38)
75#define OG_REST_PARAM_TIME_MINUTES              (1UL << 39)
76#define OG_REST_PARAM_NETMASK                   (1UL << 40)
77#define OG_REST_PARAM_SCOPE                     (1UL << 41)
78#define OG_REST_PARAM_MODE                      (1UL << 42)
79#define OG_REST_PARAM_CENTER                    (1UL << 43)
80
81static LIST_HEAD(client_list);
82static LIST_HEAD(client_wol_list);
83
84void og_client_add(struct og_client *cli)
85{
86        list_add(&cli->list, &client_list);
87}
88
89static struct og_client *og_client_find(const char *ip)
90{
91        struct og_client *client;
92        struct in_addr addr;
93        int res;
94
95        res = inet_aton(ip, &addr);
96        if (!res) {
97                syslog(LOG_ERR, "Invalid IP string: %s\n", ip);
98                return NULL;
99        }
100
101        list_for_each_entry(client, &client_list, list) {
102                if (client->addr.sin_addr.s_addr == addr.s_addr && client->agent) {
103                        return client;
104                }
105        }
106
107        return NULL;
108}
109
110static const char *og_client_status(const struct og_client *cli)
111{
112        switch (cli->last_cmd) {
113        case OG_CMD_UNSPEC:
114        case OG_CMD_PROBE:
115                break;
116        default:
117                return "BSY";
118        }
119
120        switch (cli->status) {
121        case OG_CLIENT_STATUS_BUSY:
122                return "BSY";
123        case OG_CLIENT_STATUS_OGLIVE:
124                return "OPG";
125        case OG_CLIENT_STATUS_VIRTUAL:
126                return "VDI";
127        case OG_CLIENT_STATUS_LINUX:
128                return "LINUX";
129        case OG_CLIENT_STATUS_LINUX_SESSION:
130                return "LINUX-SESSION";
131        case OG_CLIENT_STATUS_WIN:
132                return "WIN";
133        case OG_CLIENT_STATUS_WIN_SESSION:
134                return "WIN-SESSION";
135        default:
136                return "OFF";
137        }
138}
139
140static bool og_msg_params_validate(const struct og_msg_params *params,
141                                   const uint64_t flags)
142{
143        return (params->flags & flags) == flags;
144}
145
146static bool og_flags_validate(const uint64_t flags,
147                              const uint64_t required_flags)
148{
149        return (flags & required_flags) == required_flags;
150}
151
152static int og_json_parse_clients(json_t *element, struct og_msg_params *params)
153{
154        unsigned int i;
155        json_t *k;
156
157        if (json_typeof(element) != JSON_ARRAY)
158                return -1;
159
160        for (i = 0; i < json_array_size(element); i++) {
161                k = json_array_get(element, i);
162                if (json_typeof(k) != JSON_STRING)
163                        return -1;
164
165                params->ips_array[params->ips_array_len++] =
166                        json_string_value(k);
167
168                params->flags |= OG_REST_PARAM_ADDR;
169        }
170
171        return 0;
172}
173
174int og_json_parse_partition_setup(json_t *element, struct og_msg_params *params)
175{
176        unsigned int i;
177        json_t *k;
178
179        if (json_typeof(element) != JSON_ARRAY)
180                return -1;
181
182        for (i = 0; i < json_array_size(element) && i < OG_PARTITION_MAX; ++i) {
183                k = json_array_get(element, i);
184
185                if (json_typeof(k) != JSON_OBJECT)
186                        return -1;
187
188                if (og_json_parse_partition(k, &params->partition_setup[i],
189                                            OG_PARAM_PART_NUMBER |
190                                            OG_PARAM_PART_CODE |
191                                            OG_PARAM_PART_FILESYSTEM |
192                                            OG_PARAM_PART_SIZE |
193                                            OG_PARAM_PART_FORMAT) < 0)
194                        return -1;
195
196                params->flags |= (OG_REST_PARAM_PART_0 << i);
197        }
198        return 0;
199}
200
201static int og_json_parse_time_params(json_t *element,
202                                     struct og_msg_params *params)
203{
204        const char *key;
205        json_t *value;
206        int err = 0;
207
208        json_object_foreach(element, key, value) {
209                if (!strcmp(key, "years")) {
210                        err = og_json_parse_uint(value, &params->time.years);
211                        params->flags |= OG_REST_PARAM_TIME_YEARS;
212                } else if (!strcmp(key, "months")) {
213                        err = og_json_parse_uint(value, &params->time.months);
214                        params->flags |= OG_REST_PARAM_TIME_MONTHS;
215                } else if (!strcmp(key, "weeks")) {
216                        err = og_json_parse_uint(value, &params->time.weeks);
217                        params->flags |= OG_REST_PARAM_TIME_WEEKS;
218                } else if (!strcmp(key, "week_days")) {
219                        err = og_json_parse_uint(value, &params->time.week_days);
220                        params->flags |= OG_REST_PARAM_TIME_WEEK_DAYS;
221                } else if (!strcmp(key, "days")) {
222                        err = og_json_parse_uint(value, &params->time.days);
223                        params->flags |= OG_REST_PARAM_TIME_DAYS;
224                } else if (!strcmp(key, "hours")) {
225                        err = og_json_parse_uint(value, &params->time.hours);
226                        params->flags |= OG_REST_PARAM_TIME_HOURS;
227                } else if (!strcmp(key, "am_pm")) {
228                        err = og_json_parse_uint(value, &params->time.am_pm);
229                        params->flags |= OG_REST_PARAM_TIME_AM_PM;
230                } else if (!strcmp(key, "minutes")) {
231                        err = og_json_parse_uint(value, &params->time.minutes);
232                        params->flags |= OG_REST_PARAM_TIME_MINUTES;
233                }
234                if (err != 0)
235                        return err;
236        }
237
238        return err;
239}
240
241static const char *og_cmd_to_uri[OG_CMD_MAX] = {
242        [OG_CMD_WOL]            = "wol",
243        [OG_CMD_PROBE]          = "probe",
244        [OG_CMD_SHELL_RUN]      = "shell/run",
245        [OG_CMD_SESSION]        = "session",
246        [OG_CMD_POWEROFF]       = "poweroff",
247        [OG_CMD_REFRESH]        = "refresh",
248        [OG_CMD_REBOOT]         = "reboot",
249        [OG_CMD_STOP]           = "stop",
250        [OG_CMD_HARDWARE]       = "hardware",
251        [OG_CMD_SOFTWARE]       = "software",
252        [OG_CMD_IMAGE_CREATE]   = "image/create",
253        [OG_CMD_IMAGE_RESTORE]  = "image/restore",
254        [OG_CMD_SETUP]          = "setup",
255        [OG_CMD_RUN_SCHEDULE]   = "run/schedule",
256        [OG_CMD_IMAGES]         = "images",
257};
258
259static bool og_client_is_busy(const struct og_client *cli,
260                              enum og_cmd_type type)
261{
262        switch (type) {
263        case OG_CMD_REBOOT:
264        case OG_CMD_POWEROFF:
265        case OG_CMD_STOP:
266                break;
267        default:
268                if (cli->last_cmd != OG_CMD_UNSPEC)
269                        return true;
270                break;
271        }
272
273        return false;
274}
275
276int og_send_request(enum og_rest_method method, enum og_cmd_type type,
277                    const struct og_msg_params *params,
278                    const json_t *data)
279{
280        const char *content_type = "Content-Type: application/json";
281        char content [OG_MSG_REQUEST_MAXLEN - 700] = {};
282        char buf[OG_MSG_REQUEST_MAXLEN] = {};
283        unsigned int content_length;
284        char method_str[5] = {};
285        struct og_client *cli;
286        const char *uri;
287        unsigned int i;
288        int client_sd;
289
290        if (method == OG_METHOD_GET)
291                snprintf(method_str, 5, "GET");
292        else if (method == OG_METHOD_POST)
293                snprintf(method_str, 5, "POST");
294        else
295                return -1;
296
297        if (!data)
298                content_length = 0;
299        else
300                content_length = json_dumpb(data, content,
301                                            OG_MSG_REQUEST_MAXLEN - 700,
302                                            JSON_COMPACT);
303
304        uri = og_cmd_to_uri[type];
305        snprintf(buf, OG_MSG_REQUEST_MAXLEN,
306                 "%s /%s HTTP/1.1\r\nContent-Length: %d\r\n%s\r\n\r\n%s",
307                 method_str, uri, content_length, content_type, content);
308
309        for (i = 0; i < params->ips_array_len; i++) {
310                cli = og_client_find(params->ips_array[i]);
311                if (!cli)
312                        continue;
313
314                if (og_client_is_busy(cli, type))
315                        continue;
316
317                client_sd = cli->io.fd;
318                if (client_sd < 0) {
319                        syslog(LOG_INFO, "Client %s not conected\n",
320                               params->ips_array[i]);
321                        continue;
322                }
323
324                if (send(client_sd, buf, strlen(buf), 0) < 0)
325                        continue;
326
327                cli->last_cmd = type;
328        }
329
330        json_decref((json_t *)data);
331
332        return 0;
333}
334
335static int og_cmd_post_clients(json_t *element, struct og_msg_params *params)
336{
337        const char *key;
338        json_t *value;
339        int err = 0;
340
341        if (json_typeof(element) != JSON_OBJECT)
342                return -1;
343
344        json_object_foreach(element, key, value) {
345                if (!strcmp(key, "clients"))
346                        err = og_json_parse_clients(value, params);
347
348                if (err < 0)
349                        return err;
350        }
351
352        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
353                return -1;
354
355        return og_send_request(OG_METHOD_POST, OG_CMD_PROBE, params, NULL);
356}
357
358struct og_buffer {
359        char    *data;
360        int     len;
361};
362
363#define OG_MSG_RESPONSE_MAXLEN  262144
364
365static int og_json_dump_clients(const char *buffer, size_t size, void *data)
366{
367        struct og_buffer *og_buffer = (struct og_buffer *)data;
368
369        if (size >= OG_MSG_RESPONSE_MAXLEN - og_buffer->len) {
370                syslog(LOG_ERR, "Response JSON body is too large\n");
371                return -1;
372        }
373
374        memcpy(og_buffer->data + og_buffer->len, buffer, size);
375        og_buffer->len += size;
376
377        return 0;
378}
379
380static int og_json_client_append(json_t *array, struct og_client *client)
381{
382        json_t *addr, *state, *object;
383
384        object = json_object();
385        if (!object)
386                return -1;
387
388        addr = json_string(inet_ntoa(client->addr.sin_addr));
389        if (!addr) {
390                json_decref(object);
391                return -1;
392        }
393        json_object_set_new(object, "addr", addr);
394        state = json_string(og_client_status(client));
395        if (!state) {
396                json_decref(object);
397                return -1;
398        }
399        json_object_set_new(object, "state", state);
400        json_object_set_new(object, "speed", json_integer(client->speed));
401        json_array_append_new(array, object);
402
403        return 0;
404}
405
406static int og_json_client_wol_append(json_t *array,
407                                     struct og_client_wol *cli_wol)
408{
409        json_t *addr, *state, *object;
410
411        object = json_object();
412        if (!object)
413                return -1;
414
415        addr = json_string(inet_ntoa(cli_wol->addr));
416        if (!addr) {
417                json_decref(object);
418                return -1;
419        }
420        json_object_set_new(object, "addr", addr);
421        state = json_string(og_client_wol_status(cli_wol));
422        if (!state) {
423                json_decref(object);
424                return -1;
425        }
426        json_object_set_new(object, "state", state);
427        json_array_append_new(array, object);
428
429        return 0;
430}
431
432static int og_cmd_get_clients(json_t *element, struct og_msg_params *params,
433                              char *buffer_reply)
434{
435        struct og_buffer og_buffer = {
436                .data   = buffer_reply,
437        };
438        struct og_client_wol *cli_wol;
439        struct og_client *client;
440        json_t *array, *root;
441
442        array = json_array();
443        if (!array)
444                return -1;
445
446        list_for_each_entry(cli_wol, &client_wol_list, list) {
447                if (og_json_client_wol_append(array, cli_wol) < 0) {
448                        json_decref(array);
449                        return -1;
450                }
451        }
452
453        list_for_each_entry(client, &client_list, list) {
454                if (!client->agent)
455                        continue;
456
457                if (og_json_client_append(array, client) < 0) {
458                        json_decref(array);
459                        return -1;
460                }
461        }
462
463        root = json_pack("{s:o}", "clients", array);
464        if (!root) {
465                json_decref(array);
466                return -1;
467        }
468
469        if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) {
470                json_decref(root);
471                return -1;
472        }
473
474        json_decref(root);
475
476        return 0;
477}
478
479static int og_json_parse_type(json_t *element, struct og_msg_params *params)
480{
481        const char *type;
482
483        if (json_typeof(element) != JSON_STRING)
484                return -1;
485
486        params->wol_type = json_string_value(element);
487
488        type = json_string_value(element);
489        if (!strcmp(type, "unicast"))
490                params->wol_type = "2";
491        else if (!strcmp(type, "broadcast"))
492                params->wol_type = "1";
493
494        params->flags |= OG_REST_PARAM_WOL_TYPE;
495
496        return 0;
497}
498
499struct og_client_wol *og_client_wol_find(const struct in_addr *addr)
500{
501        struct og_client_wol *cli_wol;
502
503        list_for_each_entry(cli_wol, &client_wol_list, list) {
504                if (cli_wol->addr.s_addr == addr->s_addr)
505                        return cli_wol;
506        }
507
508        return NULL;
509}
510
511static int og_cmd_wol(json_t *element, struct og_msg_params *params)
512{
513        char ips_str[(OG_DB_IP_MAXLEN + 1) * OG_CLIENTS_MAX + 1] = {};
514        struct og_client_wol *cli_wol;
515        struct in_addr addr, netmask;
516        int ips_str_len = 0;
517        const char *msglog;
518        struct og_dbi *dbi;
519        int err = 0, i = 0;
520        dbi_result result;
521        const char *key;
522        json_t *value;
523        int sd;
524
525        if (json_typeof(element) != JSON_OBJECT)
526                return -1;
527
528        json_object_foreach(element, key, value) {
529                if (!strcmp(key, "clients")) {
530                        err = og_json_parse_clients(value, params);
531                } else if (!strcmp(key, "type")) {
532                        err = og_json_parse_type(value, params);
533                }
534
535                if (err < 0)
536                        return err;
537        }
538        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
539                                            OG_REST_PARAM_WOL_TYPE))
540                return -1;
541
542        for (i = 0; i < params->ips_array_len; ++i) {
543                ips_str_len += snprintf(ips_str + ips_str_len,
544                                        sizeof(ips_str) - ips_str_len,
545                                        "'%s',", params->ips_array[i]);
546        }
547        ips_str[ips_str_len - 1] = '\0';
548
549        dbi = og_dbi_open(&ogconfig.db);
550        if (!dbi) {
551                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
552                       __func__, __LINE__);
553                return -1;
554        }
555
556        result = dbi_conn_queryf(dbi->conn,
557                                 "SELECT ordenadores.ip, ordenadores.mac, "
558                                        "aulas.netmask "
559                                 "FROM   ordenadores "
560                                 "INNER JOIN aulas "
561                                         "ON ordenadores.idaula = aulas.idaula "
562                                 "WHERE  ordenadores.ip IN (%s)",
563                                 ips_str);
564        if (!result) {
565                dbi_conn_error(dbi->conn, &msglog);
566                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
567                       __func__, __LINE__, msglog);
568                og_dbi_close(dbi);
569                return -1;
570        }
571
572        for (i = 0; dbi_result_next_row(result); i++) {
573                params->ips_array[i] = dbi_result_get_string_copy(result, "ip");
574                params->mac_array[i] = dbi_result_get_string_copy(result, "mac");
575                params->netmask_array[i] = dbi_result_get_string_copy(result, "netmask");
576        }
577
578        dbi_result_free(result);
579        og_dbi_close(dbi);
580
581        if (i == 0)
582                return 0;
583
584        sd = wol_socket_open();
585        if (sd < 0) {
586                syslog(LOG_ERR, "cannot open wol socket (%s:%d)\n",
587                       __func__, __LINE__);
588                goto err_free_params;
589        }
590
591        for (i = 0; i < params->ips_array_len; i++) {
592                if (og_client_find(params->ips_array[i]))
593                        continue;
594
595                if (inet_aton(params->ips_array[i], &addr) < 0)
596                        continue;
597
598                cli_wol = og_client_wol_find(&addr);
599                if (cli_wol) {
600                        og_client_wol_refresh(cli_wol);
601                        continue;
602                }
603
604                cli_wol = og_client_wol_create(&addr);
605                if (!cli_wol)
606                        goto err_out;
607
608                list_add_tail(&cli_wol->list, &client_wol_list);
609
610                if (inet_aton(params->netmask_array[i], &netmask) < 0)
611                        continue;
612
613                if (wake_up(sd, &addr, &netmask, params->mac_array[i],
614                            atoi(params->wol_type)) < 0) {
615                        syslog(LOG_ERR, "Failed to send wol packet to %s\n",
616                               params->ips_array[i]);
617                        continue;
618                }
619        }
620err_out:
621        close(sd);
622err_free_params:
623        for (i = 0; i < params->ips_array_len; ++i) {
624                free((void *)params->ips_array[i]);
625                free((void *)params->mac_array[i]);
626                free((void *)params->netmask_array[i]);
627        }
628
629        return 0;
630}
631
632static int og_json_parse_run(json_t *element, struct og_msg_params *params)
633{
634        if (json_typeof(element) != JSON_STRING)
635                return -1;
636
637        snprintf(params->run_cmd, sizeof(params->run_cmd), "%s",
638                 json_string_value(element));
639
640        params->flags |= OG_REST_PARAM_RUN_CMD;
641
642        return 0;
643}
644
645static int og_cmd_run_post(json_t *element, struct og_msg_params *params)
646{
647        json_t *value, *clients;
648        const char *key;
649        unsigned int i;
650        int err = 0;
651
652        if (json_typeof(element) != JSON_OBJECT)
653                return -1;
654
655        json_object_foreach(element, key, value) {
656                if (!strcmp(key, "clients"))
657                        err = og_json_parse_clients(value, params);
658                else if (!strcmp(key, "run"))
659                        err = og_json_parse_run(value, params);
660                else if (!strcmp(key, "echo")) {
661                        err = og_json_parse_bool(value, &params->echo);
662                        params->flags |= OG_REST_PARAM_ECHO;
663                }
664
665                if (err < 0)
666                        return err;
667        }
668
669        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
670                                            OG_REST_PARAM_RUN_CMD |
671                                            OG_REST_PARAM_ECHO))
672                return -1;
673
674        clients = json_copy(element);
675        json_object_del(clients, "clients");
676
677        err = og_send_request(OG_METHOD_POST, OG_CMD_SHELL_RUN, params, clients);
678        if (err < 0)
679                return err;
680
681        for (i = 0; i < params->ips_array_len; i++) {
682                char filename[4096];
683                FILE *f;
684
685                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
686                f = fopen(filename, "wt");
687                fclose(f);
688        }
689
690        return 0;
691}
692
693static int og_cmd_run_get(json_t *element, struct og_msg_params *params,
694                          char *buffer_reply)
695{
696        struct og_buffer og_buffer = {
697                .data   = buffer_reply,
698        };
699        json_t *root, *value, *array;
700        const char *key;
701        unsigned int i;
702        int err = 0;
703
704        if (json_typeof(element) != JSON_OBJECT)
705                return -1;
706
707        json_object_foreach(element, key, value) {
708                if (!strcmp(key, "clients"))
709                        err = og_json_parse_clients(value, params);
710
711                if (err < 0)
712                        return err;
713        }
714
715        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
716                return -1;
717
718        array = json_array();
719        if (!array)
720                return -1;
721
722        for (i = 0; i < params->ips_array_len; i++) {
723                json_t *object, *output, *addr;
724                char data[4096] = {};
725                char filename[4096];
726                int fd, numbytes;
727
728                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
729
730                fd = open(filename, O_RDONLY);
731                if (!fd)
732                        return -1;
733
734                numbytes = read(fd, data, sizeof(data));
735                if (numbytes < 0) {
736                        close(fd);
737                        return -1;
738                }
739                data[sizeof(data) - 1] = '\0';
740                close(fd);
741
742                object = json_object();
743                if (!object) {
744                        json_decref(array);
745                        return -1;
746                }
747                addr = json_string(params->ips_array[i]);
748                if (!addr) {
749                        json_decref(object);
750                        json_decref(array);
751                        return -1;
752                }
753                json_object_set_new(object, "addr", addr);
754
755                output = json_string(data);
756                if (!output) {
757                        json_decref(object);
758                        json_decref(array);
759                        return -1;
760                }
761                json_object_set_new(object, "output", output);
762
763                json_array_append_new(array, object);
764        }
765
766        root = json_pack("{s:o}", "clients", array);
767        if (!root)
768                return -1;
769
770        if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) {
771                json_decref(root);
772                return -1;
773        }
774
775        json_decref(root);
776
777        return 0;
778}
779
780static int og_cmd_session(json_t *element, struct og_msg_params *params)
781{
782        json_t *clients, *value;
783        const char *key;
784        int err = 0;
785
786        if (json_typeof(element) != JSON_OBJECT)
787                return -1;
788
789        json_object_foreach(element, key, value) {
790                if (!strcmp(key, "clients")) {
791                        err = og_json_parse_clients(value, params);
792                } else if (!strcmp(key, "disk")) {
793                        err = og_json_parse_string(value, &params->disk);
794                        params->flags |= OG_REST_PARAM_DISK;
795                } else if (!strcmp(key, "partition")) {
796                        err = og_json_parse_string(value, &params->partition);
797                        params->flags |= OG_REST_PARAM_PARTITION;
798                }
799
800                if (err < 0)
801                        return err;
802        }
803
804        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
805                                            OG_REST_PARAM_DISK |
806                                            OG_REST_PARAM_PARTITION))
807                return -1;
808
809        clients = json_copy(element);
810        json_object_del(clients, "clients");
811
812        return og_send_request(OG_METHOD_POST, OG_CMD_SESSION, params, clients);
813}
814
815static int og_cmd_get_session(json_t *element, struct og_msg_params *params,
816                              char *buffer_reply)
817{
818        json_t *value, *root, *array, *item;
819        const char *key, *msglog, *os_name;
820        unsigned int disk, partition;
821        struct og_dbi *dbi;
822        dbi_result result;
823        int err = 0;
824
825        struct og_buffer og_buffer = {
826                .data = buffer_reply
827        };
828
829        json_object_foreach(element, key, value) {
830                if (!strcmp(key, "client"))
831                        err = og_json_parse_clients(value, params);
832                else
833                        err = -1;
834
835                if (err < 0)
836                        return err;
837        }
838
839        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
840                return -1;
841
842        dbi = og_dbi_open(&ogconfig.db);
843        if (!dbi) {
844                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
845                       __func__, __LINE__);
846                return -1;
847        }
848
849        result = dbi_conn_queryf(dbi->conn,
850                                 "SELECT op.numdisk, op.numpar, nom.nombreso "
851                                 "FROM ordenadores o "
852                                 "INNER JOIN ordenadores_particiones op "
853                                 "    ON o.idordenador = op.idordenador "
854                                 "INNER JOIN nombresos nom "
855                                 "    ON op.idnombreso = nom.idnombreso "
856                                 "WHERE o.ip = '%s'",
857                                 params->ips_array[0]);
858        if (!result) {
859                dbi_conn_error(dbi->conn, &msglog);
860                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
861                       __func__, __LINE__, msglog);
862                og_dbi_close(dbi);
863                return -1;
864        }
865
866        array = json_array();
867        if (!array) {
868                dbi_result_free(result);
869                og_dbi_close(dbi);
870                return -1;
871        }
872
873        while (dbi_result_next_row(result)) {
874                item = json_object();
875                if (!item) {
876                        dbi_result_free(result);
877                        og_dbi_close(dbi);
878                        json_decref(array);
879                        return -1;
880                }
881
882                disk = dbi_result_get_uint(result, "numdisk");
883                partition = dbi_result_get_uint(result, "numpar");
884                os_name = dbi_result_get_string(result, "nombreso");
885
886                json_object_set_new(item, "disk", json_integer(disk));
887                json_object_set_new(item, "partition", json_integer(partition));
888                json_object_set_new(item, "name", json_string(os_name));
889                json_array_append_new(array, item);
890        }
891
892        dbi_result_free(result);
893        og_dbi_close(dbi);
894
895        root = json_object();
896        if (!root){
897                json_decref(array);
898                return -1;
899        }
900
901        json_object_set_new(root, "sessions", array);
902
903        if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) {
904                json_decref(root);
905                return -1;
906        }
907
908        json_decref(root);
909        return 0;
910}
911
912static int og_cmd_poweroff(json_t *element, struct og_msg_params *params)
913{
914        const char *key;
915        json_t *value;
916        int err = 0;
917
918        if (json_typeof(element) != JSON_OBJECT)
919                return -1;
920
921        json_object_foreach(element, key, value) {
922                if (!strcmp(key, "clients"))
923                        err = og_json_parse_clients(value, params);
924
925                if (err < 0)
926                        return err;
927        }
928
929        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
930                return -1;
931
932        return og_send_request(OG_METHOD_POST, OG_CMD_POWEROFF, params, NULL);
933}
934
935static int og_cmd_refresh(json_t *element, struct og_msg_params *params)
936{
937        const char *key;
938        json_t *value;
939        int err = 0;
940
941        if (json_typeof(element) != JSON_OBJECT)
942                return -1;
943
944        json_object_foreach(element, key, value) {
945                if (!strcmp(key, "clients"))
946                        err = og_json_parse_clients(value, params);
947
948                if (err < 0)
949                        return err;
950        }
951
952        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
953                return -1;
954
955        return og_send_request(OG_METHOD_GET, OG_CMD_REFRESH, params, NULL);
956}
957
958static int og_cmd_reboot(json_t *element, struct og_msg_params *params)
959{
960        const char *key;
961        json_t *value;
962        int err = 0;
963
964        if (json_typeof(element) != JSON_OBJECT)
965                return -1;
966
967        json_object_foreach(element, key, value) {
968                if (!strcmp(key, "clients"))
969                        err = og_json_parse_clients(value, params);
970
971                if (err < 0)
972                        return err;
973        }
974
975        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
976                return -1;
977
978        return og_send_request(OG_METHOD_POST, OG_CMD_REBOOT, params, NULL);
979}
980
981#define OG_TFTP_TMPL_PATH_UEFI "/opt/opengnsys/tftpboot/grub/templates"
982#define OG_TFTP_TMPL_PATH "/opt/opengnsys/tftpboot/menu.lst/templates"
983
984static int og_cmd_get_modes(json_t *element, struct og_msg_params *params,
985                            char *buffer_reply)
986{
987        struct og_buffer og_buffer = {
988                .data = buffer_reply
989        };
990        json_t *root, *modes;
991        struct dirent *dent;
992        DIR *d = NULL;
993
994        root = json_object();
995        if (!root)
996                return -1;
997
998        modes = json_array();
999        if (!modes) {
1000                json_decref(root);
1001                return -1;
1002        }
1003
1004        d = opendir(OG_TFTP_TMPL_PATH);
1005        if (!d) {
1006                json_decref(modes);
1007                json_decref(root);
1008                syslog(LOG_ERR, "Cannot open directory %s\n",
1009                       OG_TFTP_TMPL_PATH);
1010                return -1;
1011        }
1012
1013        dent = readdir(d);
1014        while (dent) {
1015                if (dent->d_type != DT_REG) {
1016                        dent = readdir(d);
1017                        continue;
1018                }
1019                json_array_append_new(modes, json_string(dent->d_name));
1020                dent = readdir(d);
1021        }
1022        json_object_set_new(root, "modes", modes);
1023
1024        if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) {
1025                json_decref(root);
1026                return -1;
1027        }
1028
1029        json_decref(root);
1030        closedir(d);
1031
1032        return 0;
1033}
1034
1035static int og_change_db_mode(struct og_dbi *dbi, const char *mac,
1036                             const char * mode)
1037{
1038        const char *msglog;
1039        dbi_result result;
1040
1041        result = dbi_conn_queryf(dbi->conn,
1042                                 "UPDATE ordenadores SET arranque='%s' "
1043                                 "WHERE mac='%s'",
1044                                 mode, mac);
1045
1046        if (!result) {
1047                dbi_conn_error(dbi->conn, &msglog);
1048                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1049                       __func__, __LINE__, msglog);
1050                return -1;
1051        }
1052
1053        dbi_result_free(result);
1054        return 0;
1055}
1056
1057static int og_set_client_mode(struct og_dbi *dbi, const char *mac,
1058                              const char *mode, const char *template_name)
1059{
1060        char filename[PATH_MAX + 1] = "/tmp/mode_params_XXXXXX";
1061        char cmd_params[16384] = {};
1062        char params[4096] = "\0";
1063        const char *msglog;
1064        dbi_result result;
1065        unsigned int i;
1066        int numbytes;
1067        int status;
1068        int fd;
1069
1070        result = dbi_conn_queryf(dbi->conn,
1071                "SELECT ' LANG=%s', ' ip=', CONCAT_WS(':', ordenadores.ip, (SELECT (@serverip:=ipserveradm) FROM entornos LIMIT 1), aulas.router, aulas.netmask, ordenadores.nombreordenador, ordenadores.netiface, 'none'), ' group=', REPLACE(TRIM(aulas.nombreaula), ' ', '_'), ' ogrepo=', (@repoip:=IFNULL(repositorios.ip, '')), ' oglive=', @serverip, ' oglog=', @serverip, ' ogshare=', @serverip, ' oglivedir=', ordenadores.oglivedir, ' ogprof=', IF(ordenadores.idordenador=aulas.idordprofesor, 'true', 'false'), IF(perfileshard.descripcion<>'', CONCAT(' hardprofile=', REPLACE(TRIM(perfileshard.descripcion), ' ', '_')), ''), IF(aulas.ntp<>'', CONCAT(' ogntp=', aulas.ntp), ''), IF(aulas.dns<>'', CONCAT(' ogdns=', aulas.dns), ''), IF(aulas.proxy<>'', CONCAT(' ogproxy=', aulas.proxy), ''), IF(entidades.ogunit=1 AND NOT centros.directorio='', CONCAT(' ogunit=', centros.directorio), ''), CASE WHEN menus.resolucion IS NULL THEN '' WHEN menus.resolucion <= '999' THEN CONCAT(' vga=', menus.resolucion) WHEN menus.resolucion LIKE '%:%' THEN CONCAT(' video=', menus.resolucion) ELSE menus.resolucion END FROM ordenadores JOIN aulas USING(idaula) JOIN centros USING(idcentro) JOIN entidades USING(identidad) LEFT JOIN repositorios USING(idrepositorio) LEFT JOIN perfileshard USING(idperfilhard) LEFT JOIN menus USING(idmenu) WHERE ordenadores.mac='%s'", getenv("LANG"), mac);
1072
1073        if (dbi_result_get_numrows(result) != 1) {
1074                dbi_conn_error(dbi->conn, &msglog);
1075                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1076                       __FILE__, __LINE__, msglog);
1077                dbi_result_free(result);
1078                return -1;
1079        }
1080        dbi_result_next_row(result);
1081
1082        for (i = 1; i <= dbi_result_get_numfields(result); ++i)
1083                strcat(params, dbi_result_get_string_idx(result, i));
1084
1085        dbi_result_free(result);
1086
1087        snprintf(cmd_params, sizeof(cmd_params),
1088                 "MODE_FILE='%s'\nMAC='%s'\nDATA='%s'\n"
1089                 "MODE='PERM'\nTEMPLATE_NAME='%s'",
1090                 mode, mac, params, template_name);
1091
1092        fd = mkstemp(filename);
1093        if (fd < 0) {
1094                syslog(LOG_ERR, "cannot generate temp file (%s:%d)\n",
1095                       __func__, __LINE__);
1096                return -1;
1097        }
1098
1099        numbytes = write(fd, cmd_params, strlen(cmd_params) + 1);
1100        close(fd);
1101
1102        if (numbytes < 0) {
1103                syslog(LOG_ERR, "cannot write file\n");
1104                unlink(filename);
1105                return -1;
1106        }
1107
1108        if (fork() == 0) {
1109                execlp("/bin/bash", "/bin/bash",
1110                       "/opt/opengnsys/bin/setclientmode", filename, NULL);
1111                syslog(LOG_ERR, "failed script execution (%s:%d)\n",
1112                       __func__, __LINE__);
1113                exit(EXIT_FAILURE);
1114        } else {
1115                wait(&status);
1116        }
1117        unlink(filename);
1118
1119        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
1120                syslog(LOG_ERR, "failed script execution (%s:%d)\n",
1121                       __func__, __LINE__);
1122                return -1;
1123        }
1124
1125        if (og_change_db_mode(dbi, mac, mode) < 0) {
1126                syslog(LOG_ERR, "failed to change db mode (%s:%d)\n",
1127                       __func__, __LINE__);
1128                return -1;
1129        }
1130
1131        return 0;
1132}
1133
1134static int og_cmd_post_modes(json_t *element, struct og_msg_params *params)
1135{
1136        char ips_str[(OG_DB_IP_MAXLEN + 1) * OG_CLIENTS_MAX + 1] = {};
1137        char template_file_uefi[PATH_MAX + 1] = {};
1138        char template_file[PATH_MAX + 1] = {};
1139        char template_name[PATH_MAX + 1] = {};
1140        char first_line[PATH_MAX + 1] = {};
1141        const char *mode_str, *mac;
1142        int ips_str_len = 0;
1143        struct og_dbi *dbi;
1144        uint64_t flags = 0;
1145        dbi_result result;
1146        const char *key;
1147        json_t *value;
1148        int err = 0;
1149        FILE *f;
1150        int i;
1151
1152        json_object_foreach(element, key, value) {
1153                if (!strcmp(key, "clients")) {
1154                        err = og_json_parse_clients(value, params);
1155                } else if (!strcmp(key, "mode")) {
1156                        err = og_json_parse_string(value, &mode_str);
1157                        flags |= OG_REST_PARAM_MODE;
1158                } else {
1159                        err = -1;
1160                }
1161
1162                if (err < 0)
1163                        return err;
1164        }
1165
1166        if (!og_flags_validate(flags, OG_REST_PARAM_MODE) ||
1167            !og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1168                return -1;
1169
1170        snprintf(template_file, sizeof(template_file), "%s/%s",
1171                 OG_TFTP_TMPL_PATH, mode_str);
1172        f = fopen(template_file, "r");
1173        if (!f) {
1174                syslog(LOG_WARNING, "cannot open file %s (%s:%d). Trying UEFI template instead.\n",
1175                       template_file, __func__, __LINE__);
1176
1177                snprintf(template_file_uefi, sizeof(template_file_uefi), "%s/%s",
1178                         OG_TFTP_TMPL_PATH_UEFI, mode_str);
1179                f = fopen(template_file_uefi, "r");
1180                if (!f) {
1181                        syslog(LOG_ERR, "cannot open file %s (%s:%d). No template found.\n",
1182                               template_file_uefi, __func__, __LINE__);
1183                        return -1;
1184                }
1185        }
1186
1187        if (!fgets(first_line, sizeof(first_line), f)) {
1188                fclose(f);
1189                syslog(LOG_ERR, "cannot read file (%s:%d)\n",
1190                       __func__, __LINE__);
1191                return -1;
1192        }
1193
1194        fclose(f);
1195
1196        if (sscanf(first_line, "##NO-TOCAR-ESTA-LINEA %s", template_name) != 1) {
1197                syslog(LOG_ERR, "malformed template: %s", first_line);
1198                return -1;
1199        }
1200
1201        for (i = 0; i < params->ips_array_len; ++i) {
1202                ips_str_len += snprintf(ips_str + ips_str_len,
1203                                        sizeof(ips_str) - ips_str_len,
1204                                        "'%s',", params->ips_array[i]);
1205        }
1206        ips_str[ips_str_len - 1] = '\0';
1207
1208        dbi = og_dbi_open(&ogconfig.db);
1209        if (!dbi) {
1210                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1211                       __func__, __LINE__);
1212                return -1;
1213        }
1214
1215        result = dbi_conn_queryf(dbi->conn,
1216                                 "SELECT mac FROM ordenadores "
1217                                 "WHERE ip IN (%s)", ips_str);
1218
1219        while (dbi_result_next_row(result)) {
1220                mac = dbi_result_get_string(result, "mac");
1221                err = og_set_client_mode(dbi, mac, mode_str, template_name);
1222                if (err != 0) {
1223                        dbi_result_free(result);
1224                        og_dbi_close(dbi);
1225                        return -1;
1226                }
1227        }
1228
1229        dbi_result_free(result);
1230        og_dbi_close(dbi);
1231
1232        return 0;
1233}
1234
1235static int og_cmd_get_client_setup(json_t *element,
1236                                   struct og_msg_params *params,
1237                                   char *buffer_reply)
1238{
1239        json_t *value, *root, *partitions_array, *partition_json;
1240        const char *key, *msglog;
1241        unsigned int len_part;
1242        struct og_dbi *dbi;
1243        dbi_result result;
1244        int err = 0;
1245
1246        struct og_buffer og_buffer = {
1247                .data = buffer_reply
1248        };
1249
1250        struct {
1251                int disk;
1252                int number;
1253                int code;
1254                uint64_t size;
1255                int filesystem;
1256                int format;
1257                int os;
1258                int used_size;
1259                int image;
1260                int software;
1261        } partition;
1262
1263        json_object_foreach(element, key, value) {
1264                if (!strcmp(key, "client")) {
1265                        err = og_json_parse_clients(value, params);
1266                }
1267
1268                if (err < 0)
1269                        return err;
1270        }
1271
1272        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1273                return -1;
1274
1275        if (params->ips_array_len != 1)
1276                return -1;
1277
1278        root = json_object();
1279        if (!root)
1280                return -1;
1281
1282        partitions_array = json_array();
1283        if (!partitions_array) {
1284                json_decref(root);
1285                return -1;
1286        }
1287        json_object_set_new(root, "partitions", partitions_array);
1288
1289        dbi = og_dbi_open(&ogconfig.db);
1290        if (!dbi) {
1291                json_decref(root);
1292                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
1293                       __func__, __LINE__);
1294                return -1;
1295        }
1296
1297        result = dbi_conn_queryf(dbi->conn,
1298                                 "SELECT numdisk, numpar, codpar, tamano, "
1299                                 "       uso, idsistemafichero, idnombreso, "
1300                                 "       idimagen, idperfilsoft "
1301                                 "FROM ordenadores_particiones "
1302                                 "INNER JOIN ordenadores "
1303                                 "ON ordenadores.idordenador = ordenadores_particiones.idordenador "
1304                                 "WHERE ordenadores.ip='%s'",
1305                                 params->ips_array[0]);
1306        if (!result) {
1307                json_decref(root);
1308                dbi_conn_error(dbi->conn, &msglog);
1309                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1310                       __func__, __LINE__, msglog);
1311                og_dbi_close(dbi);
1312                return -1;
1313        }
1314
1315        len_part = 0;
1316        /* partition 0 represents the full disk, hence OG_PARTITION_MAX + 1. */
1317        while (dbi_result_next_row(result) && len_part < OG_PARTITION_MAX + 1) {
1318                partition.disk = dbi_result_get_int(result, "numdisk");
1319                partition.number = dbi_result_get_int(result, "numpar");
1320                partition.code = dbi_result_get_int(result, "codpar");
1321                partition.size = dbi_result_get_longlong(result, "tamano");
1322                partition.used_size = dbi_result_get_int(result, "uso");
1323                partition.filesystem = dbi_result_get_int(result, "idsistemafichero");
1324                partition.os = dbi_result_get_int(result, "idnombreso");
1325                partition.image = dbi_result_get_int(result, "idimagen");
1326                partition.software = dbi_result_get_int(result, "idperfilsoft");
1327
1328                partition_json = json_object();
1329                if (!partition_json) {
1330                        json_decref(root);
1331                        dbi_result_free(result);
1332                        og_dbi_close(dbi);
1333                        return -1;
1334                }
1335
1336                json_object_set_new(partition_json, "disk",
1337                                    json_integer(partition.disk));
1338                json_object_set_new(partition_json, "partition",
1339                                    json_integer(partition.number));
1340                json_object_set_new(partition_json, "code",
1341                                    json_integer(partition.code));
1342                json_object_set_new(partition_json, "size",
1343                                    json_integer(partition.size));
1344                json_object_set_new(partition_json, "used_size",
1345                                    json_integer(partition.used_size));
1346                json_object_set_new(partition_json, "filesystem",
1347                                    json_integer(partition.filesystem));
1348                json_object_set_new(partition_json, "os",
1349                                    json_integer(partition.os));
1350                json_object_set_new(partition_json, "image",
1351                                    json_integer(partition.image));
1352                json_object_set_new(partition_json, "software",
1353                                    json_integer(partition.software));
1354                json_array_append_new(partitions_array, partition_json);
1355
1356                ++len_part;
1357        }
1358
1359        dbi_result_free(result);
1360        og_dbi_close(dbi);
1361
1362        if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) {
1363                json_decref(root);
1364                return -1;
1365        }
1366
1367        json_decref(root);
1368        return 0;
1369}
1370
1371static int og_cmd_get_client_info(json_t *element,
1372                                  struct og_msg_params *params,
1373                                  char *buffer_reply)
1374{
1375        struct og_computer computer = {};
1376        json_t *value, *root;
1377        struct in_addr addr;
1378        struct og_dbi *dbi;
1379        const char *key;
1380        int err = 0;
1381
1382        struct og_buffer og_buffer = {
1383                .data = buffer_reply
1384        };
1385
1386        json_object_foreach(element, key, value) {
1387                if (!strcmp(key, "client")) {
1388                        err = og_json_parse_clients(value, params);
1389                }
1390
1391                if (err < 0)
1392                        return err;
1393        }
1394
1395        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1396                return -1;
1397
1398        if (params->ips_array_len != 1)
1399                return -1;
1400
1401        if (inet_aton(params->ips_array[0], &addr) == 0)
1402                return -1;
1403
1404        dbi = og_dbi_open(&ogconfig.db);
1405        if (!dbi) {
1406                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
1407                       __func__, __LINE__);
1408                return -1;
1409        }
1410
1411        if (og_dbi_get_computer_info(dbi, &computer, addr)) {
1412                og_dbi_close(dbi);
1413                return -1;
1414        }
1415
1416        og_dbi_close(dbi);
1417
1418        root = json_object();
1419        if (!root)
1420                return -1;
1421
1422        json_object_set_new(root, "serial_number",
1423                            json_string(computer.serial_number));
1424        json_object_set_new(root, "hardware_id",
1425                            json_integer(computer.hardware_id));
1426        json_object_set_new(root, "netdriver", json_string(computer.netdriver));
1427        json_object_set_new(root, "maintenance", json_boolean(computer.name));
1428        json_object_set_new(root, "netiface", json_string(computer.netiface));
1429        json_object_set_new(root, "repo_id", json_integer(computer.repo_id));
1430        json_object_set_new(root, "livedir", json_string(computer.livedir));
1431        json_object_set_new(root, "netmask", json_string(computer.netmask));
1432        json_object_set_new(root, "center", json_integer(computer.center));
1433        json_object_set_new(root, "remote", json_boolean(computer.remote));
1434        json_object_set_new(root, "room", json_integer(computer.room));
1435        json_object_set_new(root, "name", json_string(computer.name));
1436        json_object_set_new(root, "boot", json_string(computer.boot));
1437        json_object_set_new(root, "mac", json_string(computer.mac));
1438        json_object_set_new(root, "id", json_integer(computer.id));
1439        json_object_set_new(root, "ip", json_string(computer.ip));
1440
1441        if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) {
1442                json_decref(root);
1443                return -1;
1444        }
1445
1446        json_decref(root);
1447        return 0;
1448}
1449
1450static int og_cmd_post_client_add(json_t *element,
1451                                  struct og_msg_params *params,
1452                                  char *buffer_reply)
1453{
1454        struct og_computer computer = {};
1455        const char *key, *msglog;
1456        struct og_dbi *dbi;
1457        dbi_result result;
1458        json_t *value;
1459        int err = 0;
1460
1461        json_object_foreach(element, key, value) {
1462                if (!strcmp(key, "serial_number")) {
1463                        err = og_json_parse_string_copy(value,
1464                                                        computer.serial_number,
1465                                                        sizeof(computer.serial_number));
1466                } else if (!strcmp(key, "hardware_id")) {
1467                        err = og_json_parse_uint(value, &computer.hardware_id);
1468                } else if (!strcmp(key, "netdriver")) {
1469                        err = og_json_parse_string_copy(value,
1470                                                        computer.netdriver,
1471                                                        sizeof(computer.netdriver));
1472                } else if (!strcmp(key, "maintenance")) {
1473                        err = og_json_parse_bool(value, &computer.maintenance);
1474                } else if (!strcmp(key, "netiface")) {
1475                        err = og_json_parse_string_copy(value,
1476                                                        computer.netiface,
1477                                                        sizeof(computer.netiface));
1478                } else if (!strcmp(key, "repo_id")) {
1479                        err = og_json_parse_uint(value, &computer.repo_id);
1480                } else if (!strcmp(key, "livedir")) {
1481                        err = og_json_parse_string_copy(value,
1482                                                        computer.livedir,
1483                                                        sizeof(computer.livedir));
1484                } else if (!strcmp(key, "netmask")) {
1485                        err = og_json_parse_string_copy(value,
1486                                                        computer.netmask,
1487                                                        sizeof(computer.netmask));
1488                } else if (!strcmp(key, "remote")) {
1489                        err = og_json_parse_bool(value, &computer.remote);
1490                } else if (!strcmp(key, "room")) {
1491                        err = og_json_parse_uint(value, &computer.room);
1492                } else if (!strcmp(key, "name")) {
1493                        err = og_json_parse_string_copy(value,
1494                                                        computer.name,
1495                                                        sizeof(computer.name));
1496                } else if (!strcmp(key, "boot")) {
1497                        err = og_json_parse_string_copy(value,
1498                                                        computer.boot,
1499                                                        sizeof(computer.boot));
1500                } else if (!strcmp(key, "mac")) {
1501                        err = og_json_parse_string_copy(value,
1502                                                        computer.mac,
1503                                                        sizeof(computer.mac));
1504                } else if (!strcmp(key, "ip")) {
1505                        err = og_json_parse_string_copy(value,
1506                                                        computer.ip,
1507                                                        sizeof(computer.ip));
1508                }
1509
1510                if (err < 0)
1511                        return err;
1512        }
1513
1514        dbi = og_dbi_open(&ogconfig.db);
1515        if (!dbi) {
1516                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
1517                       __func__, __LINE__);
1518                return -1;
1519        }
1520
1521        result = dbi_conn_queryf(dbi->conn,
1522                                 "SELECT ip FROM ordenadores WHERE ip='%s'",
1523                                 computer.ip);
1524
1525        if (!result) {
1526                dbi_conn_error(dbi->conn, &msglog);
1527                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1528                       __func__, __LINE__, msglog);
1529                og_dbi_close(dbi);
1530                return -1;
1531        }
1532
1533        if (dbi_result_get_numrows(result) > 0) {
1534                syslog(LOG_ERR, "client with the same IP already exists: %s\n",
1535                       computer.ip);
1536                dbi_result_free(result);
1537                og_dbi_close(dbi);
1538                return -1;
1539        }
1540        dbi_result_free(result);
1541
1542        result = dbi_conn_queryf(dbi->conn,
1543                                 "INSERT INTO ordenadores("
1544                                 "  nombreordenador,"
1545                                 "  numserie,"
1546                                 "  ip,"
1547                                 "  mac,"
1548                                 "  idaula,"
1549                                 "  idperfilhard,"
1550                                 "  idrepositorio,"
1551                                 "  mascara,"
1552                                 "  arranque,"
1553                                 "  netiface,"
1554                                 "  netdriver,"
1555                                 "  oglivedir,"
1556                                 "  inremotepc,"
1557                                 "  maintenance"
1558                                 ") VALUES ('%s', '%s', '%s', '%s', %u, %u,"
1559                                 "           %u, '%s', '%s', '%s', '%s',"
1560                                 "          '%s', %u, %u)",
1561                                 computer.name, computer.serial_number,
1562                                 computer.ip, computer.mac, computer.room,
1563                                 computer.hardware_id, computer.repo_id,
1564                                 computer.netmask, computer.boot,
1565                                 computer.netiface, computer.netdriver,
1566                                 computer.livedir, computer.remote,
1567                                 computer.maintenance);
1568
1569        if (!result) {
1570                dbi_conn_error(dbi->conn, &msglog);
1571                syslog(LOG_ERR, "failed to add client to database (%s:%d) %s\n",
1572                       __func__, __LINE__, msglog);
1573                og_dbi_close(dbi);
1574                return -1;
1575        }
1576
1577        dbi_result_free(result);
1578        og_dbi_close(dbi);
1579        return 0;
1580}
1581
1582static int og_cmd_post_client_delete(json_t *element,
1583                                     struct og_msg_params *params)
1584{
1585        const char *key, *msglog;
1586        struct og_dbi *dbi;
1587        dbi_result result;
1588        unsigned int i;
1589        json_t *value;
1590        int err = 0;
1591
1592        json_object_foreach(element, key, value) {
1593                if (!strcmp(key, "clients"))
1594                        err = og_json_parse_clients(value, params);
1595
1596                if (err < 0)
1597                        return err;
1598        }
1599
1600        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1601                return -1;
1602
1603        dbi = og_dbi_open(&ogconfig.db);
1604        if (!dbi) {
1605                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
1606                       __func__, __LINE__);
1607                return -1;
1608        }
1609
1610        for (i = 0; i < params->ips_array_len; i++) {
1611                result = dbi_conn_queryf(dbi->conn,
1612                                         "DELETE FROM ordenadores WHERE ip='%s'",
1613                                         params->ips_array[i]);
1614
1615                if (!result) {
1616                        dbi_conn_error(dbi->conn, &msglog);
1617                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1618                               __func__, __LINE__, msglog);
1619                        og_dbi_close(dbi);
1620                        return -1;
1621                }
1622
1623                dbi_result_free(result);
1624        }
1625
1626        og_dbi_close(dbi);
1627        return 0;
1628}
1629
1630static int og_cmd_stop(json_t *element, struct og_msg_params *params)
1631{
1632        const char *key;
1633        json_t *value;
1634        int err = 0;
1635
1636        if (json_typeof(element) != JSON_OBJECT)
1637                return -1;
1638
1639        json_object_foreach(element, key, value) {
1640                if (!strcmp(key, "clients"))
1641                        err = og_json_parse_clients(value, params);
1642
1643                if (err < 0)
1644                        return err;
1645        }
1646
1647        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1648                return -1;
1649
1650        return og_send_request(OG_METHOD_POST, OG_CMD_STOP, params, NULL);
1651}
1652
1653static int og_cmd_hardware(json_t *element, struct og_msg_params *params)
1654{
1655        const char *key;
1656        json_t *value;
1657        int err = 0;
1658
1659        if (json_typeof(element) != JSON_OBJECT)
1660                return -1;
1661
1662        json_object_foreach(element, key, value) {
1663                if (!strcmp(key, "clients"))
1664                        err = og_json_parse_clients(value, params);
1665
1666                if (err < 0)
1667                        return err;
1668        }
1669
1670        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1671                return -1;
1672
1673        return og_send_request(OG_METHOD_GET, OG_CMD_HARDWARE, params, NULL);
1674}
1675
1676static int og_cmd_get_hardware(json_t *element, struct og_msg_params *params,
1677                               char *buffer_reply)
1678{
1679        const char *key, *msglog, *hw_item, *hw_type;
1680        json_t *value, *root, *array, *item;
1681        struct og_dbi *dbi;
1682        dbi_result result;
1683        int err = 0;
1684
1685        struct og_buffer og_buffer = {
1686                .data = buffer_reply
1687        };
1688
1689        json_object_foreach(element, key, value) {
1690                if (!strcmp(key, "client"))
1691                        err = og_json_parse_clients(value, params);
1692
1693                if (err < 0)
1694                        return err;
1695        }
1696
1697        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1698                return -1;
1699
1700        dbi = og_dbi_open(&ogconfig.db);
1701        if (!dbi) {
1702                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1703                       __func__, __LINE__);
1704                return -1;
1705        }
1706
1707        result = dbi_conn_queryf(dbi->conn,
1708                                 "SELECT hardwares.descripcion AS item, "
1709                                 "       tipohardwares.descripcion AS type "
1710                                 "FROM hardwares "
1711                                 "INNER JOIN perfileshard_hardwares "
1712                                 "    ON hardwares.idhardware = perfileshard_hardwares.idhardware "
1713                                 "INNER JOIN ordenadores "
1714                                 "    ON perfileshard_hardwares.idperfilhard = ordenadores.idperfilhard "
1715                                 "INNER JOIN tipohardwares "
1716                                 "    ON hardwares.idtipohardware = tipohardwares.idtipohardware "
1717                                 "WHERE ordenadores.ip = '%s'",
1718                                 params->ips_array[0]);
1719        if (!result) {
1720                dbi_conn_error(dbi->conn, &msglog);
1721                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1722                       __func__, __LINE__, msglog);
1723                og_dbi_close(dbi);
1724                return -1;
1725        }
1726
1727        array = json_array();
1728        if (!array) {
1729                dbi_result_free(result);
1730                og_dbi_close(dbi);
1731                return -1;
1732        }
1733
1734        while (dbi_result_next_row(result)) {
1735                item = json_object();
1736                if (!item) {
1737                        dbi_result_free(result);
1738                        og_dbi_close(dbi);
1739                        json_decref(array);
1740                        return -1;
1741                }
1742
1743                hw_item = dbi_result_get_string(result, "item");
1744                hw_type = dbi_result_get_string(result, "type");
1745
1746                json_object_set_new(item, "type", json_string(hw_type));
1747                json_object_set_new(item, "description", json_string(hw_item));
1748                json_array_append_new(array, item);
1749        }
1750
1751        dbi_result_free(result);
1752        og_dbi_close(dbi);
1753
1754        root = json_object();
1755        if (!root){
1756                json_decref(array);
1757                return -1;
1758        }
1759
1760        json_object_set_new(root, "hardware", array);
1761
1762        if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) {
1763                json_decref(root);
1764                return -1;
1765        }
1766
1767        json_decref(root);
1768        return 0;
1769}
1770
1771static int og_cmd_software(json_t *element, struct og_msg_params *params)
1772{
1773        json_t *clients, *value;
1774        const char *key;
1775        int err = 0;
1776
1777        if (json_typeof(element) != JSON_OBJECT)
1778                return -1;
1779
1780        json_object_foreach(element, key, value) {
1781                if (!strcmp(key, "clients"))
1782                        err = og_json_parse_clients(value, params);
1783                else if (!strcmp(key, "disk")) {
1784                        err = og_json_parse_string(value, &params->disk);
1785                        params->flags |= OG_REST_PARAM_DISK;
1786                }
1787                else if (!strcmp(key, "partition")) {
1788                        err = og_json_parse_string(value, &params->partition);
1789                        params->flags |= OG_REST_PARAM_PARTITION;
1790                }
1791
1792                if (err < 0)
1793                        return err;
1794        }
1795
1796        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1797                                            OG_REST_PARAM_DISK |
1798                                            OG_REST_PARAM_PARTITION))
1799                return -1;
1800
1801        clients = json_copy(element);
1802        json_object_del(clients, "clients");
1803
1804        return og_send_request(OG_METHOD_GET, OG_CMD_SOFTWARE, params, clients);
1805}
1806
1807static int og_cmd_get_software(json_t *element, struct og_msg_params *params,
1808                               char *buffer_reply)
1809{
1810        json_t *value, *software, *root;
1811        const char *key, *msglog, *name;
1812        uint64_t disk, partition;
1813        uint64_t flags = 0;
1814        struct og_dbi *dbi;
1815        dbi_result result;
1816        int err = 0;
1817
1818        struct og_buffer og_buffer = {
1819                .data = buffer_reply
1820        };
1821
1822        if (json_typeof(element) != JSON_OBJECT)
1823                return -1;
1824
1825        json_object_foreach(element, key, value) {
1826                if (!strcmp(key, "client")) {
1827                        err = og_json_parse_clients(value, params);
1828                } else if (!strcmp(key, "disk")) {
1829                        err = og_json_parse_uint64(value, &disk);
1830                        flags |= OG_REST_PARAM_DISK;
1831                } else if (!strcmp(key, "partition")) {
1832                        err = og_json_parse_uint64(value, &partition);
1833                        flags |= OG_REST_PARAM_PARTITION;
1834                }
1835
1836                if (err < 0)
1837                        return err;
1838        }
1839
1840        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR) ||
1841            !og_flags_validate(flags, OG_REST_PARAM_DISK |
1842                                      OG_REST_PARAM_PARTITION))
1843                return -1;
1844
1845        dbi = og_dbi_open(&ogconfig.db);
1846        if (!dbi) {
1847                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
1848                       __func__, __LINE__);
1849                return -1;
1850        }
1851
1852        result = dbi_conn_queryf(dbi->conn,
1853                                 "SELECT s.descripcion "
1854                                 "FROM softwares s "
1855                                 "INNER JOIN perfilessoft_softwares pss "
1856                                 "ON s.idsoftware = pss.idsoftware "
1857                                 "INNER JOIN ordenadores_particiones op "
1858                                 "ON pss.idperfilsoft = op.idperfilsoft "
1859                                 "INNER JOIN ordenadores o "
1860                                 "ON o.idordenador = op.idordenador "
1861                                 "WHERE o.ip='%s' AND "
1862                                 "      op.numdisk=%lu AND "
1863                                 "      op.numpar=%lu",
1864                                 params->ips_array[0], disk, partition);
1865        if (!result) {
1866                dbi_conn_error(dbi->conn, &msglog);
1867                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1868                       __func__, __LINE__, msglog);
1869                return -1;
1870        }
1871        software = json_array();
1872        if (!software) {
1873                dbi_result_free(result);
1874                og_dbi_close(dbi);
1875                return -1;
1876        }
1877
1878        while (dbi_result_next_row(result)) {
1879                name = dbi_result_get_string(result, "descripcion");
1880                json_array_append_new(software, json_string(name));
1881        }
1882
1883        dbi_result_free(result);
1884        og_dbi_close(dbi);
1885
1886        root = json_object();
1887        if (!root) {
1888                json_decref(software);
1889                return -1;
1890        }
1891        json_object_set_new(root, "software", software);
1892
1893        if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) {
1894                json_decref(root);
1895                return -1;
1896        }
1897
1898        json_decref(root);
1899        return 0;
1900}
1901
1902#define OG_IMAGE_TYPE_MAXLEN    4
1903
1904static int og_get_image_stats(const char *name,
1905                              struct stat *image_stats)
1906{
1907        const char *dir = ogconfig.repo.dir;
1908        char filename[PATH_MAX + 1];
1909
1910        snprintf(filename, sizeof(filename), "%s/%s.img", dir, name);
1911        if (stat(filename, image_stats) < 0) {
1912                syslog(LOG_ERR, "%s image does not exists", name);
1913                return -1;
1914        }
1915        return 0;
1916}
1917
1918static json_t *og_json_disk_alloc()
1919{
1920        const char *dir = ogconfig.repo.dir;
1921        struct statvfs buffer;
1922        json_t *disk_json;
1923        int ret;
1924
1925        ret = statvfs(dir, &buffer);
1926        if (ret)
1927                return NULL;
1928
1929        disk_json = json_object();
1930        if (!disk_json)
1931                return NULL;
1932
1933        json_object_set_new(disk_json, "total",
1934                            json_integer(buffer.f_blocks * buffer.f_frsize));
1935        json_object_set_new(disk_json, "free",
1936                            json_integer(buffer.f_bfree * buffer.f_frsize));
1937
1938        return disk_json;
1939}
1940
1941#define OG_PERMS_IRWX (S_IRWXU | S_IRWXG | S_IRWXO)
1942#define OG_PERMS_MAXLEN 4
1943
1944static json_t *og_json_image_alloc(struct og_image *image)
1945{
1946        char perms_string[OG_PERMS_MAXLEN];
1947        json_t *image_json;
1948        char *modified;
1949        uint16_t perms;
1950
1951        image_json = json_object();
1952        if (!image_json)
1953                return NULL;
1954
1955        perms = image->image_stats.st_mode & OG_PERMS_IRWX;
1956        snprintf(perms_string, sizeof(perms_string), "%o", perms);
1957
1958        modified = ctime(&image->image_stats.st_mtime);
1959        modified[strlen(modified) - 1] = '\0';
1960
1961        json_object_set_new(image_json, "name",
1962                            json_string(image->name));
1963        json_object_set_new(image_json, "datasize",
1964                            json_integer(image->datasize));
1965        json_object_set_new(image_json, "size",
1966                            json_integer(image->image_stats.st_size));
1967        json_object_set_new(image_json, "modified",
1968                            json_string(modified));
1969        json_object_set_new(image_json, "permissions",
1970                            json_string(perms_string));
1971        json_object_set_new(image_json, "software_id",
1972                            json_integer(image->software_id));
1973        json_object_set_new(image_json, "type",
1974                            json_integer(image->type));
1975        json_object_set_new(image_json, "id",
1976                            json_integer(image->id));
1977
1978        return image_json;
1979}
1980
1981static int og_cmd_images(char *buffer_reply)
1982{
1983        json_t *root, *images, *image_json, *disk_json;
1984        struct og_buffer og_buffer = {
1985                .data = buffer_reply
1986        };
1987        struct og_image image;
1988        struct og_dbi *dbi;
1989        dbi_result result;
1990
1991        root = json_object();
1992        if (!root)
1993                return -1;
1994
1995        images = json_array();
1996        if (!images) {
1997                json_decref(root);
1998                return -1;
1999        }
2000
2001        json_object_set_new(root, "images", images);
2002
2003        dbi = og_dbi_open(&ogconfig.db);
2004        if (!dbi) {
2005                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2006                       __func__, __LINE__);
2007                json_decref(root);
2008                return -1;
2009        }
2010
2011        result = dbi_conn_queryf(dbi->conn,
2012                                 "SELECT i.nombreca, o.nombreordenador, "
2013                                 "       i.clonator, i.compressor, "
2014                                 "       i.filesystem, i.datasize, "
2015                                 "       i.idperfilsoft, i.tipo, "
2016                                 "       i.idimagen "
2017                                 "FROM imagenes i "
2018                                 "LEFT JOIN ordenadores o "
2019                                 "ON i.idordenador = o.idordenador");
2020
2021        while (dbi_result_next_row(result)) {
2022                image = (struct og_image){0};
2023                image.datasize = dbi_result_get_ulonglong(result, "datasize");
2024                image.software_id = dbi_result_get_ulonglong(result, "idperfilsoft");
2025                image.type = dbi_result_get_ulonglong(result, "tipo");
2026                image.id = dbi_result_get_ulonglong(result, "idimagen");
2027                snprintf(image.name, sizeof(image.name), "%s",
2028                         dbi_result_get_string(result, "nombreca"));
2029
2030                if (og_get_image_stats(image.name, &image.image_stats)) {
2031                        continue;
2032                }
2033
2034                image_json = og_json_image_alloc(&image);
2035                if (!image_json) {
2036                        dbi_result_free(result);
2037                        og_dbi_close(dbi);
2038                        json_decref(root);
2039                        return -1;
2040                }
2041
2042                json_array_append_new(images, image_json);
2043        }
2044
2045        dbi_result_free(result);
2046        og_dbi_close(dbi);
2047
2048        disk_json = og_json_disk_alloc();
2049        if (!disk_json) {
2050                syslog(LOG_ERR, "cannot allocate disk json");
2051                json_decref(root);
2052                return -1;
2053        }
2054
2055        json_object_set_new(root, "disk", disk_json);
2056
2057        if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) {
2058                json_decref(root);
2059                return -1;
2060        }
2061
2062        json_decref(root);
2063
2064        return 0;
2065}
2066
2067int og_json_parse_create_image(json_t *element,
2068                               struct og_msg_params *params)
2069{
2070        const char *key;
2071        json_t *value;
2072        int err = 0;
2073
2074        if (json_typeof(element) != JSON_OBJECT)
2075                return -1;
2076
2077        json_object_foreach(element, key, value) {
2078                if (!strcmp(key, "disk")) {
2079                        err = og_json_parse_string(value, &params->disk);
2080                        params->flags |= OG_REST_PARAM_DISK;
2081                } else if (!strcmp(key, "partition")) {
2082                        err = og_json_parse_string(value, &params->partition);
2083                        params->flags |= OG_REST_PARAM_PARTITION;
2084                } else if (!strcmp(key, "name")) {
2085                        err = og_json_parse_string_copy(value,
2086                                                        (char *)&params->image.name,
2087                                                        sizeof(params->image.name));
2088                        params->flags |= OG_REST_PARAM_NAME;
2089                } else if (!strcmp(key, "repository")) {
2090                        err = og_json_parse_string(value, &params->repository);
2091                        params->flags |= OG_REST_PARAM_REPO;
2092                } else if (!strcmp(key, "clients")) {
2093                        err = og_json_parse_clients(value, params);
2094                } else if (!strcmp(key, "id")) {
2095                        err = og_json_parse_string(value, &params->id);
2096                        params->flags |= OG_REST_PARAM_ID;
2097                } else if (!strcmp(key, "code")) {
2098                        err = og_json_parse_string(value, &params->code);
2099                        params->flags |= OG_REST_PARAM_CODE;
2100                } else if (!strcmp(key, "description")) {
2101                        err = og_json_parse_string_copy(value,
2102                                                        (char *)&params->image.description,
2103                                                        sizeof(params->image.description));
2104                } else if (!strcmp(key, "group_id")) {
2105                        err = og_json_parse_uint64(value, &params->image.group_id);
2106                } else if (!strcmp(key, "center_id")) {
2107                        err = og_json_parse_uint64(value, &params->image.center_id);
2108                }
2109
2110                if (err < 0)
2111                        return err;
2112        }
2113
2114        return 0;
2115}
2116
2117static int og_cmd_create_image(json_t *element, struct og_msg_params *params)
2118{
2119        char new_image_id[OG_DB_INT_MAXLEN + 1];
2120        struct og_dbi *dbi;
2121        json_t *clients;
2122        int err = 0;
2123
2124        err = og_json_parse_create_image(element, params);
2125        if (err < 0)
2126                return err;
2127
2128        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2129                                            OG_REST_PARAM_DISK |
2130                                            OG_REST_PARAM_PARTITION |
2131                                            OG_REST_PARAM_CODE |
2132                                            OG_REST_PARAM_ID |
2133                                            OG_REST_PARAM_NAME |
2134                                            OG_REST_PARAM_REPO))
2135                return -1;
2136
2137        /* If there is a description, this means the image is not in the DB. */
2138        if (params->image.description[0]) {
2139                dbi = og_dbi_open(&ogconfig.db);
2140                if (!dbi) {
2141                        syslog(LOG_ERR,
2142                               "cannot open connection database (%s:%d)\n",
2143                               __func__, __LINE__);
2144                        return -1;
2145                }
2146
2147                err = og_dbi_add_image(dbi, &params->image);
2148
2149                og_dbi_close(dbi);
2150                if (err < 0)
2151                        return err;
2152
2153                snprintf(new_image_id, sizeof(new_image_id), "%u", err);
2154                params->id = new_image_id;
2155        }
2156
2157        clients = json_copy(element);
2158        json_object_del(clients, "clients");
2159
2160        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_CREATE, params,
2161                               clients);
2162}
2163
2164int og_json_parse_restore_image(json_t *element, struct og_msg_params *params)
2165{
2166        const char *key;
2167        json_t *value;
2168        int err = 0;
2169
2170        if (json_typeof(element) != JSON_OBJECT)
2171                return -1;
2172
2173        json_object_foreach(element, key, value) {
2174                if (!strcmp(key, "disk")) {
2175                        err = og_json_parse_string(value, &params->disk);
2176                        params->flags |= OG_REST_PARAM_DISK;
2177                } else if (!strcmp(key, "partition")) {
2178                        err = og_json_parse_string(value, &params->partition);
2179                        params->flags |= OG_REST_PARAM_PARTITION;
2180                } else if (!strcmp(key, "name")) {
2181                        err = og_json_parse_string(value, &params->name);
2182                        params->flags |= OG_REST_PARAM_NAME;
2183                } else if (!strcmp(key, "repository")) {
2184                        err = og_json_parse_string(value, &params->repository);
2185                        params->flags |= OG_REST_PARAM_REPO;
2186                } else if (!strcmp(key, "clients")) {
2187                        err = og_json_parse_clients(value, params);
2188                } else if (!strcmp(key, "type")) {
2189                        err = og_json_parse_string(value, &params->type);
2190                        params->flags |= OG_REST_PARAM_TYPE;
2191                } else if (!strcmp(key, "profile")) {
2192                        err = og_json_parse_string(value, &params->profile);
2193                        params->flags |= OG_REST_PARAM_PROFILE;
2194                } else if (!strcmp(key, "id")) {
2195                        err = og_json_parse_string(value, &params->id);
2196                        params->flags |= OG_REST_PARAM_ID;
2197                }
2198
2199                if (err < 0)
2200                        return err;
2201        }
2202
2203        return 0;
2204}
2205
2206static int og_cmd_restore_image(json_t *element, struct og_msg_params *params)
2207{
2208        json_t *clients;
2209        int err = 0;
2210
2211        err = og_json_parse_restore_image(element, params);
2212        if (err < 0)
2213                return err;
2214
2215        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2216                                            OG_REST_PARAM_DISK |
2217                                            OG_REST_PARAM_PARTITION |
2218                                            OG_REST_PARAM_NAME |
2219                                            OG_REST_PARAM_REPO |
2220                                            OG_REST_PARAM_TYPE |
2221                                            OG_REST_PARAM_PROFILE |
2222                                            OG_REST_PARAM_ID))
2223                return -1;
2224
2225        clients = json_copy(element);
2226        json_object_del(clients, "clients");
2227
2228        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, params,
2229                               clients);
2230}
2231
2232static int og_cmd_delete_image(json_t *element, struct og_msg_params *params)
2233{
2234        char filename[PATH_MAX + 1];
2235        const char *key, *image;
2236        struct og_dbi *dbi;
2237        dbi_result result;
2238        int rval, err = 0;
2239        json_t *value;
2240
2241
2242        if (json_typeof(element) != JSON_OBJECT)
2243                return -1;
2244
2245        json_object_foreach(element, key, value) {
2246                if (!strcmp(key, "image")) {
2247                        err = og_json_parse_string(value, &params->id);
2248                        params->flags |= OG_REST_PARAM_ID;
2249                }
2250
2251                if (err < 0)
2252                        return err;
2253        }
2254
2255        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
2256                return -1;
2257
2258        dbi = og_dbi_open(&ogconfig.db);
2259        if (!dbi) {
2260                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2261                       __func__, __LINE__);
2262                return -1;
2263        }
2264
2265        result = dbi_conn_queryf(dbi->conn,
2266                                 "SELECT nombreca FROM imagenes "
2267                                 "WHERE idimagen='%s'",
2268                                 params->id);
2269        if (!result) {
2270                og_dbi_close(dbi);
2271                syslog(LOG_ERR, "failed to query database\n");
2272                return -1;
2273        }
2274        if (!dbi_result_next_row(result)) {
2275                dbi_result_free(result);
2276                og_dbi_close(dbi);
2277                syslog(LOG_ERR, "image does not exist in database\n");
2278                return -1;
2279        }
2280
2281        image = dbi_result_get_string(result, "nombreca");
2282        snprintf(filename, sizeof(filename), "%s/%s.img", ogconfig.repo.dir,
2283                 image);
2284        dbi_result_free(result);
2285
2286        result = dbi_conn_queryf(dbi->conn,
2287                                 "DELETE FROM imagenes "
2288                                 "WHERE idimagen='%s'",
2289                                 params->id);
2290        if (!result) {
2291                og_dbi_close(dbi);
2292                syslog(LOG_ERR, "failed to query database\n");
2293                return -1;
2294        }
2295        dbi_result_free(result);
2296
2297        rval = unlink(filename);
2298        if (rval) {
2299                og_dbi_close(dbi);
2300                syslog(LOG_ERR, "cannot delete image %s: %s\n",
2301                       image, strerror(errno));
2302                return -1;
2303        }
2304        og_dbi_close(dbi);
2305
2306        return 0;
2307}
2308
2309static int og_cmd_setup(json_t *element, struct og_msg_params *params)
2310{
2311        json_t *value, *clients;
2312        const char *key;
2313        int err = 0;
2314
2315        if (json_typeof(element) != JSON_OBJECT)
2316                return -1;
2317
2318        json_object_foreach(element, key, value) {
2319                if (!strcmp(key, "clients")) {
2320                        err = og_json_parse_clients(value, params);
2321                } else if (!strcmp(key, "type")) {
2322                        err = og_json_parse_string(value, &params->type);
2323                        params->flags |= OG_REST_PARAM_TYPE;
2324                } else if (!strcmp(key, "disk")) {
2325                        err = og_json_parse_string(value, &params->disk);
2326                        params->flags |= OG_REST_PARAM_DISK;
2327                } else if (!strcmp(key, "cache")) {
2328                        err = og_json_parse_string(value, &params->cache);
2329                        params->flags |= OG_REST_PARAM_CACHE;
2330                } else if (!strcmp(key, "cache_size")) {
2331                        err = og_json_parse_string(value, &params->cache_size);
2332                        params->flags |= OG_REST_PARAM_CACHE_SIZE;
2333                } else if (!strcmp(key, "partition_setup")) {
2334                        err = og_json_parse_partition_setup(value, params);
2335                }
2336
2337                if (err < 0)
2338                        return err;
2339        }
2340
2341        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2342                                            OG_REST_PARAM_TYPE |
2343                                            OG_REST_PARAM_DISK |
2344                                            OG_REST_PARAM_CACHE |
2345                                            OG_REST_PARAM_CACHE_SIZE |
2346                                            OG_REST_PARAM_PART_0 |
2347                                            OG_REST_PARAM_PART_1 |
2348                                            OG_REST_PARAM_PART_2 |
2349                                            OG_REST_PARAM_PART_3))
2350                return -1;
2351
2352        clients = json_copy(element);
2353        json_object_del(clients, "clients");
2354
2355        return og_send_request(OG_METHOD_POST, OG_CMD_SETUP, params, clients);
2356}
2357
2358static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params)
2359{
2360        const char *key;
2361        json_t *value;
2362        int err = 0;
2363
2364        json_object_foreach(element, key, value) {
2365                if (!strcmp(key, "clients"))
2366                        err = og_json_parse_clients(value, params);
2367
2368                if (err < 0)
2369                        return err;
2370        }
2371
2372        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2373                return -1;
2374
2375        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
2376                               NULL);
2377}
2378
2379static LIST_HEAD(cmd_list);
2380
2381const struct og_cmd *og_cmd_find(const char *client_ip)
2382{
2383        struct og_cmd *cmd, *next;
2384
2385        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
2386                if (strcmp(cmd->ip, client_ip))
2387                        continue;
2388
2389                list_del(&cmd->list);
2390                return cmd;
2391        }
2392
2393        return NULL;
2394}
2395
2396void og_cmd_free(const struct og_cmd *cmd)
2397{
2398        struct og_msg_params *params = (struct og_msg_params *)&cmd->params;
2399        int i;
2400
2401        for (i = 0; i < params->ips_array_len; i++) {
2402                free((void *)params->netmask_array[i]);
2403                free((void *)params->ips_array[i]);
2404                free((void *)params->mac_array[i]);
2405        }
2406        free((void *)params->wol_type);
2407
2408        if (cmd->json)
2409                json_decref(cmd->json);
2410
2411        free((void *)cmd->ip);
2412        free((void *)cmd->mac);
2413        free((void *)cmd);
2414}
2415
2416static void og_cmd_init(struct og_cmd *cmd, enum og_rest_method method,
2417                        enum og_cmd_type type, json_t *root)
2418{
2419        cmd->type = type;
2420        cmd->method = method;
2421        cmd->params.ips_array[0] = strdup(cmd->ip);
2422        cmd->params.ips_array_len = 1;
2423        cmd->json = root;
2424        gettimeofday(&cmd->tv, NULL);
2425}
2426
2427static int og_cmd_legacy_wol(const char *input, struct og_cmd *cmd)
2428{
2429        char wol_type[2] = {};
2430        const char *msglog;
2431        struct og_dbi *dbi;
2432        dbi_result result;
2433
2434        if (sscanf(input, "mar=%s", wol_type) != 1) {
2435                syslog(LOG_ERR, "malformed database legacy input\n");
2436                return -1;
2437        }
2438
2439        dbi = og_dbi_open(&ogconfig.db);
2440        if (!dbi) {
2441                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2442                       __func__, __LINE__);
2443                return -1;
2444        }
2445
2446        result = dbi_conn_queryf(dbi->conn,
2447                                 "SELECT aulas.netmask "
2448                                 "FROM   ordenadores "
2449                                 "INNER JOIN aulas "
2450                                         "ON ordenadores.idaula = aulas.idaula "
2451                                 "WHERE  ordenadores.ip = '%s'",
2452                                 cmd->ip);
2453        if (!result) {
2454                dbi_conn_error(dbi->conn, &msglog);
2455                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2456                       __func__, __LINE__, msglog);
2457                og_dbi_close(dbi);
2458                return -1;
2459        }
2460        dbi_result_next_row(result);
2461
2462        og_cmd_init(cmd, OG_METHOD_NO_HTTP, OG_CMD_WOL, NULL);
2463        cmd->params.netmask_array[0] = dbi_result_get_string_copy(result,
2464                                                                  "netmask");
2465        cmd->params.mac_array[0] = strdup(cmd->mac);
2466        cmd->params.wol_type = strdup(wol_type);
2467
2468        dbi_result_free(result);
2469        og_dbi_close(dbi);
2470
2471        return 0;
2472}
2473
2474static int og_cmd_legacy_shell_run(const char *input, struct og_cmd *cmd)
2475{
2476        json_t *root, *script, *echo;
2477
2478        script = json_string(input + 4);
2479        echo = json_boolean(false);
2480
2481        root = json_object();
2482        if (!root)
2483                return -1;
2484        json_object_set_new(root, "run", script);
2485        json_object_set_new(root, "echo", echo);
2486
2487        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SHELL_RUN, root);
2488
2489        return 0;
2490}
2491
2492static int og_cmd_legacy_session(const char *input, struct og_cmd *cmd)
2493{
2494        char part_str[OG_DB_SMALLINT_MAXLEN + 1];
2495        char disk_str[OG_DB_SMALLINT_MAXLEN + 1];
2496        json_t *root, *disk, *partition;
2497
2498        if (sscanf(input, "dsk=%s\rpar=%s\r", disk_str, part_str) != 2)
2499                return -1;
2500        partition = json_string(part_str);
2501        disk = json_string(disk_str);
2502
2503        root = json_object();
2504        if (!root)
2505                return -1;
2506        json_object_set_new(root, "partition", partition);
2507        json_object_set_new(root, "disk", disk);
2508
2509        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SESSION, root);
2510
2511        return 0;
2512}
2513
2514static int og_cmd_legacy_poweroff(const char *input, struct og_cmd *cmd)
2515{
2516        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_POWEROFF, NULL);
2517
2518        return 0;
2519}
2520
2521static int og_cmd_legacy_refresh(const char *input, struct og_cmd *cmd)
2522{
2523        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_REFRESH, NULL);
2524
2525        return 0;
2526}
2527
2528static int og_cmd_legacy_reboot(const char *input, struct og_cmd *cmd)
2529{
2530        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_REBOOT, NULL);
2531
2532        return 0;
2533}
2534
2535static int og_cmd_legacy_stop(const char *input, struct og_cmd *cmd)
2536{
2537        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_STOP, NULL);
2538
2539        return 0;
2540}
2541
2542static int og_cmd_legacy_hardware(const char *input, struct og_cmd *cmd)
2543{
2544        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_HARDWARE, NULL);
2545
2546        return 0;
2547}
2548
2549static int og_cmd_legacy_software(const char *input, struct og_cmd *cmd)
2550{
2551        char part_str[OG_DB_SMALLINT_MAXLEN + 1];
2552        char disk_str[OG_DB_SMALLINT_MAXLEN + 1];
2553        json_t *root, *disk, *partition;
2554
2555        if (sscanf(input, "dsk=%s\rpar=%s\r", disk_str, part_str) != 2)
2556                return -1;
2557        partition = json_string(part_str);
2558        disk = json_string(disk_str);
2559
2560        root = json_object();
2561        if (!root)
2562                return -1;
2563        json_object_set_new(root, "partition", partition);
2564        json_object_set_new(root, "disk", disk);
2565
2566        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_SOFTWARE, root);
2567
2568        return 0;
2569}
2570
2571static int og_cmd_legacy_image_create(const char *input, struct og_cmd *cmd)
2572{
2573        json_t *root, *disk, *partition, *code, *image_id, *name, *repo;
2574        struct og_image_legacy img = {};
2575
2576        if (sscanf(input, "dsk=%s\rpar=%s\rcpt=%s\ridi=%s\rnci=%s\ripr=%s\r",
2577                   img.disk, img.part, img.code, img.image_id, img.name,
2578                   img.repo) != 6)
2579                return -1;
2580        image_id = json_string(img.image_id);
2581        partition = json_string(img.part);
2582        code = json_string(img.code);
2583        name = json_string(img.name);
2584        repo = json_string(img.repo);
2585        disk = json_string(img.disk);
2586
2587        root = json_object();
2588        if (!root)
2589                return -1;
2590        json_object_set_new(root, "partition", partition);
2591        json_object_set_new(root, "repository", repo);
2592        json_object_set_new(root, "id", image_id);
2593        json_object_set_new(root, "code", code);
2594        json_object_set_new(root, "name", name);
2595        json_object_set_new(root, "disk", disk);
2596
2597        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_CREATE, root);
2598
2599        return 0;
2600}
2601
2602#define OG_DB_RESTORE_TYPE_MAXLEN       64
2603
2604static int og_cmd_legacy_image_restore(const char *input, struct og_cmd *cmd)
2605{
2606        json_t *root, *disk, *partition, *image_id, *name, *repo;
2607        char restore_type_str[OG_DB_RESTORE_TYPE_MAXLEN + 1] = {};
2608        char software_id_str[OG_DB_INT_MAXLEN + 1] = {};
2609        json_t *software_id, *restore_type;
2610        struct og_image_legacy img = {};
2611
2612        if (sscanf(input,
2613                   "dsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
2614                   "ipr=%s\rifs=%s\rptc=%[^\r]\r",
2615                   img.disk, img.part, img.image_id, img.name, img.repo,
2616                   software_id_str, restore_type_str) != 7)
2617                return -1;
2618
2619        restore_type = json_string(restore_type_str);
2620        software_id = json_string(software_id_str);
2621        image_id = json_string(img.image_id);
2622        partition = json_string(img.part);
2623        name = json_string(img.name);
2624        repo = json_string(img.repo);
2625        disk = json_string(img.disk);
2626
2627        root = json_object();
2628        if (!root)
2629                return -1;
2630        json_object_set_new(root, "profile", software_id);
2631        json_object_set_new(root, "partition", partition);
2632        json_object_set_new(root, "type", restore_type);
2633        json_object_set_new(root, "repository", repo);
2634        json_object_set_new(root, "id", image_id);
2635        json_object_set_new(root, "name", name);
2636        json_object_set_new(root, "disk", disk);
2637
2638        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, root);
2639
2640        return 0;
2641}
2642
2643#define OG_PARTITION_TABLE_TYPE_MAXLEN 5
2644
2645static int og_cmd_legacy_setup(const char *input, struct og_cmd *cmd)
2646{
2647        json_t *root, *disk, *cache, *cache_size, *partition_setup, *object;
2648        char part_table_type_str[OG_PARTITION_TABLE_TYPE_MAXLEN + 1];
2649        struct og_legacy_partition part_cfg[OG_PARTITION_MAX] = {};
2650        json_t *part_table_type, *part, *code, *fs, *size, *format;
2651        char cache_size_str [OG_DB_INT_MAXLEN + 1];
2652        char disk_str [OG_DB_SMALLINT_MAXLEN + 1];
2653        unsigned int partition_len = 0;
2654        const char *in_ptr;
2655        char cache_str[2];
2656
2657        if (sscanf(input, "ttp=%s\rdsk=%s\rcfg=dis=%*[^*]*che=%[^*]*tch=%[^!]!",
2658                   part_table_type_str, disk_str, cache_str, cache_size_str) != 4)
2659                return -1;
2660
2661        in_ptr = strstr(input, "!") + 1;
2662        while (strlen(in_ptr) > 0) {
2663                if(sscanf(in_ptr,
2664                          "par=%[^*]*cpt=%[^*]*sfi=%[^*]*tam=%[^*]*ope=%[^%%]%%",
2665                          part_cfg[partition_len].partition,
2666                          part_cfg[partition_len].code,
2667                          part_cfg[partition_len].filesystem,
2668                          part_cfg[partition_len].size,
2669                          part_cfg[partition_len].format) != 5)
2670                        return -1;
2671                in_ptr = strstr(in_ptr, "%") + 1;
2672                partition_len++;
2673        }
2674
2675        root = json_object();
2676        if (!root)
2677                return -1;
2678
2679        part_table_type = json_string(part_table_type_str);
2680        cache_size = json_string(cache_size_str);
2681        cache = json_string(cache_str);
2682        partition_setup = json_array();
2683        disk = json_string(disk_str);
2684
2685        for (unsigned int i = 0; i < partition_len; ++i) {
2686                object = json_object();
2687                if (!object) {
2688                        json_decref(root);
2689                        return -1;
2690                }
2691
2692                part = json_string(part_cfg[i].partition);
2693                fs = json_string(part_cfg[i].filesystem);
2694                format = json_string(part_cfg[i].format);
2695                code = json_string(part_cfg[i].code);
2696                size = json_string(part_cfg[i].size);
2697
2698                json_object_set_new(object, "partition", part);
2699                json_object_set_new(object, "filesystem", fs);
2700                json_object_set_new(object, "format", format);
2701                json_object_set_new(object, "code", code);
2702                json_object_set_new(object, "size", size);
2703
2704                json_array_append_new(partition_setup, object);
2705        }
2706
2707        json_object_set_new(root, "partition_setup", partition_setup);
2708        json_object_set_new(root, "cache_size", cache_size);
2709        json_object_set_new(root, "type", part_table_type);
2710        json_object_set_new(root, "cache", cache);
2711        json_object_set_new(root, "disk", disk);
2712
2713        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SETUP, root);
2714
2715        return 0;
2716}
2717
2718static int og_cmd_legacy_run_schedule(const char *input, struct og_cmd *cmd)
2719{
2720        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, NULL);
2721
2722        return 0;
2723}
2724
2725static int og_cmd_legacy(const char *input, struct og_cmd *cmd)
2726{
2727        char legacy_cmd[32] = {};
2728        int err = -1;
2729
2730        if (sscanf(input, "nfn=%31s\r", legacy_cmd) != 1) {
2731                syslog(LOG_ERR, "malformed database legacy input\n");
2732                return -1;
2733        }
2734        input = strchr(input, '\r') + 1;
2735
2736        if (!strcmp(legacy_cmd, "Arrancar")) {
2737                err = og_cmd_legacy_wol(input, cmd);
2738        } else if (!strcmp(legacy_cmd, "EjecutarScript")) {
2739                err = og_cmd_legacy_shell_run(input, cmd);
2740        } else if (!strcmp(legacy_cmd, "IniciarSesion")) {
2741                err = og_cmd_legacy_session(input, cmd);
2742        } else if (!strcmp(legacy_cmd, "Apagar")) {
2743                err = og_cmd_legacy_poweroff(input, cmd);
2744        } else if (!strcmp(legacy_cmd, "Actualizar")) {
2745                err = og_cmd_legacy_refresh(input, cmd);
2746        } else if (!strcmp(legacy_cmd, "Reiniciar")) {
2747                err = og_cmd_legacy_reboot(input, cmd);
2748        } else if (!strcmp(legacy_cmd, "Purgar")) {
2749                err = og_cmd_legacy_stop(input, cmd);
2750        } else if (!strcmp(legacy_cmd, "InventarioHardware")) {
2751                err = og_cmd_legacy_hardware(input, cmd);
2752        } else if (!strcmp(legacy_cmd, "InventarioSoftware")) {
2753                err = og_cmd_legacy_software(input, cmd);
2754        } else if (!strcmp(legacy_cmd, "CrearImagen")) {
2755                err = og_cmd_legacy_image_create(input, cmd);
2756        } else if (!strcmp(legacy_cmd, "RestaurarImagen")) {
2757                err = og_cmd_legacy_image_restore(input, cmd);
2758        } else if (!strcmp(legacy_cmd, "Configurar")) {
2759                err = og_cmd_legacy_setup(input, cmd);
2760        } else if (!strcmp(legacy_cmd, "EjecutaComandosPendientes") ||
2761                   !strcmp(legacy_cmd, "Actualizar")) {
2762                err = og_cmd_legacy_run_schedule(input, cmd);
2763        }
2764
2765        return err;
2766}
2767
2768static int og_dbi_add_action(const struct og_dbi *dbi, struct og_task *task,
2769                             struct og_cmd *cmd)
2770{
2771        char start_date_string[24];
2772        struct tm *start_date;
2773        const char *msglog;
2774        dbi_result result;
2775        time_t now;
2776
2777        time(&now);
2778        start_date = localtime(&now);
2779
2780        sprintf(start_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu",
2781                start_date->tm_year + 1900, start_date->tm_mon + 1,
2782                start_date->tm_mday, start_date->tm_hour, start_date->tm_min,
2783                start_date->tm_sec);
2784        result = dbi_conn_queryf(dbi->conn,
2785                                "INSERT INTO acciones (idordenador, "
2786                                "tipoaccion, idtipoaccion, descriaccion, ip, "
2787                                "sesion, idcomando, parametros, fechahorareg, "
2788                                "estado, resultado, ambito, idambito, "
2789                                "restrambito, idprocedimiento, idcentro, "
2790                                "idprogramacion) "
2791                                "VALUES (%d, %d, %d, '%s', '%s', %d, %d, '%s', "
2792                                "'%s', %d, %d, %d, %d, '%s', %d, %d, %d)",
2793                                cmd->client_id, EJECUCION_TAREA, task->task_id,
2794                                "", cmd->ip, task->session, task->command_id,
2795                                task->params, start_date_string,
2796                                ACCION_INICIADA, ACCION_SINRESULTADO,
2797                                task->type_scope, task->scope, "",
2798                                task->procedure_id, task->center_id,
2799                                task->schedule_id);
2800        if (!result) {
2801                dbi_conn_error(dbi->conn, &msglog);
2802                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2803                       __func__, __LINE__, msglog);
2804                return -1;
2805        }
2806
2807        cmd->id = dbi_conn_sequence_last(dbi->conn, NULL);
2808        if (!task->session) {
2809                task->session = cmd->id;
2810                dbi_result_free(result);
2811                result = dbi_conn_queryf(dbi->conn,
2812                                         "UPDATE acciones SET sesion=%d "
2813                                         "WHERE idaccion=%d",
2814                                         task->session, cmd->id);
2815        }
2816
2817        dbi_result_free(result);
2818
2819        return 0;
2820}
2821
2822static int og_queue_task_command(struct og_dbi *dbi, struct og_task *task,
2823                                 char *query)
2824{
2825        struct og_cmd *cmd;
2826        const char *msglog;
2827        dbi_result result;
2828
2829        result = dbi_conn_queryf(dbi->conn, query);
2830        if (!result) {
2831                dbi_conn_error(dbi->conn, &msglog);
2832                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2833                       __func__, __LINE__, msglog);
2834                return -1;
2835        }
2836
2837        while (dbi_result_next_row(result)) {
2838                cmd = (struct og_cmd *)calloc(1, sizeof(struct og_cmd));
2839                if (!cmd) {
2840                        dbi_result_free(result);
2841                        return -1;
2842                }
2843
2844                cmd->client_id  = dbi_result_get_uint(result, "idordenador");
2845                cmd->ip         = strdup(dbi_result_get_string(result, "ip"));
2846                cmd->mac        = strdup(dbi_result_get_string(result, "mac"));
2847
2848                og_cmd_legacy(task->params, cmd);
2849
2850                if (task->procedure_id) {
2851                        if (og_dbi_add_action(dbi, task, cmd)) {
2852                                dbi_result_free(result);
2853                                return -1;
2854                        }
2855                } else {
2856                        cmd->id = task->task_id;
2857                }
2858
2859                list_add_tail(&cmd->list, &cmd_list);
2860        }
2861
2862        dbi_result_free(result);
2863
2864        return 0;
2865}
2866
2867static int og_queue_task_group_clients(struct og_dbi *dbi, struct og_task *task,
2868                                       char *query)
2869{
2870
2871        const char *msglog;
2872        dbi_result result;
2873
2874        result = dbi_conn_queryf(dbi->conn, query);
2875        if (!result) {
2876                dbi_conn_error(dbi->conn, &msglog);
2877                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2878                       __func__, __LINE__, msglog);
2879                return -1;
2880        }
2881
2882        while (dbi_result_next_row(result)) {
2883                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
2884
2885                sprintf(query, "SELECT idgrupo FROM gruposordenadores "
2886                                "WHERE grupoid=%d", group_id);
2887                if (og_queue_task_group_clients(dbi, task, query)) {
2888                        dbi_result_free(result);
2889                        return -1;
2890                }
2891
2892                sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
2893                              "WHERE grupoid=%d", group_id);
2894                if (og_queue_task_command(dbi, task, query)) {
2895                        dbi_result_free(result);
2896                        return -1;
2897                }
2898
2899        }
2900
2901        dbi_result_free(result);
2902
2903        return 0;
2904}
2905
2906static int og_queue_task_group_classrooms(struct og_dbi *dbi,
2907                                          struct og_task *task, char *query)
2908{
2909
2910        const char *msglog;
2911        dbi_result result;
2912
2913        result = dbi_conn_queryf(dbi->conn, query);
2914        if (!result) {
2915                dbi_conn_error(dbi->conn, &msglog);
2916                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2917                       __func__, __LINE__, msglog);
2918                return -1;
2919        }
2920
2921        while (dbi_result_next_row(result)) {
2922                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
2923
2924                sprintf(query, "SELECT idgrupo FROM grupos "
2925                                "WHERE grupoid=%d AND tipo=%d", group_id, AMBITO_GRUPOSAULAS);
2926                if (og_queue_task_group_classrooms(dbi, task, query)) {
2927                        dbi_result_free(result);
2928                        return -1;
2929                }
2930
2931                sprintf(query,
2932                        "SELECT ip,mac,idordenador "
2933                        "FROM ordenadores INNER JOIN aulas "
2934                        "WHERE ordenadores.idaula=aulas.idaula "
2935                        "AND aulas.grupoid=%d",
2936                        group_id);
2937                if (og_queue_task_command(dbi, task, query)) {
2938                        dbi_result_free(result);
2939                        return -1;
2940                }
2941
2942        }
2943
2944        dbi_result_free(result);
2945
2946        return 0;
2947}
2948
2949static int og_queue_task_clients(struct og_dbi *dbi, struct og_task *task)
2950{
2951        char query[4096];
2952
2953        switch (task->type_scope) {
2954                case AMBITO_CENTROS:
2955                        sprintf(query,
2956                                "SELECT ip,mac,idordenador "
2957                                "FROM ordenadores INNER JOIN aulas "
2958                                "WHERE ordenadores.idaula=aulas.idaula "
2959                                "AND idcentro=%d",
2960                                task->scope);
2961                        return og_queue_task_command(dbi, task, query);
2962                case AMBITO_GRUPOSAULAS:
2963                        sprintf(query,
2964                                "SELECT idgrupo FROM grupos "
2965                                "WHERE idgrupo=%i AND tipo=%d",
2966                                task->scope, AMBITO_GRUPOSAULAS);
2967                        return og_queue_task_group_classrooms(dbi, task, query);
2968                case AMBITO_AULAS:
2969                        sprintf(query,
2970                                "SELECT ip,mac,idordenador FROM ordenadores "
2971                                "WHERE idaula=%d",
2972                                task->scope);
2973                        return og_queue_task_command(dbi, task, query);
2974                case AMBITO_GRUPOSORDENADORES:
2975                        sprintf(query,
2976                                "SELECT idgrupo FROM gruposordenadores "
2977                                "WHERE idgrupo = %d",
2978                                task->scope);
2979                        return og_queue_task_group_clients(dbi, task, query);
2980                case AMBITO_ORDENADORES:
2981                        sprintf(query,
2982                                "SELECT ip, mac, idordenador FROM ordenadores "
2983                                "WHERE idordenador = %d",
2984                                task->scope);
2985                        return og_queue_task_command(dbi, task, query);
2986        }
2987        return 0;
2988}
2989
2990int og_dbi_queue_procedure(struct og_dbi *dbi, struct og_task *task)
2991{
2992        uint32_t procedure_id;
2993        const char *msglog;
2994        dbi_result result;
2995
2996        result = dbi_conn_queryf(dbi->conn,
2997                        "SELECT parametros, procedimientoid, idcomando "
2998                        "FROM procedimientos_acciones "
2999                        "WHERE idprocedimiento=%d ORDER BY orden", task->procedure_id);
3000        if (!result) {
3001                dbi_conn_error(dbi->conn, &msglog);
3002                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3003                       __func__, __LINE__, msglog);
3004                return -1;
3005        }
3006
3007        while (dbi_result_next_row(result)) {
3008                procedure_id = dbi_result_get_uint(result, "procedimientoid");
3009                if (procedure_id > 0) {
3010                        task->procedure_id = procedure_id;
3011                        if (og_dbi_queue_procedure(dbi, task))
3012                                return -1;
3013                        continue;
3014                }
3015
3016                task->params = dbi_result_get_string(result, "parametros");
3017                task->command_id = dbi_result_get_uint(result, "idcomando");
3018                if (og_queue_task_clients(dbi, task))
3019                        return -1;
3020        }
3021
3022        dbi_result_free(result);
3023
3024        return 0;
3025}
3026
3027static int og_dbi_queue_task(struct og_dbi *dbi, uint32_t task_id,
3028                             uint32_t schedule_id)
3029{
3030        struct og_task task = {};
3031        uint32_t task_id_next;
3032        const char *msglog;
3033        dbi_result result;
3034
3035        task.schedule_id = schedule_id;
3036
3037        result = dbi_conn_queryf(dbi->conn,
3038                        "SELECT tareas_acciones.orden, "
3039                                "tareas_acciones.idprocedimiento, "
3040                                "tareas_acciones.tareaid, "
3041                                "tareas.idtarea, "
3042                                "tareas.idcentro, "
3043                                "tareas.ambito, "
3044                                "tareas.idambito, "
3045                                "tareas.restrambito "
3046                        " FROM tareas"
3047                                " INNER JOIN tareas_acciones ON tareas_acciones.idtarea=tareas.idtarea"
3048                        " WHERE tareas_acciones.idtarea=%u ORDER BY tareas_acciones.orden ASC", task_id);
3049        if (!result) {
3050                dbi_conn_error(dbi->conn, &msglog);
3051                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3052                       __func__, __LINE__, msglog);
3053                return -1;
3054        }
3055
3056        while (dbi_result_next_row(result)) {
3057                task_id_next = dbi_result_get_uint(result, "tareaid");
3058
3059                if (task_id_next > 0) {
3060                        if (og_dbi_queue_task(dbi, task_id_next, schedule_id))
3061                                return -1;
3062
3063                        continue;
3064                }
3065                task.task_id = dbi_result_get_uint(result, "idtarea");
3066                task.center_id = dbi_result_get_uint(result, "idcentro");
3067                task.procedure_id = dbi_result_get_uint(result, "idprocedimiento");
3068                task.type_scope = dbi_result_get_uint(result, "ambito");
3069                task.scope = dbi_result_get_uint(result, "idambito");
3070                task.filtered_scope = dbi_result_get_string(result, "restrambito");
3071
3072                og_dbi_queue_procedure(dbi, &task);
3073        }
3074
3075        dbi_result_free(result);
3076
3077        return 0;
3078}
3079
3080static int og_dbi_queue_command(struct og_dbi *dbi, uint32_t task_id,
3081                                uint32_t schedule_id)
3082{
3083        struct og_task task = {};
3084        const char *msglog;
3085        dbi_result result;
3086        char query[4096];
3087
3088        result = dbi_conn_queryf(dbi->conn,
3089                        "SELECT idaccion, idcentro, idordenador, parametros "
3090                        "FROM acciones "
3091                        "WHERE sesion = %u", task_id);
3092        if (!result) {
3093                dbi_conn_error(dbi->conn, &msglog);
3094                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3095                       __func__, __LINE__, msglog);
3096                return -1;
3097        }
3098
3099        while (dbi_result_next_row(result)) {
3100                task.task_id = dbi_result_get_uint(result, "idaccion");
3101                task.center_id = dbi_result_get_uint(result, "idcentro");
3102                task.scope = dbi_result_get_uint(result, "idordenador");
3103                task.params = dbi_result_get_string(result, "parametros");
3104
3105                sprintf(query,
3106                        "SELECT ip, mac, idordenador FROM ordenadores "
3107                        "WHERE idordenador = %d",
3108                        task.scope);
3109                if (og_queue_task_command(dbi, &task, query)) {
3110                        dbi_result_free(result);
3111                        return -1;
3112                }
3113        }
3114
3115        dbi_result_free(result);
3116
3117        return 0;
3118}
3119
3120int og_dbi_update_action(uint32_t id, bool success)
3121{
3122        char end_date_string[24];
3123        struct tm *end_date;
3124        const char *msglog;
3125        struct og_dbi *dbi;
3126        uint8_t status = 2;
3127        dbi_result result;
3128        time_t now;
3129
3130        if (!id)
3131                return 0;
3132
3133        dbi = og_dbi_open(&ogconfig.db);
3134        if (!dbi) {
3135                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3136                       __func__, __LINE__);
3137                return -1;
3138        }
3139
3140        time(&now);
3141        end_date = localtime(&now);
3142
3143        sprintf(end_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu",
3144                end_date->tm_year + 1900, end_date->tm_mon + 1,
3145                end_date->tm_mday, end_date->tm_hour, end_date->tm_min,
3146                end_date->tm_sec);
3147        result = dbi_conn_queryf(dbi->conn,
3148                                 "UPDATE acciones SET fechahorafin='%s', "
3149                                 "estado=%d, resultado=%d WHERE idaccion=%d",
3150                                 end_date_string, ACCION_FINALIZADA,
3151                                 status - success, id);
3152
3153        if (!result) {
3154                dbi_conn_error(dbi->conn, &msglog);
3155                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3156                       __func__, __LINE__, msglog);
3157                og_dbi_close(dbi);
3158                return -1;
3159        }
3160        dbi_result_free(result);
3161        og_dbi_close(dbi);
3162
3163        return 0;
3164}
3165
3166void og_schedule_run(unsigned int task_id, unsigned int schedule_id,
3167                     enum og_schedule_type type)
3168{
3169        struct og_msg_params params = {};
3170        struct in_addr addr, netmask;
3171        struct og_cmd *cmd, *next;
3172        bool duplicated = false;
3173        struct og_dbi *dbi;
3174        unsigned int i;
3175        int sd;
3176
3177        dbi = og_dbi_open(&ogconfig.db);
3178        if (!dbi) {
3179                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3180                       __func__, __LINE__);
3181                return;
3182        }
3183
3184        switch (type) {
3185        case OG_SCHEDULE_TASK:
3186                og_dbi_queue_task(dbi, task_id, schedule_id);
3187                break;
3188        case OG_SCHEDULE_PROCEDURE:
3189        case OG_SCHEDULE_COMMAND:
3190                og_dbi_queue_command(dbi, task_id, schedule_id);
3191                break;
3192        }
3193        og_dbi_close(dbi);
3194
3195        list_for_each_entry(cmd, &cmd_list, list) {
3196                for (i = 0; i < params.ips_array_len; i++) {
3197                        if (!strncmp(cmd->ip, params.ips_array[i],
3198                                     OG_DB_IP_MAXLEN)) {
3199                                duplicated = true;
3200                                break;
3201                        }
3202                }
3203
3204                if (!duplicated)
3205                        params.ips_array[params.ips_array_len++] = strdup(cmd->ip);
3206                else
3207                        duplicated = false;
3208        }
3209
3210        sd = wol_socket_open();
3211        if (sd < 0) {
3212                syslog(LOG_ERR, "cannot open wol socket (%s:%d)\n",
3213                       __func__, __LINE__);
3214                goto err_out;
3215        }
3216
3217        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
3218                if (cmd->type != OG_CMD_WOL)
3219                        continue;
3220
3221                for (i = 0; i < cmd->params.ips_array_len; i++) {
3222                        if (inet_aton(cmd->params.ips_array[i], &addr) < 0)
3223                                continue;
3224                        if (inet_aton(cmd->params.netmask_array[i], &netmask) < 0)
3225                                continue;
3226
3227                        if (wake_up(sd, &addr, &netmask,
3228                                    cmd->params.mac_array[i],
3229                                    atoi(cmd->params.wol_type)) < 0) {
3230                                syslog(LOG_ERR, "Failed to send wol packet to %s\n",
3231                                       params.ips_array[i]);
3232                                continue;
3233                        }
3234                        og_dbi_update_action(cmd->id, true);
3235                }
3236
3237                list_del(&cmd->list);
3238                og_cmd_free(cmd);
3239        }
3240
3241        close(sd);
3242
3243        og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, &params, NULL);
3244
3245err_out:
3246        for (i = 0; i < params.ips_array_len; i++)
3247                free((void *)params.ips_array[i]);
3248}
3249
3250static int og_cmd_task_post(json_t *element, struct og_msg_params *params)
3251{
3252        struct og_cmd *cmd;
3253        struct og_dbi *dbi;
3254        const char *key;
3255        json_t *value;
3256        int err = 0;
3257
3258        if (json_typeof(element) != JSON_OBJECT)
3259                return -1;
3260
3261        json_object_foreach(element, key, value) {
3262                if (!strcmp(key, "task")) {
3263                        err = og_json_parse_string(value, &params->task_id);
3264                        params->flags |= OG_REST_PARAM_TASK;
3265                }
3266
3267                if (err < 0)
3268                        return err;
3269        }
3270
3271        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK))
3272                return -1;
3273
3274        dbi = og_dbi_open(&ogconfig.db);
3275        if (!dbi) {
3276                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3277                           __func__, __LINE__);
3278                return -1;
3279        }
3280
3281        og_schedule_run(atoi(params->task_id), 0, OG_SCHEDULE_TASK);
3282        og_dbi_close(dbi);
3283
3284        list_for_each_entry(cmd, &cmd_list, list)
3285                params->ips_array[params->ips_array_len++] = cmd->ip;
3286
3287        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
3288                               NULL);
3289}
3290
3291#define OG_QUERY_MAXLEN 4096
3292
3293static int og_dbi_scope_get_computer(const struct og_dbi *dbi, json_t *array,
3294                                     const char* query)
3295{
3296        const char *computer_name, *computer_ip;
3297        uint32_t computer_id;
3298        const char *msglog;
3299        dbi_result result;
3300        json_t *computer;
3301
3302        result = dbi_conn_queryf(dbi->conn, query);
3303        if (!result) {
3304                dbi_conn_error(dbi->conn, &msglog);
3305                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3306                       __func__, __LINE__, msglog);
3307                return -1;
3308        }
3309
3310        while (dbi_result_next_row(result)) {
3311                computer_id = dbi_result_get_uint(result, "idordenador");
3312                computer_name = dbi_result_get_string(result, "nombreordenador");
3313                computer_ip = dbi_result_get_string(result, "ip");
3314
3315                computer = json_object();
3316                if (!computer) {
3317                        dbi_result_free(result);
3318                        return -1;
3319                }
3320
3321                json_object_set_new(computer, "name", json_string(computer_name));
3322                json_object_set_new(computer, "type", json_string("computer"));
3323                json_object_set_new(computer, "id", json_integer(computer_id));
3324                json_object_set_new(computer, "scope", json_array());
3325                json_object_set_new(computer, "ip", json_string(computer_ip));
3326                json_array_append(array, computer);
3327                json_decref(computer);
3328        }
3329        dbi_result_free(result);
3330
3331        return 0;
3332}
3333
3334static int og_dbi_scope_get_computer_from_room(const struct og_dbi *dbi,
3335                                               json_t *array, char *query,
3336                                               const uint32_t room_id)
3337{
3338        int ret = snprintf(query, OG_QUERY_MAXLEN,
3339                           "SELECT idordenador, nombreordenador, ip "
3340                           "FROM ordenadores WHERE idaula=%d and grupoid=0",
3341                           room_id);
3342        if (ret <= 0 || ret >= OG_QUERY_MAXLEN)
3343                return -1;
3344
3345        return og_dbi_scope_get_computer(dbi, array, query);
3346}
3347
3348static int og_dbi_scope_get_computer_from_computers(const struct og_dbi *dbi,
3349                                                    json_t *array,
3350                                                    char *query,
3351                                                    const uint32_t computers_id)
3352{
3353        int ret = snprintf(query, OG_QUERY_MAXLEN,
3354                           "SELECT idordenador, nombreordenador, ip "
3355                           "FROM ordenadores WHERE grupoid=%d",
3356                           computers_id);
3357        if (ret <= 0 || ret >= OG_QUERY_MAXLEN)
3358                return -1;
3359
3360        return og_dbi_scope_get_computer(dbi, array, query);
3361}
3362
3363static int og_dbi_scope_get_computers_from_computers(const struct og_dbi *dbi,
3364                                                     json_t *array,
3365                                                     char *query,
3366                                                     const uint32_t group_id);
3367
3368static int og_dbi_scope_get_computers(const struct og_dbi *dbi, json_t *array,
3369                                     char *query)
3370{
3371        const char *msglog, *computers_name;
3372        json_t *computers, *scope_array;
3373        uint32_t computers_id;
3374        dbi_result result;
3375
3376        result = dbi_conn_queryf(dbi->conn, query);
3377        if (!result) {
3378                dbi_conn_error(dbi->conn, &msglog);
3379                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3380                       __func__, __LINE__, msglog);
3381                return -1;
3382        }
3383
3384        while (dbi_result_next_row(result)) {
3385                computers_id = dbi_result_get_uint(result, "idgrupo");
3386                computers_name = dbi_result_get_string(result,
3387                                                      "nombregrupoordenador");
3388
3389                computers = json_object();
3390                if (!computers) {
3391                        dbi_result_free(result);
3392                        return -1;
3393                }
3394
3395                json_object_set_new(computers, "name",
3396                                    json_string(computers_name));
3397                json_object_set_new(computers, "type", json_string("folder"));
3398                json_object_set_new(computers, "id",
3399                                    json_integer(computers_id));
3400                json_object_set_new(computers, "scope", json_array());
3401                json_array_append(array, computers);
3402                json_decref(computers);
3403
3404                scope_array = json_object_get(computers, "scope");
3405                if (!scope_array) {
3406                        dbi_result_free(result);
3407                        return -1;
3408                }
3409
3410                if (og_dbi_scope_get_computers_from_computers(dbi,
3411                                                              scope_array,
3412                                                              query,
3413                                                              computers_id)) {
3414                        dbi_result_free(result);
3415                        return -1;
3416                }
3417
3418                if (og_dbi_scope_get_computer_from_computers(dbi,
3419                                                             scope_array,
3420                                                             query,
3421                                                             computers_id)) {
3422                        dbi_result_free(result);
3423                        return -1;
3424                }
3425        }
3426        dbi_result_free(result);
3427
3428        return 0;
3429}
3430
3431static int og_dbi_scope_get_computers_from_room(const struct og_dbi *dbi,
3432                                                json_t *array, char *query,
3433                                                const uint32_t room_id)
3434{
3435        int ret = snprintf(query, OG_QUERY_MAXLEN,
3436                           "SELECT idgrupo, nombregrupoordenador "
3437                           "FROM gruposordenadores "
3438                           "WHERE idaula=%d AND grupoid=0",
3439                           room_id);
3440        if (ret <= 0 || ret >= OG_QUERY_MAXLEN)
3441                return -1;
3442
3443        return og_dbi_scope_get_computers(dbi, array, query);
3444}
3445
3446static int og_dbi_scope_get_computers_from_computers(const struct og_dbi *dbi,
3447                                                     json_t *array,
3448                                                     char *query,
3449                                                     const uint32_t group_id)
3450{
3451        int ret = snprintf(query, OG_QUERY_MAXLEN,
3452                           "SELECT idgrupo, nombregrupoordenador "
3453                           "FROM gruposordenadores WHERE grupoid=%d",
3454                           group_id);
3455        if (ret <= 0 || ret >= OG_QUERY_MAXLEN)
3456                return -1;
3457
3458        return og_dbi_scope_get_computers(dbi, array, query);
3459}
3460
3461static int og_dbi_scope_get_room(const struct og_dbi *dbi, json_t *array,
3462                                 char *query)
3463{
3464        const char *msglog, *room_name;
3465        json_t *room, *scope_array;
3466        dbi_result result;
3467        uint32_t room_id;
3468
3469        result = dbi_conn_queryf(dbi->conn, query);
3470        if (!result) {
3471                dbi_conn_error(dbi->conn, &msglog);
3472                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3473                       __func__, __LINE__, msglog);
3474                return -1;
3475        }
3476
3477        while (dbi_result_next_row(result)) {
3478                room_id = dbi_result_get_uint(result, "idaula");
3479                room_name = dbi_result_get_string(result, "nombreaula");
3480
3481                room = json_object();
3482                if (!room) {
3483                        dbi_result_free(result);
3484                        return -1;
3485                }
3486
3487                json_object_set_new(room, "name", json_string(room_name));
3488                json_object_set_new(room, "type", json_string("room"));
3489                json_object_set_new(room, "id", json_integer(room_id));
3490                json_object_set_new(room, "scope", json_array());
3491                json_array_append(array, room);
3492                json_decref(room);
3493
3494                scope_array = json_object_get(room, "scope");
3495                if (!scope_array) {
3496                        dbi_result_free(result);
3497                        return -1;
3498                }
3499
3500                if (og_dbi_scope_get_computers_from_room(dbi, scope_array,
3501                                                         query, room_id)) {
3502                        dbi_result_free(result);
3503                        return -1;
3504                }
3505
3506                if (og_dbi_scope_get_computer_from_room(dbi, scope_array,
3507                                                        query, room_id)) {
3508                        dbi_result_free(result);
3509                        return -1;
3510                }
3511        }
3512        dbi_result_free(result);
3513
3514        return 0;
3515}
3516
3517static int og_dbi_scope_get_room_from_group(const struct og_dbi *dbi,
3518                                            json_t *array,
3519                                            char *query,
3520                                            const uint32_t group_id)
3521{
3522        int ret = snprintf(query, OG_QUERY_MAXLEN,
3523                           "SELECT idaula, nombreaula "
3524                           "FROM aulas WHERE grupoid=%d", group_id);
3525        if (ret <= 0 || ret >= OG_QUERY_MAXLEN)
3526                return -1;
3527
3528        return og_dbi_scope_get_room(dbi, array, query);
3529}
3530
3531static int og_dbi_scope_get_room_from_center(const struct og_dbi *dbi,
3532                                             json_t *array,
3533                                             char *query,
3534                                             const uint32_t center_id)
3535{
3536        int ret = snprintf(query, OG_QUERY_MAXLEN,
3537                           "SELECT idaula, nombreaula "
3538                           "FROM aulas WHERE idcentro=%d AND grupoid=0",
3539                           center_id);
3540        if (ret <= 0 || ret >= OG_QUERY_MAXLEN)
3541                return -1;
3542
3543        return og_dbi_scope_get_room(dbi, array, query);
3544}
3545
3546static int og_dbi_scope_get_group_from_group(const struct og_dbi *dbi,
3547                                             json_t *array,
3548                                             char *query,
3549                                             const uint32_t group_id);
3550
3551static int og_dbi_scope_get_group(const struct og_dbi *dbi,
3552                                  json_t *array,
3553                                  char *query)
3554{
3555        const char *msglog, *group_name;
3556        json_t *group, *scope_array;
3557        dbi_result result;
3558        uint32_t group_id;
3559
3560        result = dbi_conn_queryf(dbi->conn, query);
3561        if (!result) {
3562                dbi_conn_error(dbi->conn, &msglog);
3563                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3564                       __func__, __LINE__, msglog);
3565                return -1;
3566        }
3567
3568        while (dbi_result_next_row(result)) {
3569                group_id = dbi_result_get_uint(result, "idgrupo");
3570                group_name = dbi_result_get_string(result, "nombregrupo");
3571
3572                group = json_object();
3573                if (!group) {
3574                        dbi_result_free(result);
3575                        return -1;
3576                }
3577
3578                json_object_set_new(group, "name", json_string(group_name));
3579                json_object_set_new(group, "type", json_string("folder"));
3580                json_object_set_new(group, "id", json_integer(group_id));
3581                json_object_set_new(group, "scope", json_array());
3582                json_array_append(array, group);
3583                json_decref(group);
3584
3585                scope_array = json_object_get(group, "scope");
3586                if (!scope_array) {
3587                        dbi_result_free(result);
3588                        return -1;
3589                }
3590
3591                if (og_dbi_scope_get_group_from_group(dbi, scope_array, query,
3592                                                      group_id)) {
3593                        dbi_result_free(result);
3594                        return -1;
3595                }
3596
3597                if (og_dbi_scope_get_room_from_group(dbi, scope_array, query,
3598                                                     group_id)) {
3599                        dbi_result_free(result);
3600                        return -1;
3601                }
3602        }
3603        dbi_result_free(result);
3604
3605        return 0;
3606}
3607
3608static int og_dbi_scope_get_group_from_group(const struct og_dbi *dbi,
3609                                              json_t *array,
3610                                              char *query,
3611                                              const uint32_t group_id)
3612{
3613        int ret = snprintf(query, OG_QUERY_MAXLEN,
3614                           "SELECT idgrupo, nombregrupo "
3615                           "FROM grupos WHERE grupoid=%d", group_id);
3616        if (ret <= 0 || ret >= OG_QUERY_MAXLEN)
3617                return -1;
3618
3619        return og_dbi_scope_get_group(dbi, array, query);
3620}
3621
3622static int og_dbi_scope_get_group_from_center(const struct og_dbi *dbi,
3623                                              json_t *array,
3624                                              char *query,
3625                                              const uint32_t center_id)
3626{
3627        int group_type_room = 2;
3628        int ret = snprintf(query, OG_QUERY_MAXLEN,
3629                           "SELECT idgrupo, nombregrupo "
3630                           "FROM grupos "
3631                           "WHERE idcentro=%d AND grupoid=0 AND tipo=%d",
3632                           center_id, group_type_room);
3633        if (ret <= 0 || ret >= OG_QUERY_MAXLEN)
3634                return -1;
3635
3636        return og_dbi_scope_get_group(dbi, array, query);
3637}
3638
3639static int og_dbi_scope_get(struct og_dbi *dbi, json_t *array)
3640{
3641        const char *msglog, *center_name;
3642        json_t *center, *scope_array;
3643        char query[OG_QUERY_MAXLEN];
3644        uint32_t center_id;
3645        dbi_result result;
3646
3647        result = dbi_conn_queryf(dbi->conn,
3648                                 "SELECT nombrecentro, idcentro FROM centros");
3649        if (!result) {
3650                dbi_conn_error(dbi->conn, &msglog);
3651                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3652                       __func__, __LINE__, msglog);
3653                return -1;
3654        }
3655
3656        while (dbi_result_next_row(result)) {
3657                center_id = dbi_result_get_uint(result, "idcentro");
3658                center_name = dbi_result_get_string(result, "nombrecentro");
3659
3660                center = json_object();
3661                if (!center) {
3662                        dbi_result_free(result);
3663                        return -1;
3664                }
3665
3666                scope_array = json_array();
3667                if (!scope_array) {
3668                        dbi_result_free(result);
3669                        json_decref(center);
3670                        return -1;
3671                }
3672
3673                json_object_set_new(center, "name", json_string(center_name));
3674                json_object_set_new(center, "type", json_string("center"));
3675                json_object_set_new(center, "id", json_integer(center_id));
3676                json_object_set_new(center, "scope", scope_array);
3677                json_array_append(array, center);
3678                json_decref(center);
3679
3680                if (og_dbi_scope_get_group_from_center(dbi, scope_array, query,
3681                                                       center_id)) {
3682                        dbi_result_free(result);
3683                        return -1;
3684                }
3685
3686                if (og_dbi_scope_get_room_from_center(dbi, scope_array, query,
3687                                                      center_id)) {
3688                        dbi_result_free(result);
3689                        return -1;
3690                }
3691        }
3692
3693        dbi_result_free(result);
3694
3695        return 0;
3696}
3697
3698static int og_cmd_scope_get(json_t *element, struct og_msg_params *params,
3699                            char *buffer_reply)
3700{
3701        struct og_buffer og_buffer = {
3702                .data = buffer_reply
3703        };
3704        json_t *root, *array;
3705        struct og_dbi *dbi;
3706
3707        root = json_object();
3708        if (!root)
3709                return -1;
3710
3711        array = json_array();
3712        if (!array) {
3713                json_decref(root);
3714                return -1;
3715        }
3716        json_object_set_new(root, "scope", array);
3717
3718        dbi = og_dbi_open(&ogconfig.db);
3719        if (!dbi) {
3720                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3721                       __func__, __LINE__);
3722                json_decref(root);
3723                return -1;
3724        }
3725
3726        if (og_dbi_scope_get(dbi, array)) {
3727                og_dbi_close(dbi);
3728                json_decref(root);
3729                return -1;
3730        }
3731
3732        og_dbi_close(dbi);
3733
3734        if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) {
3735                json_decref(root);
3736                return -1;
3737        }
3738
3739        json_decref(root);
3740
3741        return 0;
3742}
3743
3744int og_dbi_schedule_get(void)
3745{
3746        uint32_t schedule_id, task_id;
3747        struct og_schedule_time time;
3748        struct og_dbi *dbi;
3749        const char *msglog;
3750        dbi_result result;
3751
3752        dbi = og_dbi_open(&ogconfig.db);
3753        if (!dbi) {
3754                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3755                       __func__, __LINE__);
3756                return -1;
3757        }
3758
3759        result = dbi_conn_queryf(dbi->conn,
3760                                 "SELECT idprogramacion, tipoaccion, identificador, "
3761                                 "sesion, annos, meses, diario, dias, semanas, horas, "
3762                                 "ampm, minutos FROM programaciones "
3763                                 "WHERE suspendida = 0");
3764        if (!result) {
3765                dbi_conn_error(dbi->conn, &msglog);
3766                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3767                       __func__, __LINE__, msglog);
3768                og_dbi_close(dbi);
3769                return -1;
3770        }
3771
3772        while (dbi_result_next_row(result)) {
3773                memset(&time, 0, sizeof(time));
3774                schedule_id = dbi_result_get_uint(result, "idprogramacion");
3775                task_id = dbi_result_get_uint(result, "identificador");
3776                time.years = dbi_result_get_uint(result, "annos");
3777                time.months = dbi_result_get_uint(result, "meses");
3778                time.weeks = dbi_result_get_uint(result, "semanas");
3779                time.week_days = dbi_result_get_uint(result, "dias");
3780                time.days = dbi_result_get_uint(result, "diario");
3781                time.hours = dbi_result_get_uint(result, "horas");
3782                time.am_pm = dbi_result_get_uint(result, "ampm");
3783                time.minutes = dbi_result_get_uint(result, "minutos");
3784                time.check_stale = true;
3785
3786                og_schedule_create(schedule_id, task_id, OG_SCHEDULE_TASK,
3787                                   &time);
3788        }
3789
3790        dbi_result_free(result);
3791        og_dbi_close(dbi);
3792
3793        return 0;
3794}
3795
3796static int og_dbi_schedule_create(struct og_dbi *dbi,
3797                                  struct og_msg_params *params,
3798                                  uint32_t *schedule_id,
3799                                  enum og_schedule_type schedule_type)
3800{
3801        uint8_t suspended = 0;
3802        uint32_t session = 0;
3803        const char *msglog;
3804        dbi_result result;
3805        uint8_t type;
3806
3807        switch (schedule_type) {
3808        case OG_SCHEDULE_TASK:
3809                type = 3;
3810                break;
3811        case OG_SCHEDULE_PROCEDURE:
3812                type = 2;
3813                break;
3814        case OG_SCHEDULE_COMMAND:
3815                session = atoi(params->task_id);
3816                type = 1;
3817                break;
3818        }
3819
3820        result = dbi_conn_queryf(dbi->conn,
3821                                 "INSERT INTO programaciones (tipoaccion,"
3822                                 " identificador, nombrebloque, annos, meses,"
3823                                 " semanas, dias, diario, horas, ampm, minutos,"
3824                                 " suspendida, sesion) VALUES (%d, %s, '%s',"
3825                                 " %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)",
3826                                 type, params->task_id, params->name,
3827                                 params->time.years, params->time.months,
3828                                 params->time.weeks, params->time.week_days,
3829                                 params->time.days, params->time.hours,
3830                                 params->time.am_pm, params->time.minutes,
3831                                 suspended, session);
3832        if (!result) {
3833                dbi_conn_error(dbi->conn, &msglog);
3834                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3835                       __func__, __LINE__, msglog);
3836                return -1;
3837        }
3838        dbi_result_free(result);
3839
3840        *schedule_id = dbi_conn_sequence_last(dbi->conn, NULL);
3841
3842        return 0;
3843}
3844
3845static int og_dbi_schedule_update(struct og_dbi *dbi,
3846                                  struct og_msg_params *params)
3847{
3848        const char *msglog;
3849        dbi_result result;
3850        uint8_t type = 3;
3851
3852        result = dbi_conn_queryf(dbi->conn,
3853                                 "UPDATE programaciones SET tipoaccion=%d, "
3854                                 "identificador='%s', nombrebloque='%s', "
3855                                 "annos=%d, meses=%d, "
3856                                 "diario=%d, horas=%d, ampm=%d, minutos=%d "
3857                                 "WHERE idprogramacion='%s'",
3858                                 type, params->task_id, params->name,
3859                                 params->time.years, params->time.months,
3860                                 params->time.days, params->time.hours,
3861                                 params->time.am_pm, params->time.minutes,
3862                                 params->id);
3863
3864        if (!result) {
3865                dbi_conn_error(dbi->conn, &msglog);
3866                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3867                       __func__, __LINE__, msglog);
3868                return -1;
3869        }
3870        dbi_result_free(result);
3871
3872        return 0;
3873}
3874
3875static int og_dbi_schedule_delete(struct og_dbi *dbi, uint32_t id)
3876{
3877        const char *msglog;
3878        dbi_result result;
3879
3880        result = dbi_conn_queryf(dbi->conn,
3881                                 "DELETE FROM programaciones WHERE idprogramacion=%d",
3882                                 id);
3883        if (!result) {
3884                dbi_conn_error(dbi->conn, &msglog);
3885                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3886                       __func__, __LINE__, msglog);
3887                return -1;
3888        }
3889        dbi_result_free(result);
3890
3891        return 0;
3892}
3893
3894struct og_db_schedule {
3895        uint32_t                id;
3896        uint32_t                task_id;
3897        const char              *name;
3898        struct og_schedule_time time;
3899        uint32_t                week_days;
3900        uint32_t                weeks;
3901        uint32_t                suspended;
3902        uint32_t                session;
3903};
3904
3905static int og_dbi_schedule_get_json(struct og_dbi *dbi, json_t *root,
3906                                    const char *task_id, const char *schedule_id)
3907{
3908        struct og_db_schedule schedule;
3909        json_t *obj, *array;
3910        const char *msglog;
3911        dbi_result result;
3912        int err = 0;
3913
3914        if (task_id) {
3915                result = dbi_conn_queryf(dbi->conn,
3916                                         "SELECT idprogramacion,"
3917                                         "       identificador, nombrebloque,"
3918                                         "       annos, meses, diario, dias,"
3919                                         "       semanas, horas, ampm,"
3920                                         "       minutos,suspendida, sesion "
3921                                         "FROM programaciones "
3922                                         "WHERE identificador=%d",
3923                                         atoi(task_id));
3924        } else if (schedule_id) {
3925                result = dbi_conn_queryf(dbi->conn,
3926                                         "SELECT idprogramacion,"
3927                                         "       identificador, nombrebloque,"
3928                                         "       annos, meses, diario, dias,"
3929                                         "       semanas, horas, ampm,"
3930                                         "       minutos,suspendida, sesion "
3931                                         "FROM programaciones "
3932                                         "WHERE idprogramacion=%d",
3933                                         atoi(schedule_id));
3934        } else {
3935                result = dbi_conn_queryf(dbi->conn,
3936                                         "SELECT idprogramacion,"
3937                                         "       identificador, nombrebloque,"
3938                                         "       annos, meses, diario, dias,"
3939                                         "       semanas, horas, ampm,"
3940                                         "       minutos,suspendida, sesion "
3941                                         "FROM programaciones");
3942        }
3943
3944        if (!result) {
3945                dbi_conn_error(dbi->conn, &msglog);
3946                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3947                       __func__, __LINE__, msglog);
3948                return -1;
3949        }
3950
3951        array = json_array();
3952        if (!array)
3953                return -1;
3954
3955        while (dbi_result_next_row(result)) {
3956                schedule.id = dbi_result_get_uint(result, "idprogramacion");
3957                schedule.task_id = dbi_result_get_uint(result, "identificador");
3958                schedule.name = dbi_result_get_string(result, "nombrebloque");
3959                schedule.time.years = dbi_result_get_uint(result, "annos");
3960                schedule.time.months = dbi_result_get_uint(result, "meses");
3961                schedule.time.days = dbi_result_get_uint(result, "diario");
3962                schedule.time.hours = dbi_result_get_uint(result, "horas");
3963                schedule.time.am_pm = dbi_result_get_uint(result, "ampm");
3964                schedule.time.minutes = dbi_result_get_uint(result, "minutos");
3965                schedule.week_days = dbi_result_get_uint(result, "dias");
3966                schedule.weeks = dbi_result_get_uint(result, "semanas");
3967                schedule.suspended = dbi_result_get_uint(result, "suspendida");
3968                schedule.session = dbi_result_get_uint(result, "sesion");
3969
3970                obj = json_object();
3971                if (!obj) {
3972                        err = -1;
3973                        break;
3974                }
3975                json_object_set_new(obj, "id", json_integer(schedule.id));
3976                json_object_set_new(obj, "task", json_integer(schedule.task_id));
3977                json_object_set_new(obj, "name", json_string(schedule.name));
3978                json_object_set_new(obj, "years", json_integer(schedule.time.years));
3979                json_object_set_new(obj, "months", json_integer(schedule.time.months));
3980                json_object_set_new(obj, "days", json_integer(schedule.time.days));
3981                json_object_set_new(obj, "hours", json_integer(schedule.time.hours));
3982                json_object_set_new(obj, "am_pm", json_integer(schedule.time.am_pm));
3983                json_object_set_new(obj, "minutes", json_integer(schedule.time.minutes));
3984                json_object_set_new(obj, "week_days", json_integer(schedule.week_days));
3985                json_object_set_new(obj, "weeks", json_integer(schedule.weeks));
3986                json_object_set_new(obj, "suspended", json_integer(schedule.suspended));
3987                json_object_set_new(obj, "session", json_integer(schedule.session));
3988
3989                json_array_append_new(array, obj);
3990        }
3991
3992        json_object_set_new(root, "schedule", array);
3993
3994        dbi_result_free(result);
3995
3996        return err;
3997}
3998
3999static int og_task_schedule_create(struct og_msg_params *params)
4000{
4001        enum og_schedule_type type;
4002        uint32_t schedule_id;
4003        struct og_dbi *dbi;
4004        int err;
4005
4006        if (!strcmp(params->type, "task"))
4007                type = OG_SCHEDULE_TASK;
4008        else if (!strcmp(params->type, "procedure"))
4009                type = OG_SCHEDULE_PROCEDURE;
4010        else if (!strcmp(params->type, "command"))
4011                type = OG_SCHEDULE_COMMAND;
4012        else
4013                return -1;
4014
4015        dbi = og_dbi_open(&ogconfig.db);
4016        if (!dbi) {
4017                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4018                       __func__, __LINE__);
4019                return -1;
4020        }
4021
4022        err = og_dbi_schedule_create(dbi, params, &schedule_id, type);
4023        if (err < 0) {
4024                og_dbi_close(dbi);
4025                return -1;
4026        }
4027        og_schedule_create(schedule_id, atoi(params->task_id), type,
4028                           &params->time);
4029        og_schedule_refresh(og_loop);
4030        og_dbi_close(dbi);
4031
4032        return 0;
4033}
4034
4035static uint32_t og_tm_years_mask(struct tm *tm)
4036{
4037        int i, j = 0;
4038
4039        for (i = 2010; i < 2026; i++, j++) {
4040                if (tm->tm_year + 1900 == i)
4041                        break;
4042        }
4043
4044        return (1 << j);
4045}
4046
4047static uint32_t og_tm_months_mask(struct tm *tm)
4048{
4049        return 1 << tm->tm_mon;
4050}
4051
4052static uint16_t og_tm_hours_mask(struct tm *tm)
4053{
4054        return tm->tm_hour >= 12 ? 1 << (tm->tm_hour - 12) : 1 << tm->tm_hour;
4055}
4056
4057static uint32_t og_tm_ampm(struct tm *tm)
4058{
4059        return tm->tm_hour < 12 ? 0 : 1;
4060}
4061
4062static uint32_t og_tm_days_mask(struct tm *tm)
4063{
4064        return 1 << (tm->tm_mday - 1);
4065}
4066
4067static void og_schedule_time_now(struct og_schedule_time *ogtime)
4068{
4069        struct tm *tm;
4070        time_t now;
4071
4072        now = time(NULL);
4073        tm = localtime(&now);
4074
4075        ogtime->years = og_tm_years_mask(tm);
4076        ogtime->months = og_tm_months_mask(tm);
4077        ogtime->weeks = 0;
4078        ogtime->week_days = 0;
4079        ogtime->days =  og_tm_days_mask(tm);
4080        ogtime->hours = og_tm_hours_mask(tm);
4081        ogtime->am_pm = og_tm_ampm(tm);
4082        ogtime->minutes = tm->tm_min;
4083}
4084
4085static int og_cmd_schedule_create(json_t *element, struct og_msg_params *params)
4086{
4087        bool when = false;
4088        const char *key;
4089        json_t *value;
4090        int err = 0;
4091
4092        if (json_typeof(element) != JSON_OBJECT)
4093                return -1;
4094
4095        json_object_foreach(element, key, value) {
4096                if (!strcmp(key, "task")) {
4097                        err = og_json_parse_string(value, &params->task_id);
4098                        params->flags |= OG_REST_PARAM_TASK;
4099                } else if (!strcmp(key, "name")) {
4100                        err = og_json_parse_string(value, &params->name);
4101                        params->flags |= OG_REST_PARAM_NAME;
4102                } else if (!strcmp(key, "when")) {
4103                        err = og_json_parse_time_params(value, params);
4104                        when = true;
4105                } else if (!strcmp(key, "type")) {
4106                        err = og_json_parse_string(value, &params->type);
4107                        params->flags |= OG_REST_PARAM_TYPE;
4108                }
4109
4110                if (err < 0)
4111                        return err;
4112        }
4113
4114        if (!when) {
4115                params->time.check_stale = false;
4116                og_schedule_time_now(&params->time);
4117                params->flags |= OG_REST_PARAM_TIME_YEARS |
4118                                 OG_REST_PARAM_TIME_MONTHS |
4119                                 OG_REST_PARAM_TIME_WEEKS |
4120                                 OG_REST_PARAM_TIME_WEEK_DAYS |
4121                                 OG_REST_PARAM_TIME_DAYS |
4122                                 OG_REST_PARAM_TIME_HOURS |
4123                                 OG_REST_PARAM_TIME_AM_PM |
4124                                 OG_REST_PARAM_TIME_MINUTES;
4125        } else {
4126                params->time.check_stale = true;
4127        }
4128
4129        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK |
4130                                            OG_REST_PARAM_NAME |
4131                                            OG_REST_PARAM_TIME_YEARS |
4132                                            OG_REST_PARAM_TIME_MONTHS |
4133                                            OG_REST_PARAM_TIME_WEEKS |
4134                                            OG_REST_PARAM_TIME_WEEK_DAYS |
4135                                            OG_REST_PARAM_TIME_DAYS |
4136                                            OG_REST_PARAM_TIME_HOURS |
4137                                            OG_REST_PARAM_TIME_MINUTES |
4138                                            OG_REST_PARAM_TIME_AM_PM |
4139                                            OG_REST_PARAM_TYPE))
4140                return -1;
4141
4142        return og_task_schedule_create(params);
4143}
4144
4145static int og_cmd_schedule_update(json_t *element, struct og_msg_params *params)
4146{
4147        struct og_dbi *dbi;
4148        bool when = false;
4149        const char *key;
4150        json_t *value;
4151        int err = 0;
4152
4153        if (json_typeof(element) != JSON_OBJECT)
4154                return -1;
4155
4156        json_object_foreach(element, key, value) {
4157                if (!strcmp(key, "id")) {
4158                        err = og_json_parse_string(value, &params->id);
4159                        params->flags |= OG_REST_PARAM_ID;
4160                } else if (!strcmp(key, "task")) {
4161                        err = og_json_parse_string(value, &params->task_id);
4162                        params->flags |= OG_REST_PARAM_TASK;
4163                } else if (!strcmp(key, "name")) {
4164                        err = og_json_parse_string(value, &params->name);
4165                        params->flags |= OG_REST_PARAM_NAME;
4166                } else if (!strcmp(key, "when")) {
4167                        err = og_json_parse_time_params(value, params);
4168                        when = true;
4169                }
4170
4171                if (err < 0)
4172                        return err;
4173        }
4174
4175        if (!when) {
4176                params->time.check_stale = false;
4177                og_schedule_time_now(&params->time);
4178                params->flags |= OG_REST_PARAM_TIME_YEARS |
4179                                 OG_REST_PARAM_TIME_MONTHS |
4180                                 OG_REST_PARAM_TIME_WEEKS |
4181                                 OG_REST_PARAM_TIME_WEEK_DAYS |
4182                                 OG_REST_PARAM_TIME_DAYS |
4183                                 OG_REST_PARAM_TIME_HOURS |
4184                                 OG_REST_PARAM_TIME_AM_PM |
4185                                 OG_REST_PARAM_TIME_MINUTES;
4186        } else {
4187                params->time.check_stale = true;
4188        }
4189
4190        if (!og_msg_params_validate(params, OG_REST_PARAM_ID |
4191                                            OG_REST_PARAM_TASK |
4192                                            OG_REST_PARAM_NAME |
4193                                            OG_REST_PARAM_TIME_YEARS |
4194                                            OG_REST_PARAM_TIME_MONTHS |
4195                                            OG_REST_PARAM_TIME_DAYS |
4196                                            OG_REST_PARAM_TIME_HOURS |
4197                                            OG_REST_PARAM_TIME_MINUTES |
4198                                            OG_REST_PARAM_TIME_AM_PM))
4199                return -1;
4200
4201        dbi = og_dbi_open(&ogconfig.db);
4202        if (!dbi) {
4203                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4204                           __func__, __LINE__);
4205                return -1;
4206        }
4207
4208        err = og_dbi_schedule_update(dbi, params);
4209        og_dbi_close(dbi);
4210
4211        if (err < 0)
4212                return err;
4213
4214        og_schedule_update(og_loop, atoi(params->id), atoi(params->task_id),
4215                           &params->time);
4216        og_schedule_refresh(og_loop);
4217
4218        return err;
4219}
4220
4221static int og_cmd_schedule_delete(json_t *element, struct og_msg_params *params)
4222{
4223        struct og_dbi *dbi;
4224        const char *key;
4225        json_t *value;
4226        int err = 0;
4227
4228        if (json_typeof(element) != JSON_OBJECT)
4229                return -1;
4230
4231        json_object_foreach(element, key, value) {
4232                if (!strcmp(key, "id")) {
4233                        err = og_json_parse_string(value, &params->id);
4234                        params->flags |= OG_REST_PARAM_ID;
4235                }
4236
4237                if (err < 0)
4238                        return err;
4239        }
4240
4241        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
4242                return -1;
4243
4244        dbi = og_dbi_open(&ogconfig.db);
4245        if (!dbi) {
4246                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4247                           __func__, __LINE__);
4248                return -1;
4249        }
4250
4251        err = og_dbi_schedule_delete(dbi, atoi(params->id));
4252        og_dbi_close(dbi);
4253
4254        og_schedule_delete(og_loop, atoi(params->id));
4255
4256        return err;
4257}
4258
4259static int og_cmd_schedule_get(json_t *element, struct og_msg_params *params,
4260                               char *buffer_reply)
4261{
4262        struct og_buffer og_buffer = {
4263                .data   = buffer_reply,
4264        };
4265        json_t *schedule_root;
4266        struct og_dbi *dbi;
4267        const char *key;
4268        json_t *value;
4269        int err = 0;
4270
4271        if (element) {
4272                if (json_typeof(element) != JSON_OBJECT)
4273                        return -1;
4274
4275                json_object_foreach(element, key, value) {
4276                        if (!strcmp(key, "task")) {
4277                                err = og_json_parse_string(value,
4278                                                           &params->task_id);
4279                        } else if (!strcmp(key, "id")) {
4280                                err = og_json_parse_string(value, &params->id);
4281                        }
4282
4283                        if (err < 0)
4284                                return err;
4285                }
4286        }
4287
4288        dbi = og_dbi_open(&ogconfig.db);
4289        if (!dbi) {
4290                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4291                           __func__, __LINE__);
4292                return -1;
4293        }
4294
4295        schedule_root = json_object();
4296        if (!schedule_root) {
4297                og_dbi_close(dbi);
4298                return -1;
4299        }
4300
4301        err = og_dbi_schedule_get_json(dbi, schedule_root,
4302                                       params->task_id, params->id);
4303        og_dbi_close(dbi);
4304
4305        if (err >= 0)
4306                err = json_dump_callback(schedule_root, og_json_dump_clients,
4307                                         &og_buffer, 0);
4308
4309        json_decref(schedule_root);
4310
4311        return err;
4312}
4313
4314#define OG_LIVE_JSON_FILE_PATH "/opt/opengnsys/etc/ogliveinfo.json"
4315
4316static int og_cmd_oglive_list(char *buffer_reply)
4317{
4318        struct og_buffer og_buffer = {
4319                .data = buffer_reply
4320        };
4321        json_error_t json_err;
4322        json_t *root;
4323
4324        root = json_load_file(OG_LIVE_JSON_FILE_PATH, 0, &json_err);
4325        if (!root) {
4326                syslog(LOG_ERR, "malformed json line %d: %s\n",
4327                       json_err.line, json_err.text);
4328                return -1;
4329        }
4330
4331        if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) {
4332                json_decref(root);
4333                return -1;
4334        }
4335
4336        json_decref(root);
4337
4338        return 0;
4339}
4340
4341static int og_cmd_post_center_add(json_t *element,
4342                                  struct og_msg_params *params,
4343                                  char *buffer_reply)
4344{
4345        const char *key, *msglog;
4346        struct og_dbi *dbi;
4347        dbi_result result;
4348        json_t *value;
4349        int err = 0;
4350
4351        json_object_foreach(element, key, value) {
4352                if (!strcmp(key, "name")) {
4353                        err = og_json_parse_string(value, &params->name);
4354                        params->flags |= OG_REST_PARAM_NAME;
4355                } else if (!strcmp(key, "comment")) {
4356                        err = og_json_parse_string(value, &params->comment);
4357                }
4358
4359                if (err < 0)
4360                        return err;
4361        }
4362
4363        if (!og_msg_params_validate(params, OG_REST_PARAM_NAME))
4364                return -1;
4365        if (!params->comment)
4366                params->comment = "";
4367
4368        dbi = og_dbi_open(&ogconfig.db);
4369        if (!dbi) {
4370                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
4371                       __func__, __LINE__);
4372                return -1;
4373        }
4374
4375        result = dbi_conn_queryf(dbi->conn,
4376                                 "SELECT nombrecentro FROM centros WHERE nombrecentro='%s'",
4377                                 params->name);
4378
4379        if (!result) {
4380                dbi_conn_error(dbi->conn, &msglog);
4381                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4382                       __func__, __LINE__, msglog);
4383                og_dbi_close(dbi);
4384                return -1;
4385        }
4386
4387        if (dbi_result_get_numrows(result) > 0) {
4388                syslog(LOG_ERR, "Center with name %s already exists\n",
4389                       params->name);
4390                dbi_result_free(result);
4391                og_dbi_close(dbi);
4392                return -1;
4393        }
4394        dbi_result_free(result);
4395
4396        result = dbi_conn_queryf(dbi->conn,
4397                                 "INSERT INTO centros("
4398                                 "  nombrecentro,"
4399                                 "  comentarios,"
4400                                 "  identidad) VALUES ("
4401                                 "'%s', '%s', 1)",
4402                                 params->name, params->comment);
4403
4404        if (!result) {
4405                dbi_conn_error(dbi->conn, &msglog);
4406                syslog(LOG_ERR, "failed to add center to database (%s:%d) %s\n",
4407                       __func__, __LINE__, msglog);
4408                og_dbi_close(dbi);
4409                return -1;
4410        }
4411
4412        dbi_result_free(result);
4413        og_dbi_close(dbi);
4414        return 0;
4415}
4416
4417static int og_cmd_post_center_delete(json_t *element,
4418                                     struct og_msg_params *params)
4419{
4420        const char *key, *msglog;
4421        struct og_dbi *dbi;
4422        dbi_result result;
4423        json_t *value;
4424        int err = 0;
4425
4426        json_object_foreach(element, key, value) {
4427                if (!strcmp(key, "id")) {
4428                        err = og_json_parse_string(value, &params->id);
4429                        params->flags |= OG_REST_PARAM_ID;
4430                }
4431                if (err < 0)
4432                        return err;
4433        }
4434
4435        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
4436                return -1;
4437
4438        dbi = og_dbi_open(&ogconfig.db);
4439        if (!dbi) {
4440                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
4441                       __func__, __LINE__);
4442                return -1;
4443        }
4444
4445        result = dbi_conn_queryf(dbi->conn,
4446                                 "DELETE FROM centros WHERE idcentro=%s",
4447                                 params->id);
4448
4449        if (!result) {
4450                dbi_conn_error(dbi->conn, &msglog);
4451                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4452                       __func__, __LINE__, msglog);
4453                og_dbi_close(dbi);
4454                return -1;
4455        }
4456
4457        dbi_result_free(result);
4458
4459        og_dbi_close(dbi);
4460        return 0;
4461}
4462
4463int og_procedure_add_steps(struct og_dbi *dbi, struct og_procedure *proc)
4464{
4465        struct og_procedure_step *step;
4466        const char *legacy_params;
4467        const char *msglog;
4468        dbi_result result;
4469        int i;
4470
4471        for (i = 0; i < proc->num_steps; i++) {
4472                step = &proc->steps[i];
4473                switch (step->type) {
4474                case OG_STEP_COMMAND:
4475                        legacy_params = og_msg_params_to_legacy(&step->cmd);
4476                        if (!legacy_params) {
4477                                og_dbi_close(dbi);
4478                                return -1;
4479                        }
4480                        result = dbi_conn_queryf(dbi->conn,
4481                                                 "INSERT INTO procedimientos_acciones "
4482                                                 "(idprocedimiento, orden, parametros) "
4483                                                 "VALUES (%d, %d, '%s')",
4484                                                 proc->id,
4485                                                 step->position,
4486                                                 legacy_params);
4487                        if (!result) {
4488                                dbi_conn_error(dbi->conn, &msglog);
4489                                syslog(LOG_ERR,
4490                                       "failed to add procedure command to database (%s:%d) %s\n",
4491                                       __func__, __LINE__, msglog);
4492                                og_dbi_close(dbi);
4493                                free((char *)legacy_params);
4494                                return -1;
4495                        }
4496
4497                        dbi_result_free(result);
4498                        free((char *)legacy_params);
4499                        break;
4500                case OG_STEP_PROCEDURE:
4501                        result = dbi_conn_queryf(dbi->conn,
4502                                                 "INSERT INTO procedimientos_acciones "
4503                                                 "(idprocedimiento, orden, procedimientoid) "
4504                                                 "VALUES (%d, %d, %d)",
4505                                                 proc->id,
4506                                                 step->position,
4507                                                 step->procedure.id);
4508                        if (!result) {
4509                                dbi_conn_error(dbi->conn, &msglog);
4510                                syslog(LOG_ERR,
4511                                       "failed to add procedure child to database (%s:%d) %s\n",
4512                                       __func__, __LINE__, msglog);
4513                                og_dbi_close(dbi);
4514                                return -1;
4515                        }
4516                        dbi_result_free(result);
4517                        break;
4518                case OG_STEP_TASK:
4519                        syslog(LOG_ERR, "Procedures can not include tasks. "
4520                                        "Invalid step: %d\n",
4521                               step->position);
4522                        return -1;
4523                        break;
4524                }
4525        }
4526
4527        return 0;
4528}
4529
4530static int og_cmd_post_procedure_add(json_t *element,
4531                                     struct og_msg_params *params)
4532{
4533        struct og_procedure proc = {};
4534        const char *key, *msglog;
4535        struct og_dbi *dbi;
4536        dbi_result result;
4537        json_t *value;
4538        int err = 0;
4539
4540        json_object_foreach(element, key, value) {
4541                if (!strcmp(key, "center")) {
4542                        err = og_json_parse_string(value, &params->id);
4543                        params->flags |= OG_REST_PARAM_ID;
4544                } else if (!strcmp(key, "name")) {
4545                        err = og_json_parse_string(value, &params->name);
4546                        params->flags |= OG_REST_PARAM_NAME;
4547                } else if (!strcmp(key, "description")) {
4548                        err = og_json_parse_string(value, &params->comment);
4549                } else if (!strcmp(key, "steps")) {
4550                        err = og_json_parse_procedure(value, &proc);
4551                }
4552
4553                if (err < 0)
4554                        return err;
4555        }
4556
4557        if (!og_msg_params_validate(params, OG_REST_PARAM_ID |
4558                                            OG_REST_PARAM_NAME))
4559                return -1;
4560
4561        dbi = og_dbi_open(&ogconfig.db);
4562        if (!dbi) {
4563                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
4564                       __func__, __LINE__);
4565                return -1;
4566        }
4567
4568        result = dbi_conn_queryf(dbi->conn,
4569                                 "SELECT descripcion FROM procedimientos "
4570                                 "WHERE descripcion='%s' AND idcentro=%s",
4571                                 params->name, params->id);
4572
4573        if (!result) {
4574                dbi_conn_error(dbi->conn, &msglog);
4575                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4576                       __func__, __LINE__, msglog);
4577                og_dbi_close(dbi);
4578                return -1;
4579        }
4580
4581        if (dbi_result_get_numrows(result) > 0) {
4582                syslog(LOG_ERR, "Procedure with name %s already exists in the "
4583                                "center with id %s\n",
4584                       params->name, params->id);
4585                dbi_result_free(result);
4586                og_dbi_close(dbi);
4587                return -1;
4588        }
4589        dbi_result_free(result);
4590
4591        result = dbi_conn_queryf(dbi->conn,
4592                                 "INSERT INTO procedimientos("
4593                                 "idcentro, descripcion, comentarios) "
4594                                 "VALUES (%s, '%s', '%s')",
4595                                 params->id, params->name, params->comment);
4596
4597        if (!result) {
4598                dbi_conn_error(dbi->conn, &msglog);
4599                syslog(LOG_ERR,
4600                       "failed to add procedure to database (%s:%d) %s\n",
4601                       __func__, __LINE__, msglog);
4602                og_dbi_close(dbi);
4603                return -1;
4604        }
4605        dbi_result_free(result);
4606
4607        proc.id = dbi_conn_sequence_last(dbi->conn, NULL);
4608        err = og_procedure_add_steps(dbi, &proc);
4609
4610        og_dbi_close(dbi);
4611
4612        return err;
4613}
4614
4615static int og_cmd_post_procedure_delete(json_t *element,
4616                                        struct og_msg_params *params)
4617{
4618        const char *key, *msglog;
4619        struct og_dbi *dbi;
4620        dbi_result result;
4621        json_t *value;
4622        int err = 0;
4623
4624        json_object_foreach(element, key, value) {
4625                if (!strcmp(key, "id")) {
4626                        err = og_json_parse_string(value, &params->id);
4627                        params->flags |= OG_REST_PARAM_ID;
4628                }
4629                if (err < 0)
4630                        return err;
4631        }
4632
4633        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
4634                return -1;
4635
4636        dbi = og_dbi_open(&ogconfig.db);
4637        if (!dbi) {
4638                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
4639                       __func__, __LINE__);
4640                return -1;
4641        }
4642
4643        result = dbi_conn_queryf(dbi->conn,
4644                                 "DELETE FROM procedimientos WHERE idprocedimiento=%s",
4645                                 params->id);
4646
4647        if (!result) {
4648                dbi_conn_error(dbi->conn, &msglog);
4649                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4650                       __func__, __LINE__, msglog);
4651                og_dbi_close(dbi);
4652                return -1;
4653        } else if (dbi_result_get_numrows_affected(result) < 1) {
4654                syslog(LOG_ERR, "delete did not modify any row (%s:%d)\n",
4655                       __func__, __LINE__);
4656        }
4657
4658        dbi_result_free(result);
4659
4660        og_dbi_close(dbi);
4661        return 0;
4662}
4663
4664static int og_cmd_post_procedure_update(json_t *element,
4665                                        struct og_msg_params *params)
4666{
4667        struct og_procedure proc = {};
4668        const char *key, *msglog;
4669        struct og_dbi *dbi;
4670        dbi_result result;
4671        json_t *value;
4672        int err = 0;
4673
4674        json_object_foreach(element, key, value) {
4675                if (!strcmp(key, "procedure")) {
4676                        err = og_json_parse_string(value, &params->task_id);
4677                        params->flags |= OG_REST_PARAM_TASK;
4678                } else if (!strcmp(key, "center")) {
4679                        err = og_json_parse_string(value, &params->id);
4680                        params->flags |= OG_REST_PARAM_ID;
4681                } else if (!strcmp(key, "name")) {
4682                        err = og_json_parse_string(value, &params->name);
4683                        params->flags |= OG_REST_PARAM_NAME;
4684                } else if (!strcmp(key, "description")) {
4685                        err = og_json_parse_string(value, &params->comment);
4686                } else if (!strcmp(key, "steps")) {
4687                        err = og_json_parse_procedure(value, &proc);
4688                }
4689
4690                if (err < 0)
4691                        return err;
4692        }
4693
4694        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK |
4695                                            OG_REST_PARAM_ID |
4696                                            OG_REST_PARAM_NAME))
4697                return -1;
4698
4699        dbi = og_dbi_open(&ogconfig.db);
4700        if (!dbi) {
4701                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
4702                       __func__, __LINE__);
4703                return -1;
4704        }
4705
4706        result = dbi_conn_queryf(dbi->conn,
4707                                 "SELECT descripcion FROM procedimientos "
4708                                 "WHERE descripcion = '%s' AND idcentro = %s "
4709                                 "AND idprocedimiento <> %s",
4710                                 params->name, params->id, params->task_id);
4711
4712        if (!result) {
4713                dbi_conn_error(dbi->conn, &msglog);
4714                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4715                       __func__, __LINE__, msglog);
4716                og_dbi_close(dbi);
4717                return -1;
4718        }
4719
4720        if (dbi_result_get_numrows(result) > 0) {
4721                syslog(LOG_ERR, "Procedure with name %s already exists in the "
4722                                "center with id %s\n",
4723                       params->name, params->id);
4724                dbi_result_free(result);
4725                og_dbi_close(dbi);
4726                return -1;
4727        }
4728        dbi_result_free(result);
4729
4730        result = dbi_conn_queryf(dbi->conn,
4731                                 "UPDATE procedimientos SET idcentro = %s, "
4732                                 "descripcion = '%s', comentarios = '%s' "
4733                                 "WHERE idprocedimiento = %s",
4734                                 params->id, params->name, params->comment,
4735                                 params->task_id);
4736
4737        if (!result) {
4738                dbi_conn_error(dbi->conn, &msglog);
4739                syslog(LOG_ERR,
4740                       "failed to update procedure %s (%s:%d) %s\n",
4741                       params->task_id, __func__, __LINE__, msglog);
4742                og_dbi_close(dbi);
4743                return -1;
4744        }
4745        dbi_result_free(result);
4746
4747        result = dbi_conn_queryf(dbi->conn,
4748                                 "DELETE FROM procedimientos_acciones "
4749                                 "WHERE idprocedimiento = %s",
4750                                 params->task_id);
4751
4752        if (!result) {
4753                dbi_conn_error(dbi->conn, &msglog);
4754                syslog(LOG_ERR,
4755                       "failed to delete old procedure %s steps (%s:%d) %s\n",
4756                       params->task_id, __func__, __LINE__, msglog);
4757                og_dbi_close(dbi);
4758                return -1;
4759        }
4760        dbi_result_free(result);
4761
4762        proc.id = atoll(params->task_id);
4763        err = og_procedure_add_steps(dbi, &proc);
4764
4765        og_dbi_close(dbi);
4766
4767        return err;
4768}
4769
4770static int og_task_add_steps(struct og_dbi *dbi, struct og_procedure *task)
4771{
4772        struct og_procedure_step *step;
4773        const char *msglog;
4774        dbi_result result;
4775        int i;
4776
4777        for (i = 0; i < task->num_steps; i++) {
4778                step = &task->steps[i];
4779                switch (step->type) {
4780                case OG_STEP_COMMAND:
4781                        syslog(LOG_ERR, "Tasks can not include commands. "
4782                                        "Invalid step: %d\n",
4783                               step->position);
4784                        return -1;
4785                        break;
4786                case OG_STEP_PROCEDURE:
4787                        result = dbi_conn_queryf(dbi->conn,
4788                                                 "INSERT INTO tareas_acciones "
4789                                                 "(idtarea, orden, idprocedimiento) "
4790                                                 "VALUES (%d, %d, %d)",
4791                                                 task->id,
4792                                                 step->position,
4793                                                 step->procedure.id);
4794                        if (!result) {
4795                                dbi_conn_error(dbi->conn, &msglog);
4796                                syslog(LOG_ERR,
4797                                       "failed to add procedure child to database (%s:%d) %s\n",
4798                                       __func__, __LINE__, msglog);
4799                                og_dbi_close(dbi);
4800                                return -1;
4801                        }
4802                        dbi_result_free(result);
4803                        break;
4804                case OG_STEP_TASK:
4805                        result = dbi_conn_queryf(dbi->conn,
4806                                                 "INSERT INTO tareas_acciones "
4807                                                 "(idtarea, orden, tareaid) "
4808                                                 "VALUES (%d, %d, %d)",
4809                                                 task->id,
4810                                                 step->position,
4811                                                 step->procedure.id);
4812                        if (!result) {
4813                                dbi_conn_error(dbi->conn, &msglog);
4814                                syslog(LOG_ERR,
4815                                       "failed to add task child to database (%s:%d) %s\n",
4816                                       __func__, __LINE__, msglog);
4817                                og_dbi_close(dbi);
4818                                return -1;
4819                        }
4820                        dbi_result_free(result);
4821                        break;
4822                }
4823        }
4824
4825        return 0;
4826}
4827
4828static int og_cmd_post_task_add(json_t *element,
4829                                     struct og_msg_params *params)
4830{
4831        struct og_procedure task = {};
4832        const char *key, *msglog;
4833        struct og_dbi *dbi;
4834        dbi_result result;
4835        json_t *value;
4836        int err = 0;
4837
4838        json_object_foreach(element, key, value) {
4839                if (!strcmp(key, "center")) {
4840                        err = og_json_parse_string(value, &params->id);
4841                        params->flags |= OG_REST_PARAM_ID;
4842                } else if (!strcmp(key, "name")) {
4843                        err = og_json_parse_string(value, &params->name);
4844                        params->flags |= OG_REST_PARAM_NAME;
4845                } else if (!strcmp(key, "description")) {
4846                        err = og_json_parse_string(value, &params->comment);
4847                } else if (!strcmp(key, "steps")) {
4848                        err = og_json_parse_procedure(value, &task);
4849                }
4850
4851                if (err < 0)
4852                        return err;
4853        }
4854
4855        if (!og_msg_params_validate(params, OG_REST_PARAM_ID |
4856                                            OG_REST_PARAM_NAME))
4857                return -1;
4858
4859        dbi = og_dbi_open(&ogconfig.db);
4860        if (!dbi) {
4861                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
4862                       __func__, __LINE__);
4863                return -1;
4864        }
4865
4866        result = dbi_conn_queryf(dbi->conn,
4867                                 "SELECT descripcion FROM tareas "
4868                                 "WHERE descripcion='%s' AND idcentro=%s",
4869                                 params->name, params->id);
4870
4871        if (!result) {
4872                dbi_conn_error(dbi->conn, &msglog);
4873                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4874                       __func__, __LINE__, msglog);
4875                og_dbi_close(dbi);
4876                return -1;
4877        }
4878
4879        if (dbi_result_get_numrows(result) > 0) {
4880                syslog(LOG_ERR, "Task with name %s already exists in the "
4881                                "center with id %s\n",
4882                       params->name, params->id);
4883                dbi_result_free(result);
4884                og_dbi_close(dbi);
4885                return -1;
4886        }
4887        dbi_result_free(result);
4888
4889        result = dbi_conn_queryf(dbi->conn,
4890                                 "INSERT INTO tareas("
4891                                 "idcentro, descripcion, comentarios) "
4892                                 "VALUES (%s, '%s', '%s')",
4893                                 params->id, params->name, params->comment);
4894
4895        if (!result) {
4896                dbi_conn_error(dbi->conn, &msglog);
4897                syslog(LOG_ERR,
4898                       "failed to add task to database (%s:%d) %s\n",
4899                       __func__, __LINE__, msglog);
4900                og_dbi_close(dbi);
4901                return -1;
4902        }
4903        dbi_result_free(result);
4904
4905        task.id = dbi_conn_sequence_last(dbi->conn, NULL);
4906        err = og_task_add_steps(dbi, &task);
4907
4908        og_dbi_close(dbi);
4909
4910        return err;
4911}
4912
4913static int og_cmd_post_room_add(json_t *element,
4914                                struct og_msg_params *params)
4915{
4916        struct og_room room = {};
4917        const char *key, *msglog;
4918        struct og_dbi *dbi;
4919        dbi_result result;
4920        json_t *value;
4921        int err = 0;
4922
4923        json_object_foreach(element, key, value) {
4924                if (!strcmp(key, "name")) {
4925                        err = og_json_parse_string_copy(value, room.name,
4926                                                        sizeof(room.name));
4927                        params->flags |= OG_REST_PARAM_NAME;
4928                } else if (!strcmp(key, "location")) {
4929                        err = og_json_parse_string_copy(value, room.location,
4930                                                        sizeof(room.location));
4931                } else if (!strcmp(key, "gateway")) {
4932                        err = og_json_parse_string_copy(value, room.gateway,
4933                                                        sizeof(room.gateway));
4934                } else if (!strcmp(key, "netmask")) {
4935                        err = og_json_parse_string_copy(value, room.netmask,
4936                                                        sizeof(room.netmask));
4937                        params->flags |= OG_REST_PARAM_NETMASK;
4938                } else if (!strcmp(key, "ntp")) {
4939                        err = og_json_parse_string_copy(value, room.ntp,
4940                                                        sizeof(room.ntp));
4941                } else if (!strcmp(key, "dns")) {
4942                        err = og_json_parse_string_copy(value, room.dns,
4943                                                        sizeof(room.dns));
4944                } else if (!strcmp(key, "center")) {
4945                        err = og_json_parse_uint(value, &room.center);
4946                        params->flags |= OG_REST_PARAM_CENTER;
4947                } else if (!strcmp(key, "group")) {
4948                        err = og_json_parse_uint(value, &room.group);
4949                } else if (!strcmp(key, "remote")) {
4950                        err = og_json_parse_bool(value, &room.remote);
4951                }
4952
4953                if (err < 0)
4954                        return err;
4955        }
4956
4957        if (!og_msg_params_validate(params, OG_REST_PARAM_NAME |
4958                                            OG_REST_PARAM_NETMASK |
4959                                            OG_REST_PARAM_CENTER))
4960                return -1;
4961
4962        dbi = og_dbi_open(&ogconfig.db);
4963        if (!dbi) {
4964                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
4965                       __func__, __LINE__);
4966                return -1;
4967        }
4968
4969        result = dbi_conn_queryf(dbi->conn,
4970                                 "SELECT nombreaula FROM aulas "
4971                                 "WHERE nombreaula='%s' AND idcentro=%d",
4972                                 room.name, room.center);
4973
4974        if (!result) {
4975                dbi_conn_error(dbi->conn, &msglog);
4976                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4977                       __func__, __LINE__, msglog);
4978                og_dbi_close(dbi);
4979                return -1;
4980        }
4981
4982        if (dbi_result_get_numrows(result) > 0) {
4983                syslog(LOG_ERR, "Room with name %s already exists in the "
4984                                "center with id %d\n",
4985                       room.name, room.center);
4986                dbi_result_free(result);
4987                og_dbi_close(dbi);
4988                return -1;
4989        }
4990        dbi_result_free(result);
4991
4992        result = dbi_conn_queryf(dbi->conn,
4993                                 "INSERT INTO aulas("
4994                                 "  idcentro,"
4995                                 "  nombreaula,"
4996                                 "  netmask,"
4997                                 "  grupoid,"
4998                                 "  ubicacion,"
4999                                 "  router,"
5000                                 "  dns,"
5001                                 "  ntp,"
5002                                 "  inremotepc) VALUES ("
5003                                 "%d, '%s', '%s', %d, '%s', "
5004                                 "'%s', '%s', '%s', %d)",
5005                                 room.center, room.name, room.netmask,
5006                                 room.group, room.location, room.gateway,
5007                                 room.dns, room.ntp, room.remote);
5008
5009        if (!result) {
5010                dbi_conn_error(dbi->conn, &msglog);
5011                syslog(LOG_ERR, "failed to add room to database (%s:%d) %s\n",
5012                       __func__, __LINE__, msglog);
5013                og_dbi_close(dbi);
5014                return -1;
5015        }
5016
5017        dbi_result_free(result);
5018        og_dbi_close(dbi);
5019        return 0;
5020}
5021
5022static int og_cmd_post_room_delete(json_t *element,
5023                                   struct og_msg_params *params)
5024{
5025        const char *key, *msglog;
5026        struct og_dbi *dbi;
5027        dbi_result result;
5028        json_t *value;
5029        int err = 0;
5030
5031        json_object_foreach(element, key, value) {
5032                if (!strcmp(key, "id")) {
5033                        err = og_json_parse_string(value, &params->id);
5034                        params->flags |= OG_REST_PARAM_ID;
5035                }
5036                if (err < 0)
5037                        return err;
5038        }
5039
5040        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
5041                return -1;
5042
5043        dbi = og_dbi_open(&ogconfig.db);
5044        if (!dbi) {
5045                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
5046                       __func__, __LINE__);
5047                return -1;
5048        }
5049
5050        result = dbi_conn_queryf(dbi->conn,
5051                                 "DELETE FROM aulas WHERE idaula=%s",
5052                                 params->id);
5053
5054        if (!result) {
5055                dbi_conn_error(dbi->conn, &msglog);
5056                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
5057                       __func__, __LINE__, msglog);
5058                og_dbi_close(dbi);
5059                return -1;
5060        }
5061
5062        dbi_result_free(result);
5063
5064        og_dbi_close(dbi);
5065        return 0;
5066}
5067
5068enum {
5069        OG_SCHEDULE_CMD_TYPE    = 0,
5070        OG_SCHEDULE_CMD_PARAMS,
5071};
5072
5073static bool og_cmd_validate(const struct og_cmd_json *cmd,
5074                            const uint64_t flags)
5075{
5076        return (cmd->flags & flags) == flags;
5077}
5078
5079
5080static int og_cmd_post_schedule_command(json_t *element,
5081                                        struct og_msg_params *params)
5082{
5083        char *centerid_query  = "SELECT o.idordenador, c.idcentro "
5084                                "FROM `ordenadores` AS o "
5085                                "INNER JOIN aulas AS a ON o.idaula = a.idaula "
5086                                "INNER JOIN centros AS c ON a.idcentro = c.idcentro "
5087                                "WHERE o.ip = '%s';";
5088        uint32_t sequence, session = 0;
5089        int center_id, client_id, len;
5090        struct og_cmd_json cmd = {};
5091        const char *legacy_params;
5092        const char *key, *msglog;
5093        struct og_dbi *dbi;
5094        char task_id[128];
5095        bool when = false;
5096        dbi_result result;
5097        json_t *value;
5098        int err = 0, i;
5099
5100        json_object_foreach(element, key, value) {
5101                if (!strcmp(key, "clients")) {
5102                        err = og_json_parse_clients(value, params);
5103                } else if (!strcmp(key, "command")) {
5104                        err = og_json_parse_string(value, &cmd.type);
5105                        cmd.flags |= OG_SCHEDULE_CMD_TYPE;
5106                } else if (!strcmp(key, "params")) {
5107                        cmd.json = value;
5108                        cmd.flags |= OG_SCHEDULE_CMD_PARAMS;
5109                } else if (!strcmp(key, "when")) {
5110                        err = og_json_parse_time_params(value, params);
5111                        when = true;
5112                }
5113
5114                if (err < 0)
5115                        return err;
5116        }
5117
5118        if (!og_cmd_validate(&cmd, OG_SCHEDULE_CMD_TYPE |
5119                                   OG_SCHEDULE_CMD_PARAMS))
5120                return -1;
5121
5122        if (!when) {
5123                params->time.check_stale = false;
5124                og_schedule_time_now(&params->time);
5125                params->flags |= OG_REST_PARAM_TIME_YEARS |
5126                                 OG_REST_PARAM_TIME_MONTHS |
5127                                 OG_REST_PARAM_TIME_WEEKS |
5128                                 OG_REST_PARAM_TIME_WEEK_DAYS |
5129                                 OG_REST_PARAM_TIME_DAYS |
5130                                 OG_REST_PARAM_TIME_HOURS |
5131                                 OG_REST_PARAM_TIME_AM_PM |
5132                                 OG_REST_PARAM_TIME_MINUTES;
5133        } else {
5134                params->time.check_stale = true;
5135        }
5136
5137        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
5138                                            OG_REST_PARAM_TIME_YEARS |
5139                                            OG_REST_PARAM_TIME_MONTHS |
5140                                            OG_REST_PARAM_TIME_WEEKS |
5141                                            OG_REST_PARAM_TIME_WEEK_DAYS |
5142                                            OG_REST_PARAM_TIME_DAYS |
5143                                            OG_REST_PARAM_TIME_HOURS |
5144                                            OG_REST_PARAM_TIME_MINUTES |
5145                                            OG_REST_PARAM_TIME_AM_PM))
5146                return -1;
5147
5148        params->type = "command";
5149        dbi = og_dbi_open(&ogconfig.db);
5150        if (!dbi) {
5151                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
5152                       __func__, __LINE__);
5153                goto err_dbi_open;
5154        }
5155
5156        legacy_params = og_msg_params_to_legacy(&cmd);
5157        if (!legacy_params)
5158                goto err_legacy_params;
5159
5160        /* ips_array -> ids */
5161        for (i = 0; i < params->ips_array_len; i++) {
5162
5163                result = dbi_conn_queryf(dbi->conn, centerid_query, params->ips_array[i]);
5164                if (!result) {
5165                        dbi_conn_error(dbi->conn, &msglog);
5166                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
5167                               __func__, __LINE__, msglog);
5168                        goto err_dbi_result;
5169                }
5170                if (dbi_result_get_numrows(result) != 1) {
5171                        dbi_conn_error(dbi->conn, &msglog);
5172                        syslog(LOG_ERR, "client not found (%s:%d) %s\n",
5173                               __func__, __LINE__, msglog);
5174                        goto err_dbi;
5175                }
5176
5177                if (!dbi_result_next_row(result)) {
5178                        dbi_conn_error(dbi->conn, &msglog);
5179                        syslog(LOG_ERR, "failed to get idcentro (%s:%d) %s\n",
5180                               __func__, __LINE__, msglog);
5181                        goto err_dbi;
5182                }
5183                center_id = dbi_result_get_uint(result, "idcentro");
5184                if (!center_id) {
5185                        dbi_conn_error(dbi->conn, &msglog);
5186                        syslog(LOG_ERR, "failed to get idcentro (%s:%d) %s\n",
5187                               __func__, __LINE__, msglog);
5188                        goto err_dbi;
5189                }
5190                client_id = dbi_result_get_uint(result, "idordenador");
5191                dbi_result_free(result);
5192
5193                result = dbi_conn_queryf(dbi->conn, "INSERT INTO acciones (idordenador, "
5194                                                    "idcentro, parametros)"
5195                                                    "VALUES (%d, %d, '%s')",
5196                                         client_id, center_id, legacy_params);
5197                if (!result) {
5198                        dbi_conn_error(dbi->conn, &msglog);
5199                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
5200                               __func__, __LINE__, msglog);
5201                        goto err_dbi_result;
5202                }
5203                dbi_result_free(result);
5204
5205                sequence = dbi_conn_sequence_last(dbi->conn, NULL);
5206
5207                /* This 'session' ID allows us to correlate the schedule with
5208                 * the commands after expansion.
5209                 */
5210                if (!session)
5211                        session = dbi_conn_sequence_last(dbi->conn, NULL);
5212
5213                result = dbi_conn_queryf(dbi->conn, "UPDATE acciones SET idordenador=%d, "
5214                                                    "idcentro=%d, parametros='%s', sesion=%d"
5215                                                    "WHERE idaccion=%d",
5216                                         client_id, center_id, legacy_params,
5217                                         session, sequence);
5218                if (!result) {
5219                        dbi_conn_error(dbi->conn, &msglog);
5220                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
5221                               __func__, __LINE__, msglog);
5222                        goto err_dbi_result;
5223                }
5224                dbi_result_free(result);
5225        }
5226
5227        len = snprintf(task_id, sizeof(session), "%d", session);
5228        if (len >= (int)sizeof(task_id)) {
5229                syslog(LOG_ERR, "truncated snprintf (%s:%d)\n",
5230                       __func__, __LINE__);
5231                goto err_dbi_result;
5232        }
5233        params->task_id = task_id;
5234
5235        og_task_schedule_create(params);
5236
5237        free((char *)legacy_params);
5238        og_dbi_close(dbi);
5239        return 0;
5240
5241err_dbi:
5242        dbi_result_free(result);
5243err_dbi_result:
5244        free((char *)legacy_params);
5245err_legacy_params:
5246        og_dbi_close(dbi);
5247err_dbi_open:
5248        return -1;
5249}
5250
5251static int og_cmd_post_procedure_run(json_t *element,
5252                                     struct og_msg_params *params)
5253{
5254        const char *centerid_query  = "SELECT o.idordenador, c.idcentro "
5255                                      "FROM `ordenadores` AS o "
5256                                      "INNER JOIN aulas AS a "
5257                                      "ON o.idaula = a.idaula "
5258                                      "INNER JOIN centros AS c "
5259                                      "ON a.idcentro = c.idcentro "
5260                                      "WHERE o.ip = '%s';";
5261        struct og_task task = {};
5262        const char *key, *msglog;
5263        struct og_dbi *dbi;
5264        dbi_result result;
5265        int i, err = 0;
5266        json_t *value;
5267
5268        json_object_foreach(element, key, value) {
5269                if (!strcmp(key, "clients")) {
5270                        err = og_json_parse_clients(value, params);
5271                } else if (!strcmp(key, "procedure")) {
5272                        err = og_json_parse_string(value, &params->id);
5273                        params->flags |= OG_REST_PARAM_ID;
5274                }
5275
5276                if (err < 0)
5277                        goto err_return;
5278        }
5279
5280        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
5281                                            OG_REST_PARAM_ID ))
5282                goto err_return;
5283
5284        task.type_scope = AMBITO_ORDENADORES;
5285        task.procedure_id = atoi(params->id);
5286
5287        dbi = og_dbi_open(&ogconfig.db);
5288        if (!dbi) {
5289                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
5290                       __func__, __LINE__);
5291                goto err_return;
5292        }
5293
5294        for (i = 0; i < params->ips_array_len; i++) {
5295
5296                result = dbi_conn_queryf(dbi->conn, centerid_query, params->ips_array[i]);
5297                if (!result) {
5298                        dbi_conn_error(dbi->conn, &msglog);
5299                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
5300                               __func__, __LINE__, msglog);
5301                        goto err_close_dbi;
5302                }
5303
5304                if (dbi_result_get_numrows(result) != 1 ||
5305                    !dbi_result_next_row(result) ||
5306                    !dbi_result_get_uint(result, "idcentro") ||
5307                    !dbi_result_get_uint(result, "idordenador")) {
5308                        dbi_conn_error(dbi->conn, &msglog);
5309                        syslog(LOG_ERR, "failed to get query data (%s:%d) %s\n",
5310                               __func__, __LINE__, msglog);
5311                        goto err_free_result;
5312                }
5313
5314                task.center_id = dbi_result_get_uint(result, "idcentro");
5315                task.scope = dbi_result_get_uint(result, "idordenador");
5316                dbi_result_free(result);
5317
5318                if (og_dbi_queue_procedure(dbi, &task))
5319                        goto err_close_dbi;
5320        }
5321
5322        og_dbi_close(dbi);
5323
5324        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
5325                               NULL);
5326
5327err_free_result:
5328        dbi_result_free(result);
5329err_close_dbi:
5330        og_dbi_close(dbi);
5331err_return:
5332        return -1;
5333}
5334
5335static int og_dbi_update_oglive(struct og_dbi *dbi, const char *mac,
5336                                const char * oglive)
5337{
5338        const char *msglog;
5339        dbi_result result;
5340
5341        result = dbi_conn_queryf(dbi->conn,
5342                                 "UPDATE ordenadores SET oglivedir='%s' "
5343                                 "WHERE mac='%s'",
5344                                 oglive, mac);
5345
5346        if (!result) {
5347                dbi_conn_error(dbi->conn, &msglog);
5348                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
5349                       __func__, __LINE__, msglog);
5350                return -1;
5351        }
5352
5353        dbi_result_free(result);
5354        return 0;
5355}
5356
5357static int og_cmd_oglive_set(json_t *element, struct og_msg_params *params)
5358{
5359        char ips_str[(OG_DB_IP_MAXLEN + 1) * OG_CLIENTS_MAX + 1] = {};
5360        const char legacy_default_oglive_str[] = "ogLive";
5361        const char *oglive_str, *mac, *mode_str;
5362        const char template_name[] = "ogLive";
5363        int ips_str_len = 0;
5364        struct og_dbi *dbi;
5365        uint64_t flags = 0;
5366        dbi_result result;
5367        const char *key;
5368        json_t *value;
5369        int err = 0;
5370        int i;
5371
5372        json_object_foreach(element, key, value) {
5373                if (!strcmp(key, "clients")) {
5374                        err = og_json_parse_clients(value, params);
5375                } else if (!strcmp(key, "name")) {
5376                        err = og_json_parse_string(value, &oglive_str);
5377                        flags |= OG_REST_PARAM_NAME;
5378                } else {
5379                        err = -1;
5380                }
5381
5382                if (err < 0)
5383                        return err;
5384        }
5385
5386        if (!og_flags_validate(flags, OG_REST_PARAM_NAME) ||
5387            !og_msg_params_validate(params, OG_REST_PARAM_ADDR))
5388                return -1;
5389
5390        if (!strcmp(oglive_str, "default"))
5391                oglive_str = legacy_default_oglive_str;
5392
5393        for (i = 0; i < params->ips_array_len; ++i) {
5394                ips_str_len += snprintf(ips_str + ips_str_len,
5395                                        sizeof(ips_str) - ips_str_len,
5396                                        "'%s',", params->ips_array[i]);
5397        }
5398        ips_str[ips_str_len - 1] = '\0';
5399
5400        dbi = og_dbi_open(&ogconfig.db);
5401        if (!dbi) {
5402                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5403                       __func__, __LINE__);
5404                return -1;
5405        }
5406
5407        result = dbi_conn_queryf(dbi->conn,
5408                                 "SELECT mac, arranque FROM ordenadores "
5409                                 "WHERE ip IN (%s)", ips_str);
5410
5411        while (dbi_result_next_row(result)) {
5412                mac = dbi_result_get_string(result, "mac");
5413                mode_str = dbi_result_get_string(result, "arranque");
5414                err = og_dbi_update_oglive(dbi, mac, oglive_str);
5415                if (err != 0) {
5416                        syslog(LOG_ERR, "failed to change db oglive (%s:%d)\n",
5417                               __func__, __LINE__);
5418                        dbi_result_free(result);
5419                        og_dbi_close(dbi);
5420                        return -1;
5421                }
5422                err = og_set_client_mode(dbi, mac, mode_str, template_name);
5423                if (err != 0) {
5424                        dbi_result_free(result);
5425                        og_dbi_close(dbi);
5426                        return -1;
5427                }
5428        }
5429
5430        dbi_result_free(result);
5431        og_dbi_close(dbi);
5432
5433        return 0;
5434}
5435
5436static int og_client_method_not_found(struct og_client *cli)
5437{
5438        /* To meet RFC 7231, this function MUST generate an Allow header field
5439         * containing the correct methods. For example: "Allow: POST\r\n"
5440         */
5441        char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n"
5442                     "Content-Length: 0\r\n\r\n";
5443
5444        send(og_client_socket(cli), buf, strlen(buf), 0);
5445
5446        return -1;
5447}
5448
5449static int og_client_bad_request(struct og_client *cli)
5450{
5451        char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
5452
5453        send(og_client_socket(cli), buf, strlen(buf), 0);
5454
5455        return -1;
5456}
5457
5458static int og_client_not_found(struct og_client *cli)
5459{
5460        char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
5461
5462        send(og_client_socket(cli), buf, strlen(buf), 0);
5463
5464        return -1;
5465}
5466
5467static int og_client_not_authorized(struct og_client *cli)
5468{
5469        char buf[] = "HTTP/1.1 401 Unauthorized\r\n"
5470                     "WWW-Authenticate: Basic\r\n"
5471                     "Content-Length: 0\r\n\r\n";
5472
5473        send(og_client_socket(cli), buf, strlen(buf), 0);
5474
5475        return -1;
5476}
5477
5478static int og_server_internal_error(struct og_client *cli)
5479{
5480        char buf[] = "HTTP/1.1 500 Internal Server Error\r\n"
5481                     "Content-Length: 0\r\n\r\n";
5482
5483        send(og_client_socket(cli), buf, strlen(buf), 0);
5484
5485        return -1;
5486}
5487
5488static int og_client_ok(struct og_client *cli, char *buf_reply)
5489{
5490        char buf[OG_MSG_RESPONSE_MAXLEN] = {};
5491        int len;
5492
5493        len = snprintf(buf, sizeof(buf),
5494                       "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
5495                       strlen(buf_reply), buf_reply);
5496        if (len >= (int)sizeof(buf)) {
5497                syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n",
5498                       inet_ntoa(cli->addr.sin_addr),
5499                       ntohs(cli->addr.sin_port));
5500                return og_server_internal_error(cli);
5501        }
5502
5503        send(og_client_socket(cli), buf, strlen(buf), 0);
5504
5505        return 0;
5506}
5507
5508int og_client_state_process_payload_rest(struct og_client *cli)
5509{
5510        char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {};
5511        struct og_msg_params params = {};
5512        enum og_rest_method method;
5513        const char *cmd, *body;
5514        json_error_t json_err;
5515        json_t *root = NULL;
5516        int err = 0;
5517
5518        syslog(LOG_DEBUG, "%s:%hu %.32s ...\n",
5519               inet_ntoa(cli->addr.sin_addr),
5520               ntohs(cli->addr.sin_port), cli->buf);
5521
5522        if (!strncmp(cli->buf, "GET", strlen("GET"))) {
5523                method = OG_METHOD_GET;
5524                cmd = cli->buf + strlen("GET") + 2;
5525        } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
5526                method = OG_METHOD_POST;
5527                cmd = cli->buf + strlen("POST") + 2;
5528        } else
5529                return og_client_method_not_found(cli);
5530
5531        body = strstr(cli->buf, "\r\n\r\n") + 4;
5532
5533        if (strcmp(cli->auth_token, ogconfig.rest.api_token)) {
5534                syslog(LOG_ERR, "wrong Authentication key\n");
5535                return og_client_not_authorized(cli);
5536        }
5537
5538        if (cli->content_length) {
5539                root = json_loads(body, 0, &json_err);
5540                if (!root) {
5541                        syslog(LOG_ERR, "malformed json line %d: %s\n",
5542                               json_err.line, json_err.text);
5543                        return og_client_not_found(cli);
5544                }
5545        }
5546
5547        if (!strncmp(cmd, "clients", strlen("clients"))) {
5548                if (method != OG_METHOD_POST &&
5549                    method != OG_METHOD_GET) {
5550                        err = og_client_method_not_found(cli);
5551                        goto err_process_rest_payload;
5552                }
5553
5554                if (method == OG_METHOD_POST && !root) {
5555                        syslog(LOG_ERR, "command clients with no payload\n");
5556                        err = og_client_bad_request(cli);
5557                        goto err_process_rest_payload;
5558                }
5559                switch (method) {
5560                case OG_METHOD_POST:
5561                        err = og_cmd_post_clients(root, &params);
5562                        break;
5563                case OG_METHOD_GET:
5564                        err = og_cmd_get_clients(root, &params, buf_reply);
5565                        break;
5566                default:
5567                        err = og_client_bad_request(cli);
5568                        goto err_process_rest_payload;
5569                }
5570        } else if (!strncmp(cmd, "client/setup",
5571                            strlen("client/setup"))) {
5572                if (method != OG_METHOD_GET) {
5573                        err = og_client_method_not_found(cli);
5574                        goto err_process_rest_payload;
5575                }
5576
5577                if (!root) {
5578                        syslog(LOG_ERR,
5579                               "command client partitions with no payload\n");
5580                        err = og_client_bad_request(cli);
5581                        goto err_process_rest_payload;
5582                }
5583
5584                err = og_cmd_get_client_setup(root, &params, buf_reply);
5585        } else if (!strncmp(cmd, "client/info",
5586                            strlen("client/info"))) {
5587                if (method != OG_METHOD_GET) {
5588                        err = og_client_method_not_found(cli);
5589                        goto err_process_rest_payload;
5590                }
5591                if (!root) {
5592                        syslog(LOG_ERR,
5593                               "command client info with no payload\n");
5594                        err = og_client_bad_request(cli);
5595                        goto err_process_rest_payload;
5596                }
5597
5598                err = og_cmd_get_client_info(root, &params, buf_reply);
5599        } else if (!strncmp(cmd, "client/add", strlen("client/add"))) {
5600                if (method != OG_METHOD_POST) {
5601                        err = og_client_method_not_found(cli);
5602                        goto err_process_rest_payload;
5603                }
5604
5605                if (!root) {
5606                        syslog(LOG_ERR,
5607                               "command client info with no payload\n");
5608                        err = og_client_bad_request(cli);
5609                        goto err_process_rest_payload;
5610                }
5611
5612                err = og_cmd_post_client_add(root, &params, buf_reply);
5613        } else if (!strncmp(cmd, "client/delete", strlen("client/delete"))) {
5614                if (method != OG_METHOD_POST) {
5615                        err = og_client_method_not_found(cli);
5616                        goto err_process_rest_payload;
5617                }
5618
5619                if (!root) {
5620                        syslog(LOG_ERR,
5621                               "command client delete with no payload\n");
5622                        err = og_client_bad_request(cli);
5623                        goto err_process_rest_payload;
5624                }
5625
5626                err = og_cmd_post_client_delete(root, &params);
5627        } else if (!strncmp(cmd, "wol", strlen("wol"))) {
5628                if (method != OG_METHOD_POST) {
5629                        err = og_client_method_not_found(cli);
5630                        goto err_process_rest_payload;
5631                }
5632
5633                if (!root) {
5634                        syslog(LOG_ERR, "command wol with no payload\n");
5635                        err = og_client_bad_request(cli);
5636                        goto err_process_rest_payload;
5637                }
5638                err = og_cmd_wol(root, &params);
5639        } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) {
5640                if (method != OG_METHOD_POST) {
5641                        err = og_client_method_not_found(cli);
5642                        goto err_process_rest_payload;
5643                }
5644
5645                if (!root) {
5646                        syslog(LOG_ERR, "command run with no payload\n");
5647                        err = og_client_bad_request(cli);
5648                        goto err_process_rest_payload;
5649                }
5650                err = og_cmd_run_post(root, &params);
5651        } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) {
5652                if (method != OG_METHOD_POST) {
5653                        err = og_client_method_not_found(cli);
5654                        goto err_process_rest_payload;
5655                }
5656
5657                if (!root) {
5658                        syslog(LOG_ERR, "command output with no payload\n");
5659                        err = og_client_bad_request(cli);
5660                        goto err_process_rest_payload;
5661                }
5662
5663                err = og_cmd_run_get(root, &params, buf_reply);
5664        } else if (!strncmp(cmd, "session", strlen("session"))) {
5665                if (method != OG_METHOD_POST && method != OG_METHOD_GET) {
5666                        err = og_client_method_not_found(cli);
5667                        goto err_process_rest_payload;
5668                }
5669
5670                if (!root) {
5671                        syslog(LOG_ERR, "command session with no payload\n");
5672                        err = og_client_bad_request(cli);
5673                        goto err_process_rest_payload;
5674                }
5675
5676                if (method == OG_METHOD_POST)
5677                        err = og_cmd_session(root, &params);
5678                else
5679                        err = og_cmd_get_session(root, &params, buf_reply);
5680        } else if (!strncmp(cmd, "scopes", strlen("scopes"))) {
5681                if (method != OG_METHOD_GET) {
5682                        err = og_client_method_not_found(cli);
5683                        goto err_process_rest_payload;
5684                }
5685
5686                if (root) {
5687                        syslog(LOG_ERR, "command scopes with payload\n");
5688                        err = og_client_bad_request(cli);
5689                        goto err_process_rest_payload;
5690                }
5691
5692                err = og_cmd_scope_get(root, &params, buf_reply);
5693        } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) {
5694                if (method != OG_METHOD_POST) {
5695                        err = og_client_method_not_found(cli);
5696                        goto err_process_rest_payload;
5697                }
5698
5699                if (!root) {
5700                        syslog(LOG_ERR, "command poweroff with no payload\n");
5701                        err = og_client_bad_request(cli);
5702                        goto err_process_rest_payload;
5703                }
5704                err = og_cmd_poweroff(root, &params);
5705        } else if (!strncmp(cmd, "reboot", strlen("reboot"))) {
5706                if (method != OG_METHOD_POST) {
5707                        err = og_client_method_not_found(cli);
5708                        goto err_process_rest_payload;
5709                }
5710
5711                if (!root) {
5712                        syslog(LOG_ERR, "command reboot with no payload\n");
5713                        err = og_client_bad_request(cli);
5714                        goto err_process_rest_payload;
5715                }
5716                err = og_cmd_reboot(root, &params);
5717        } else if (!strncmp(cmd, "mode", strlen("mode"))) {
5718                if (method != OG_METHOD_GET && method != OG_METHOD_POST) {
5719                        err = og_client_method_not_found(cli);
5720                        goto err_process_rest_payload;
5721                }
5722
5723                if (method == OG_METHOD_POST && !root) {
5724                        syslog(LOG_ERR, "command mode with no payload\n");
5725                        err = og_client_bad_request(cli);
5726                        goto err_process_rest_payload;
5727                }
5728
5729                if (method == OG_METHOD_GET)
5730                        err = og_cmd_get_modes(root, &params, buf_reply);
5731                else if (method == OG_METHOD_POST)
5732                        err = og_cmd_post_modes(root, &params);
5733        } else if (!strncmp(cmd, "stop", strlen("stop"))) {
5734                if (method != OG_METHOD_POST) {
5735                        err = og_client_method_not_found(cli);
5736                        goto err_process_rest_payload;
5737                }
5738
5739                if (!root) {
5740                        syslog(LOG_ERR, "command stop with no payload\n");
5741                        err = og_client_bad_request(cli);
5742                        goto err_process_rest_payload;
5743                }
5744                err = og_cmd_stop(root, &params);
5745        } else if (!strncmp(cmd, "refresh", strlen("refresh"))) {
5746                if (method != OG_METHOD_POST) {
5747                        err = og_client_method_not_found(cli);
5748                        goto err_process_rest_payload;
5749                }
5750
5751                if (!root) {
5752                        syslog(LOG_ERR, "command refresh with no payload\n");
5753                        err = og_client_bad_request(cli);
5754                        goto err_process_rest_payload;
5755                }
5756                err = og_cmd_refresh(root, &params);
5757        } else if (!strncmp(cmd, "hardware", strlen("hardware"))) {
5758                if (method != OG_METHOD_GET && method != OG_METHOD_POST) {
5759                        err = og_client_method_not_found(cli);
5760                        goto err_process_rest_payload;
5761                }
5762
5763                if (!root) {
5764                        syslog(LOG_ERR, "command hardware with no payload\n");
5765                        err = og_client_bad_request(cli);
5766                        goto err_process_rest_payload;
5767                }
5768
5769                if (method == OG_METHOD_GET)
5770                        err = og_cmd_get_hardware(root, &params, buf_reply);
5771                else if (method == OG_METHOD_POST)
5772                        err = og_cmd_hardware(root, &params);
5773        } else if (!strncmp(cmd, "software", strlen("software"))) {
5774                if (method != OG_METHOD_POST && method != OG_METHOD_GET) {
5775                        err = og_client_method_not_found(cli);
5776                        goto err_process_rest_payload;
5777                }
5778
5779                if (!root) {
5780                        syslog(LOG_ERR, "command software with no payload\n");
5781                        err = og_client_bad_request(cli);
5782                        goto err_process_rest_payload;
5783                }
5784
5785                if (method == OG_METHOD_POST)
5786                        err = og_cmd_software(root, &params);
5787                else
5788                        err = og_cmd_get_software(root, &params, buf_reply);
5789        } else if (!strncmp(cmd, "images", strlen("images"))) {
5790                if (method != OG_METHOD_GET) {
5791                        err = og_client_method_not_found(cli);
5792                        goto err_process_rest_payload;
5793                }
5794
5795                if (root) {
5796                        err = og_client_bad_request(cli);
5797                        goto err_process_rest_payload;
5798                }
5799
5800                err = og_cmd_images(buf_reply);
5801        } else if (!strncmp(cmd, "image/create", strlen("image/create"))) {
5802                if (method != OG_METHOD_POST) {
5803                        err = og_client_method_not_found(cli);
5804                        goto err_process_rest_payload;
5805                }
5806
5807                if (!root) {
5808                        syslog(LOG_ERR, "command create with no payload\n");
5809                        err = og_client_bad_request(cli);
5810                        goto err_process_rest_payload;
5811                }
5812                err = og_cmd_create_image(root, &params);
5813        } else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) {
5814                if (method != OG_METHOD_POST) {
5815                        err = og_client_method_not_found(cli);
5816                        goto err_process_rest_payload;
5817                }
5818
5819                if (!root) {
5820                        syslog(LOG_ERR, "command create with no payload\n");
5821                        err = og_client_bad_request(cli);
5822                        goto err_process_rest_payload;
5823                }
5824                err = og_cmd_restore_image(root, &params);
5825        } else if (!strncmp(cmd, "image/delete", strlen("image/delete"))) {
5826                if (method != OG_METHOD_POST) {
5827                        err = og_client_method_not_found(cli);
5828                        goto err_process_rest_payload;
5829                }
5830
5831                if (!root) {
5832                        syslog(LOG_ERR,
5833                               "command image delete with no payload\n");
5834                        err = og_client_bad_request(cli);
5835                        goto err_process_rest_payload;
5836                }
5837                err = og_cmd_delete_image(root, &params);
5838        } else if (!strncmp(cmd, "setup", strlen("setup"))) {
5839                if (method != OG_METHOD_POST) {
5840                        err = og_client_method_not_found(cli);
5841                        goto err_process_rest_payload;
5842                }
5843
5844                if (!root) {
5845                        syslog(LOG_ERR, "command create with no payload\n");
5846                        err = og_client_bad_request(cli);
5847                        goto err_process_rest_payload;
5848                }
5849                err = og_cmd_setup(root, &params);
5850        } else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) {
5851                if (method != OG_METHOD_POST) {
5852                        err = og_client_method_not_found(cli);
5853                        goto err_process_rest_payload;
5854                }
5855
5856                if (!root) {
5857                        syslog(LOG_ERR, "command create with no payload\n");
5858                        err = og_client_bad_request(cli);
5859                        goto err_process_rest_payload;
5860                }
5861
5862                err = og_cmd_run_schedule(root, &params);
5863        } else if (!strncmp(cmd, "task/run", strlen("task/run"))) {
5864                if (method != OG_METHOD_POST) {
5865                        err = og_client_method_not_found(cli);
5866                        goto err_process_rest_payload;
5867                }
5868
5869                if (!root) {
5870                        syslog(LOG_ERR, "command task with no payload\n");
5871                        err = og_client_bad_request(cli);
5872                        goto err_process_rest_payload;
5873                }
5874                err = og_cmd_task_post(root, &params);
5875        } else if (!strncmp(cmd, "schedule/create",
5876                            strlen("schedule/create"))) {
5877                if (method != OG_METHOD_POST) {
5878                        err = og_client_method_not_found(cli);
5879                        goto err_process_rest_payload;
5880                }
5881
5882                if (!root) {
5883                        syslog(LOG_ERR, "command task with no payload\n");
5884                        err = og_client_bad_request(cli);
5885                        goto err_process_rest_payload;
5886                }
5887                err = og_cmd_schedule_create(root, &params);
5888        } else if (!strncmp(cmd, "schedule/delete",
5889                            strlen("schedule/delete"))) {
5890                if (method != OG_METHOD_POST) {
5891                        err = og_client_method_not_found(cli);
5892                        goto err_process_rest_payload;
5893                }
5894
5895                if (!root) {
5896                        syslog(LOG_ERR, "command task with no payload\n");
5897                        err = og_client_bad_request(cli);
5898                        goto err_process_rest_payload;
5899                }
5900                err = og_cmd_schedule_delete(root, &params);
5901        } else if (!strncmp(cmd, "schedule/update",
5902                            strlen("schedule/update"))) {
5903                if (method != OG_METHOD_POST) {
5904                        err = og_client_method_not_found(cli);
5905                        goto err_process_rest_payload;
5906                }
5907
5908                if (!root) {
5909                        syslog(LOG_ERR, "command task with no payload\n");
5910                        err = og_client_bad_request(cli);
5911                        goto err_process_rest_payload;
5912                }
5913                err = og_cmd_schedule_update(root, &params);
5914        } else if (!strncmp(cmd, "schedule/get",
5915                            strlen("schedule/get"))) {
5916                if (method != OG_METHOD_POST) {
5917                        err = og_client_method_not_found(cli);
5918                        goto err_process_rest_payload;
5919                }
5920
5921                err = og_cmd_schedule_get(root, &params, buf_reply);
5922        } else if (!strncmp(cmd, "oglive/list",
5923                            strlen("oglive/list"))) {
5924                if (method != OG_METHOD_GET) {
5925                        err = og_client_method_not_found(cli);
5926                        goto err_process_rest_payload;
5927                }
5928
5929                err = og_cmd_oglive_list(buf_reply);
5930        } else if (!strncmp(cmd, "oglive/set", strlen("oglive/set"))) {
5931                if (method != OG_METHOD_POST) {
5932                        err = og_client_method_not_found(cli);
5933                        goto err_process_rest_payload;
5934                }
5935
5936                if (!root) {
5937                        syslog(LOG_ERR,
5938                               "command oglive set with no payload\n");
5939                        err = og_client_bad_request(cli);
5940                        goto err_process_rest_payload;
5941                }
5942                err = og_cmd_oglive_set(root, &params);
5943        } else if (!strncmp(cmd, "center/add",
5944                            strlen("center/add"))) {
5945                if (method != OG_METHOD_POST) {
5946                        err = og_client_method_not_found(cli);
5947                        goto err_process_rest_payload;
5948                }
5949
5950                err = og_cmd_post_center_add(root, &params, buf_reply);
5951        } else if (!strncmp(cmd, "center/delete", strlen("center/delete"))) {
5952                if (method != OG_METHOD_POST) {
5953                        err = og_client_method_not_found(cli);
5954                        goto err_process_rest_payload;
5955                }
5956
5957                if (!root) {
5958                        syslog(LOG_ERR,
5959                               "command center delete with no payload\n");
5960                        err = og_client_bad_request(cli);
5961                        goto err_process_rest_payload;
5962                }
5963                err = og_cmd_post_center_delete(root, &params);
5964        } else if (!strncmp(cmd, "room/add",
5965                            strlen("room/add"))) {
5966                if (method != OG_METHOD_POST) {
5967                        err = og_client_method_not_found(cli);
5968                        goto err_process_rest_payload;
5969                }
5970
5971                if (!root) {
5972                        syslog(LOG_ERR, "command task with no payload\n");
5973                        err = og_client_bad_request(cli);
5974                        goto err_process_rest_payload;
5975                }
5976                err = og_cmd_post_room_add(root, &params);
5977        } else if (!strncmp(cmd, "room/delete", strlen("room/delete"))) {
5978                if (method != OG_METHOD_POST) {
5979                        err = og_client_method_not_found(cli);
5980                        goto err_process_rest_payload;
5981                }
5982
5983                if (!root) {
5984                        syslog(LOG_ERR,
5985                               "command room delete with no payload\n");
5986                        err = og_client_bad_request(cli);
5987                        goto err_process_rest_payload;
5988                }
5989                err = og_cmd_post_room_delete(root, &params);
5990        } else if (!strncmp(cmd, "procedure/add", strlen("procedure/add"))) {
5991                if (method != OG_METHOD_POST) {
5992                        err = og_client_method_not_found(cli);
5993                        goto err_process_rest_payload;
5994                }
5995
5996                if (!root) {
5997                        syslog(LOG_ERR,
5998                               "command procedure add with no payload\n");
5999                        err = og_client_bad_request(cli);
6000                        goto err_process_rest_payload;
6001                }
6002                err = og_cmd_post_procedure_add(root, &params);
6003        } else if (!strncmp(cmd, "procedure/update",
6004                            strlen("procedure/update"))) {
6005                if (method != OG_METHOD_POST) {
6006                        err = og_client_method_not_found(cli);
6007                        goto err_process_rest_payload;
6008                }
6009
6010                if (!root) {
6011                        syslog(LOG_ERR,
6012                               "command procedure update with no payload\n");
6013                        err = og_client_bad_request(cli);
6014                        goto err_process_rest_payload;
6015                }
6016                err = og_cmd_post_procedure_update(root, &params);
6017        } else if (!strncmp(cmd, "procedure/run", strlen("procedure/run"))) {
6018                if (method != OG_METHOD_POST) {
6019                        err = og_client_method_not_found(cli);
6020                        goto err_process_rest_payload;
6021                }
6022
6023                if (!root) {
6024                        syslog(LOG_ERR,
6025                               "command procedure run with no payload\n");
6026                        err = og_client_bad_request(cli);
6027                        goto err_process_rest_payload;
6028                }
6029                err = og_cmd_post_procedure_run(root, &params);
6030        } else if (!strncmp(cmd, "schedule/command", strlen("schedule/command"))) {
6031                if (method != OG_METHOD_POST) {
6032                        err = og_client_method_not_found(cli);
6033                        goto err_process_rest_payload;
6034                }
6035
6036                if (!root) {
6037                        syslog(LOG_ERR,
6038                               "command schedule action with no payload\n");
6039                        err = og_client_bad_request(cli);
6040                        goto err_process_rest_payload;
6041                }
6042                err = og_cmd_post_schedule_command(root, &params);
6043        } else if (!strncmp(cmd, "procedure/delete", strlen("schedule/command"))) {
6044                if (method != OG_METHOD_POST) {
6045                        err = og_client_method_not_found(cli);
6046                        goto err_process_rest_payload;
6047                }
6048
6049                if (!root) {
6050                        syslog(LOG_ERR,
6051                               "command procedure delete with no payload\n");
6052                        err = og_client_bad_request(cli);
6053                        goto err_process_rest_payload;
6054                }
6055                err = og_cmd_post_procedure_delete(root, &params);
6056        } else if (!strncmp(cmd, "task/add", strlen("task/add"))) {
6057                if (method != OG_METHOD_POST) {
6058                        err = og_client_method_not_found(cli);
6059                        goto err_process_rest_payload;
6060                }
6061
6062                if (!root) {
6063                        syslog(LOG_ERR,
6064                               "command task add with no payload\n");
6065                        err = og_client_bad_request(cli);
6066                        goto err_process_rest_payload;
6067                }
6068                err = og_cmd_post_task_add(root, &params);
6069        } else {
6070                syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd);
6071                err = og_client_not_found(cli);
6072        }
6073
6074        json_decref(root);
6075
6076        if (err < 0)
6077                return og_client_bad_request(cli);
6078
6079        return og_client_ok(cli, buf_reply);
6080
6081err_process_rest_payload:
6082        json_decref(root);
6083
6084        return err;
6085}
Note: See TracBrowser for help on using the repository browser.