From e4bae38e3a5d345c025ed9edddbf401c81756dd5 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 13 Jul 2020 00:07:56 +0200 Subject: Finish 'downloaded' command --- buffer.c | 4 ++ buffer.h | 1 + fileutils.c | 33 +++++++++++++ fileutils.h | 2 + main.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 178 insertions(+), 14 deletions(-) diff --git a/buffer.c b/buffer.c index 879a62b..5768b3a 100644 --- a/buffer.c +++ b/buffer.c @@ -52,3 +52,7 @@ void* buffer_begin(Buffer *self) { void* buffer_end(Buffer *self) { return (char*)self->data + self->size; } + +size_t buffer_get_size(Buffer *self, size_t type_size) { + return self->size / type_size; +} diff --git a/buffer.h b/buffer.h index a8c1940..0aefe99 100644 --- a/buffer.h +++ b/buffer.h @@ -26,5 +26,6 @@ void buffer_append(Buffer *self, const void *data, size_t size); void* buffer_pop(Buffer *self, size_t size); void* buffer_begin(Buffer *self); void* buffer_end(Buffer *self); +size_t buffer_get_size(Buffer *self, size_t type_size); #endif diff --git a/fileutils.c b/fileutils.c index 233138c..137373b 100644 --- a/fileutils.c +++ b/fileutils.c @@ -1,6 +1,9 @@ #include "fileutils.h" +#include "alloc.h" +#include #include +#include #include #include @@ -12,3 +15,33 @@ const char* get_home_dir() { } return home_dir; } + +int file_get_content(const char *filepath, char **data, long *size) { + int result = 0; + FILE *file = fopen(filepath, "rb"); + if(!file) { + int err = -errno; + perror(filepath); + return err; + } + + fseek(file, 0, SEEK_END); + *size = ftell(file); + if(*size == -1) { + fprintf(stderr, "Failed to tell the size of file %s, is it not a file?\n", filepath); + result = -1; + goto cleanup; + } + fseek(file, 0, SEEK_SET); + + *data = alloc_or_crash(*size); + if((long)fread(*data, 1, *size, file) != *size) { + fprintf(stderr, "Failed to read all bytes in file %s\n", filepath); + result = -1; + goto cleanup; + } + + cleanup: + fclose(file); + return result; +} diff --git a/fileutils.h b/fileutils.h index 9780392..413648f 100644 --- a/fileutils.h +++ b/fileutils.h @@ -2,5 +2,7 @@ #define FILEUTILS_H const char* get_home_dir(); +/* Returns 0 on success */ +int file_get_content(const char *filepath, char **data, long *size); #endif diff --git a/main.c b/main.c index 6655ed5..33bc2fd 100644 --- a/main.c +++ b/main.c @@ -1,11 +1,13 @@ #include "program.h" #include "buffer.h" #include "fileutils.h" +#include "json.h" #include #include #include #include +#include #include @@ -50,7 +52,113 @@ static void usage_sync(void) { exit(1); } -static void get_downloaded_items(const char *tracked_dir) { +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 void (*DownloadedListCallback)(const char *title, double timestamp, void *userdata); + +static void data_file_get_downloaded(const char *dir_name, const char *data_filepath, bool is_html, DownloadedListCallback callback, void *userdata) { + char *file_data; + long file_size; + if(file_get_content(data_filepath, &file_data, &file_size) != 0) { + fprintf(stderr, "Failed to read the content of file %s\n", data_filepath); + return; + } + + struct json_value_s *json_root = json_parse(file_data, file_size); + if(!json_root) { + fprintf(stderr, "Failed to parse file %s as json\n", data_filepath); + goto cleanup; + } + + struct json_object_s *json_root_obj = json_value_as_object(json_root); + if(!json_root_obj) { + fprintf(stderr, "File %s contains malformed json. Expected json root element to be an object\n", data_filepath); + goto cleanup; + } + + struct json_value_s *downloaded_json = json_object_get_field_by_name(json_root_obj, "downloaded"); + if(!downloaded_json) { + fprintf(stderr, "File %s contains malformed json. Expected json to contain \"downloaded\"\n", data_filepath); + goto cleanup; + } + + struct json_array_s *downloaded_json_arr = json_value_as_array(downloaded_json); + if(!downloaded_json_arr) { + fprintf(stderr, "File %s contains malformed json. Expected \"downloaded\" to be an array\n", data_filepath); + goto cleanup; + } + + size_t dir_name_len = strlen(dir_name); + + struct json_array_element_s *downloaded_item = downloaded_json_arr->start; + for(; downloaded_item; downloaded_item = downloaded_item->next) { + struct json_object_s *downloaded_item_obj = json_value_as_object(downloaded_item->value); + if(!downloaded_item_obj) + continue; + + struct json_value_s *time_json = json_object_get_field_by_name(downloaded_item_obj, "time"); + if(!time_json || time_json->type != json_type_string) + continue; + struct json_string_s *time_json_str = json_value_as_string(time_json); + + struct json_value_s *title_json = json_object_get_field_by_name(downloaded_item_obj, "title"); + struct json_string_s *title_str = NULL; + if(title_json && title_json->type == json_type_string) + title_str = json_value_as_string(title_json); + + struct json_value_s *filename_json = json_object_get_field_by_name(downloaded_item_obj, "filename"); + struct json_string_s *filename_str = NULL; + if(filename_json && filename_json->type == json_type_string) + filename_str = json_value_as_string(filename_json); + + /* Filename limit is 256, so this should be safe... */ + char title[256]; + if(filename_str) { + strcpy(title, filename_str->string); + } else if(title_str) { + if(is_html) { + strcpy(title, dir_name); + title[dir_name_len] = '/'; + strcpy(title + dir_name_len + 1, title_str->string); + } else { + strcpy(title, title_str->string); + } + } else { + continue; + } + + callback(title, atof(time_json_str->string), userdata); + } + + cleanup: + if(json_root) + free(json_root); + free(file_data); +} + +typedef struct { + char *title; + double timestamp; +} DownloadedListData; + +static void downloaded_list_callback(const char *title, double timestamp, void *userdata) { + DownloadedListData list_data; + list_data.title = strdup(title); + list_data.timestamp = timestamp; + + Buffer *buffer = userdata; + buffer_append(buffer, &list_data, sizeof(list_data)); +} + +static void get_downloaded_items(const char *tracked_dir, bool is_html, void *userdata) { struct dirent *dir; DIR *d = opendir(tracked_dir); if(!d) @@ -68,26 +176,42 @@ static void get_downloaded_items(const char *tracked_dir) { strcpy(data_filepath + data_filepath_length, dir->d_name); strcpy(data_filepath + data_filepath_length + strlen(dir->d_name), "/data"); - puts(data_filepath); + data_file_get_downloaded(dir->d_name, data_filepath, is_html, downloaded_list_callback, userdata); } closedir(d); } +static int compare_downloaded_item(const void *a, const void *b) { + const DownloadedListData *list_data_a = a; + const DownloadedListData *list_data_b = b; + return list_data_a->timestamp - list_data_b->timestamp; +} + static void command_downloaded(const char *rss_config_dir, const char *html_config_dir) { - char rss_tracked_dir[PATH_MAX] = {0}; - strcat(rss_tracked_dir, rss_config_dir); + char rss_tracked_dir[PATH_MAX]; + strcpy(rss_tracked_dir, rss_config_dir); strcat(rss_tracked_dir, "/tracked"); - char html_tracked_dir[PATH_MAX] = {0}; - strcat(html_tracked_dir, html_config_dir); + char html_tracked_dir[PATH_MAX]; + strcpy(html_tracked_dir, html_config_dir); strcat(html_tracked_dir, "/tracked"); - printf("files in %s: \n", rss_tracked_dir); - get_downloaded_items(rss_tracked_dir); + Buffer downloaded_items; + buffer_init(&downloaded_items); + + get_downloaded_items(rss_tracked_dir, false, &downloaded_items); + get_downloaded_items(html_tracked_dir, true, &downloaded_items); + + qsort(downloaded_items.data, buffer_get_size(&downloaded_items, sizeof(DownloadedListData)), sizeof(DownloadedListData), compare_downloaded_item); + DownloadedListData *list_it = buffer_begin(&downloaded_items); + DownloadedListData *list_end = buffer_end(&downloaded_items); + for(; list_it != list_end; ++list_it) { + puts(list_it->title); + free(list_it->title); + } - printf("files in %s: \n", html_tracked_dir); - get_downloaded_items(html_tracked_dir); + buffer_deinit(&downloaded_items); } int main(int argc, char **argv) { @@ -96,12 +220,12 @@ int main(int argc, char **argv) { const char *home_dir = get_home_dir(); - char rss_config_dir[PATH_MAX] = {0}; - strcat(rss_config_dir, home_dir); + char rss_config_dir[PATH_MAX];; + strcpy(rss_config_dir, home_dir); strcat(rss_config_dir, "/.config/automedia/rss"); - char html_config_dir[PATH_MAX] = {0}; - strcat(html_config_dir, home_dir); + char html_config_dir[PATH_MAX]; + strcpy(html_config_dir, home_dir); strcat(html_config_dir, "/.config/automedia/html"); const char *command = argv[1]; -- cgit v1.2.3