1 /* Copyright (C) 2020-2021 Greenbone Networks GmbH
2 *
3 * SPDX-License-Identifier: AGPL-3.0-or-later
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20 * @file manage_report_formats.c
21 * @brief GVM management layer: Report formats.
22 *
23 * Non-SQL report format code for the GVM management layer.
24 */
25
26 #include "manage_report_formats.h"
27 #include "gmp_report_formats.h"
28 #include "manage.h"
29 #include "manage_sql.h"
30 #include "manage_sql_report_formats.h"
31 #include "utils.h"
32
33 #include <assert.h>
34 #include <errno.h>
35 #include <glib.h>
36 #include <gvm/util/fileutils.h>
37 #include <locale.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #undef G_LOG_DOMAIN
42 /**
43 * @brief GLib log domain.
44 */
45 #define G_LOG_DOMAIN "md manage"
46
47 /**
48 * @brief Find a report format for a specific permission, given a UUID.
49 *
50 * @param[in] uuid UUID of report format.
51 * @param[out] report_format Report format return, 0 if successfully failed to
52 * find report_format.
53 * @param[in] permission Permission.
54 *
55 * @return FALSE on success (including if failed to find report_format), TRUE
56 * on error.
57 */
58 gboolean
find_report_format_with_permission(const char * uuid,report_format_t * report_format,const char * permission)59 find_report_format_with_permission (const char *uuid,
60 report_format_t *report_format,
61 const char *permission)
62 {
63 return find_resource_with_permission ("report_format", uuid, report_format,
64 permission, 0);
65 }
66
67 /**
68 * @brief Return whether a report format is writable.
69 *
70 * @param[in] report_format Report Format.
71 *
72 * @return 1 if writable, else 0.
73 */
74 int
report_format_writable(report_format_t report_format)75 report_format_writable (report_format_t report_format)
76 {
77 return report_format_in_use (report_format) == 0;
78 }
79
80 /**
81 * @brief Return whether a trashcan report_format is writable.
82 *
83 * @param[in] report_format Report Format.
84 *
85 * @return 1 if writable, else 0.
86 */
87 int
trash_report_format_writable(report_format_t report_format)88 trash_report_format_writable (report_format_t report_format)
89 {
90 return trash_report_format_in_use (report_format) == 0;
91 }
92
93 /**
94 * @brief Get the name of a report format param type.
95 *
96 * @param[in] type Param type.
97 *
98 * @return The name of the param type.
99 */
100 const char *
report_format_param_type_name(report_format_param_type_t type)101 report_format_param_type_name (report_format_param_type_t type)
102 {
103 switch (type)
104 {
105 case REPORT_FORMAT_PARAM_TYPE_BOOLEAN:
106 return "boolean";
107 case REPORT_FORMAT_PARAM_TYPE_INTEGER:
108 return "integer";
109 case REPORT_FORMAT_PARAM_TYPE_SELECTION:
110 return "selection";
111 case REPORT_FORMAT_PARAM_TYPE_STRING:
112 return "string";
113 case REPORT_FORMAT_PARAM_TYPE_TEXT:
114 return "text";
115 case REPORT_FORMAT_PARAM_TYPE_REPORT_FORMAT_LIST:
116 return "report_format_list";
117 default:
118 assert (0);
119 case REPORT_FORMAT_PARAM_TYPE_ERROR:
120 return "ERROR";
121 }
122 }
123
124 /**
125 * @brief Get a report format param type from a name.
126 *
127 * @param[in] name Param type name.
128 *
129 * @return The param type.
130 */
131 report_format_param_type_t
report_format_param_type_from_name(const char * name)132 report_format_param_type_from_name (const char *name)
133 {
134 if (strcmp (name, "boolean") == 0)
135 return REPORT_FORMAT_PARAM_TYPE_BOOLEAN;
136 if (strcmp (name, "integer") == 0)
137 return REPORT_FORMAT_PARAM_TYPE_INTEGER;
138 if (strcmp (name, "selection") == 0)
139 return REPORT_FORMAT_PARAM_TYPE_SELECTION;
140 if (strcmp (name, "string") == 0)
141 return REPORT_FORMAT_PARAM_TYPE_STRING;
142 if (strcmp (name, "text") == 0)
143 return REPORT_FORMAT_PARAM_TYPE_TEXT;
144 if (strcmp (name, "report_format_list") == 0)
145 return REPORT_FORMAT_PARAM_TYPE_REPORT_FORMAT_LIST;
146 return REPORT_FORMAT_PARAM_TYPE_ERROR;
147 }
148
149 /**
150 * @brief Return whether a name is a backup file name.
151 *
152 * @param[in] name Name.
153 *
154 * @return 0 if normal file name, 1 if backup file name.
155 */
156 static int
backup_file_name(const char * name)157 backup_file_name (const char *name)
158 {
159 int length = strlen (name);
160
161 if (length && (name[length - 1] == '~'))
162 return 1;
163
164 if ((length > 3)
165 && (name[length - 4] == '.'))
166 return ((name[length - 3] == 'b')
167 && (name[length - 2] == 'a')
168 && (name[length - 1] == 'k'))
169 || ((name[length - 3] == 'B')
170 && (name[length - 2] == 'A')
171 && (name[length - 1] == 'K'))
172 || ((name[length - 3] == 'C')
173 && (name[length - 2] == 'K')
174 && (name[length - 1] == 'P'));
175
176 return 0;
177 }
178
179 /**
180 * @brief Get files associated with a report format.
181 *
182 * @param[in] dir_name Location of files.
183 * @param[out] start Files on success.
184 *
185 * @return 0 if successful, -1 otherwise.
186 */
187 static int
get_report_format_files(const char * dir_name,GPtrArray ** start)188 get_report_format_files (const char *dir_name, GPtrArray **start)
189 {
190 GPtrArray *files;
191 struct dirent **names;
192 int n, index;
193 char *locale;
194
195 files = g_ptr_array_new ();
196
197 locale = setlocale (LC_ALL, "C");
198 n = scandir (dir_name, &names, NULL, alphasort);
199 setlocale (LC_ALL, locale);
200 if (n < 0)
201 {
202 g_warning ("%s: failed to open dir %s: %s",
203 __func__,
204 dir_name,
205 strerror (errno));
206 return -1;
207 }
208
209 for (index = 0; index < n; index++)
210 {
211 if (strcmp (names[index]->d_name, ".")
212 && strcmp (names[index]->d_name, "..")
213 && (backup_file_name (names[index]->d_name) == 0))
214 g_ptr_array_add (files, g_strdup (names[index]->d_name));
215 free (names[index]);
216 }
217 free (names);
218
219 g_ptr_array_add (files, NULL);
220
221 *start = files;
222 return 0;
223 }
224
225 /**
226 * @brief Initialise a report format file iterator.
227 *
228 * @param[in] iterator Iterator.
229 * @param[in] report_format Single report format to iterate over, NULL for
230 * all.
231 *
232 * @return 0 on success, -1 on error.
233 */
234 int
init_report_format_file_iterator(file_iterator_t * iterator,report_format_t report_format)235 init_report_format_file_iterator (file_iterator_t* iterator,
236 report_format_t report_format)
237 {
238 gchar *dir_name, *uuid, *owner_uuid;
239
240 uuid = report_format_uuid (report_format);
241 if (uuid == NULL)
242 return -1;
243
244 owner_uuid = report_format_owner_uuid (report_format);
245 if (owner_uuid == NULL)
246 return -1;
247 dir_name = g_build_filename (GVMD_STATE_DIR,
248 "report_formats",
249 owner_uuid,
250 uuid,
251 NULL);
252 g_free (owner_uuid);
253 g_free (uuid);
254
255 if (get_report_format_files (dir_name, &iterator->start))
256 {
257 g_free (dir_name);
258 return -1;
259 }
260
261 iterator->current = iterator->start->pdata;
262 iterator->current--;
263 iterator->dir_name = dir_name;
264 return 0;
265 }
266
267 /**
268 * @brief Cleanup a report type iterator.
269 *
270 * @param[in] iterator Iterator.
271 */
272 void
cleanup_file_iterator(file_iterator_t * iterator)273 cleanup_file_iterator (file_iterator_t* iterator)
274 {
275 array_free (iterator->start);
276 g_free (iterator->dir_name);
277 }
278
279 /**
280 * @brief Increment a report type iterator.
281 *
282 * The caller must stop using this after it returns FALSE.
283 *
284 * @param[in] iterator Task iterator.
285 *
286 * @return TRUE if there was a next item, else FALSE.
287 */
288 gboolean
next_file(file_iterator_t * iterator)289 next_file (file_iterator_t* iterator)
290 {
291 iterator->current++;
292 if (*iterator->current == NULL) return FALSE;
293 return TRUE;
294 }
295
296 /**
297 * @brief Return the name from a file iterator.
298 *
299 * @param[in] iterator Iterator.
300 *
301 * @return File name.
302 */
303 const char*
file_iterator_name(file_iterator_t * iterator)304 file_iterator_name (file_iterator_t* iterator)
305 {
306 return (const char*) *iterator->current;
307 }
308
309 /**
310 * @brief Return the file contents from a file iterator.
311 *
312 * @param[in] iterator Iterator.
313 *
314 * @return Freshly allocated file contents, in base64.
315 */
316 gchar*
file_iterator_content_64(file_iterator_t * iterator)317 file_iterator_content_64 (file_iterator_t* iterator)
318 {
319 gchar *path_name, *content;
320 GError *error;
321 gsize content_size;
322
323 path_name = g_build_filename (iterator->dir_name,
324 (gchar*) *iterator->current,
325 NULL);
326
327 /* Read in the contents. */
328
329 error = NULL;
330 if (g_file_get_contents (path_name,
331 &content,
332 &content_size,
333 &error)
334 == FALSE)
335 {
336 if (error)
337 {
338 g_debug ("%s: failed to read %s: %s",
339 __func__, path_name, error->message);
340 g_error_free (error);
341 }
342 g_free (path_name);
343 return NULL;
344 }
345
346 g_free (path_name);
347
348 /* Base64 encode the contents. */
349
350 if (content && (content_size > 0))
351 {
352 gchar *base64 = g_base64_encode ((guchar*) content, content_size);
353 g_free (content);
354 return base64;
355 }
356
357 return content;
358 }
359
360
361 /* Feed report formats. */
362
363 /**
364 * @brief Get path to report formats in feed.
365 *
366 * @return Path to report formats in feed.
367 */
368 static const gchar *
feed_dir_report_formats()369 feed_dir_report_formats ()
370 {
371 static gchar *path = NULL;
372 if (path == NULL)
373 path = g_build_filename (GVMD_FEED_DIR,
374 GMP_VERSION_FEED,
375 "report_formats",
376 NULL);
377 return path;
378 }
379
380 /**
381 * @brief Create a report format from an XML file.
382 *
383 * @param[in] report_format Existing report format.
384 * @param[in] path Full path to report format XML.
385 *
386 * @return 0 success, -1 error.
387 */
388 static int
update_report_format_from_file(report_format_t report_format,const gchar * path)389 update_report_format_from_file (report_format_t report_format,
390 const gchar *path)
391 {
392 entity_t entity;
393 array_t *files, *params, *params_options;
394 char *name, *content_type, *extension, *summary, *description, *signature;
395 const char *report_format_id;
396
397 g_debug ("%s: updating %s", __func__, path);
398
399 /* Parse the file into an entity. */
400
401 if (parse_xml_file (path, &entity))
402 return 1;
403
404 /* Parse the data out of the entity. */
405
406 parse_report_format_entity (entity, &report_format_id, &name,
407 &content_type, &extension, &summary,
408 &description, &signature, &files, ¶ms,
409 ¶ms_options);
410
411 /* Update the report format. */
412
413 update_report_format (report_format, report_format_id, name, content_type,
414 extension, summary, description, signature, files,
415 params, params_options);
416
417 /* Cleanup. */
418
419 array_free (files);
420 params_options_free (params_options);
421 array_free (params);
422 free_entity (entity);
423
424 return 0;
425 }
426
427 /**
428 * @brief Grant 'Feed Import Roles' access to a report format.
429 *
430 * @param[in] report_format_id UUID of report format.
431 */
432 static void
create_feed_report_format_permissions(const gchar * report_format_id)433 create_feed_report_format_permissions (const gchar *report_format_id)
434 {
435 gchar *roles, **split, **point;
436
437 setting_value (SETTING_UUID_FEED_IMPORT_ROLES, &roles);
438
439 if (roles == NULL || strlen (roles) == 0)
440 {
441 g_debug ("%s: no 'Feed Import Roles', so not creating permissions",
442 __func__);
443 g_free (roles);
444 return;
445 }
446
447 point = split = g_strsplit (roles, ",", 0);
448 while (*point)
449 {
450 permission_t permission;
451
452 if (create_permission_no_acl ("get_report_formats",
453 "Automatically created for report format"
454 " from feed",
455 NULL,
456 report_format_id,
457 "role",
458 g_strstrip (*point),
459 &permission))
460 /* Keep going because we aren't strict about checking the value
461 * of the setting, and because we don't adjust the setting when
462 * roles are removed. */
463 g_warning ("%s: failed to create permission for role '%s'",
464 __func__, g_strstrip (*point));
465
466 point++;
467 }
468 g_strfreev (split);
469
470 g_free (roles);
471 }
472
473 /**
474 * @brief Create a report format from an XML file.
475 *
476 * @param[in] path Path to report format XML.
477 *
478 * @return 0 success, -1 error.
479 */
480 static int
create_report_format_from_file(const gchar * path)481 create_report_format_from_file (const gchar *path)
482 {
483 entity_t report_format;
484 array_t *files, *params, *params_options;
485 char *name, *content_type, *extension, *summary, *description, *signature;
486 const char *report_format_id;
487 report_format_t new_report_format;
488
489 g_debug ("%s: creating %s", __func__, path);
490
491 /* Parse the file into an entity. */
492
493 if (parse_xml_file (path, &report_format))
494 return 1;
495
496 /* Parse the data out of the entity. */
497
498 parse_report_format_entity (report_format, &report_format_id, &name,
499 &content_type, &extension, &summary,
500 &description, &signature, &files, ¶ms,
501 ¶ms_options);
502
503 /* Create the report format. */
504
505 switch (create_report_format_no_acl (report_format_id,
506 name,
507 content_type,
508 extension,
509 summary,
510 description,
511 files,
512 params,
513 params_options,
514 signature,
515 1,
516 &new_report_format))
517 {
518 case 0:
519 {
520 gchar *uuid;
521
522 uuid = report_format_uuid (new_report_format);
523 log_event ("report_format", "Report format", uuid, "created");
524
525 /* Create permissions. */
526 create_feed_report_format_permissions (uuid);
527
528 g_free (uuid);
529 break;
530 }
531 case 1:
532 g_warning ("%s: Report Format exists already", __func__);
533 log_event_fail ("report_format", "Report format", NULL, "created");
534 break;
535 case 2:
536 g_warning ("%s: Every FILE must have a name attribute", __func__);
537 log_event_fail ("report_format", "Report Format", NULL,
538 "created");
539 break;
540 case 3:
541 g_warning ("%s: Parameter value validation failed", __func__);
542 log_event_fail ("report_format", "Report Format", NULL,
543 "created");
544 break;
545 case 4:
546 g_warning ("%s: Parameter default validation failed", __func__);
547 log_event_fail ("report_format", "Report Format", NULL,
548 "created");
549 break;
550 case 5:
551 g_warning ("%s: PARAM requires a DEFAULT element", __func__);
552 log_event_fail ("report_format", "Report Format", NULL,
553 "created");
554 break;
555 case 6:
556 g_warning ("%s: PARAM MIN or MAX out of range", __func__);
557 log_event_fail ("report_format", "Report Format", NULL,
558 "created");
559 break;
560 case 7:
561 g_warning ("%s: PARAM requires a TYPE element", __func__);
562 log_event_fail ("report_format", "Report Format", NULL,
563 "created");
564 break;
565 case 8:
566 g_warning ("%s: Duplicate PARAM name", __func__);
567 log_event_fail ("report_format", "Report Format", NULL,
568 "created");
569 break;
570 case 9:
571 g_warning ("%s: Bogus PARAM type", __func__);
572 log_event_fail ("report_format", "Report Format", NULL,
573 "created");
574 break;
575 case 99:
576 g_warning ("%s: Permission denied", __func__);
577 log_event_fail ("report_format", "Report format", NULL, "created");
578 break;
579 default:
580 case -1:
581 g_warning ("%s: Internal error", __func__);
582 log_event_fail ("report_format", "Report format", NULL, "created");
583 break;
584 }
585
586 /* Cleanup. */
587
588 array_free (files);
589 params_options_free (params_options);
590 array_free (params);
591 free_entity (report_format);
592
593 return 0;
594 }
595
596 /**
597 * @brief Gets if a report format must be synced to a file path in the feed.
598 *
599 * @param[in] path Path to report format XML in feed.
600 * @param[in] rebuild Whether ignore timestamps to force a rebuild.
601 * @param[out] report_format Report format id if it already exists, 0 if new.
602 *
603 * @return 1 if report format should be synced, 0 otherwise
604 */
605 static int
should_sync_report_format_from_path(const char * path,gboolean rebuild,report_format_t * report_format)606 should_sync_report_format_from_path (const char *path,
607 gboolean rebuild,
608 report_format_t *report_format)
609 {
610 gchar **split, *full_path, *uuid;
611
612 *report_format = 0;
613
614 split = g_regex_split_simple
615 (/* Full-and-Fast--daba56c8-73ec-11df-a475-002264764cea.xml */
616 "^.*([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12}).xml$",
617 path, 0, 0);
618
619 if (split == NULL || g_strv_length (split) != 7)
620 {
621 g_strfreev (split);
622 g_warning ("%s: path not in required format: %s", __func__, path);
623 return 0;
624 }
625
626 uuid = g_strdup_printf ("%s-%s-%s-%s-%s",
627 split[1], split[2], split[3], split[4], split[5]);
628 g_strfreev (split);
629 if (find_report_format_no_acl (uuid, report_format) == 0
630 && *report_format)
631 {
632 if (rebuild)
633 return 1;
634
635 full_path = g_build_filename (feed_dir_report_formats (), path, NULL);
636
637 g_free (uuid);
638
639 g_debug ("%s: considering %s for update", __func__, path);
640
641 if (report_format_updated_in_feed (*report_format, full_path))
642 {
643 return 1;
644 }
645
646 g_free (full_path);
647 return 0;
648 }
649
650 if (find_trash_report_format_no_acl (uuid, report_format) == 0
651 && *report_format)
652 {
653 g_free (uuid);
654 *report_format = 0;
655 return 0;
656 }
657
658 g_free (uuid);
659 *report_format = 0;
660 return 1;
661 }
662
663 /**
664 * @brief Sync a single report format with the feed.
665 *
666 * @param[in] path Path to report format XML in feed.
667 * @param[in] rebuild Whether ignore timestamps to force a rebuild.
668 */
669 static void
sync_report_format_with_feed(const gchar * path,gboolean rebuild)670 sync_report_format_with_feed (const gchar *path, gboolean rebuild)
671 {
672 report_format_t report_format;
673
674 g_debug ("%s: considering %s", __func__, path);
675
676 if (should_sync_report_format_from_path (path, rebuild, &report_format))
677 {
678 gchar *full_path;
679 full_path = g_build_filename (feed_dir_report_formats (), path, NULL);
680 switch (report_format)
681 {
682 case 0:
683 g_debug ("%s: adding %s", __func__, path);
684 create_report_format_from_file (full_path);
685 break;
686 default:
687 g_debug ("%s: updating %s", __func__, path);
688 update_report_format_from_file (report_format, full_path);
689 }
690 g_free (full_path);
691 }
692 }
693
694 /**
695 * @brief Open the report formats feed directory if it is available and the
696 * feed owner is set.
697 * Optionally set the current user to the feed owner on success.
698 *
699 * The sync will be skipped if the feed directory does not exist or
700 * the feed owner is not set.
701 *
702 * @param[out] dir The directory as GDir if available and feed owner is set,
703 * NULL otherwise.
704 * @param[in] set_current_user Whether to set current user to feed owner.
705 *
706 * @return 0 success, 1 no feed directory, 2 no feed owner, -1 error.
707 */
708 static int
try_open_report_formats_feed_dir(GDir ** dir,gboolean set_current_user)709 try_open_report_formats_feed_dir (GDir **dir, gboolean set_current_user)
710 {
711 char *feed_owner_uuid, *feed_owner_name;
712 GError *error;
713
714 /* Test if base feed directory exists */
715
716 if (report_formats_feed_dir_exists () == FALSE)
717 return 1;
718
719 /* Setup owner. */
720
721 setting_value (SETTING_UUID_FEED_IMPORT_OWNER, &feed_owner_uuid);
722
723 if (feed_owner_uuid == NULL
724 || strlen (feed_owner_uuid) == 0)
725 {
726 /* Sync is disabled by having no "Feed Import Owner". */
727 g_debug ("%s: no Feed Import Owner so not syncing from feed", __func__);
728 return 2;
729 }
730
731 feed_owner_name = user_name (feed_owner_uuid);
732 if (feed_owner_name == NULL)
733 {
734 g_debug ("%s: unknown Feed Import Owner so not syncing from feed",
735 __func__);
736 return 2;
737 }
738
739 /* Open feed import directory. */
740
741 error = NULL;
742 *dir = g_dir_open (feed_dir_report_formats (), 0, &error);
743 if (*dir == NULL)
744 {
745 g_warning ("%s: Failed to open directory '%s': %s",
746 __func__, feed_dir_report_formats (), error->message);
747 g_error_free (error);
748 free (feed_owner_uuid);
749 free (feed_owner_name);
750 return -1;
751 }
752
753 if (set_current_user)
754 {
755 current_credentials.uuid = feed_owner_uuid;
756 current_credentials.username = feed_owner_name;
757 }
758 else
759 {
760 free (feed_owner_uuid);
761 free (feed_owner_name);
762 }
763
764 return 0;
765 }
766
767 /**
768 * @brief Sync all report formats with the feed.
769 *
770 * Create report formats that exists in the feed but not in the db.
771 * Update report formats in the db that have changed on the feed.
772 * Do nothing to report formats in db that have been removed from the feed.
773 *
774 * @param[in] rebuild Whether ignore timestamps to force a rebuild.
775 *
776 * @return 0 success, 1 no feed directory, 2 no feed owner, -1 error.
777 */
778 int
sync_report_formats_with_feed(gboolean rebuild)779 sync_report_formats_with_feed (gboolean rebuild)
780 {
781 int ret;
782 GDir *dir;
783 const gchar *report_format_path;
784
785 ret = try_open_report_formats_feed_dir (&dir, TRUE);
786 switch (ret)
787 {
788 case 0:
789 // Successfully opened directory
790 break;
791 default:
792 return ret;
793 }
794
795 /* Sync each file in the directory. */
796
797 while ((report_format_path = g_dir_read_name (dir)))
798 if (g_str_has_prefix (report_format_path, ".") == 0
799 && strlen (report_format_path) >= (36 /* UUID */ + strlen (".xml"))
800 && g_str_has_suffix (report_format_path, ".xml"))
801 sync_report_format_with_feed (report_format_path, rebuild);
802
803 /* Cleanup. */
804
805 g_dir_close (dir);
806 g_free (current_credentials.uuid);
807 g_free (current_credentials.username);
808 current_credentials.uuid = NULL;
809 current_credentials.username = NULL;
810
811 return 0;
812 }
813
814 /**
815 * @brief Tests if the report formats feed directory exists.
816 *
817 * @return TRUE if the directory exists.
818 */
819 gboolean
report_formats_feed_dir_exists()820 report_formats_feed_dir_exists ()
821 {
822 return gvm_file_is_readable (feed_dir_report_formats ());
823 }
824
825 /**
826 * @brief Sync report formats with the feed.
827 */
828 void
manage_sync_report_formats()829 manage_sync_report_formats ()
830 {
831 sync_report_formats_with_feed (FALSE);
832 }
833
834 /**
835 * @brief Rebuild port lists from the feed.
836 *
837 * @return 0 success, 1 no feed directory, 2 no feed owner, -1 error.
838 */
839 int
manage_rebuild_report_formats()840 manage_rebuild_report_formats ()
841 {
842 return sync_report_formats_with_feed (TRUE);
843 }
844
845 /**
846 * @brief Checks if the report formats should be synced with the feed.
847 *
848 * @return 1 if report formats should be synced, 0 otherwise
849 */
850 gboolean
should_sync_report_formats()851 should_sync_report_formats ()
852 {
853 GDir *dir;
854 const gchar *report_format_path;
855 report_format_t report_format;
856
857 if (try_open_report_formats_feed_dir (&dir, FALSE))
858 return FALSE;
859
860 while ((report_format_path = g_dir_read_name (dir)))
861 if (g_str_has_prefix (report_format_path, ".") == 0
862 && strlen (report_format_path) >= (36 /* UUID */ + strlen (".xml"))
863 && g_str_has_suffix (report_format_path, ".xml")
864 && should_sync_report_format_from_path (report_format_path,
865 FALSE,
866 &report_format))
867 return TRUE;
868
869 return FALSE;
870 }