source: ogServer-Git/sources/rest.c @ 9c8e5c7

Last change on this file since 9c8e5c7 was 04ca20e, checked in by OpenGnSys Support Team <soporte-og@…>, 4 years ago

#971 split into smaller file

Split ogAdmServer into several files:

  • sources/rest.c that implements the server REST API.
  • sources/client.c that implements the client REST API.
  • sources/json.c that provides a few JSON helpers.
  • Property mode set to 100644
File size: 81.6 KB
Line 
1/*
2 * Copyright (C) 2020 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, version 3.
7 */
8
9#include "ogAdmServer.h"
10#include "dbi.h"
11#include "utils.h"
12#include "list.h"
13#include "rest.h"
14#include "schedule.h"
15#include <ev.h>
16#include <syslog.h>
17#include <sys/ioctl.h>
18#include <ifaddrs.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22#include <jansson.h>
23#include <time.h>
24
25static TRAMA *og_msg_alloc(char *data, unsigned int len)
26{
27        TRAMA *ptrTrama;
28
29        ptrTrama = calloc(1, sizeof(TRAMA));
30        if (!ptrTrama) {
31                syslog(LOG_ERR, "OOM\n");
32                return NULL;
33        }
34
35        initParametros(ptrTrama, len);
36        memcpy(ptrTrama, "@JMMLCAMDJ_MCDJ", LONGITUD_CABECERATRAMA);
37        memcpy(ptrTrama->parametros, data, len);
38        ptrTrama->lonprm = len;
39
40        return ptrTrama;
41}
42
43static void og_msg_free(TRAMA *ptrTrama)
44{
45        free(ptrTrama->parametros);
46        free(ptrTrama);
47}
48
49static bool og_send_cmd(char *ips_array[], int ips_array_len,
50                        const char *state, TRAMA *ptrTrama)
51{
52        int i, idx;
53
54        for (i = 0; i < ips_array_len; i++) {
55                if (clienteDisponible(ips_array[i], &idx)) { // Si el cliente puede recibir comandos
56                        int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1;
57
58                        strcpy(tbsockets[idx].estado, state); // Actualiza el estado del cliente
59                        if (sock >= 0 && !mandaTrama(&sock, ptrTrama)) {
60                                syslog(LOG_ERR, "failed to send response to %s:%s\n",
61                                       ips_array[i], strerror(errno));
62                        }
63                }
64        }
65        return true;
66}
67
68#define OG_REST_PARAM_ADDR                      (1UL << 0)
69#define OG_REST_PARAM_MAC                       (1UL << 1)
70#define OG_REST_PARAM_WOL_TYPE                  (1UL << 2)
71#define OG_REST_PARAM_RUN_CMD                   (1UL << 3)
72#define OG_REST_PARAM_DISK                      (1UL << 4)
73#define OG_REST_PARAM_PARTITION                 (1UL << 5)
74#define OG_REST_PARAM_REPO                      (1UL << 6)
75#define OG_REST_PARAM_NAME                      (1UL << 7)
76#define OG_REST_PARAM_ID                        (1UL << 8)
77#define OG_REST_PARAM_CODE                      (1UL << 9)
78#define OG_REST_PARAM_TYPE                      (1UL << 10)
79#define OG_REST_PARAM_PROFILE                   (1UL << 11)
80#define OG_REST_PARAM_CACHE                     (1UL << 12)
81#define OG_REST_PARAM_CACHE_SIZE                (1UL << 13)
82#define OG_REST_PARAM_PART_0                    (1UL << 14)
83#define OG_REST_PARAM_PART_1                    (1UL << 15)
84#define OG_REST_PARAM_PART_2                    (1UL << 16)
85#define OG_REST_PARAM_PART_3                    (1UL << 17)
86#define OG_REST_PARAM_SYNC_SYNC                 (1UL << 18)
87#define OG_REST_PARAM_SYNC_DIFF                 (1UL << 19)
88#define OG_REST_PARAM_SYNC_REMOVE               (1UL << 20)
89#define OG_REST_PARAM_SYNC_COMPRESS             (1UL << 21)
90#define OG_REST_PARAM_SYNC_CLEANUP              (1UL << 22)
91#define OG_REST_PARAM_SYNC_CACHE                (1UL << 23)
92#define OG_REST_PARAM_SYNC_CLEANUP_CACHE        (1UL << 24)
93#define OG_REST_PARAM_SYNC_REMOVE_DST           (1UL << 25)
94#define OG_REST_PARAM_SYNC_DIFF_ID              (1UL << 26)
95#define OG_REST_PARAM_SYNC_DIFF_NAME            (1UL << 27)
96#define OG_REST_PARAM_SYNC_PATH                 (1UL << 28)
97#define OG_REST_PARAM_SYNC_METHOD               (1UL << 29)
98#define OG_REST_PARAM_ECHO                      (1UL << 30)
99#define OG_REST_PARAM_TASK                      (1UL << 31)
100#define OG_REST_PARAM_TIME_YEARS                (1UL << 32)
101#define OG_REST_PARAM_TIME_MONTHS               (1UL << 33)
102#define OG_REST_PARAM_TIME_WEEKS                (1UL << 34)
103#define OG_REST_PARAM_TIME_WEEK_DAYS            (1UL << 35)
104#define OG_REST_PARAM_TIME_DAYS                 (1UL << 36)
105#define OG_REST_PARAM_TIME_HOURS                (1UL << 37)
106#define OG_REST_PARAM_TIME_AM_PM                (1UL << 38)
107#define OG_REST_PARAM_TIME_MINUTES              (1UL << 39)
108
109static LIST_HEAD(client_list);
110
111void og_client_add(struct og_client *cli)
112{
113        list_add(&cli->list, &client_list);
114}
115
116static struct og_client *og_client_find(const char *ip)
117{
118        struct og_client *client;
119        struct in_addr addr;
120        int res;
121
122        res = inet_aton(ip, &addr);
123        if (!res) {
124                syslog(LOG_ERR, "Invalid IP string: %s\n", ip);
125                return NULL;
126        }
127
128        list_for_each_entry(client, &client_list, list) {
129                if (client->addr.sin_addr.s_addr == addr.s_addr && client->agent) {
130                        return client;
131                }
132        }
133
134        return NULL;
135}
136
137static const char *og_client_status(const struct og_client *cli)
138{
139        if (cli->last_cmd != OG_CMD_UNSPEC)
140                return "BSY";
141
142        switch (cli->status) {
143        case OG_CLIENT_STATUS_BUSY:
144                return "BSY";
145        case OG_CLIENT_STATUS_OGLIVE:
146                return "OPG";
147        default:
148                return "OFF";
149        }
150}
151
152static bool og_msg_params_validate(const struct og_msg_params *params,
153                                   const uint64_t flags)
154{
155        return (params->flags & flags) == flags;
156}
157
158static int og_json_parse_clients(json_t *element, struct og_msg_params *params)
159{
160        unsigned int i;
161        json_t *k;
162
163        if (json_typeof(element) != JSON_ARRAY)
164                return -1;
165
166        for (i = 0; i < json_array_size(element); i++) {
167                k = json_array_get(element, i);
168                if (json_typeof(k) != JSON_STRING)
169                        return -1;
170
171                params->ips_array[params->ips_array_len++] =
172                        json_string_value(k);
173
174                params->flags |= OG_REST_PARAM_ADDR;
175        }
176
177        return 0;
178}
179
180static int og_json_parse_sync_params(json_t *element,
181                                     struct og_msg_params *params)
182{
183        const char *key;
184        json_t *value;
185        int err = 0;
186
187        json_object_foreach(element, key, value) {
188                if (!strcmp(key, "sync")) {
189                        err = og_json_parse_string(value, &params->sync_setup.sync);
190                        params->flags |= OG_REST_PARAM_SYNC_SYNC;
191                } else if (!strcmp(key, "diff")) {
192                        err = og_json_parse_string(value, &params->sync_setup.diff);
193                        params->flags |= OG_REST_PARAM_SYNC_DIFF;
194                } else if (!strcmp(key, "remove")) {
195                        err = og_json_parse_string(value, &params->sync_setup.remove);
196                        params->flags |= OG_REST_PARAM_SYNC_REMOVE;
197                } else if (!strcmp(key, "compress")) {
198                        err = og_json_parse_string(value, &params->sync_setup.compress);
199                        params->flags |= OG_REST_PARAM_SYNC_COMPRESS;
200                } else if (!strcmp(key, "cleanup")) {
201                        err = og_json_parse_string(value, &params->sync_setup.cleanup);
202                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP;
203                } else if (!strcmp(key, "cache")) {
204                        err = og_json_parse_string(value, &params->sync_setup.cache);
205                        params->flags |= OG_REST_PARAM_SYNC_CACHE;
206                } else if (!strcmp(key, "cleanup_cache")) {
207                        err = og_json_parse_string(value, &params->sync_setup.cleanup_cache);
208                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP_CACHE;
209                } else if (!strcmp(key, "remove_dst")) {
210                        err = og_json_parse_string(value, &params->sync_setup.remove_dst);
211                        params->flags |= OG_REST_PARAM_SYNC_REMOVE_DST;
212                } else if (!strcmp(key, "diff_id")) {
213                        err = og_json_parse_string(value, &params->sync_setup.diff_id);
214                        params->flags |= OG_REST_PARAM_SYNC_DIFF_ID;
215                } else if (!strcmp(key, "diff_name")) {
216                        err = og_json_parse_string(value, &params->sync_setup.diff_name);
217                        params->flags |= OG_REST_PARAM_SYNC_DIFF_NAME;
218                } else if (!strcmp(key, "path")) {
219                        err = og_json_parse_string(value, &params->sync_setup.path);
220                        params->flags |= OG_REST_PARAM_SYNC_PATH;
221                } else if (!strcmp(key, "method")) {
222                        err = og_json_parse_string(value, &params->sync_setup.method);
223                        params->flags |= OG_REST_PARAM_SYNC_METHOD;
224                }
225
226                if (err != 0)
227                        return err;
228        }
229        return err;
230}
231
232static int og_json_parse_partition_setup(json_t *element,
233                                         struct og_msg_params *params)
234{
235        unsigned int i;
236        json_t *k;
237
238        if (json_typeof(element) != JSON_ARRAY)
239                return -1;
240
241        for (i = 0; i < json_array_size(element) && i < OG_PARTITION_MAX; ++i) {
242                k = json_array_get(element, i);
243
244                if (json_typeof(k) != JSON_OBJECT)
245                        return -1;
246
247                if (og_json_parse_partition(k, &params->partition_setup[i],
248                                            OG_PARAM_PART_NUMBER |
249                                            OG_PARAM_PART_CODE |
250                                            OG_PARAM_PART_FILESYSTEM |
251                                            OG_PARAM_PART_SIZE |
252                                            OG_PARAM_PART_FORMAT) < 0)
253                        return -1;
254
255                params->flags |= (OG_REST_PARAM_PART_0 << i);
256        }
257        return 0;
258}
259
260static int og_json_parse_time_params(json_t *element,
261                                     struct og_msg_params *params)
262{
263        const char *key;
264        json_t *value;
265        int err = 0;
266
267        json_object_foreach(element, key, value) {
268                if (!strcmp(key, "years")) {
269                        err = og_json_parse_uint(value, &params->time.years);
270                        params->flags |= OG_REST_PARAM_TIME_YEARS;
271                } else if (!strcmp(key, "months")) {
272                        err = og_json_parse_uint(value, &params->time.months);
273                        params->flags |= OG_REST_PARAM_TIME_MONTHS;
274                } else if (!strcmp(key, "weeks")) {
275                        err = og_json_parse_uint(value, &params->time.weeks);
276                        params->flags |= OG_REST_PARAM_TIME_WEEKS;
277                } else if (!strcmp(key, "week_days")) {
278                        err = og_json_parse_uint(value, &params->time.week_days);
279                        params->flags |= OG_REST_PARAM_TIME_WEEK_DAYS;
280                } else if (!strcmp(key, "days")) {
281                        err = og_json_parse_uint(value, &params->time.days);
282                        params->flags |= OG_REST_PARAM_TIME_DAYS;
283                } else if (!strcmp(key, "hours")) {
284                        err = og_json_parse_uint(value, &params->time.hours);
285                        params->flags |= OG_REST_PARAM_TIME_HOURS;
286                } else if (!strcmp(key, "am_pm")) {
287                        err = og_json_parse_uint(value, &params->time.am_pm);
288                        params->flags |= OG_REST_PARAM_TIME_AM_PM;
289                } else if (!strcmp(key, "minutes")) {
290                        err = og_json_parse_uint(value, &params->time.minutes);
291                        params->flags |= OG_REST_PARAM_TIME_MINUTES;
292                }
293                if (err != 0)
294                        return err;
295        }
296
297        return err;
298}
299
300static const char *og_cmd_to_uri[OG_CMD_MAX] = {
301        [OG_CMD_WOL]            = "wol",
302        [OG_CMD_PROBE]          = "probe",
303        [OG_CMD_SHELL_RUN]      = "shell/run",
304        [OG_CMD_SESSION]        = "session",
305        [OG_CMD_POWEROFF]       = "poweroff",
306        [OG_CMD_REFRESH]        = "refresh",
307        [OG_CMD_REBOOT]         = "reboot",
308        [OG_CMD_STOP]           = "stop",
309        [OG_CMD_HARDWARE]       = "hardware",
310        [OG_CMD_SOFTWARE]       = "software",
311        [OG_CMD_IMAGE_CREATE]   = "image/create",
312        [OG_CMD_IMAGE_RESTORE]  = "image/restore",
313        [OG_CMD_SETUP]          = "setup",
314        [OG_CMD_RUN_SCHEDULE]   = "run/schedule",
315};
316
317static bool og_client_is_busy(const struct og_client *cli,
318                              enum og_cmd_type type)
319{
320        switch (type) {
321        case OG_CMD_REBOOT:
322        case OG_CMD_POWEROFF:
323        case OG_CMD_STOP:
324                break;
325        default:
326                if (cli->last_cmd != OG_CMD_UNSPEC)
327                        return true;
328                break;
329        }
330
331        return false;
332}
333
334int og_send_request(enum og_rest_method method, enum og_cmd_type type,
335                    const struct og_msg_params *params,
336                    const json_t *data)
337{
338        const char *content_type = "Content-Type: application/json";
339        char content [OG_MSG_REQUEST_MAXLEN - 700] = {};
340        char buf[OG_MSG_REQUEST_MAXLEN] = {};
341        unsigned int content_length;
342        char method_str[5] = {};
343        struct og_client *cli;
344        const char *uri;
345        unsigned int i;
346        int client_sd;
347
348        if (method == OG_METHOD_GET)
349                snprintf(method_str, 5, "GET");
350        else if (method == OG_METHOD_POST)
351                snprintf(method_str, 5, "POST");
352        else
353                return -1;
354
355        if (!data)
356                content_length = 0;
357        else
358                content_length = json_dumpb(data, content,
359                                            OG_MSG_REQUEST_MAXLEN - 700,
360                                            JSON_COMPACT);
361
362        uri = og_cmd_to_uri[type];
363        snprintf(buf, OG_MSG_REQUEST_MAXLEN,
364                 "%s /%s HTTP/1.1\r\nContent-Length: %d\r\n%s\r\n\r\n%s",
365                 method_str, uri, content_length, content_type, content);
366
367        for (i = 0; i < params->ips_array_len; i++) {
368                cli = og_client_find(params->ips_array[i]);
369                if (!cli)
370                        continue;
371
372                if (og_client_is_busy(cli, type))
373                        continue;
374
375                client_sd = cli->io.fd;
376                if (client_sd < 0) {
377                        syslog(LOG_INFO, "Client %s not conected\n",
378                               params->ips_array[i]);
379                        continue;
380                }
381
382                if (send(client_sd, buf, strlen(buf), 0) < 0)
383                        continue;
384
385                cli->last_cmd = type;
386        }
387
388        return 0;
389}
390
391static int og_cmd_post_clients(json_t *element, struct og_msg_params *params)
392{
393        const char *key;
394        json_t *value;
395        int err = 0;
396
397        if (json_typeof(element) != JSON_OBJECT)
398                return -1;
399
400        json_object_foreach(element, key, value) {
401                if (!strcmp(key, "clients"))
402                        err = og_json_parse_clients(value, params);
403
404                if (err < 0)
405                        break;
406        }
407
408        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
409                return -1;
410
411        return og_send_request(OG_METHOD_POST, OG_CMD_PROBE, params, NULL);
412}
413
414struct og_buffer {
415        char    *data;
416        int     len;
417};
418
419static int og_json_dump_clients(const char *buffer, size_t size, void *data)
420{
421        struct og_buffer *og_buffer = (struct og_buffer *)data;
422
423        memcpy(og_buffer->data + og_buffer->len, buffer, size);
424        og_buffer->len += size;
425
426        return 0;
427}
428
429static int og_cmd_get_clients(json_t *element, struct og_msg_params *params,
430                              char *buffer_reply)
431{
432        json_t *root, *array, *addr, *state, *object;
433        struct og_client *client;
434        struct og_buffer og_buffer = {
435                .data   = buffer_reply,
436        };
437
438        array = json_array();
439        if (!array)
440                return -1;
441
442        list_for_each_entry(client, &client_list, list) {
443                if (!client->agent)
444                        continue;
445
446                object = json_object();
447                if (!object) {
448                        json_decref(array);
449                        return -1;
450                }
451                addr = json_string(inet_ntoa(client->addr.sin_addr));
452                if (!addr) {
453                        json_decref(object);
454                        json_decref(array);
455                        return -1;
456                }
457                json_object_set_new(object, "addr", addr);
458                state = json_string(og_client_status(client));
459                if (!state) {
460                        json_decref(object);
461                        json_decref(array);
462                        return -1;
463                }
464                json_object_set_new(object, "state", state);
465                json_array_append_new(array, object);
466        }
467        root = json_pack("{s:o}", "clients", array);
468        if (!root) {
469                json_decref(array);
470                return -1;
471        }
472
473        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
474        json_decref(root);
475
476        return 0;
477}
478
479static int og_json_parse_target(json_t *element, struct og_msg_params *params)
480{
481        const char *key;
482        json_t *value;
483
484        if (json_typeof(element) != JSON_OBJECT) {
485                return -1;
486        }
487
488        json_object_foreach(element, key, value) {
489                if (!strcmp(key, "addr")) {
490                        if (json_typeof(value) != JSON_STRING)
491                                return -1;
492
493                        params->ips_array[params->ips_array_len] =
494                                json_string_value(value);
495
496                        params->flags |= OG_REST_PARAM_ADDR;
497                } else if (!strcmp(key, "mac")) {
498                        if (json_typeof(value) != JSON_STRING)
499                                return -1;
500
501                        params->mac_array[params->ips_array_len] =
502                                json_string_value(value);
503
504                        params->flags |= OG_REST_PARAM_MAC;
505                }
506        }
507
508        return 0;
509}
510
511static int og_json_parse_targets(json_t *element, struct og_msg_params *params)
512{
513        unsigned int i;
514        json_t *k;
515        int err;
516
517        if (json_typeof(element) != JSON_ARRAY)
518                return -1;
519
520        for (i = 0; i < json_array_size(element); i++) {
521                k = json_array_get(element, i);
522
523                if (json_typeof(k) != JSON_OBJECT)
524                        return -1;
525
526                err = og_json_parse_target(k, params);
527                if (err < 0)
528                        return err;
529
530                params->ips_array_len++;
531        }
532        return 0;
533}
534
535static int og_json_parse_type(json_t *element, struct og_msg_params *params)
536{
537        const char *type;
538
539        if (json_typeof(element) != JSON_STRING)
540                return -1;
541
542        params->wol_type = json_string_value(element);
543
544        type = json_string_value(element);
545        if (!strcmp(type, "unicast"))
546                params->wol_type = "2";
547        else if (!strcmp(type, "broadcast"))
548                params->wol_type = "1";
549
550        params->flags |= OG_REST_PARAM_WOL_TYPE;
551
552        return 0;
553}
554
555static int og_cmd_wol(json_t *element, struct og_msg_params *params)
556{
557        const char *key;
558        json_t *value;
559        int err = 0;
560
561        if (json_typeof(element) != JSON_OBJECT)
562                return -1;
563
564        json_object_foreach(element, key, value) {
565                if (!strcmp(key, "clients")) {
566                        err = og_json_parse_targets(value, params);
567                } else if (!strcmp(key, "type")) {
568                        err = og_json_parse_type(value, params);
569                }
570
571                if (err < 0)
572                        break;
573        }
574
575        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
576                                            OG_REST_PARAM_MAC |
577                                            OG_REST_PARAM_WOL_TYPE))
578                return -1;
579
580        if (!Levanta((char **)params->ips_array, (char **)params->mac_array,
581                     params->ips_array_len, (char *)params->wol_type))
582                return -1;
583
584        return 0;
585}
586
587static int og_json_parse_run(json_t *element, struct og_msg_params *params)
588{
589        if (json_typeof(element) != JSON_STRING)
590                return -1;
591
592        snprintf(params->run_cmd, sizeof(params->run_cmd), "%s",
593                 json_string_value(element));
594
595        params->flags |= OG_REST_PARAM_RUN_CMD;
596
597        return 0;
598}
599
600static int og_cmd_run_post(json_t *element, struct og_msg_params *params)
601{
602        json_t *value, *clients;
603        const char *key;
604        unsigned int i;
605        int err = 0;
606
607        if (json_typeof(element) != JSON_OBJECT)
608                return -1;
609
610        json_object_foreach(element, key, value) {
611                if (!strcmp(key, "clients"))
612                        err = og_json_parse_clients(value, params);
613                else if (!strcmp(key, "run"))
614                        err = og_json_parse_run(value, params);
615                else if (!strcmp(key, "echo")) {
616                        err = og_json_parse_bool(value, &params->echo);
617                        params->flags |= OG_REST_PARAM_ECHO;
618                }
619
620                if (err < 0)
621                        break;
622        }
623
624        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
625                                            OG_REST_PARAM_RUN_CMD |
626                                            OG_REST_PARAM_ECHO))
627                return -1;
628
629        clients = json_copy(element);
630        json_object_del(clients, "clients");
631
632        err = og_send_request(OG_METHOD_POST, OG_CMD_SHELL_RUN, params, clients);
633        if (err < 0)
634                return err;
635
636        for (i = 0; i < params->ips_array_len; i++) {
637                char filename[4096];
638                FILE *f;
639
640                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
641                f = fopen(filename, "wt");
642                fclose(f);
643        }
644
645        return 0;
646}
647
648static int og_cmd_run_get(json_t *element, struct og_msg_params *params,
649                          char *buffer_reply)
650{
651        struct og_buffer og_buffer = {
652                .data   = buffer_reply,
653        };
654        json_t *root, *value, *array;
655        const char *key;
656        unsigned int i;
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
666                if (err < 0)
667                        return err;
668        }
669
670        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
671                return -1;
672
673        array = json_array();
674        if (!array)
675                return -1;
676
677        for (i = 0; i < params->ips_array_len; i++) {
678                json_t *object, *output, *addr;
679                char data[4096] = {};
680                char filename[4096];
681                int fd, numbytes;
682
683                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
684
685                fd = open(filename, O_RDONLY);
686                if (!fd)
687                        return -1;
688
689                numbytes = read(fd, data, sizeof(data));
690                if (numbytes < 0) {
691                        close(fd);
692                        return -1;
693                }
694                data[sizeof(data) - 1] = '\0';
695                close(fd);
696
697                object = json_object();
698                if (!object) {
699                        json_decref(array);
700                        return -1;
701                }
702                addr = json_string(params->ips_array[i]);
703                if (!addr) {
704                        json_decref(object);
705                        json_decref(array);
706                        return -1;
707                }
708                json_object_set_new(object, "addr", addr);
709
710                output = json_string(data);
711                if (!output) {
712                        json_decref(object);
713                        json_decref(array);
714                        return -1;
715                }
716                json_object_set_new(object, "output", output);
717
718                json_array_append_new(array, object);
719        }
720
721        root = json_pack("{s:o}", "clients", array);
722        if (!root)
723                return -1;
724
725        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
726        json_decref(root);
727
728        return 0;
729}
730
731static int og_cmd_session(json_t *element, struct og_msg_params *params)
732{
733        json_t *clients, *value;
734        const char *key;
735        int err = 0;
736
737        if (json_typeof(element) != JSON_OBJECT)
738                return -1;
739
740        json_object_foreach(element, key, value) {
741                if (!strcmp(key, "clients")) {
742                        err = og_json_parse_clients(value, params);
743                } else if (!strcmp(key, "disk")) {
744                        err = og_json_parse_string(value, &params->disk);
745                        params->flags |= OG_REST_PARAM_DISK;
746                } else if (!strcmp(key, "partition")) {
747                        err = og_json_parse_string(value, &params->partition);
748                        params->flags |= OG_REST_PARAM_PARTITION;
749                }
750
751                if (err < 0)
752                        return err;
753        }
754
755        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
756                                            OG_REST_PARAM_DISK |
757                                            OG_REST_PARAM_PARTITION))
758                return -1;
759
760        clients = json_copy(element);
761        json_object_del(clients, "clients");
762
763        return og_send_request(OG_METHOD_POST, OG_CMD_SESSION, params, clients);
764}
765
766static int og_cmd_poweroff(json_t *element, struct og_msg_params *params)
767{
768        const char *key;
769        json_t *value;
770        int err = 0;
771
772        if (json_typeof(element) != JSON_OBJECT)
773                return -1;
774
775        json_object_foreach(element, key, value) {
776                if (!strcmp(key, "clients"))
777                        err = og_json_parse_clients(value, params);
778
779                if (err < 0)
780                        break;
781        }
782
783        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
784                return -1;
785
786        return og_send_request(OG_METHOD_POST, OG_CMD_POWEROFF, params, NULL);
787}
788
789static int og_cmd_refresh(json_t *element, struct og_msg_params *params)
790{
791        const char *key;
792        json_t *value;
793        int err = 0;
794
795        if (json_typeof(element) != JSON_OBJECT)
796                return -1;
797
798        json_object_foreach(element, key, value) {
799                if (!strcmp(key, "clients"))
800                        err = og_json_parse_clients(value, params);
801
802                if (err < 0)
803                        break;
804        }
805
806        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
807                return -1;
808
809        return og_send_request(OG_METHOD_GET, OG_CMD_REFRESH, params, NULL);
810}
811
812static int og_cmd_reboot(json_t *element, struct og_msg_params *params)
813{
814        const char *key;
815        json_t *value;
816        int err = 0;
817
818        if (json_typeof(element) != JSON_OBJECT)
819                return -1;
820
821        json_object_foreach(element, key, value) {
822                if (!strcmp(key, "clients"))
823                        err = og_json_parse_clients(value, params);
824
825                if (err < 0)
826                        break;
827        }
828
829        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
830                return -1;
831
832        return og_send_request(OG_METHOD_POST, OG_CMD_REBOOT, params, NULL);
833}
834
835static int og_cmd_stop(json_t *element, struct og_msg_params *params)
836{
837        const char *key;
838        json_t *value;
839        int err = 0;
840
841        if (json_typeof(element) != JSON_OBJECT)
842                return -1;
843
844        json_object_foreach(element, key, value) {
845                if (!strcmp(key, "clients"))
846                        err = og_json_parse_clients(value, params);
847
848                if (err < 0)
849                        break;
850        }
851
852        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
853                return -1;
854
855        return og_send_request(OG_METHOD_POST, OG_CMD_STOP, params, NULL);
856}
857
858static int og_cmd_hardware(json_t *element, struct og_msg_params *params)
859{
860        const char *key;
861        json_t *value;
862        int err = 0;
863
864        if (json_typeof(element) != JSON_OBJECT)
865                return -1;
866
867        json_object_foreach(element, key, value) {
868                if (!strcmp(key, "clients"))
869                        err = og_json_parse_clients(value, params);
870
871                if (err < 0)
872                        break;
873        }
874
875        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
876                return -1;
877
878        return og_send_request(OG_METHOD_GET, OG_CMD_HARDWARE, params, NULL);
879}
880
881static int og_cmd_software(json_t *element, struct og_msg_params *params)
882{
883        json_t *clients, *value;
884        const char *key;
885        int err = 0;
886
887        if (json_typeof(element) != JSON_OBJECT)
888                return -1;
889
890        json_object_foreach(element, key, value) {
891                if (!strcmp(key, "clients"))
892                        err = og_json_parse_clients(value, params);
893                else if (!strcmp(key, "disk")) {
894                        err = og_json_parse_string(value, &params->disk);
895                        params->flags |= OG_REST_PARAM_DISK;
896                }
897                else if (!strcmp(key, "partition")) {
898                        err = og_json_parse_string(value, &params->partition);
899                        params->flags |= OG_REST_PARAM_PARTITION;
900                }
901
902                if (err < 0)
903                        break;
904        }
905
906        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
907                                            OG_REST_PARAM_DISK |
908                                            OG_REST_PARAM_PARTITION))
909                return -1;
910
911        clients = json_copy(element);
912        json_object_del(clients, "clients");
913
914        return og_send_request(OG_METHOD_POST, OG_CMD_SOFTWARE, params, clients);
915}
916
917static int og_cmd_create_image(json_t *element, struct og_msg_params *params)
918{
919        json_t *value, *clients;
920        const char *key;
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, "disk")) {
928                        err = og_json_parse_string(value, &params->disk);
929                        params->flags |= OG_REST_PARAM_DISK;
930                } else if (!strcmp(key, "partition")) {
931                        err = og_json_parse_string(value, &params->partition);
932                        params->flags |= OG_REST_PARAM_PARTITION;
933                } else if (!strcmp(key, "name")) {
934                        err = og_json_parse_string(value, &params->name);
935                        params->flags |= OG_REST_PARAM_NAME;
936                } else if (!strcmp(key, "repository")) {
937                        err = og_json_parse_string(value, &params->repository);
938                        params->flags |= OG_REST_PARAM_REPO;
939                } else if (!strcmp(key, "clients")) {
940                        err = og_json_parse_clients(value, params);
941                } else if (!strcmp(key, "id")) {
942                        err = og_json_parse_string(value, &params->id);
943                        params->flags |= OG_REST_PARAM_ID;
944                } else if (!strcmp(key, "code")) {
945                        err = og_json_parse_string(value, &params->code);
946                        params->flags |= OG_REST_PARAM_CODE;
947                }
948
949                if (err < 0)
950                        break;
951        }
952
953        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
954                                            OG_REST_PARAM_DISK |
955                                            OG_REST_PARAM_PARTITION |
956                                            OG_REST_PARAM_CODE |
957                                            OG_REST_PARAM_ID |
958                                            OG_REST_PARAM_NAME |
959                                            OG_REST_PARAM_REPO))
960                return -1;
961
962        clients = json_copy(element);
963        json_object_del(clients, "clients");
964
965        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_CREATE, params,
966                               clients);
967}
968
969static int og_cmd_restore_image(json_t *element, struct og_msg_params *params)
970{
971        json_t *clients, *value;
972        const char *key;
973        int err = 0;
974
975        if (json_typeof(element) != JSON_OBJECT)
976                return -1;
977
978        json_object_foreach(element, key, value) {
979                if (!strcmp(key, "disk")) {
980                        err = og_json_parse_string(value, &params->disk);
981                        params->flags |= OG_REST_PARAM_DISK;
982                } else if (!strcmp(key, "partition")) {
983                        err = og_json_parse_string(value, &params->partition);
984                        params->flags |= OG_REST_PARAM_PARTITION;
985                } else if (!strcmp(key, "name")) {
986                        err = og_json_parse_string(value, &params->name);
987                        params->flags |= OG_REST_PARAM_NAME;
988                } else if (!strcmp(key, "repository")) {
989                        err = og_json_parse_string(value, &params->repository);
990                        params->flags |= OG_REST_PARAM_REPO;
991                } else if (!strcmp(key, "clients")) {
992                        err = og_json_parse_clients(value, params);
993                } else if (!strcmp(key, "type")) {
994                        err = og_json_parse_string(value, &params->type);
995                        params->flags |= OG_REST_PARAM_TYPE;
996                } else if (!strcmp(key, "profile")) {
997                        err = og_json_parse_string(value, &params->profile);
998                        params->flags |= OG_REST_PARAM_PROFILE;
999                } else if (!strcmp(key, "id")) {
1000                        err = og_json_parse_string(value, &params->id);
1001                        params->flags |= OG_REST_PARAM_ID;
1002                }
1003
1004                if (err < 0)
1005                        break;
1006        }
1007
1008        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1009                                            OG_REST_PARAM_DISK |
1010                                            OG_REST_PARAM_PARTITION |
1011                                            OG_REST_PARAM_NAME |
1012                                            OG_REST_PARAM_REPO |
1013                                            OG_REST_PARAM_TYPE |
1014                                            OG_REST_PARAM_PROFILE |
1015                                            OG_REST_PARAM_ID))
1016                return -1;
1017
1018        clients = json_copy(element);
1019        json_object_del(clients, "clients");
1020
1021        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, params,
1022                               clients);
1023}
1024
1025static int og_cmd_setup(json_t *element, struct og_msg_params *params)
1026{
1027        json_t *value, *clients;
1028        const char *key;
1029        int err = 0;
1030
1031        if (json_typeof(element) != JSON_OBJECT)
1032                return -1;
1033
1034        json_object_foreach(element, key, value) {
1035                if (!strcmp(key, "clients")) {
1036                        err = og_json_parse_clients(value, params);
1037                } else if (!strcmp(key, "disk")) {
1038                        err = og_json_parse_string(value, &params->disk);
1039                        params->flags |= OG_REST_PARAM_DISK;
1040                } else if (!strcmp(key, "cache")) {
1041                        err = og_json_parse_string(value, &params->cache);
1042                        params->flags |= OG_REST_PARAM_CACHE;
1043                } else if (!strcmp(key, "cache_size")) {
1044                        err = og_json_parse_string(value, &params->cache_size);
1045                        params->flags |= OG_REST_PARAM_CACHE_SIZE;
1046                } else if (!strcmp(key, "partition_setup")) {
1047                        err = og_json_parse_partition_setup(value, params);
1048                }
1049
1050                if (err < 0)
1051                        break;
1052        }
1053
1054        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1055                                            OG_REST_PARAM_DISK |
1056                                            OG_REST_PARAM_CACHE |
1057                                            OG_REST_PARAM_CACHE_SIZE |
1058                                            OG_REST_PARAM_PART_0 |
1059                                            OG_REST_PARAM_PART_1 |
1060                                            OG_REST_PARAM_PART_2 |
1061                                            OG_REST_PARAM_PART_3))
1062                return -1;
1063
1064        clients = json_copy(element);
1065        json_object_del(clients, "clients");
1066
1067        return og_send_request(OG_METHOD_POST, OG_CMD_SETUP, params, clients);
1068}
1069
1070static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params)
1071{
1072        const char *key;
1073        json_t *value;
1074        int err = 0;
1075
1076        json_object_foreach(element, key, value) {
1077                if (!strcmp(key, "clients"))
1078                        err = og_json_parse_clients(value, params);
1079
1080                if (err < 0)
1081                        break;
1082        }
1083
1084        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1085                return -1;
1086
1087        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
1088                               NULL);
1089}
1090
1091static int og_cmd_create_basic_image(json_t *element, struct og_msg_params *params)
1092{
1093        char buf[4096] = {};
1094        int err = 0, len;
1095        const char *key;
1096        json_t *value;
1097        TRAMA *msg;
1098
1099        if (json_typeof(element) != JSON_OBJECT)
1100                return -1;
1101
1102        json_object_foreach(element, key, value) {
1103                if (!strcmp(key, "clients")) {
1104                        err = og_json_parse_clients(value, params);
1105                } else if (!strcmp(key, "disk")) {
1106                        err = og_json_parse_string(value, &params->disk);
1107                        params->flags |= OG_REST_PARAM_DISK;
1108                } else if (!strcmp(key, "partition")) {
1109                        err = og_json_parse_string(value, &params->partition);
1110                        params->flags |= OG_REST_PARAM_PARTITION;
1111                } else if (!strcmp(key, "code")) {
1112                        err = og_json_parse_string(value, &params->code);
1113                        params->flags |= OG_REST_PARAM_CODE;
1114                } else if (!strcmp(key, "id")) {
1115                        err = og_json_parse_string(value, &params->id);
1116                        params->flags |= OG_REST_PARAM_ID;
1117                } else if (!strcmp(key, "name")) {
1118                        err = og_json_parse_string(value, &params->name);
1119                        params->flags |= OG_REST_PARAM_NAME;
1120                } else if (!strcmp(key, "repository")) {
1121                        err = og_json_parse_string(value, &params->repository);
1122                        params->flags |= OG_REST_PARAM_REPO;
1123                } else if (!strcmp(key, "sync_params")) {
1124                        err = og_json_parse_sync_params(value, params);
1125                }
1126
1127                if (err < 0)
1128                        break;
1129        }
1130
1131        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1132                                            OG_REST_PARAM_DISK |
1133                                            OG_REST_PARAM_PARTITION |
1134                                            OG_REST_PARAM_CODE |
1135                                            OG_REST_PARAM_ID |
1136                                            OG_REST_PARAM_NAME |
1137                                            OG_REST_PARAM_REPO |
1138                                            OG_REST_PARAM_SYNC_SYNC |
1139                                            OG_REST_PARAM_SYNC_DIFF |
1140                                            OG_REST_PARAM_SYNC_REMOVE |
1141                                            OG_REST_PARAM_SYNC_COMPRESS |
1142                                            OG_REST_PARAM_SYNC_CLEANUP |
1143                                            OG_REST_PARAM_SYNC_CACHE |
1144                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
1145                                            OG_REST_PARAM_SYNC_REMOVE_DST))
1146                return -1;
1147
1148        len = snprintf(buf, sizeof(buf),
1149                       "nfn=CrearImagenBasica\rdsk=%s\rpar=%s\rcpt=%s\ridi=%s\r"
1150                       "nci=%s\ripr=%s\rrti=\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\r"
1151                       "cpc=%s\rbpc=%s\rnba=%s\r",
1152                       params->disk, params->partition, params->code, params->id,
1153                       params->name, params->repository, params->sync_setup.sync,
1154                       params->sync_setup.diff, params->sync_setup.remove,
1155                       params->sync_setup.compress, params->sync_setup.cleanup,
1156                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
1157                       params->sync_setup.remove_dst);
1158
1159        msg = og_msg_alloc(buf, len);
1160        if (!msg)
1161                return -1;
1162
1163        og_send_cmd((char **)params->ips_array, params->ips_array_len,
1164                    CLIENTE_OCUPADO, msg);
1165
1166        og_msg_free(msg);
1167
1168        return 0;
1169}
1170
1171static int og_cmd_create_incremental_image(json_t *element, struct og_msg_params *params)
1172{
1173        char buf[4096] = {};
1174        int err = 0, len;
1175        const char *key;
1176        json_t *value;
1177        TRAMA *msg;
1178
1179        if (json_typeof(element) != JSON_OBJECT)
1180                return -1;
1181
1182        json_object_foreach(element, key, value) {
1183                if (!strcmp(key, "clients"))
1184                        err = og_json_parse_clients(value, params);
1185                else if (!strcmp(key, "disk")) {
1186                        err = og_json_parse_string(value, &params->disk);
1187                        params->flags |= OG_REST_PARAM_DISK;
1188                } else if (!strcmp(key, "partition")) {
1189                        err = og_json_parse_string(value, &params->partition);
1190                        params->flags |= OG_REST_PARAM_PARTITION;
1191                } else if (!strcmp(key, "id")) {
1192                        err = og_json_parse_string(value, &params->id);
1193                        params->flags |= OG_REST_PARAM_ID;
1194                } else if (!strcmp(key, "name")) {
1195                        err = og_json_parse_string(value, &params->name);
1196                        params->flags |= OG_REST_PARAM_NAME;
1197                } else if (!strcmp(key, "repository")) {
1198                        err = og_json_parse_string(value, &params->repository);
1199                        params->flags |= OG_REST_PARAM_REPO;
1200                } else if (!strcmp(key, "sync_params")) {
1201                        err = og_json_parse_sync_params(value, params);
1202                }
1203
1204                if (err < 0)
1205                        break;
1206        }
1207
1208        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1209                                            OG_REST_PARAM_DISK |
1210                                            OG_REST_PARAM_PARTITION |
1211                                            OG_REST_PARAM_ID |
1212                                            OG_REST_PARAM_NAME |
1213                                            OG_REST_PARAM_REPO |
1214                                            OG_REST_PARAM_SYNC_SYNC |
1215                                            OG_REST_PARAM_SYNC_PATH |
1216                                            OG_REST_PARAM_SYNC_DIFF |
1217                                            OG_REST_PARAM_SYNC_DIFF_ID |
1218                                            OG_REST_PARAM_SYNC_DIFF_NAME |
1219                                            OG_REST_PARAM_SYNC_REMOVE |
1220                                            OG_REST_PARAM_SYNC_COMPRESS |
1221                                            OG_REST_PARAM_SYNC_CLEANUP |
1222                                            OG_REST_PARAM_SYNC_CACHE |
1223                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
1224                                            OG_REST_PARAM_SYNC_REMOVE_DST))
1225                return -1;
1226
1227        len = snprintf(buf, sizeof(buf),
1228                       "nfn=CrearSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
1229                       "rti=%s\ripr=%s\ridf=%s\rncf=%s\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\r"
1230                       "bpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
1231                       params->disk, params->partition, params->id, params->name,
1232                       params->sync_setup.path, params->repository, params->sync_setup.diff_id,
1233                       params->sync_setup.diff_name, params->sync_setup.sync,
1234                       params->sync_setup.diff, params->sync_setup.remove_dst,
1235                       params->sync_setup.compress, params->sync_setup.cleanup,
1236                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
1237                       params->sync_setup.remove_dst);
1238
1239        msg = og_msg_alloc(buf, len);
1240        if (!msg)
1241                return -1;
1242
1243        og_send_cmd((char **)params->ips_array, params->ips_array_len,
1244                    CLIENTE_OCUPADO, msg);
1245
1246        og_msg_free(msg);
1247
1248        return 0;
1249}
1250
1251static int og_cmd_restore_basic_image(json_t *element, struct og_msg_params *params)
1252{
1253        char buf[4096] = {};
1254        int err = 0, len;
1255        const char *key;
1256        json_t *value;
1257        TRAMA *msg;
1258
1259        if (json_typeof(element) != JSON_OBJECT)
1260                return -1;
1261
1262        json_object_foreach(element, key, value) {
1263                if (!strcmp(key, "clients")) {
1264                        err = og_json_parse_clients(value, params);
1265                } else if (!strcmp(key, "disk")) {
1266                        err = og_json_parse_string(value, &params->disk);
1267                        params->flags |= OG_REST_PARAM_DISK;
1268                } else if (!strcmp(key, "partition")) {
1269                        err = og_json_parse_string(value, &params->partition);
1270                        params->flags |= OG_REST_PARAM_PARTITION;
1271                } else if (!strcmp(key, "id")) {
1272                        err = og_json_parse_string(value, &params->id);
1273                        params->flags |= OG_REST_PARAM_ID;
1274                } else if (!strcmp(key, "name")) {
1275                        err = og_json_parse_string(value, &params->name);
1276                        params->flags |= OG_REST_PARAM_NAME;
1277                } else if (!strcmp(key, "repository")) {
1278                        err = og_json_parse_string(value, &params->repository);
1279                        params->flags |= OG_REST_PARAM_REPO;
1280                } else if (!strcmp(key, "profile")) {
1281                        err = og_json_parse_string(value, &params->profile);
1282                        params->flags |= OG_REST_PARAM_PROFILE;
1283                } else if (!strcmp(key, "type")) {
1284                        err = og_json_parse_string(value, &params->type);
1285                        params->flags |= OG_REST_PARAM_TYPE;
1286                } else if (!strcmp(key, "sync_params")) {
1287                        err = og_json_parse_sync_params(value, params);
1288                }
1289
1290                if (err < 0)
1291                        break;
1292        }
1293
1294        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1295                                            OG_REST_PARAM_DISK |
1296                                            OG_REST_PARAM_PARTITION |
1297                                            OG_REST_PARAM_ID |
1298                                            OG_REST_PARAM_NAME |
1299                                            OG_REST_PARAM_REPO |
1300                                            OG_REST_PARAM_PROFILE |
1301                                            OG_REST_PARAM_TYPE |
1302                                            OG_REST_PARAM_SYNC_PATH |
1303                                            OG_REST_PARAM_SYNC_METHOD |
1304                                            OG_REST_PARAM_SYNC_SYNC |
1305                                            OG_REST_PARAM_SYNC_DIFF |
1306                                            OG_REST_PARAM_SYNC_REMOVE |
1307                                            OG_REST_PARAM_SYNC_COMPRESS |
1308                                            OG_REST_PARAM_SYNC_CLEANUP |
1309                                            OG_REST_PARAM_SYNC_CACHE |
1310                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
1311                                            OG_REST_PARAM_SYNC_REMOVE_DST))
1312                return -1;
1313
1314        len = snprintf(buf, sizeof(buf),
1315                       "nfn=RestaurarImagenBasica\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
1316                           "ipr=%s\rifs=%s\rrti=%s\rmet=%s\rmsy=%s\rtpt=%s\rwhl=%s\r"
1317                           "eli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
1318                       params->disk, params->partition, params->id, params->name,
1319                           params->repository, params->profile, params->sync_setup.path,
1320                           params->sync_setup.method, params->sync_setup.sync, params->type,
1321                           params->sync_setup.diff, params->sync_setup.remove,
1322                       params->sync_setup.compress, params->sync_setup.cleanup,
1323                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
1324                       params->sync_setup.remove_dst);
1325
1326        msg = og_msg_alloc(buf, len);
1327        if (!msg)
1328                return -1;
1329
1330        og_send_cmd((char **)params->ips_array, params->ips_array_len,
1331                    CLIENTE_OCUPADO, msg);
1332
1333        og_msg_free(msg);
1334
1335        return 0;
1336}
1337
1338static int og_cmd_restore_incremental_image(json_t *element, struct og_msg_params *params)
1339{
1340        char buf[4096] = {};
1341        int err = 0, len;
1342        const char *key;
1343        json_t *value;
1344        TRAMA *msg;
1345
1346        if (json_typeof(element) != JSON_OBJECT)
1347                return -1;
1348
1349        json_object_foreach(element, key, value) {
1350                if (!strcmp(key, "clients")) {
1351                        err = og_json_parse_clients(value, params);
1352                } else if (!strcmp(key, "disk")) {
1353                        err = og_json_parse_string(value, &params->disk);
1354                        params->flags |= OG_REST_PARAM_DISK;
1355                } else if (!strcmp(key, "partition")) {
1356                        err = og_json_parse_string(value, &params->partition);
1357                        params->flags |= OG_REST_PARAM_PARTITION;
1358                } else if (!strcmp(key, "id")) {
1359                        err = og_json_parse_string(value, &params->id);
1360                        params->flags |= OG_REST_PARAM_ID;
1361                } else if (!strcmp(key, "name")) {
1362                        err = og_json_parse_string(value, &params->name);
1363                        params->flags |= OG_REST_PARAM_NAME;
1364                } else if (!strcmp(key, "repository")) {
1365                        err = og_json_parse_string(value, &params->repository);
1366                        params->flags |= OG_REST_PARAM_REPO;
1367                } else if (!strcmp(key, "profile")) {
1368                        err = og_json_parse_string(value, &params->profile);
1369                        params->flags |= OG_REST_PARAM_PROFILE;
1370                } else if (!strcmp(key, "type")) {
1371                        err = og_json_parse_string(value, &params->type);
1372                        params->flags |= OG_REST_PARAM_TYPE;
1373                } else if (!strcmp(key, "sync_params")) {
1374                        err = og_json_parse_sync_params(value, params);
1375                }
1376
1377                if (err < 0)
1378                        break;
1379        }
1380
1381        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1382                                            OG_REST_PARAM_DISK |
1383                                            OG_REST_PARAM_PARTITION |
1384                                            OG_REST_PARAM_ID |
1385                                            OG_REST_PARAM_NAME |
1386                                            OG_REST_PARAM_REPO |
1387                                            OG_REST_PARAM_PROFILE |
1388                                            OG_REST_PARAM_TYPE |
1389                                            OG_REST_PARAM_SYNC_DIFF_ID |
1390                                            OG_REST_PARAM_SYNC_DIFF_NAME |
1391                                            OG_REST_PARAM_SYNC_PATH |
1392                                            OG_REST_PARAM_SYNC_METHOD |
1393                                            OG_REST_PARAM_SYNC_SYNC |
1394                                            OG_REST_PARAM_SYNC_DIFF |
1395                                            OG_REST_PARAM_SYNC_REMOVE |
1396                                            OG_REST_PARAM_SYNC_COMPRESS |
1397                                            OG_REST_PARAM_SYNC_CLEANUP |
1398                                            OG_REST_PARAM_SYNC_CACHE |
1399                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
1400                                            OG_REST_PARAM_SYNC_REMOVE_DST))
1401                return -1;
1402
1403        len = snprintf(buf, sizeof(buf),
1404                       "nfn=RestaurarSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
1405                           "ipr=%s\rifs=%s\ridf=%s\rncf=%s\rrti=%s\rmet=%s\rmsy=%s\r"
1406                           "tpt=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\r"
1407                           "nba=%s\r",
1408                       params->disk, params->partition, params->id, params->name,
1409                           params->repository, params->profile, params->sync_setup.diff_id,
1410                           params->sync_setup.diff_name, params->sync_setup.path,
1411                           params->sync_setup.method, params->sync_setup.sync, params->type,
1412                           params->sync_setup.diff, params->sync_setup.remove,
1413                       params->sync_setup.compress, params->sync_setup.cleanup,
1414                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
1415                       params->sync_setup.remove_dst);
1416
1417        msg = og_msg_alloc(buf, len);
1418        if (!msg)
1419                return -1;
1420
1421        og_send_cmd((char **)params->ips_array, params->ips_array_len,
1422                    CLIENTE_OCUPADO, msg);
1423
1424        og_msg_free(msg);
1425
1426        return 0;
1427}
1428
1429static LIST_HEAD(cmd_list);
1430
1431const struct og_cmd *og_cmd_find(const char *client_ip)
1432{
1433        struct og_cmd *cmd, *next;
1434
1435        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
1436                if (strcmp(cmd->ip, client_ip))
1437                        continue;
1438
1439                list_del(&cmd->list);
1440                return cmd;
1441        }
1442
1443        return NULL;
1444}
1445
1446void og_cmd_free(const struct og_cmd *cmd)
1447{
1448        struct og_msg_params *params = (struct og_msg_params *)&cmd->params;
1449        int i;
1450
1451        for (i = 0; i < params->ips_array_len; i++) {
1452                free((void *)params->ips_array[i]);
1453                free((void *)params->mac_array[i]);
1454        }
1455        free((void *)params->wol_type);
1456
1457        if (cmd->json)
1458                json_decref(cmd->json);
1459
1460        free((void *)cmd->ip);
1461        free((void *)cmd->mac);
1462        free((void *)cmd);
1463}
1464
1465static void og_cmd_init(struct og_cmd *cmd, enum og_rest_method method,
1466                        enum og_cmd_type type, json_t *root)
1467{
1468        cmd->type = type;
1469        cmd->method = method;
1470        cmd->params.ips_array[0] = strdup(cmd->ip);
1471        cmd->params.ips_array_len = 1;
1472        cmd->json = root;
1473}
1474
1475static int og_cmd_legacy_wol(const char *input, struct og_cmd *cmd)
1476{
1477        char wol_type[2] = {};
1478
1479        if (sscanf(input, "mar=%s", wol_type) != 1) {
1480                syslog(LOG_ERR, "malformed database legacy input\n");
1481                return -1;
1482        }
1483
1484        og_cmd_init(cmd, OG_METHOD_NO_HTTP, OG_CMD_WOL, NULL);
1485        cmd->params.mac_array[0] = strdup(cmd->mac);
1486        cmd->params.wol_type = strdup(wol_type);
1487
1488        return 0;
1489}
1490
1491static int og_cmd_legacy_shell_run(const char *input, struct og_cmd *cmd)
1492{
1493        json_t *root, *script, *echo;
1494
1495        script = json_string(input + 4);
1496        echo = json_boolean(false);
1497
1498        root = json_object();
1499        if (!root)
1500                return -1;
1501        json_object_set_new(root, "run", script);
1502        json_object_set_new(root, "echo", echo);
1503
1504        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SHELL_RUN, root);
1505
1506        return 0;
1507}
1508
1509static int og_cmd_legacy_session(const char *input, struct og_cmd *cmd)
1510{
1511        char part_str[OG_DB_SMALLINT_MAXLEN + 1];
1512        char disk_str[OG_DB_SMALLINT_MAXLEN + 1];
1513        json_t *root, *disk, *partition;
1514
1515        if (sscanf(input, "dsk=%s\rpar=%s\r", disk_str, part_str) != 2)
1516                return -1;
1517        partition = json_string(part_str);
1518        disk = json_string(disk_str);
1519
1520        root = json_object();
1521        if (!root)
1522                return -1;
1523        json_object_set_new(root, "partition", partition);
1524        json_object_set_new(root, "disk", disk);
1525
1526        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SESSION, root);
1527
1528        return 0;
1529}
1530
1531static int og_cmd_legacy_poweroff(const char *input, struct og_cmd *cmd)
1532{
1533        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_POWEROFF, NULL);
1534
1535        return 0;
1536}
1537
1538static int og_cmd_legacy_refresh(const char *input, struct og_cmd *cmd)
1539{
1540        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_REFRESH, NULL);
1541
1542        return 0;
1543}
1544
1545static int og_cmd_legacy_reboot(const char *input, struct og_cmd *cmd)
1546{
1547        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_REBOOT, NULL);
1548
1549        return 0;
1550}
1551
1552static int og_cmd_legacy_stop(const char *input, struct og_cmd *cmd)
1553{
1554        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_STOP, NULL);
1555
1556        return 0;
1557}
1558
1559static int og_cmd_legacy_hardware(const char *input, struct og_cmd *cmd)
1560{
1561        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_HARDWARE, NULL);
1562
1563        return 0;
1564}
1565
1566static int og_cmd_legacy_software(const char *input, struct og_cmd *cmd)
1567{
1568        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_SOFTWARE, NULL);
1569
1570        return 0;
1571}
1572
1573static int og_cmd_legacy_image_create(const char *input, struct og_cmd *cmd)
1574{
1575        json_t *root, *disk, *partition, *code, *image_id, *name, *repo;
1576        struct og_image_legacy img = {};
1577
1578        if (sscanf(input, "dsk=%s\rpar=%s\rcpt=%s\ridi=%s\rnci=%s\ripr=%s\r",
1579                   img.disk, img.part, img.code, img.image_id, img.name,
1580                   img.repo) != 6)
1581                return -1;
1582        image_id = json_string(img.image_id);
1583        partition = json_string(img.part);
1584        code = json_string(img.code);
1585        name = json_string(img.name);
1586        repo = json_string(img.repo);
1587        disk = json_string(img.disk);
1588
1589        root = json_object();
1590        if (!root)
1591                return -1;
1592        json_object_set_new(root, "partition", partition);
1593        json_object_set_new(root, "repository", repo);
1594        json_object_set_new(root, "id", image_id);
1595        json_object_set_new(root, "code", code);
1596        json_object_set_new(root, "name", name);
1597        json_object_set_new(root, "disk", disk);
1598
1599        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_CREATE, root);
1600
1601        return 0;
1602}
1603
1604#define OG_DB_RESTORE_TYPE_MAXLEN       64
1605
1606static int og_cmd_legacy_image_restore(const char *input, struct og_cmd *cmd)
1607{
1608        json_t *root, *disk, *partition, *image_id, *name, *repo;
1609        char restore_type_str[OG_DB_RESTORE_TYPE_MAXLEN + 1] = {};
1610        char software_id_str[OG_DB_INT_MAXLEN + 1] = {};
1611        json_t *software_id, *restore_type;
1612        struct og_image_legacy img = {};
1613
1614        if (sscanf(input,
1615                   "dsk=%s\rpar=%s\ridi=%s\rnci=%s\ripr=%s\rifs=%s\rptc=%s\r",
1616                   img.disk, img.part, img.image_id, img.name, img.repo,
1617                   software_id_str, restore_type_str) != 7)
1618                return -1;
1619
1620        restore_type = json_string(restore_type_str);
1621        software_id = json_string(software_id_str);
1622        image_id = json_string(img.image_id);
1623        partition = json_string(img.part);
1624        name = json_string(img.name);
1625        repo = json_string(img.repo);
1626        disk = json_string(img.disk);
1627
1628        root = json_object();
1629        if (!root)
1630                return -1;
1631        json_object_set_new(root, "profile", software_id);
1632        json_object_set_new(root, "partition", partition);
1633        json_object_set_new(root, "type", restore_type);
1634        json_object_set_new(root, "repository", repo);
1635        json_object_set_new(root, "id", image_id);
1636        json_object_set_new(root, "name", name);
1637        json_object_set_new(root, "disk", disk);
1638
1639        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, root);
1640
1641        return 0;
1642}
1643
1644static int og_cmd_legacy_setup(const char *input, struct og_cmd *cmd)
1645{
1646        json_t *root, *disk, *cache, *cache_size, *partition_setup, *object;
1647        struct og_legacy_partition part_cfg[OG_PARTITION_MAX] = {};
1648        char cache_size_str [OG_DB_INT_MAXLEN + 1];
1649        char disk_str [OG_DB_SMALLINT_MAXLEN + 1];
1650        json_t *part, *code, *fs, *size, *format;
1651        unsigned int partition_len = 0;
1652        const char *in_ptr;
1653        char cache_str[2];
1654
1655        if (sscanf(input, "dsk=%s\rcfg=dis=%*[^*]*che=%[^*]*tch=%[^!]!",
1656                   disk_str, cache_str, cache_size_str) != 3)
1657                return -1;
1658
1659        in_ptr = strstr(input, "!") + 1;
1660        while (strlen(in_ptr) > 0) {
1661                if(sscanf(in_ptr,
1662                          "par=%[^*]*cpt=%[^*]*sfi=%[^*]*tam=%[^*]*ope=%[^%%]%%",
1663                          part_cfg[partition_len].partition,
1664                          part_cfg[partition_len].code,
1665                          part_cfg[partition_len].filesystem,
1666                          part_cfg[partition_len].size,
1667                          part_cfg[partition_len].format) != 5)
1668                        return -1;
1669                in_ptr = strstr(in_ptr, "%") + 1;
1670                partition_len++;
1671        }
1672
1673        root = json_object();
1674        if (!root)
1675                return -1;
1676
1677        cache_size = json_string(cache_size_str);
1678        cache = json_string(cache_str);
1679        partition_setup = json_array();
1680        disk = json_string(disk_str);
1681
1682        for (unsigned int i = 0; i < partition_len; ++i) {
1683                object = json_object();
1684                if (!object) {
1685                        json_decref(root);
1686                        return -1;
1687                }
1688
1689                part = json_string(part_cfg[i].partition);
1690                fs = json_string(part_cfg[i].filesystem);
1691                format = json_string(part_cfg[i].format);
1692                code = json_string(part_cfg[i].code);
1693                size = json_string(part_cfg[i].size);
1694
1695                json_object_set_new(object, "partition", part);
1696                json_object_set_new(object, "filesystem", fs);
1697                json_object_set_new(object, "format", format);
1698                json_object_set_new(object, "code", code);
1699                json_object_set_new(object, "size", size);
1700
1701                json_array_append_new(partition_setup, object);
1702        }
1703
1704        json_object_set_new(root, "partition_setup", partition_setup);
1705        json_object_set_new(root, "cache_size", cache_size);
1706        json_object_set_new(root, "cache", cache);
1707        json_object_set_new(root, "disk", disk);
1708
1709        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SETUP, root);
1710
1711        return 0;
1712}
1713
1714static int og_cmd_legacy_run_schedule(const char *input, struct og_cmd *cmd)
1715{
1716        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, NULL);
1717
1718        return 0;
1719}
1720
1721static int og_cmd_legacy(const char *input, struct og_cmd *cmd)
1722{
1723        char legacy_cmd[32] = {};
1724        int err = -1;
1725
1726        if (sscanf(input, "nfn=%31s\r", legacy_cmd) != 1) {
1727                syslog(LOG_ERR, "malformed database legacy input\n");
1728                return -1;
1729        }
1730        input = strchr(input, '\r') + 1;
1731
1732        if (!strcmp(legacy_cmd, "Arrancar")) {
1733                err = og_cmd_legacy_wol(input, cmd);
1734        } else if (!strcmp(legacy_cmd, "EjecutarScript")) {
1735                err = og_cmd_legacy_shell_run(input, cmd);
1736        } else if (!strcmp(legacy_cmd, "IniciarSesion")) {
1737                err = og_cmd_legacy_session(input, cmd);
1738        } else if (!strcmp(legacy_cmd, "Apagar")) {
1739                err = og_cmd_legacy_poweroff(input, cmd);
1740        } else if (!strcmp(legacy_cmd, "Actualizar")) {
1741                err = og_cmd_legacy_refresh(input, cmd);
1742        } else if (!strcmp(legacy_cmd, "Reiniciar")) {
1743                err = og_cmd_legacy_reboot(input, cmd);
1744        } else if (!strcmp(legacy_cmd, "Purgar")) {
1745                err = og_cmd_legacy_stop(input, cmd);
1746        } else if (!strcmp(legacy_cmd, "InventarioHardware")) {
1747                err = og_cmd_legacy_hardware(input, cmd);
1748        } else if (!strcmp(legacy_cmd, "InventarioSoftware")) {
1749                err = og_cmd_legacy_software(input, cmd);
1750        } else if (!strcmp(legacy_cmd, "CrearImagen")) {
1751                err = og_cmd_legacy_image_create(input, cmd);
1752        } else if (!strcmp(legacy_cmd, "RestaurarImagen")) {
1753                err = og_cmd_legacy_image_restore(input, cmd);
1754        } else if (!strcmp(legacy_cmd, "Configurar")) {
1755                err = og_cmd_legacy_setup(input, cmd);
1756        } else if (!strcmp(legacy_cmd, "EjecutaComandosPendientes") ||
1757                   !strcmp(legacy_cmd, "Actualizar")) {
1758                err = og_cmd_legacy_run_schedule(input, cmd);
1759        }
1760
1761        return err;
1762}
1763
1764static int og_dbi_add_action(const struct og_dbi *dbi, const struct og_task *task,
1765                             struct og_cmd *cmd)
1766{
1767        char start_date_string[24];
1768        struct tm *start_date;
1769        const char *msglog;
1770        dbi_result result;
1771        time_t now;
1772
1773        time(&now);
1774        start_date = localtime(&now);
1775
1776        sprintf(start_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu",
1777                start_date->tm_year + 1900, start_date->tm_mon + 1,
1778                start_date->tm_mday, start_date->tm_hour, start_date->tm_min,
1779                start_date->tm_sec);
1780        result = dbi_conn_queryf(dbi->conn,
1781                                "INSERT INTO acciones (idordenador, "
1782                                "tipoaccion, idtipoaccion, descriaccion, ip, "
1783                                "sesion, idcomando, parametros, fechahorareg, "
1784                                "estado, resultado, ambito, idambito, "
1785                                "restrambito, idprocedimiento, idcentro, "
1786                                "idprogramacion) "
1787                                "VALUES (%d, %d, %d, '%s', '%s', %d, %d, '%s', "
1788                                "'%s', %d, %d, %d, %d, '%s', %d, %d, %d)",
1789                                cmd->client_id, EJECUCION_TAREA, task->task_id,
1790                                "", cmd->ip, 0, task->command_id,
1791                                task->params, start_date_string,
1792                                ACCION_INICIADA, ACCION_SINRESULTADO,
1793                                task->type_scope, task->scope, "",
1794                                task->procedure_id, task->center_id,
1795                                task->schedule_id);
1796        if (!result) {
1797                dbi_conn_error(dbi->conn, &msglog);
1798                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1799                       __func__, __LINE__, msglog);
1800                return -1;
1801        }
1802        cmd->id = dbi_conn_sequence_last(dbi->conn, NULL);
1803        dbi_result_free(result);
1804
1805        return 0;
1806}
1807
1808static int og_queue_task_command(struct og_dbi *dbi, const struct og_task *task,
1809                                 char *query)
1810{
1811        struct og_cmd *cmd;
1812        const char *msglog;
1813        dbi_result result;
1814
1815        result = dbi_conn_queryf(dbi->conn, query);
1816        if (!result) {
1817                dbi_conn_error(dbi->conn, &msglog);
1818                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1819                       __func__, __LINE__, msglog);
1820                return -1;
1821        }
1822
1823        while (dbi_result_next_row(result)) {
1824                cmd = (struct og_cmd *)calloc(1, sizeof(struct og_cmd));
1825                if (!cmd) {
1826                        dbi_result_free(result);
1827                        return -1;
1828                }
1829
1830                cmd->client_id  = dbi_result_get_uint(result, "idordenador");
1831                cmd->ip         = strdup(dbi_result_get_string(result, "ip"));
1832                cmd->mac        = strdup(dbi_result_get_string(result, "mac"));
1833
1834                og_cmd_legacy(task->params, cmd);
1835
1836                if (task->procedure_id) {
1837                        if (og_dbi_add_action(dbi, task, cmd)) {
1838                                dbi_result_free(result);
1839                                return -1;
1840                        }
1841                } else {
1842                        cmd->id = task->task_id;
1843                }
1844
1845                list_add_tail(&cmd->list, &cmd_list);
1846        }
1847
1848        dbi_result_free(result);
1849
1850        return 0;
1851}
1852
1853static int og_queue_task_group_clients(struct og_dbi *dbi, struct og_task *task,
1854                                       char *query)
1855{
1856
1857        const char *msglog;
1858        dbi_result result;
1859
1860        result = dbi_conn_queryf(dbi->conn, query);
1861        if (!result) {
1862                dbi_conn_error(dbi->conn, &msglog);
1863                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1864                       __func__, __LINE__, msglog);
1865                return -1;
1866        }
1867
1868        while (dbi_result_next_row(result)) {
1869                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
1870
1871                sprintf(query, "SELECT idgrupo FROM gruposordenadores "
1872                                "WHERE grupoid=%d", group_id);
1873                if (og_queue_task_group_clients(dbi, task, query)) {
1874                        dbi_result_free(result);
1875                        return -1;
1876                }
1877
1878                sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
1879                              "WHERE grupoid=%d", group_id);
1880                if (og_queue_task_command(dbi, task, query)) {
1881                        dbi_result_free(result);
1882                        return -1;
1883                }
1884
1885        }
1886
1887        dbi_result_free(result);
1888
1889        return 0;
1890}
1891
1892static int og_queue_task_group_classrooms(struct og_dbi *dbi,
1893                                          struct og_task *task, char *query)
1894{
1895
1896        const char *msglog;
1897        dbi_result result;
1898
1899        result = dbi_conn_queryf(dbi->conn, query);
1900        if (!result) {
1901                dbi_conn_error(dbi->conn, &msglog);
1902                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1903                       __func__, __LINE__, msglog);
1904                return -1;
1905        }
1906
1907        while (dbi_result_next_row(result)) {
1908                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
1909
1910                sprintf(query, "SELECT idgrupo FROM grupos "
1911                                "WHERE grupoid=%d AND tipo=%d", group_id, AMBITO_GRUPOSAULAS);
1912                if (og_queue_task_group_classrooms(dbi, task, query)) {
1913                        dbi_result_free(result);
1914                        return -1;
1915                }
1916
1917                sprintf(query,
1918                        "SELECT ip,mac,idordenador "
1919                        "FROM ordenadores INNER JOIN aulas "
1920                        "WHERE ordenadores.idaula=aulas.idaula "
1921                        "AND aulas.grupoid=%d",
1922                        group_id);
1923                if (og_queue_task_command(dbi, task, query)) {
1924                        dbi_result_free(result);
1925                        return -1;
1926                }
1927
1928        }
1929
1930        dbi_result_free(result);
1931
1932        return 0;
1933}
1934
1935static int og_queue_task_clients(struct og_dbi *dbi, struct og_task *task)
1936{
1937        char query[4096];
1938
1939        switch (task->type_scope) {
1940                case AMBITO_CENTROS:
1941                        sprintf(query,
1942                                "SELECT ip,mac,idordenador "
1943                                "FROM ordenadores INNER JOIN aulas "
1944                                "WHERE ordenadores.idaula=aulas.idaula "
1945                                "AND idcentro=%d",
1946                                task->scope);
1947                        return og_queue_task_command(dbi, task, query);
1948                case AMBITO_GRUPOSAULAS:
1949                        sprintf(query,
1950                                "SELECT idgrupo FROM grupos "
1951                                "WHERE idgrupo=%i AND tipo=%d",
1952                                task->scope, AMBITO_GRUPOSAULAS);
1953                        return og_queue_task_group_classrooms(dbi, task, query);
1954                case AMBITO_AULAS:
1955                        sprintf(query,
1956                                "SELECT ip,mac,idordenador FROM ordenadores "
1957                                "WHERE idaula=%d",
1958                                task->scope);
1959                        return og_queue_task_command(dbi, task, query);
1960                case AMBITO_GRUPOSORDENADORES:
1961                        sprintf(query,
1962                                "SELECT idgrupo FROM gruposordenadores "
1963                                "WHERE idgrupo = %d",
1964                                task->scope);
1965                        return og_queue_task_group_clients(dbi, task, query);
1966                case AMBITO_ORDENADORES:
1967                        sprintf(query,
1968                                "SELECT ip, mac, idordenador FROM ordenadores "
1969                                "WHERE idordenador = %d",
1970                                task->scope);
1971                        return og_queue_task_command(dbi, task, query);
1972        }
1973        return 0;
1974}
1975
1976int og_dbi_queue_procedure(struct og_dbi *dbi, struct og_task *task)
1977{
1978        uint32_t procedure_id;
1979        const char *msglog;
1980        dbi_result result;
1981
1982        result = dbi_conn_queryf(dbi->conn,
1983                        "SELECT parametros, procedimientoid, idcomando "
1984                        "FROM procedimientos_acciones "
1985                        "WHERE idprocedimiento=%d ORDER BY orden", task->procedure_id);
1986        if (!result) {
1987                dbi_conn_error(dbi->conn, &msglog);
1988                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1989                       __func__, __LINE__, msglog);
1990                return -1;
1991        }
1992
1993        while (dbi_result_next_row(result)) {
1994                procedure_id = dbi_result_get_uint(result, "procedimientoid");
1995                if (procedure_id > 0) {
1996                        task->procedure_id = procedure_id;
1997                        if (og_dbi_queue_procedure(dbi, task))
1998                                return -1;
1999                        continue;
2000                }
2001
2002                task->params    = strdup(dbi_result_get_string(result, "parametros"));
2003                task->command_id = dbi_result_get_uint(result, "idcomando");
2004                if (og_queue_task_clients(dbi, task))
2005                        return -1;
2006        }
2007
2008        dbi_result_free(result);
2009
2010        return 0;
2011}
2012
2013static int og_dbi_queue_task(struct og_dbi *dbi, uint32_t task_id,
2014                             uint32_t schedule_id)
2015{
2016        struct og_task task = {};
2017        uint32_t task_id_next;
2018        const char *msglog;
2019        dbi_result result;
2020
2021        task.schedule_id = schedule_id;
2022
2023        result = dbi_conn_queryf(dbi->conn,
2024                        "SELECT tareas_acciones.orden, "
2025                                "tareas_acciones.idprocedimiento, "
2026                                "tareas_acciones.tareaid, "
2027                                "tareas.idtarea, "
2028                                "tareas.idcentro, "
2029                                "tareas.ambito, "
2030                                "tareas.idambito, "
2031                                "tareas.restrambito "
2032                        " FROM tareas"
2033                                " INNER JOIN tareas_acciones ON tareas_acciones.idtarea=tareas.idtarea"
2034                        " WHERE tareas_acciones.idtarea=%u ORDER BY tareas_acciones.orden ASC", task_id);
2035        if (!result) {
2036                dbi_conn_error(dbi->conn, &msglog);
2037                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2038                       __func__, __LINE__, msglog);
2039                return -1;
2040        }
2041
2042        while (dbi_result_next_row(result)) {
2043                task_id_next = dbi_result_get_uint(result, "tareaid");
2044
2045                if (task_id_next > 0) {
2046                        if (og_dbi_queue_task(dbi, task_id_next, schedule_id))
2047                                return -1;
2048
2049                        continue;
2050                }
2051                task.task_id = dbi_result_get_uint(result, "idtarea");
2052                task.center_id = dbi_result_get_uint(result, "idcentro");
2053                task.procedure_id = dbi_result_get_uint(result, "idprocedimiento");
2054                task.type_scope = dbi_result_get_uint(result, "ambito");
2055                task.scope = dbi_result_get_uint(result, "idambito");
2056                task.filtered_scope = dbi_result_get_string(result, "restrambito");
2057
2058                og_dbi_queue_procedure(dbi, &task);
2059        }
2060
2061        dbi_result_free(result);
2062
2063        return 0;
2064}
2065
2066static int og_dbi_queue_command(struct og_dbi *dbi, uint32_t task_id,
2067                                uint32_t schedule_id)
2068{
2069        struct og_task task = {};
2070        const char *msglog;
2071        dbi_result result;
2072        char query[4096];
2073
2074        result = dbi_conn_queryf(dbi->conn,
2075                        "SELECT idaccion, idcentro, idordenador, parametros "
2076                        "FROM acciones "
2077                        "WHERE sesion = %u", task_id);
2078        if (!result) {
2079                dbi_conn_error(dbi->conn, &msglog);
2080                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2081                       __func__, __LINE__, msglog);
2082                return -1;
2083        }
2084
2085        while (dbi_result_next_row(result)) {
2086                task.task_id = dbi_result_get_uint(result, "idaccion");
2087                task.center_id = dbi_result_get_uint(result, "idcentro");
2088                task.scope = dbi_result_get_uint(result, "idordenador");
2089                task.params = strdup(dbi_result_get_string(result, "parametros"));
2090
2091                sprintf(query,
2092                        "SELECT ip, mac, idordenador FROM ordenadores "
2093                        "WHERE idordenador = %d",
2094                        task.scope);
2095                if (og_queue_task_command(dbi, &task, query)) {
2096                        dbi_result_free(result);
2097                        return -1;
2098                }
2099        }
2100
2101        dbi_result_free(result);
2102
2103        return 0;
2104}
2105
2106int og_dbi_update_action(uint32_t id, bool success)
2107{
2108        char end_date_string[24];
2109        struct tm *end_date;
2110        const char *msglog;
2111        struct og_dbi *dbi;
2112        uint8_t status = 2;
2113        dbi_result result;
2114        time_t now;
2115
2116        if (!id)
2117                return 0;
2118
2119        dbi = og_dbi_open(&dbi_config);
2120        if (!dbi) {
2121                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2122                       __func__, __LINE__);
2123                return -1;
2124        }
2125
2126        time(&now);
2127        end_date = localtime(&now);
2128
2129        sprintf(end_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu",
2130                end_date->tm_year + 1900, end_date->tm_mon + 1,
2131                end_date->tm_mday, end_date->tm_hour, end_date->tm_min,
2132                end_date->tm_sec);
2133        result = dbi_conn_queryf(dbi->conn,
2134                                 "UPDATE acciones SET fechahorafin='%s', "
2135                                 "estado=%d, resultado=%d WHERE idaccion=%d",
2136                                 end_date_string, ACCION_FINALIZADA,
2137                                 status - success, id);
2138
2139        if (!result) {
2140                dbi_conn_error(dbi->conn, &msglog);
2141                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2142                       __func__, __LINE__, msglog);
2143                og_dbi_close(dbi);
2144                return -1;
2145        }
2146        dbi_result_free(result);
2147        og_dbi_close(dbi);
2148
2149        return 0;
2150}
2151
2152void og_schedule_run(unsigned int task_id, unsigned int schedule_id,
2153                     enum og_schedule_type type)
2154{
2155        struct og_msg_params params = {};
2156        bool duplicated = false;
2157        struct og_cmd *cmd, *next;
2158        struct og_dbi *dbi;
2159        unsigned int i;
2160
2161        dbi = og_dbi_open(&dbi_config);
2162        if (!dbi) {
2163                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2164                       __func__, __LINE__);
2165                return;
2166        }
2167
2168        switch (type) {
2169        case OG_SCHEDULE_TASK:
2170                og_dbi_queue_task(dbi, task_id, schedule_id);
2171                break;
2172        case OG_SCHEDULE_PROCEDURE:
2173        case OG_SCHEDULE_COMMAND:
2174                og_dbi_queue_command(dbi, task_id, schedule_id);
2175                break;
2176        }
2177        og_dbi_close(dbi);
2178
2179        list_for_each_entry(cmd, &cmd_list, list) {
2180                for (i = 0; i < params.ips_array_len; i++) {
2181                        if (!strncmp(cmd->ip, params.ips_array[i],
2182                                     OG_DB_IP_MAXLEN)) {
2183                                duplicated = true;
2184                                break;
2185                        }
2186                }
2187
2188                if (!duplicated)
2189                        params.ips_array[params.ips_array_len++] = cmd->ip;
2190                else
2191                        duplicated = false;
2192        }
2193
2194        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
2195                if (cmd->type != OG_CMD_WOL)
2196                        continue;
2197
2198                if (Levanta((char **)cmd->params.ips_array,
2199                            (char **)cmd->params.mac_array,
2200                            cmd->params.ips_array_len,
2201                            (char *)cmd->params.wol_type))
2202                        og_dbi_update_action(cmd->id, true);
2203
2204                list_del(&cmd->list);
2205                og_cmd_free(cmd);
2206        }
2207
2208        og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, &params, NULL);
2209}
2210
2211static int og_cmd_task_post(json_t *element, struct og_msg_params *params)
2212{
2213        struct og_cmd *cmd;
2214        struct og_dbi *dbi;
2215        const char *key;
2216        json_t *value;
2217        int err;
2218
2219        if (json_typeof(element) != JSON_OBJECT)
2220                return -1;
2221
2222        json_object_foreach(element, key, value) {
2223                if (!strcmp(key, "task")) {
2224                        err = og_json_parse_string(value, &params->task_id);
2225                        params->flags |= OG_REST_PARAM_TASK;
2226                }
2227
2228                if (err < 0)
2229                        break;
2230        }
2231
2232        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK))
2233                return -1;
2234
2235        dbi = og_dbi_open(&dbi_config);
2236        if (!dbi) {
2237                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2238                           __func__, __LINE__);
2239                return -1;
2240        }
2241
2242        og_schedule_run(atoi(params->task_id), 0, OG_SCHEDULE_TASK);
2243        og_dbi_close(dbi);
2244
2245        list_for_each_entry(cmd, &cmd_list, list)
2246                params->ips_array[params->ips_array_len++] = cmd->ip;
2247
2248        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
2249                               NULL);
2250}
2251
2252int og_dbi_schedule_get(void)
2253{
2254        uint32_t schedule_id, task_id;
2255        struct og_schedule_time time;
2256        struct og_dbi *dbi;
2257        const char *msglog;
2258        dbi_result result;
2259
2260        dbi = og_dbi_open(&dbi_config);
2261        if (!dbi) {
2262                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2263                       __func__, __LINE__);
2264                return -1;
2265        }
2266
2267        result = dbi_conn_queryf(dbi->conn,
2268                                 "SELECT idprogramacion, tipoaccion, identificador, "
2269                                 "sesion, annos, meses, diario, dias, semanas, horas, "
2270                                 "ampm, minutos FROM programaciones "
2271                                 "WHERE suspendida = 0");
2272        if (!result) {
2273                dbi_conn_error(dbi->conn, &msglog);
2274                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2275                       __func__, __LINE__, msglog);
2276                og_dbi_close(dbi);
2277                return -1;
2278        }
2279
2280        while (dbi_result_next_row(result)) {
2281                memset(&time, 0, sizeof(time));
2282                schedule_id = dbi_result_get_uint(result, "idprogramacion");
2283                task_id = dbi_result_get_uint(result, "identificador");
2284                time.years = dbi_result_get_uint(result, "annos");
2285                time.months = dbi_result_get_uint(result, "meses");
2286                time.weeks = dbi_result_get_uint(result, "semanas");
2287                time.week_days = dbi_result_get_uint(result, "dias");
2288                time.days = dbi_result_get_uint(result, "diario");
2289                time.hours = dbi_result_get_uint(result, "horas");
2290                time.am_pm = dbi_result_get_uint(result, "ampm");
2291                time.minutes = dbi_result_get_uint(result, "minutos");
2292                time.on_start = true;
2293
2294                og_schedule_create(schedule_id, task_id, OG_SCHEDULE_TASK,
2295                                   &time);
2296        }
2297
2298        dbi_result_free(result);
2299        og_dbi_close(dbi);
2300
2301        return 0;
2302}
2303
2304static int og_dbi_schedule_create(struct og_dbi *dbi,
2305                                  struct og_msg_params *params,
2306                                  uint32_t *schedule_id,
2307                                  enum og_schedule_type schedule_type)
2308{
2309        uint8_t suspended = 0;
2310        uint32_t session = 0;
2311        const char *msglog;
2312        dbi_result result;
2313        uint8_t type;
2314
2315        switch (schedule_type) {
2316        case OG_SCHEDULE_TASK:
2317                type = 3;
2318                break;
2319        case OG_SCHEDULE_PROCEDURE:
2320                type = 2;
2321                break;
2322        case OG_SCHEDULE_COMMAND:
2323                session = atoi(params->task_id);
2324                type = 1;
2325                break;
2326        }
2327
2328        result = dbi_conn_queryf(dbi->conn,
2329                                 "INSERT INTO programaciones (tipoaccion,"
2330                                 " identificador, nombrebloque, annos, meses,"
2331                                 " semanas, dias, diario, horas, ampm, minutos,"
2332                                 " suspendida, sesion) VALUES (%d, %s, '%s',"
2333                                 " %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)",
2334                                 type, params->task_id, params->name,
2335                                 params->time.years, params->time.months,
2336                                 params->time.weeks, params->time.week_days,
2337                                 params->time.days, params->time.hours,
2338                                 params->time.am_pm, params->time.minutes,
2339                                 suspended, session);
2340        if (!result) {
2341                dbi_conn_error(dbi->conn, &msglog);
2342                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2343                       __func__, __LINE__, msglog);
2344                return -1;
2345        }
2346        dbi_result_free(result);
2347
2348        *schedule_id = dbi_conn_sequence_last(dbi->conn, NULL);
2349
2350        return 0;
2351}
2352
2353static int og_dbi_schedule_update(struct og_dbi *dbi,
2354                                  struct og_msg_params *params)
2355{
2356        const char *msglog;
2357        dbi_result result;
2358        uint8_t type = 3;
2359
2360        result = dbi_conn_queryf(dbi->conn,
2361                                 "UPDATE programaciones SET tipoaccion=%d, "
2362                                 "identificador='%s', nombrebloque='%s', "
2363                                 "annos=%d, meses=%d, "
2364                                 "diario=%d, horas=%d, ampm=%d, minutos=%d "
2365                                 "WHERE idprogramacion='%s'",
2366                                 type, params->task_id, params->name,
2367                                 params->time.years, params->time.months,
2368                                 params->time.days, params->time.hours,
2369                                 params->time.am_pm, params->time.minutes,
2370                                 params->id);
2371
2372        if (!result) {
2373                dbi_conn_error(dbi->conn, &msglog);
2374                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2375                       __func__, __LINE__, msglog);
2376                return -1;
2377        }
2378        dbi_result_free(result);
2379
2380        return 0;
2381}
2382
2383static int og_dbi_schedule_delete(struct og_dbi *dbi, uint32_t id)
2384{
2385        const char *msglog;
2386        dbi_result result;
2387
2388        result = dbi_conn_queryf(dbi->conn,
2389                                 "DELETE FROM programaciones WHERE idprogramacion=%d",
2390                                 id);
2391        if (!result) {
2392                dbi_conn_error(dbi->conn, &msglog);
2393                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2394                       __func__, __LINE__, msglog);
2395                return -1;
2396        }
2397        dbi_result_free(result);
2398
2399        return 0;
2400}
2401
2402struct og_db_schedule {
2403        uint32_t                id;
2404        uint32_t                task_id;
2405        const char              *name;
2406        struct og_schedule_time time;
2407        uint32_t                week_days;
2408        uint32_t                weeks;
2409        uint32_t                suspended;
2410        uint32_t                session;
2411};
2412
2413static int og_dbi_schedule_get_json(struct og_dbi *dbi, json_t *root,
2414                                    const char *task_id, const char *schedule_id)
2415{
2416        struct og_db_schedule schedule;
2417        json_t *obj, *array;
2418        const char *msglog;
2419        dbi_result result;
2420        int err = 0;
2421
2422        if (task_id) {
2423                result = dbi_conn_queryf(dbi->conn,
2424                                         "SELECT idprogramacion,"
2425                                         "       identificador, nombrebloque,"
2426                                         "       annos, meses, diario, dias,"
2427                                         "       semanas, horas, ampm,"
2428                                         "       minutos,suspendida, sesion "
2429                                         "FROM programaciones "
2430                                         "WHERE identificador=%d",
2431                                         atoi(task_id));
2432        } else if (schedule_id) {
2433                result = dbi_conn_queryf(dbi->conn,
2434                                         "SELECT idprogramacion,"
2435                                         "       identificador, nombrebloque,"
2436                                         "       annos, meses, diario, dias,"
2437                                         "       semanas, horas, ampm,"
2438                                         "       minutos,suspendida, sesion "
2439                                         "FROM programaciones "
2440                                         "WHERE idprogramacion=%d",
2441                                         atoi(schedule_id));
2442        } else {
2443                result = dbi_conn_queryf(dbi->conn,
2444                                         "SELECT idprogramacion,"
2445                                         "       identificador, nombrebloque,"
2446                                         "       annos, meses, diario, dias,"
2447                                         "       semanas, horas, ampm,"
2448                                         "       minutos,suspendida, sesion "
2449                                         "FROM programaciones");
2450        }
2451
2452        if (!result) {
2453                dbi_conn_error(dbi->conn, &msglog);
2454                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2455                       __func__, __LINE__, msglog);
2456                return -1;
2457        }
2458
2459        array = json_array();
2460        if (!array)
2461                return -1;
2462
2463        while (dbi_result_next_row(result)) {
2464                schedule.id = dbi_result_get_uint(result, "idprogramacion");
2465                schedule.task_id = dbi_result_get_uint(result, "identificador");
2466                schedule.name = dbi_result_get_string(result, "nombrebloque");
2467                schedule.time.years = dbi_result_get_uint(result, "annos");
2468                schedule.time.months = dbi_result_get_uint(result, "meses");
2469                schedule.time.days = dbi_result_get_uint(result, "diario");
2470                schedule.time.hours = dbi_result_get_uint(result, "horas");
2471                schedule.time.am_pm = dbi_result_get_uint(result, "ampm");
2472                schedule.time.minutes = dbi_result_get_uint(result, "minutos");
2473                schedule.week_days = dbi_result_get_uint(result, "dias");
2474                schedule.weeks = dbi_result_get_uint(result, "semanas");
2475                schedule.suspended = dbi_result_get_uint(result, "suspendida");
2476                schedule.session = dbi_result_get_uint(result, "sesion");
2477
2478                obj = json_object();
2479                if (!obj) {
2480                        err = -1;
2481                        break;
2482                }
2483                json_object_set_new(obj, "id", json_integer(schedule.id));
2484                json_object_set_new(obj, "task", json_integer(schedule.task_id));
2485                json_object_set_new(obj, "name", json_string(schedule.name));
2486                json_object_set_new(obj, "years", json_integer(schedule.time.years));
2487                json_object_set_new(obj, "months", json_integer(schedule.time.months));
2488                json_object_set_new(obj, "days", json_integer(schedule.time.days));
2489                json_object_set_new(obj, "hours", json_integer(schedule.time.hours));
2490                json_object_set_new(obj, "am_pm", json_integer(schedule.time.am_pm));
2491                json_object_set_new(obj, "minutes", json_integer(schedule.time.minutes));
2492                json_object_set_new(obj, "week_days", json_integer(schedule.week_days));
2493                json_object_set_new(obj, "weeks", json_integer(schedule.weeks));
2494                json_object_set_new(obj, "suspended", json_integer(schedule.suspended));
2495                json_object_set_new(obj, "session", json_integer(schedule.session));
2496
2497                json_array_append_new(array, obj);
2498        }
2499
2500        json_object_set_new(root, "schedule", array);
2501
2502        dbi_result_free(result);
2503
2504        return err;
2505}
2506
2507static int og_task_schedule_create(struct og_msg_params *params)
2508{
2509        enum og_schedule_type type;
2510        uint32_t schedule_id;
2511        struct og_dbi *dbi;
2512        int err;
2513
2514        if (!strcmp(params->type, "task"))
2515                type = OG_SCHEDULE_TASK;
2516        else if (!strcmp(params->type, "procedure"))
2517                type = OG_SCHEDULE_PROCEDURE;
2518        else if (!strcmp(params->type, "command"))
2519                type = OG_SCHEDULE_COMMAND;
2520        else
2521                return -1;
2522
2523        dbi = og_dbi_open(&dbi_config);
2524        if (!dbi) {
2525                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2526                       __func__, __LINE__);
2527                return -1;
2528        }
2529
2530        err = og_dbi_schedule_create(dbi, params, &schedule_id, type);
2531        if (err < 0) {
2532                og_dbi_close(dbi);
2533                return -1;
2534        }
2535        og_schedule_create(schedule_id, atoi(params->task_id), type,
2536                           &params->time);
2537        og_schedule_refresh(og_loop);
2538        og_dbi_close(dbi);
2539
2540        return 0;
2541}
2542
2543static int og_cmd_schedule_create(json_t *element, struct og_msg_params *params)
2544{
2545        const char *key;
2546        json_t *value;
2547        int err;
2548
2549        if (json_typeof(element) != JSON_OBJECT)
2550                return -1;
2551
2552        json_object_foreach(element, key, value) {
2553                if (!strcmp(key, "task")) {
2554                        err = og_json_parse_string(value, &params->task_id);
2555                        params->flags |= OG_REST_PARAM_TASK;
2556                } else if (!strcmp(key, "name")) {
2557                        err = og_json_parse_string(value, &params->name);
2558                        params->flags |= OG_REST_PARAM_NAME;
2559                } else if (!strcmp(key, "when")) {
2560                        err = og_json_parse_time_params(value, params);
2561                } else if (!strcmp(key, "type")) {
2562                        err = og_json_parse_string(value, &params->type);
2563                        params->flags |= OG_REST_PARAM_TYPE;
2564                }
2565
2566                if (err < 0)
2567                        break;
2568        }
2569
2570        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK |
2571                                            OG_REST_PARAM_NAME |
2572                                            OG_REST_PARAM_TIME_YEARS |
2573                                            OG_REST_PARAM_TIME_MONTHS |
2574                                            OG_REST_PARAM_TIME_WEEKS |
2575                                            OG_REST_PARAM_TIME_WEEK_DAYS |
2576                                            OG_REST_PARAM_TIME_DAYS |
2577                                            OG_REST_PARAM_TIME_HOURS |
2578                                            OG_REST_PARAM_TIME_MINUTES |
2579                                            OG_REST_PARAM_TIME_AM_PM |
2580                                            OG_REST_PARAM_TYPE))
2581                return -1;
2582
2583        return og_task_schedule_create(params);
2584}
2585
2586static int og_cmd_schedule_update(json_t *element, struct og_msg_params *params)
2587{
2588        struct og_dbi *dbi;
2589        const char *key;
2590        json_t *value;
2591        int err;
2592
2593        if (json_typeof(element) != JSON_OBJECT)
2594                return -1;
2595
2596        json_object_foreach(element, key, value) {
2597                if (!strcmp(key, "id")) {
2598                        err = og_json_parse_string(value, &params->id);
2599                        params->flags |= OG_REST_PARAM_ID;
2600                } else if (!strcmp(key, "task")) {
2601                        err = og_json_parse_string(value, &params->task_id);
2602                        params->flags |= OG_REST_PARAM_TASK;
2603                } else if (!strcmp(key, "name")) {
2604                        err = og_json_parse_string(value, &params->name);
2605                        params->flags |= OG_REST_PARAM_NAME;
2606                } else if (!strcmp(key, "when"))
2607                        err = og_json_parse_time_params(value, params);
2608
2609                if (err < 0)
2610                        break;
2611        }
2612
2613        if (!og_msg_params_validate(params, OG_REST_PARAM_ID |
2614                                            OG_REST_PARAM_TASK |
2615                                            OG_REST_PARAM_NAME |
2616                                            OG_REST_PARAM_TIME_YEARS |
2617                                            OG_REST_PARAM_TIME_MONTHS |
2618                                            OG_REST_PARAM_TIME_DAYS |
2619                                            OG_REST_PARAM_TIME_HOURS |
2620                                            OG_REST_PARAM_TIME_MINUTES |
2621                                            OG_REST_PARAM_TIME_AM_PM))
2622                return -1;
2623
2624        dbi = og_dbi_open(&dbi_config);
2625        if (!dbi) {
2626                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2627                           __func__, __LINE__);
2628                return -1;
2629        }
2630
2631        err = og_dbi_schedule_update(dbi, params);
2632        og_dbi_close(dbi);
2633
2634        if (err < 0)
2635                return err;
2636
2637        og_schedule_update(og_loop, atoi(params->id), atoi(params->task_id),
2638                           &params->time);
2639        og_schedule_refresh(og_loop);
2640
2641        return err;
2642}
2643
2644static int og_cmd_schedule_delete(json_t *element, struct og_msg_params *params)
2645{
2646        struct og_dbi *dbi;
2647        const char *key;
2648        json_t *value;
2649        int err;
2650
2651        if (json_typeof(element) != JSON_OBJECT)
2652                return -1;
2653
2654        json_object_foreach(element, key, value) {
2655                if (!strcmp(key, "id")) {
2656                        err = og_json_parse_string(value, &params->id);
2657                        params->flags |= OG_REST_PARAM_ID;
2658                } else {
2659                        return -1;
2660                }
2661
2662                if (err < 0)
2663                        break;
2664        }
2665
2666        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
2667                return -1;
2668
2669        dbi = og_dbi_open(&dbi_config);
2670        if (!dbi) {
2671                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2672                           __func__, __LINE__);
2673                return -1;
2674        }
2675
2676        err = og_dbi_schedule_delete(dbi, atoi(params->id));
2677        og_dbi_close(dbi);
2678
2679        og_schedule_delete(og_loop, atoi(params->id));
2680
2681        return err;
2682}
2683
2684static int og_cmd_schedule_get(json_t *element, struct og_msg_params *params,
2685                               char *buffer_reply)
2686{
2687        struct og_buffer og_buffer = {
2688                .data   = buffer_reply,
2689        };
2690        json_t *schedule_root;
2691        struct og_dbi *dbi;
2692        const char *key;
2693        json_t *value;
2694        int err;
2695
2696        if (element) {
2697                if (json_typeof(element) != JSON_OBJECT)
2698                        return -1;
2699
2700                json_object_foreach(element, key, value) {
2701                        if (!strcmp(key, "task")) {
2702                                err = og_json_parse_string(value,
2703                                                           &params->task_id);
2704                        } else if (!strcmp(key, "id")) {
2705                                err = og_json_parse_string(value, &params->id);
2706                        } else {
2707                                return -1;
2708                        }
2709
2710                        if (err < 0)
2711                                break;
2712                }
2713        }
2714
2715        dbi = og_dbi_open(&dbi_config);
2716        if (!dbi) {
2717                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2718                           __func__, __LINE__);
2719                return -1;
2720        }
2721
2722        schedule_root = json_object();
2723        if (!schedule_root) {
2724                og_dbi_close(dbi);
2725                return -1;
2726        }
2727
2728        err = og_dbi_schedule_get_json(dbi, schedule_root,
2729                                       params->task_id, params->id);
2730        og_dbi_close(dbi);
2731
2732        if (err >= 0)
2733                json_dump_callback(schedule_root, og_json_dump_clients, &og_buffer, 0);
2734
2735        json_decref(schedule_root);
2736
2737        return err;
2738}
2739
2740static int og_client_method_not_found(struct og_client *cli)
2741{
2742        /* To meet RFC 7231, this function MUST generate an Allow header field
2743         * containing the correct methods. For example: "Allow: POST\r\n"
2744         */
2745        char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n"
2746                     "Content-Length: 0\r\n\r\n";
2747
2748        send(og_client_socket(cli), buf, strlen(buf), 0);
2749
2750        return -1;
2751}
2752
2753static int og_client_bad_request(struct og_client *cli)
2754{
2755        char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
2756
2757        send(og_client_socket(cli), buf, strlen(buf), 0);
2758
2759        return -1;
2760}
2761
2762static int og_client_not_found(struct og_client *cli)
2763{
2764        char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
2765
2766        send(og_client_socket(cli), buf, strlen(buf), 0);
2767
2768        return -1;
2769}
2770
2771static int og_client_not_authorized(struct og_client *cli)
2772{
2773        char buf[] = "HTTP/1.1 401 Unauthorized\r\n"
2774                     "WWW-Authenticate: Basic\r\n"
2775                     "Content-Length: 0\r\n\r\n";
2776
2777        send(og_client_socket(cli), buf, strlen(buf), 0);
2778
2779        return -1;
2780}
2781
2782static int og_server_internal_error(struct og_client *cli)
2783{
2784        char buf[] = "HTTP/1.1 500 Internal Server Error\r\n"
2785                     "Content-Length: 0\r\n\r\n";
2786
2787        send(og_client_socket(cli), buf, strlen(buf), 0);
2788
2789        return -1;
2790}
2791
2792#define OG_MSG_RESPONSE_MAXLEN  65536
2793
2794static int og_client_ok(struct og_client *cli, char *buf_reply)
2795{
2796        char buf[OG_MSG_RESPONSE_MAXLEN] = {};
2797        int err = 0, len;
2798
2799        len = snprintf(buf, sizeof(buf),
2800                       "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
2801                       strlen(buf_reply), buf_reply);
2802        if (len >= (int)sizeof(buf))
2803                err = og_server_internal_error(cli);
2804
2805        send(og_client_socket(cli), buf, strlen(buf), 0);
2806
2807        return err;
2808}
2809
2810int og_client_state_process_payload_rest(struct og_client *cli)
2811{
2812        char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {};
2813        struct og_msg_params params = {};
2814        enum og_rest_method method;
2815        const char *cmd, *body;
2816        json_error_t json_err;
2817        json_t *root = NULL;
2818        int err = 0;
2819
2820        syslog(LOG_DEBUG, "%s:%hu %.32s ...\n",
2821               inet_ntoa(cli->addr.sin_addr),
2822               ntohs(cli->addr.sin_port), cli->buf);
2823
2824        if (!strncmp(cli->buf, "GET", strlen("GET"))) {
2825                method = OG_METHOD_GET;
2826                cmd = cli->buf + strlen("GET") + 2;
2827        } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
2828                method = OG_METHOD_POST;
2829                cmd = cli->buf + strlen("POST") + 2;
2830        } else
2831                return og_client_method_not_found(cli);
2832
2833        body = strstr(cli->buf, "\r\n\r\n") + 4;
2834
2835        if (strcmp(cli->auth_token, auth_token)) {
2836                syslog(LOG_ERR, "wrong Authentication key\n");
2837                return og_client_not_authorized(cli);
2838        }
2839
2840        if (cli->content_length) {
2841                root = json_loads(body, 0, &json_err);
2842                if (!root) {
2843                        syslog(LOG_ERR, "malformed json line %d: %s\n",
2844                               json_err.line, json_err.text);
2845                        return og_client_not_found(cli);
2846                }
2847        }
2848
2849        if (!strncmp(cmd, "clients", strlen("clients"))) {
2850                if (method != OG_METHOD_POST &&
2851                    method != OG_METHOD_GET)
2852                        return og_client_method_not_found(cli);
2853
2854                if (method == OG_METHOD_POST && !root) {
2855                        syslog(LOG_ERR, "command clients with no payload\n");
2856                        return og_client_bad_request(cli);
2857                }
2858                switch (method) {
2859                case OG_METHOD_POST:
2860                        err = og_cmd_post_clients(root, &params);
2861                        break;
2862                case OG_METHOD_GET:
2863                        err = og_cmd_get_clients(root, &params, buf_reply);
2864                        break;
2865                default:
2866                        return og_client_bad_request(cli);
2867                }
2868        } else if (!strncmp(cmd, "wol", strlen("wol"))) {
2869                if (method != OG_METHOD_POST)
2870                        return og_client_method_not_found(cli);
2871
2872                if (!root) {
2873                        syslog(LOG_ERR, "command wol with no payload\n");
2874                        return og_client_bad_request(cli);
2875                }
2876                err = og_cmd_wol(root, &params);
2877        } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) {
2878                if (method != OG_METHOD_POST)
2879                        return og_client_method_not_found(cli);
2880
2881                if (!root) {
2882                        syslog(LOG_ERR, "command run with no payload\n");
2883                        return og_client_bad_request(cli);
2884                }
2885                err = og_cmd_run_post(root, &params);
2886        } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) {
2887                if (method != OG_METHOD_POST)
2888                        return og_client_method_not_found(cli);
2889
2890                if (!root) {
2891                        syslog(LOG_ERR, "command output with no payload\n");
2892                        return og_client_bad_request(cli);
2893                }
2894
2895                err = og_cmd_run_get(root, &params, buf_reply);
2896        } else if (!strncmp(cmd, "session", strlen("session"))) {
2897                if (method != OG_METHOD_POST)
2898                        return og_client_method_not_found(cli);
2899
2900                if (!root) {
2901                        syslog(LOG_ERR, "command session with no payload\n");
2902                        return og_client_bad_request(cli);
2903                }
2904                err = og_cmd_session(root, &params);
2905        } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) {
2906                if (method != OG_METHOD_POST)
2907                        return og_client_method_not_found(cli);
2908
2909                if (!root) {
2910                        syslog(LOG_ERR, "command poweroff with no payload\n");
2911                        return og_client_bad_request(cli);
2912                }
2913                err = og_cmd_poweroff(root, &params);
2914        } else if (!strncmp(cmd, "reboot", strlen("reboot"))) {
2915                if (method != OG_METHOD_POST)
2916                        return og_client_method_not_found(cli);
2917
2918                if (!root) {
2919                        syslog(LOG_ERR, "command reboot with no payload\n");
2920                        return og_client_bad_request(cli);
2921                }
2922                err = og_cmd_reboot(root, &params);
2923        } else if (!strncmp(cmd, "stop", strlen("stop"))) {
2924                if (method != OG_METHOD_POST)
2925                        return og_client_method_not_found(cli);
2926
2927                if (!root) {
2928                        syslog(LOG_ERR, "command stop with no payload\n");
2929                        return og_client_bad_request(cli);
2930                }
2931                err = og_cmd_stop(root, &params);
2932        } else if (!strncmp(cmd, "refresh", strlen("refresh"))) {
2933                if (method != OG_METHOD_POST)
2934                        return og_client_method_not_found(cli);
2935
2936                if (!root) {
2937                        syslog(LOG_ERR, "command refresh with no payload\n");
2938                        return og_client_bad_request(cli);
2939                }
2940                err = og_cmd_refresh(root, &params);
2941        } else if (!strncmp(cmd, "hardware", strlen("hardware"))) {
2942                if (method != OG_METHOD_POST)
2943                        return og_client_method_not_found(cli);
2944
2945                if (!root) {
2946                        syslog(LOG_ERR, "command hardware with no payload\n");
2947                        return og_client_bad_request(cli);
2948                }
2949                err = og_cmd_hardware(root, &params);
2950        } else if (!strncmp(cmd, "software", strlen("software"))) {
2951                if (method != OG_METHOD_POST)
2952                        return og_client_method_not_found(cli);
2953
2954                if (!root) {
2955                        syslog(LOG_ERR, "command software with no payload\n");
2956                        return og_client_bad_request(cli);
2957                }
2958                err = og_cmd_software(root, &params);
2959        } else if (!strncmp(cmd, "image/create/basic",
2960                            strlen("image/create/basic"))) {
2961                if (method != OG_METHOD_POST)
2962                        return og_client_method_not_found(cli);
2963
2964                if (!root) {
2965                        syslog(LOG_ERR, "command create with no payload\n");
2966                        return og_client_bad_request(cli);
2967                }
2968                err = og_cmd_create_basic_image(root, &params);
2969        } else if (!strncmp(cmd, "image/create/incremental",
2970                            strlen("image/create/incremental"))) {
2971                if (method != OG_METHOD_POST)
2972                        return og_client_method_not_found(cli);
2973
2974                if (!root) {
2975                        syslog(LOG_ERR, "command create with no payload\n");
2976                        return og_client_bad_request(cli);
2977                }
2978                err = og_cmd_create_incremental_image(root, &params);
2979        } else if (!strncmp(cmd, "image/create", strlen("image/create"))) {
2980                if (method != OG_METHOD_POST)
2981                        return og_client_method_not_found(cli);
2982
2983                if (!root) {
2984                        syslog(LOG_ERR, "command create with no payload\n");
2985                        return og_client_bad_request(cli);
2986                }
2987                err = og_cmd_create_image(root, &params);
2988        } else if (!strncmp(cmd, "image/restore/basic",
2989                                strlen("image/restore/basic"))) {
2990                if (method != OG_METHOD_POST)
2991                        return og_client_method_not_found(cli);
2992
2993                if (!root) {
2994                        syslog(LOG_ERR, "command create with no payload\n");
2995                        return og_client_bad_request(cli);
2996                }
2997                err = og_cmd_restore_basic_image(root, &params);
2998        } else if (!strncmp(cmd, "image/restore/incremental",
2999                                strlen("image/restore/incremental"))) {
3000                if (method != OG_METHOD_POST)
3001                        return og_client_method_not_found(cli);
3002
3003                if (!root) {
3004                        syslog(LOG_ERR, "command create with no payload\n");
3005                        return og_client_bad_request(cli);
3006                }
3007                err = og_cmd_restore_incremental_image(root, &params);
3008        } else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) {
3009                if (method != OG_METHOD_POST)
3010                        return og_client_method_not_found(cli);
3011
3012                if (!root) {
3013                        syslog(LOG_ERR, "command create with no payload\n");
3014                        return og_client_bad_request(cli);
3015                }
3016                err = og_cmd_restore_image(root, &params);
3017        } else if (!strncmp(cmd, "setup", strlen("setup"))) {
3018                if (method != OG_METHOD_POST)
3019                        return og_client_method_not_found(cli);
3020
3021                if (!root) {
3022                        syslog(LOG_ERR, "command create with no payload\n");
3023                        return og_client_bad_request(cli);
3024                }
3025                err = og_cmd_setup(root, &params);
3026        } else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) {
3027                if (method != OG_METHOD_POST)
3028                        return og_client_method_not_found(cli);
3029
3030                if (!root) {
3031                        syslog(LOG_ERR, "command create with no payload\n");
3032                        return og_client_bad_request(cli);
3033                }
3034
3035                err = og_cmd_run_schedule(root, &params);
3036        } else if (!strncmp(cmd, "task/run", strlen("task/run"))) {
3037                if (method != OG_METHOD_POST)
3038                        return og_client_method_not_found(cli);
3039
3040                if (!root) {
3041                        syslog(LOG_ERR, "command task with no payload\n");
3042                        return og_client_bad_request(cli);
3043                }
3044                err = og_cmd_task_post(root, &params);
3045        } else if (!strncmp(cmd, "schedule/create",
3046                            strlen("schedule/create"))) {
3047                if (method != OG_METHOD_POST)
3048                        return og_client_method_not_found(cli);
3049
3050                if (!root) {
3051                        syslog(LOG_ERR, "command task with no payload\n");
3052                        return og_client_bad_request(cli);
3053                }
3054                err = og_cmd_schedule_create(root, &params);
3055        } else if (!strncmp(cmd, "schedule/delete",
3056                            strlen("schedule/delete"))) {
3057                if (method != OG_METHOD_POST)
3058                        return og_client_method_not_found(cli);
3059
3060                if (!root) {
3061                        syslog(LOG_ERR, "command task with no payload\n");
3062                        return og_client_bad_request(cli);
3063                }
3064                err = og_cmd_schedule_delete(root, &params);
3065        } else if (!strncmp(cmd, "schedule/update",
3066                            strlen("schedule/update"))) {
3067                if (method != OG_METHOD_POST)
3068                        return og_client_method_not_found(cli);
3069
3070                if (!root) {
3071                        syslog(LOG_ERR, "command task with no payload\n");
3072                        return og_client_bad_request(cli);
3073                }
3074                err = og_cmd_schedule_update(root, &params);
3075        } else if (!strncmp(cmd, "schedule/get",
3076                            strlen("schedule/get"))) {
3077                if (method != OG_METHOD_POST)
3078                        return og_client_method_not_found(cli);
3079
3080                err = og_cmd_schedule_get(root, &params, buf_reply);
3081        } else {
3082                syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd);
3083                err = og_client_not_found(cli);
3084        }
3085
3086        if (root)
3087                json_decref(root);
3088
3089        if (err < 0)
3090                return og_client_bad_request(cli);
3091
3092        err = og_client_ok(cli, buf_reply);
3093        if (err < 0) {
3094                syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n",
3095                       inet_ntoa(cli->addr.sin_addr),
3096                       ntohs(cli->addr.sin_port));
3097        }
3098
3099        return err;
3100}
Note: See TracBrowser for help on using the repository browser.