source: ogServer-Git/src/rest.c @ 281d661

Last change on this file since 281d661 was 281d661, checked in by Jose M. Guisado <jguisado@…>, 3 years ago

#1065 og_client_status compatible with webconsole

Report linux and windows client status in a compatible manner
with webconsole. This way clients are colored accordingly in
a room view depending on their status.

WIN/WINS: Windows, Windows session
LNX/LNXS: Linux, Linux session

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