aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-07-14 06:55:18 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-14 06:55:18 +0200
commit94c45e3c4d185b3f0d70f0d2d761b72c6561e1b5 (patch)
tree7c3c06987f82f726422bda9e5de86172f60c3065
parenta15d7ad07a5865f2f51e85d5e4e049922c50deec (diff)
Implement add_html
-rwxr-xr-xbuild.sh9
-rw-r--r--src/fileutils.c3
-rw-r--r--src/html.c264
-rw-r--r--src/html.h6
-rw-r--r--src/main.c18
-rw-r--r--src/program.c175
-rw-r--r--src/program.h5
-rw-r--r--src/rss.c174
-rw-r--r--src/rss_html_common.c158
-rw-r--r--src/rss_html_common.h6
10 files changed, 605 insertions, 213 deletions
diff --git a/build.sh b/build.sh
index 1db2702..9ecbe97 100755
--- a/build.sh
+++ b/build.sh
@@ -1,8 +1,5 @@
#!/bin/sh
-CFLAGS="-O0 -g3 -Wall -Wextra -Werror"
-#CFLAGS="-O3 -s -flto"
-#LIBS="-lcurl"
-LIBS=""
-#gcc
-musl-gcc -static src/main.c src/program.c src/alloc.c src/buffer.c src/fileutils.c src/transmission.c src/rss.c src/download.c src/stringutils.c -o automedia $CFLAGS $LIBS
+CFLAGS="-O3 -s -flto"
+[ -z "$RELEASE" ] && CFLAGS="-O0 -g3 -Wall -Wextra -Werror";
+musl-gcc -static src/main.c src/program.c src/alloc.c src/buffer.c src/fileutils.c src/transmission.c src/rss.c src/html.c src/rss_html_common.c src/download.c src/stringutils.c -o automedia $CFLAGS
diff --git a/src/fileutils.c b/src/fileutils.c
index fe9ab88..64c7a48 100644
--- a/src/fileutils.c
+++ b/src/fileutils.c
@@ -83,8 +83,7 @@ int create_directory_recursive(char *path) {
}
int file_exists(const char *path) {
- struct stat st;
- return stat(path, &st);
+ return access(path, F_OK);
}
int create_lock_file(const char *path) {
diff --git a/src/html.c b/src/html.c
new file mode 100644
index 0000000..de888a0
--- /dev/null
+++ b/src/html.c
@@ -0,0 +1,264 @@
+#include "html.h"
+#include "fileutils.h"
+#include "program.h"
+#include "buffer.h"
+#include "stringutils.h"
+#include "rss_html_common.h"
+#include "json.h"
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <signal.h>
+#include <time.h>
+
+static int str_starts_with(const char *str, int len, const char *substr, int substr_len) {
+ return len >= substr_len && memcmp(str, substr, substr_len) == 0;
+}
+
+static int url_extract_domain(const char *url, char *domain, int domain_len) {
+ int url_len = strlen(url);
+ if(str_starts_with(url, url_len, "http://", 7)) {
+ url += 7;
+ url_len -= 7;
+ } else if(str_starts_with(url, url_len, "https://", 8)) {
+ url += 8;
+ url_len -= 8;
+ }
+
+ if(str_starts_with(url, url_len, "www.", 4)) {
+ url += 4;
+ url_len -= 4;
+ }
+
+ char *end = strchr(url, '.');
+ if(end) {
+ int len = end - url;
+ if(len >= domain_len)
+ return -1;
+ memcpy(domain, url, len);
+ domain[len] = '\0';
+ } else {
+ if(url_len >= domain_len)
+ return -1;
+ memcpy(domain, url, url_len);
+ domain[url_len] = '\0';
+ }
+ return 0;
+}
+
+static struct json_value_s* json_object_get_field_by_name(struct json_object_s *json_obj, const char *name) {
+ struct json_object_element_s *obj_element = json_obj->start;
+ while(obj_element) {
+ if(strcmp(obj_element->name->string, name) == 0)
+ return obj_element->value;
+ obj_element = obj_element->next;
+ }
+ return NULL;
+}
+
+typedef int (*PluginListCallback)(const char *name, const char *url, void *userdata);
+static struct json_value_s* plugin_list(char *plugin_filepath, const char *url, const char *latest, PluginListCallback callback, void *userdata) {
+ (void)latest;
+ int result;
+ Buffer buffer;
+ buffer_init(&buffer);
+
+ const char *args[] = { plugin_filepath, "list", url, NULL };
+ int process_id = -1;
+ int stdin_file = -1;
+ int stdout_file = -1;
+ result = program_exec_async(args, &process_id, &stdin_file, &stdout_file);
+ if(result != 0) {
+ fprintf(stderr, "Failed to launch plugin list for plugin %s\n", basename(plugin_filepath));
+ goto err_cleanup;
+ }
+
+ result = program_wait_until_exit(process_id, stdin_file, stdout_file, program_buffer_write_callback, &buffer);
+ if(result != 0) {
+ fprintf(stderr, "Failed to launch plugin list for plugin %s\n", basename(plugin_filepath));
+ goto err_cleanup;
+ }
+
+ /*fprintf(stderr, "plugin list: %s\n", (char*)buffer.data);*/
+
+ struct json_value_s *json_root = json_parse(buffer.data, buffer.size);
+ if(!json_root) {
+ fprintf(stderr, "Failed to load plugin %s list output as json\n", basename(plugin_filepath));
+ goto err_cleanup;
+ }
+
+ struct json_array_s *json_root_array = json_value_as_array(json_root);
+ if(!json_root_array) {
+ fprintf(stderr, "Failed to load plugin %s list output as json\n", basename(plugin_filepath));
+ free(json_root);
+ goto err_cleanup;
+ }
+
+ struct json_array_element_s *json_array_element = json_root_array->start;
+ for(; json_array_element; json_array_element = json_array_element->next) {
+ struct json_object_s *array_element_value = json_value_as_object(json_array_element->value);
+ if(!array_element_value)
+ continue;
+
+ struct json_value_s *name_json = json_object_get_field_by_name(array_element_value, "name");
+ struct json_value_s *url_json = json_object_get_field_by_name(array_element_value, "url");
+ struct json_string_s *name_json_str = json_value_as_string(name_json);
+ struct json_string_s *url_json_str = json_value_as_string(url_json);
+ if(!name_json_str || !url_json_str)
+ continue;
+
+ /* Cast from const to mutable variable because I can */
+ char *name = (char*)name_json_str->string;
+ string_replace(name, '/', '_');
+ name = strip(name);
+ if(callback(name, url_json_str->string, userdata) != 0)
+ break;
+ }
+
+ buffer_deinit(&buffer);
+ return json_root;
+
+ err_cleanup:
+ buffer_deinit(&buffer);
+ return NULL;
+}
+
+typedef struct {
+ const char *start_after;
+ int found_start_after;
+ const char *start_after_url;
+} PluginListUserdata;
+
+static int plugin_list_callback(const char *name, const char *url, void *userdata) {
+ /*fprintf(stderr, "name: |%s|, url: |%s|\n", name, url);*/
+ PluginListUserdata *plugin_list_userdata = userdata;
+ if(plugin_list_userdata->start_after && strcmp(plugin_list_userdata->start_after, name) == 0) {
+ plugin_list_userdata->found_start_after = 1;
+ plugin_list_userdata->start_after_url = url;
+ return 1;
+ }
+ return 0;
+}
+
+int add_html(const char *name, const char *url, char *html_config_dir, char *program_dir, const char *start_after) {
+ int result = 0;
+
+ if(!name || name[0] == '\0') {
+ fprintf(stderr, "Name not provided or empty\n");
+ return -1;
+ }
+
+ char domain[2086];
+ if(url_extract_domain(url, domain, sizeof(domain)) != 0) {
+ fprintf(stderr, "Url %s is too long\n", url);
+ return -1;
+ }
+
+ if(domain[0] == '\0') {
+ fprintf(stderr, "Invalid url: %s\n", url);
+ return -1;
+ }
+
+ const char *path_components[] = { program_dir, "plugins" };
+ char domain_plugin_path[PATH_MAX];
+ path_join(domain_plugin_path, path_components, 2);
+ if(file_exists(domain_plugin_path) != 0) {
+ strcpy(domain_plugin_path, "/usr/share/automedia/plugins");
+ if(file_exists(domain_plugin_path) != 0) {
+ fprintf(stderr, "Failed to find plugins directory\n");
+ return -1;
+ }
+ }
+
+ strcat(domain_plugin_path, "/");
+ strcat(domain_plugin_path, domain);
+ if(file_exists(domain_plugin_path) != 0) {
+ strcat(domain_plugin_path, ".py");
+ if(file_exists(domain_plugin_path) != 0) {
+ fprintf(stderr, "Plugin doesn't exist: %s\n", domain);
+ return -1;
+ }
+ }
+
+ PluginListUserdata plugin_list_userdata;
+ plugin_list_userdata.start_after = start_after;
+ plugin_list_userdata.found_start_after = 0;
+ plugin_list_userdata.start_after_url = NULL;
+
+ struct json_value_s *json_root = plugin_list(domain_plugin_path, url, NULL, plugin_list_callback, &plugin_list_userdata);
+ if(!json_root)
+ return -1;
+
+ if(start_after && !plugin_list_userdata.found_start_after) {
+ fprintf(stderr, "Failed to find %s in html %s\n", start_after, url);
+ result = -1;
+ goto cleanup;
+ }
+
+ char *html_tracked_dir = html_config_dir;
+ strcat(html_tracked_dir, "/tracked/");
+ strcat(html_tracked_dir, name);
+
+ if(file_exists(html_tracked_dir) == 0) {
+ fprintf(stderr, "You are already tracking %s\n", url);
+ result = -1;
+ goto cleanup;
+ }
+
+ result = create_directory_recursive(html_tracked_dir);
+ if(result != 0) {
+ fprintf(stderr, "Failed to create %s, error: %s\n", html_tracked_dir, strerror(result));
+ goto cleanup;
+ }
+
+ /*
+ Create an ".in_progress" file to prevent periodic sync from reading rss data
+ before we have finished adding all the data.
+ */
+ char in_progress_filepath[PATH_MAX];
+ strcpy(in_progress_filepath, html_tracked_dir);
+ strcat(in_progress_filepath, "/.in_progress");
+ result = create_lock_file(in_progress_filepath);
+ if(result != 0) {
+ fprintf(stderr, "Failed to create %s/.in_progress\n", html_tracked_dir);
+ goto cleanup;
+ }
+
+ result = file_overwrite_in_dir(html_tracked_dir, "link", url, strlen(url));
+ if(result != 0) {
+ fprintf(stderr, "Failed to create %s/link\n", html_tracked_dir);
+ remove(html_tracked_dir);
+ goto cleanup;
+ }
+
+ char *plugin_name = basename(domain_plugin_path);
+ result = file_overwrite_in_dir(html_tracked_dir, "plugin", plugin_name, strlen(plugin_name));
+ if(result != 0) {
+ fprintf(stderr, "Failed to create %s/link\n", html_tracked_dir);
+ remove(html_tracked_dir);
+ goto cleanup;
+ }
+
+ char updated[32];
+ sprintf(updated, "%ld", time(NULL));
+ result = file_overwrite_in_dir(html_tracked_dir, "updated", updated, strlen(updated));
+ if(result != 0) {
+ fprintf(stderr, "Failed to create %s/updated\n", html_tracked_dir);
+ remove(html_tracked_dir);
+ goto cleanup;
+ }
+
+ result = write_plugin_json_to_file(html_tracked_dir, "data", url, updated, start_after, plugin_list_userdata.start_after_url, plugin_name);
+ if(result != 0) {
+ fprintf(stderr, "Failed to create %s/data\n", html_tracked_dir);
+ remove(html_tracked_dir);
+ goto cleanup;
+ }
+
+ remove(in_progress_filepath);
+
+ cleanup:
+ free(json_root);
+ return result;
+}
diff --git a/src/html.h b/src/html.h
new file mode 100644
index 0000000..02c0f7b
--- /dev/null
+++ b/src/html.h
@@ -0,0 +1,6 @@
+#ifndef HTML_H
+#define HTML_H
+
+int add_html(const char *name, const char *url, char *html_config_dir, char *program_dir, const char *start_after);
+
+#endif
diff --git a/src/main.c b/src/main.c
index 11b2a5d..bc554b5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,6 +4,7 @@
#include "fileutils.h"
#include "stringutils.h"
#include "rss.h"
+#include "html.h"
#include "json.h"
#include <stdio.h>
@@ -12,6 +13,7 @@
#include <limits.h>
#include <dirent.h>
+#include <libgen.h>
#define NAME_MAX_LEN 250
@@ -136,8 +138,7 @@ static void data_file_get_downloaded(const char *dir_name, const char *data_file
}
cleanup:
- if(json_root)
- free(json_root);
+ free(json_root);
free(file_data);
}
@@ -185,7 +186,7 @@ static int compare_downloaded_item(const void *a, const void *b) {
return list_data_a->timestamp - list_data_b->timestamp;
}
-static void command_add(int argc, char **argv, char *rss_config_dir, char *html_config_dir) {
+static void command_add(int argc, char **argv, char *rss_config_dir, char *html_config_dir, char *program_dir) {
if(argc < 2)
usage_add();
@@ -246,7 +247,14 @@ static void command_add(int argc, char **argv, char *rss_config_dir, char *html_
if(add_rss(media_name, media_url, rss_config_dir, start_after) != 0)
exit(1);
} else if(strcmp(media_type, "html") == 0) {
- (void)html_config_dir;
+ int res = create_directory_recursive(html_config_dir);
+ if(res != 0) {
+ fprintf(stderr, "Failed to create %s, error: %s\n", html_config_dir, strerror(res));
+ exit(1);
+ }
+
+ if(add_html(media_name, media_url, html_config_dir, program_dir, start_after) != 0)
+ exit(1);
} else {
fprintf(stderr, "type should be either rss or html\n");
usage_add();
@@ -307,7 +315,7 @@ int main(int argc, char **argv) {
const char *command = argv[1];
if(strcmp(command, "add") == 0) {
- command_add(argc - 2, argv + 2, rss_config_dir, html_config_dir);
+ command_add(argc - 2, argv + 2, rss_config_dir, html_config_dir, dirname(argv[0]));
} else if(strcmp(command, "sync") == 0) {
command_sync(argc - 2, argv + 2);
} else if(strcmp(command, "downloaded") == 0) {
diff --git a/src/program.c b/src/program.c
index c396695..6150616 100644
--- a/src/program.c
+++ b/src/program.c
@@ -18,8 +18,42 @@ int program_buffer_write_callback(char *data, int size, void *userdata) {
return 0;
}
+static int program_read_output(int process_id, int read_fd, ProgramOutputCallback output_callback, void *userdata) {
+ int status;
+ char buffer[4097];
+
+ for(;;) {
+ ssize_t bytes_read = read(read_fd, buffer, sizeof(buffer) - 1);
+ if(bytes_read == 0) {
+ break;
+ } else if(bytes_read == -1) {
+ int err = errno;
+ fprintf(stderr, "Failed to read from pipe, error: %s\n", strerror(err));
+ return -err;
+ }
+
+ buffer[bytes_read] = '\0';
+ if(output_callback && output_callback(buffer, bytes_read, userdata) != 0)
+ break;
+ }
+
+ if(waitpid(process_id, &status, 0) == -1) {
+ perror("waitpid failed");
+ return -5;
+ }
+
+ if(!WIFEXITED(status))
+ return -4;
+
+ int exit_status = WEXITSTATUS(status);
+ if(exit_status != 0)
+ return -exit_status;
+
+ return 0;
+}
+
int program_exec(const char **args, ProgramOutputCallback output_callback, void *userdata) {
- /* 1 arguments */
+ /* 1 argument */
if(args[0] == NULL)
return -1;
@@ -34,6 +68,8 @@ int program_exec(const char **args, ProgramOutputCallback output_callback, void
pid_t pid = fork();
if(pid == -1) {
perror("Failed to fork");
+ close(fd[READ_END]);
+ close(fd[WRITE_END]);
return -3;
} else if(pid == 0) { /* child */
if(prctl(PR_SET_PDEATHSIG, SIGTERM) == -1) {
@@ -55,42 +91,8 @@ int program_exec(const char **args, ProgramOutputCallback output_callback, void
} else { /* parent */
close(fd[WRITE_END]);
- int result = 0;
- int status;
-
- char buffer[4097];
-
- if(output_callback) {
- for(;;) {
- ssize_t bytes_read = read(fd[READ_END], buffer, sizeof(buffer) - 1);
- if(bytes_read == 0) {
- break;
- } else if(bytes_read == -1) {
- int err = errno;
- fprintf(stderr, "Failed to read from pipe to program %s, error: %s\n", args[0], strerror(err));
- result = -err;
- goto cleanup;
- }
-
- buffer[bytes_read] = '\0';
- if(output_callback(buffer, bytes_read, userdata) != 0)
- break;
- }
- }
-
- if(waitpid(pid, &status, 0) == -1) {
- perror("waitpid failed");
- result = -5;
- goto cleanup;
- }
-
- if(!WIFEXITED(status)) {
- result = -4;
- goto cleanup;
- }
-
- int exit_status = WEXITSTATUS(status);
- if(exit_status != 0) {
+ int result = program_read_output(pid, fd[READ_END], output_callback, userdata);
+ if(result != 0) {
fprintf(stderr, "Failed to execute program (");
const char **arg = args;
while(*arg) {
@@ -99,13 +101,104 @@ int program_exec(const char **args, ProgramOutputCallback output_callback, void
fprintf(stderr, "'%s'", *arg);
++arg;
}
- fprintf(stderr, "), exit status %d\n", exit_status);
- result = -exit_status;
- goto cleanup;
+ fprintf(stderr, ")\n");
}
- cleanup:
close(fd[READ_END]);
return result;
}
}
+
+int program_exec_async(const char **args, int *process_id, int *stdin_file, int *stdout_file) {
+ int result = 0;
+
+ /* 1 argument */
+ if(args[0] == NULL)
+ return -1;
+
+ int stdin_fd[2] = { -1, -1 };
+ int stdout_fd[2] = { -1, -1 };
+
+ if(stdin_file) {
+ if(pipe(stdin_fd) == -1) {
+ perror("Failed to open pipe");
+ result = -2;
+ goto cleanup;
+ }
+ }
+
+ if(stdout_file) {
+ if(pipe(stdout_fd) == -1) {
+ perror("Failed to open pipe");
+ result = -2;
+ goto cleanup;
+ }
+ }
+
+ pid_t parent_pid = getpid();
+
+ pid_t pid = fork();
+ if(pid == -1) {
+ result = -errno;
+ perror("failed to fork");
+ goto cleanup;
+ } else if(pid == 0) { /* child */
+ if(prctl(PR_SET_PDEATHSIG, SIGTERM) == -1) {
+ perror("prctl(PR_SET_PDEATHSIG, SIGTERM) failed");
+ exit(127);
+ }
+
+ /* Test if the parent died before the above call to prctl */
+ if(getppid() != parent_pid)
+ exit(127);
+
+ if(stdin_file) {
+ dup2(stdin_fd[READ_END], STDIN_FILENO);
+ close(stdin_fd[READ_END]);
+ close(stdin_fd[WRITE_END]);
+ }
+
+ if(stdout_file) {
+ dup2(stdout_fd[WRITE_END], STDOUT_FILENO);
+ close(stdout_fd[READ_END]);
+ close(stdout_fd[WRITE_END]);
+ }
+
+ execvp(args[0], (char* const*)args);
+ perror("execvp");
+ exit(127);
+ } else { /* parent */
+ if(process_id)
+ *process_id = pid;
+
+ if(stdin_file)
+ close(stdin_fd[READ_END]);
+
+ if(stdout_file)
+ close(stdout_fd[WRITE_END]);
+
+ *stdin_file = stdin_fd[WRITE_END];
+ *stdout_file = stdout_fd[READ_END];
+
+ return 0;
+ }
+
+ cleanup:
+ if(stdin_fd[0] != -1) close(stdin_fd[0]);
+ if(stdin_fd[1] != -1) close(stdin_fd[1]);
+ if(stdout_fd[0] != -1) close(stdout_fd[0]);
+ if(stdout_fd[1] != -1) close(stdout_fd[1]);
+ return result;
+}
+
+int program_wait_until_exit(int process_id, int stdin_file, int stdout_file, ProgramOutputCallback output_callback, void *userdata) {
+ if(stdin_file != -1)
+ close(stdin_file);
+
+ int result = program_read_output(process_id, stdout_file, output_callback, userdata);
+
+ if(stdout_file != -1)
+ close(stdout_file);
+
+ return result;
+}
diff --git a/src/program.h b/src/program.h
index 265dfa5..8bf721c 100644
--- a/src/program.h
+++ b/src/program.h
@@ -8,8 +8,11 @@ int program_buffer_write_callback(char *data, int size, void *userdata);
/*
@args need to have at least 2 arguments. The first which is the program name
- and the last which is NULL, which indicates end of args
+ and the last which is NULL, which indicates end of args.
*/
int program_exec(const char **args, ProgramOutputCallback output_callback, void *userdata);
+int program_exec_async(const char **args, int *process_id, int *stdin_file, int *stdout_file);
+/* If stdin_file is -1 or stdout_file is -1 then they are not used */
+int program_wait_until_exit(int process_id, int stdin_file, int stdout_file, ProgramOutputCallback output_callback, void *userdata);
#endif
diff --git a/src/rss.c b/src/rss.c
index 23ccf89..84fa345 100644
--- a/src/rss.c
+++ b/src/rss.c
@@ -3,12 +3,12 @@
#include "stringutils.h"
#include "fileutils.h"
#include "buffer.h"
+#include "rss_html_common.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
-#include "json.h"
static int is_alpha_lowercase(char c) {
return c >= 'a' && c <= 'z';
@@ -163,150 +163,14 @@ static int rss_parse_callback(char *title, char *link, void *userdata) {
return 0;
}
-static void create_json_string(struct json_string_s *json_result, const char *str, int len) {
- json_result->string = str;
- json_result->string_size = len;
-}
-
-static void init_json_value_str(struct json_value_s *json_value, struct json_string_s *json_str) {
- json_value->payload = json_str;
- json_value->type = json_type_string;
-}
-
-static int write_rss_json_to_file(const char *dir, const char *filename, const char *url, const char *updated, const char *start_after, const char *start_after_url) {
- struct json_string_s title_json_key;
- create_json_string(&title_json_key, "title", 5);
-
- struct json_string_s title_json_value_str;
- create_json_string(&title_json_value_str, start_after, start_after ? strlen(start_after) : 0);
- struct json_value_s title_json_value;
- init_json_value_str(&title_json_value, &title_json_value_str);
-
- struct json_string_s time_json_key;
- create_json_string(&time_json_key, "time", 4);
-
- struct json_string_s time_value_str;
- create_json_string(&time_value_str, updated, updated ? strlen(updated) : 0);
- struct json_value_s time_json_value;
- init_json_value_str(&time_json_value, &time_value_str);
-
- struct json_string_s url_json_key;
- create_json_string(&url_json_key, "url", 3);
-
- struct json_string_s url_value_str;
- create_json_string(&url_value_str, start_after_url, start_after_url ? strlen(start_after_url) : 0);
- struct json_value_s url_json_value;
- init_json_value_str(&url_json_value, &url_value_str);
-
- struct json_string_s link_json_key;
- create_json_string(&link_json_key, "link", 4);
-
- struct json_string_s link_json_value_str;
- create_json_string(&link_json_value_str, url, strlen(url));
- struct json_value_s link_json_value;
- init_json_value_str(&link_json_value, &link_json_value_str);
-
- struct json_string_s updated_json_key;
- create_json_string(&updated_json_key, "updated", 7);
-
- struct json_string_s updated_json_value_str;
- create_json_string(&updated_json_value_str, updated, strlen(updated));
- struct json_value_s updated_json_value;
- init_json_value_str(&updated_json_value, &updated_json_value_str);
-
- struct json_string_s downloaded_json_key;
- create_json_string(&downloaded_json_key, "downloaded", 10);
-
- struct json_object_s downloaded_json;
- downloaded_json.start = NULL;
- downloaded_json.length = 0;
-
- struct json_value_s downloaded_json_value;
- downloaded_json_value.payload = &downloaded_json;
- downloaded_json_value.type = json_type_object;
-
- struct json_object_element_s downloaded_title_element;
- downloaded_title_element.name = &title_json_key;
- downloaded_title_element.value = &title_json_value;
-
- struct json_object_element_s downloaded_time_element;
- downloaded_time_element.name = &time_json_key;
- downloaded_time_element.value = &time_json_value;
-
- struct json_object_element_s downloaded_url_element;
- downloaded_url_element.name = &url_json_key;
- downloaded_url_element.value = &url_json_value;
-
- downloaded_title_element.next = &downloaded_time_element;
- downloaded_time_element.next = &downloaded_url_element;
- downloaded_url_element.next = NULL;
-
- struct json_array_s downloaded_json_array;
- downloaded_json_array.start = NULL;
- downloaded_json_array.length = 0;
- struct json_array_element_s downloaded_json_array_element;
-
- if(start_after) {
- downloaded_json.start = &downloaded_title_element;
- downloaded_json.length = 3;
-
- downloaded_json_array_element.value = &downloaded_json_value;
- downloaded_json_array_element.next = NULL;
- downloaded_json_array.start = &downloaded_json_array_element;
- downloaded_json_array.length = 1;
- }
-
- struct json_value_s downloaded_json_array_value;
- downloaded_json_array_value.payload = &downloaded_json_array;
- downloaded_json_array_value.type = json_type_array;
-
- struct json_object_s json_root;
- json_root.length = 3;
-
- struct json_object_element_s link_element;
- link_element.name = &link_json_key;
- link_element.value = &link_json_value;
-
- struct json_object_element_s updated_element;
- updated_element.name = &updated_json_key;
- updated_element.value = &updated_json_value;
-
- struct json_object_element_s downloaded_element;
- downloaded_element.name = &downloaded_json_key;
- downloaded_element.value = &downloaded_json_array_value;
-
- link_element.next = &updated_element;
- updated_element.next = &downloaded_element;
- downloaded_element.next = NULL;
- json_root.start = &link_element;
-
- struct json_value_s json_root_value;
- json_root_value.payload = &json_root;
- json_root_value.type = json_type_object;
- size_t json_body_size = 0;
- char *json_body_str = json_write_pretty(&json_root_value, " ", "\n", &json_body_size);
- if(!json_body_str || json_body_size == 0) {
- fprintf(stderr, "Failed to write json data to rss file %s/%s\n", dir, filename);
- return -1;
- }
-
- int result = file_overwrite_in_dir(dir, filename, json_body_str, json_body_size - 1);
- free(json_body_str);
- return result;
-}
-
int add_rss(const char *name, const char *url, char *rss_config_dir, const char *start_after) {
- (void)name;
- (void)rss_config_dir;
- (void)start_after;
int result = 0;
Buffer buffer;
buffer_init(&buffer);
- int res = download_to_buffer(url, &buffer);
- if(res != 0) {
+ result = download_to_buffer(url, &buffer);
+ if(result != 0) {
fprintf(stderr, "Failed to download rss: %s\n", url);
- result = res;
goto cleanup;
}
@@ -317,10 +181,9 @@ int add_rss(const char *name, const char *url, char *rss_config_dir, const char
/* TODO: What if rss title is longer than this? */
char rss_title[250];
- res = parse_rss(buffer.data, rss_title, sizeof(rss_title), rss_parse_callback, &rss_parse_userdata);
- if(res != 0) {
+ result = parse_rss(buffer.data, rss_title, sizeof(rss_title), rss_parse_callback, &rss_parse_userdata);
+ if(result != 0) {
fprintf(stderr, "Failed to parse rss for url: %s\n", url);
- result = res;
goto cleanup;
}
@@ -354,10 +217,9 @@ int add_rss(const char *name, const char *url, char *rss_config_dir, const char
goto cleanup;
}
- res = create_directory_recursive(rss_tracked_dir);
- if(res != 0) {
- fprintf(stderr, "Failed to create %s, error: %s\n", rss_tracked_dir, strerror(res));
- result = res;
+ result = create_directory_recursive(rss_tracked_dir);
+ if(result != 0) {
+ fprintf(stderr, "Failed to create %s, error: %s\n", rss_tracked_dir, strerror(result));
goto cleanup;
}
@@ -368,36 +230,32 @@ int add_rss(const char *name, const char *url, char *rss_config_dir, const char
char in_progress_filepath[PATH_MAX];
strcpy(in_progress_filepath, rss_tracked_dir);
strcat(in_progress_filepath, "/.in_progress");
- res = create_lock_file(in_progress_filepath);
- if(res != 0) {
+ result = create_lock_file(in_progress_filepath);
+ if(result != 0) {
fprintf(stderr, "Failed to create %s/.in_progress\n", rss_tracked_dir);
- result = res;
goto cleanup;
}
- res = file_overwrite_in_dir(rss_tracked_dir, "link", url, strlen(url));
- if(res != 0) {
+ result = file_overwrite_in_dir(rss_tracked_dir, "link", url, strlen(url));
+ if(result != 0) {
fprintf(stderr, "Failed to create %s/link\n", rss_tracked_dir);
remove(rss_tracked_dir);
- result = res;
goto cleanup;
}
char updated[32];
sprintf(updated, "%ld", time(NULL));
- res = file_overwrite_in_dir(rss_tracked_dir, "updated", updated, strlen(updated));
- if(res != 0) {
+ result = file_overwrite_in_dir(rss_tracked_dir, "updated", updated, strlen(updated));
+ if(result != 0) {
fprintf(stderr, "Failed to create %s/updated\n", rss_tracked_dir);
remove(rss_tracked_dir);
- result = res;
goto cleanup;
}
- res = write_rss_json_to_file(rss_tracked_dir, "data", url, updated, start_after, rss_parse_userdata.start_after_url);
- if(res != 0) {
+ result = write_plugin_json_to_file(rss_tracked_dir, "data", url, updated, start_after, rss_parse_userdata.start_after_url, NULL);
+ if(result != 0) {
fprintf(stderr, "Failed to create %s/data\n", rss_tracked_dir);
remove(rss_tracked_dir);
- result = res;
goto cleanup;
}
diff --git a/src/rss_html_common.c b/src/rss_html_common.c
new file mode 100644
index 0000000..56e1ccb
--- /dev/null
+++ b/src/rss_html_common.c
@@ -0,0 +1,158 @@
+#include "rss_html_common.h"
+#include "json.h"
+#include "fileutils.h"
+#include <string.h>
+#include <stdio.h>
+
+static void create_json_string(struct json_string_s *json_result, const char *str, int len) {
+ json_result->string = str;
+ json_result->string_size = len;
+}
+
+static void init_json_value_str(struct json_value_s *json_value, struct json_string_s *json_str) {
+ json_value->payload = json_str;
+ json_value->type = json_type_string;
+}
+
+int write_plugin_json_to_file(const char *dir, const char *filename, const char *url, const char *updated, const char *start_after, const char *start_after_url, const char *plugin_name) {
+ struct json_string_s title_json_key;
+ create_json_string(&title_json_key, "title", 5);
+
+ struct json_string_s title_json_value_str;
+ create_json_string(&title_json_value_str, start_after, start_after ? strlen(start_after) : 0);
+ struct json_value_s title_json_value;
+ init_json_value_str(&title_json_value, &title_json_value_str);
+
+ struct json_string_s time_json_key;
+ create_json_string(&time_json_key, "time", 4);
+
+ struct json_string_s time_value_str;
+ create_json_string(&time_value_str, updated, strlen(updated));
+ struct json_value_s time_json_value;
+ init_json_value_str(&time_json_value, &time_value_str);
+
+ struct json_string_s url_json_key;
+ create_json_string(&url_json_key, "url", 3);
+
+ struct json_string_s url_value_str;
+ create_json_string(&url_value_str, start_after_url, start_after_url ? strlen(start_after_url) : 0);
+ struct json_value_s url_json_value;
+ init_json_value_str(&url_json_value, &url_value_str);
+
+ struct json_string_s plugin_json_key;
+ create_json_string(&plugin_json_key, "plugin", 6);
+
+ struct json_string_s plugin_json_value_str;
+ create_json_string(&plugin_json_value_str, plugin_name, plugin_name ? strlen(plugin_name) : 0);
+ struct json_value_s plugin_json_value;
+ init_json_value_str(&plugin_json_value, &plugin_json_value_str);
+
+ struct json_string_s link_json_key;
+ create_json_string(&link_json_key, "link", 4);
+
+ struct json_string_s link_json_value_str;
+ create_json_string(&link_json_value_str, url, strlen(url));
+ struct json_value_s link_json_value;
+ init_json_value_str(&link_json_value, &link_json_value_str);
+
+ struct json_string_s updated_json_key;
+ create_json_string(&updated_json_key, "updated", 7);
+
+ struct json_string_s updated_json_value_str;
+ create_json_string(&updated_json_value_str, updated, strlen(updated));
+ struct json_value_s updated_json_value;
+ init_json_value_str(&updated_json_value, &updated_json_value_str);
+
+ struct json_string_s downloaded_json_key;
+ create_json_string(&downloaded_json_key, "downloaded", 10);
+
+ struct json_object_s downloaded_json;
+ downloaded_json.start = NULL;
+ downloaded_json.length = 0;
+
+ struct json_value_s downloaded_json_value;
+ downloaded_json_value.payload = &downloaded_json;
+ downloaded_json_value.type = json_type_object;
+
+ struct json_object_element_s downloaded_title_element;
+ downloaded_title_element.name = &title_json_key;
+ downloaded_title_element.value = &title_json_value;
+
+ struct json_object_element_s downloaded_time_element;
+ downloaded_time_element.name = &time_json_key;
+ downloaded_time_element.value = &time_json_value;
+
+ struct json_object_element_s downloaded_url_element;
+ downloaded_url_element.name = &url_json_key;
+ downloaded_url_element.value = &url_json_value;
+
+ downloaded_title_element.next = &downloaded_time_element;
+ downloaded_time_element.next = &downloaded_url_element;
+ downloaded_url_element.next = NULL;
+
+ struct json_array_s downloaded_json_array;
+ downloaded_json_array.start = NULL;
+ downloaded_json_array.length = 0;
+ struct json_array_element_s downloaded_json_array_element;
+
+ if(start_after) {
+ downloaded_json.start = &downloaded_title_element;
+ downloaded_json.length = 3;
+
+ downloaded_json_array_element.value = &downloaded_json_value;
+ downloaded_json_array_element.next = NULL;
+ downloaded_json_array.start = &downloaded_json_array_element;
+ downloaded_json_array.length = 1;
+ }
+
+ struct json_value_s downloaded_json_array_value;
+ downloaded_json_array_value.payload = &downloaded_json_array;
+ downloaded_json_array_value.type = json_type_array;
+
+ struct json_object_s json_root;
+ json_root.length = 3;
+
+ struct json_object_element_s link_element;
+ link_element.name = &link_json_key;
+ link_element.value = &link_json_value;
+
+ struct json_object_element_s updated_element;
+ updated_element.name = &updated_json_key;
+ updated_element.value = &updated_json_value;
+
+ struct json_object_element_s downloaded_element;
+ downloaded_element.name = &downloaded_json_key;
+ downloaded_element.value = &downloaded_json_array_value;
+
+ struct json_object_element_s plugin_element;
+ plugin_element.name = &plugin_json_key;
+ plugin_element.value = &plugin_json_value;
+
+ link_element.next = &updated_element;
+ updated_element.next = &downloaded_element;
+ downloaded_element.next = NULL;
+
+ if(plugin_name) {
+ json_root.start = &plugin_element;
+ plugin_element.next = &link_element;
+ } else {
+ json_root.start = &link_element;
+ }
+
+ struct json_value_s json_root_value;
+ json_root_value.payload = &json_root;
+ json_root_value.type = json_type_object;
+ size_t json_body_size = 0;
+ char *json_body_str = json_write_pretty(&json_root_value, " ", "\n", &json_body_size);
+ if(!json_body_str || json_body_size == 0) {
+ fprintf(stderr, "Failed to write json data to file %s/%s\n", dir, filename);
+ return -1;
+ }
+
+ /* Workaround json bug (?) */
+ json_body_size = strlen(json_body_str);
+
+ int result = file_overwrite_in_dir(dir, filename, json_body_str, json_body_size);
+ free(json_body_str);
+ return result;
+} \ No newline at end of file
diff --git a/src/rss_html_common.h b/src/rss_html_common.h
new file mode 100644
index 0000000..99f7778
--- /dev/null
+++ b/src/rss_html_common.h
@@ -0,0 +1,6 @@
+#ifndef RSS_HTML_COMMON_H
+#define RSS_HTML_COMMON_H
+
+int write_plugin_json_to_file(const char *dir, const char *filename, const char *url, const char *updated, const char *start_after, const char *start_after_url, const char *plugin_name);
+
+#endif \ No newline at end of file