From 9483c8f1dbde014432c7a99416fcda3a6ccb3563 Mon Sep 17 00:00:00 2001 From: Anna Figueiredo Gomes Date: Mon, 20 Feb 2023 17:12:32 -0300 Subject: initial Signed-off-by: Anna Figueiredo Gomes --- Makefile | 36 +++++++++++++ TODO.md | 14 +++++ src/curl.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/curl.h | 24 +++++++++ src/db.c | 79 +++++++++++++++++++++++++++ src/db.h | 20 +++++++ src/feed.c | 21 ++++++++ src/feed.h | 13 +++++ src/main.c | 47 ++++++++++++++++ src/util.h | 20 +++++++ 10 files changed, 451 insertions(+) create mode 100644 Makefile create mode 100644 TODO.md create mode 100644 src/curl.c create mode 100644 src/curl.h create mode 100644 src/db.c create mode 100644 src/db.h create mode 100644 src/feed.c create mode 100644 src/feed.h create mode 100644 src/main.c create mode 100644 src/util.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3a69811 --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +CC = clang +CFLAGS = -g -DDEBUG -fsanitize=address +LDFLAGS != pkg-config --libs libcurl sqlite3 + +BIN=bin/newspaddle + +SRC=$(wildcard src/*.c) +OBJ=$(patsubst src/%.c, obj/%.o, $(SRC)) + +all: bin/ obj/ $(BIN) + +$(BIN): $(OBJ) + $(CC) $^ $(LDFLAGS) -fsanitize=address -o $@ + +obj/%.o: src/%.c + $(CC) $(CFLAGS) -c $< -o $@ + +bin/: + mkdir bin + +obj/: + mkdir obj + +run: all + ./$(BIN) + +debug: all + gdb ./$(BIN) + +scan: + make clean + scan-build make + +clean: + rm -r bin/ + rm -r obj/ diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..c666d56 --- /dev/null +++ b/TODO.md @@ -0,0 +1,14 @@ +* Connect to miniflux +* Get newsraft db + +# Sync feeds +* Get list of all newsraft feeds and all miniflux feeds +* Feeds missing in miniflux should be added + Feeds are going to be one way for now, only newsraft -> miniflux. +* Refresh all feeds on miniflux + +* Get all local items, all remote items, compare and mark as read the different ones + +# A +* Update miniflux +* Update newsraft diff --git a/src/curl.c b/src/curl.c new file mode 100644 index 0000000..4046d3d --- /dev/null +++ b/src/curl.c @@ -0,0 +1,177 @@ +#include +#include "util.h" +#include "curl.h" + +const char* +get_apikey() +{ + return check_get_env("MINIFLUX_APIKEY"); +} + +const char * +get_url() +{ + return check_get_env("MINIFLUX_URL"); +} + +char * +get_endpoint(char* endpoint) +{ + char *url = calloc(sizeof(char), PATH_MAX); + snprintf(url, PATH_MAX, "%s/v1/%s", get_url(), endpoint); + return url; +} + +bool +curl_init() +{ + curl = curl_easy_init(); + + if (!curl) { + fprintf(stderr, "Error in curl init\n"); + return false; + } + + api_header = calloc(sizeof(char), MAX_URL); + snprintf(api_header, sizeof(char) * MAX_URL, "X-Auth-Token: %s", get_apikey()); + +#ifdef DEBUG + fprintf(stderr, "api: %s\n", api_header); +#endif + + return true; +} + +size_t +parse_header_reply( + char* ptr, size_t size, size_t nmemb, struct reply *userdata) +{ + size_t s = 0; + if (sscanf(ptr, "Content-Length: %ld\n", &s) != 0) { + userdata->size = s + 1; +#ifdef DEBUG + printf("Len: %ld\n", s); +#endif + } + return size * nmemb; +} + +size_t +parse_body_reply( + char *ptr, size_t size, size_t nmemb, struct reply *userdata) +{ + if (userdata->size == 0) { + return 0; + } + size_t realsize = size * nmemb; + char *tmp = realloc(userdata->data, userdata->size); + if (!tmp) { + fprintf(stderr, "Not enough memory\n"); + return 0; + } else { + userdata->data = tmp; + } + + strncat(userdata->data, ptr, realsize); + return realsize; +} + +struct feed * +get_remote_feeds() +{ + CURLcode res; + struct curl_slist *header = NULL; + + char *url = get_endpoint("feeds"); + curl_easy_setopt(curl, CURLOPT_URL, url); + free(url); + header = curl_slist_append(header, api_header); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); + + struct reply data = {0}; + data.size = 0; + data.data = malloc(1); + data.data[0] = '\0'; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &parse_body_reply); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data); + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &parse_header_reply); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, &data); + + + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + fprintf(stderr, "Curl failed: %s", curl_easy_strerror(res)); + return NULL; + } + +#ifdef DEBUG + printf("%s\n", data.data); +#endif + + struct feed *feeds = calloc(sizeof(struct feed), 1); + // TODO: populate feed; + free(data.data); + curl_slist_free_all(header); + return feeds; +} + +void +curl_clean() +{ + curl_easy_cleanup(curl); + free(api_header); +} + +size_t +print_reply( + char *ptr, size_t size, size_t nmemb, void *null) +{ + printf("%s\n", ptr); + return size * nmemb; +} + +void +remote_add_feed(struct feed feed) +{ + char *json = calloc(sizeof(char), 4096); + snprintf(json, 4096, "{ \"feed_url\": \"%s\", \"category_id\": 1 }", feed.url); + char *url = get_endpoint("feeds"); + + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json); + + struct curl_slist *header = NULL; + header = curl_slist_append(header, api_header); + header = curl_slist_append(header, "Content-Type: application/json"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &print_reply); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); + + curl_easy_perform(curl); + free(url); + free(json); + curl_slist_free_all(header); +} + +bool +create_category(char *title) +{ + char *json = calloc(sizeof(char), 4096); + snprintf(json, 4096, "{ \"title\": \"%s\" }", title); + char *url = get_endpoint("categories"); + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json); + struct curl_slist *header = NULL; + header = curl_slist_append(header, api_header); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &print_reply); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); + + curl_easy_perform(curl); + free(url); + free(json); + curl_slist_free_all(header); + + return true; +} diff --git a/src/curl.h b/src/curl.h new file mode 100644 index 0000000..d496962 --- /dev/null +++ b/src/curl.h @@ -0,0 +1,24 @@ +#ifndef _CURL_H_ +#define _CURL_H_ + +#include +#include +#include +#include "feed.h" + +#define MAX_URL 2048 +static CURL *curl; +static char *api_header; + +struct reply { + size_t size; + char *data; +}; + +bool curl_init(); +void curl_clean(); +struct feed *get_remote_feeds(); +bool create_category(char *title); +void remote_add_feed(struct feed feed); + +#endif diff --git a/src/db.c b/src/db.c new file mode 100644 index 0000000..7211b8c --- /dev/null +++ b/src/db.c @@ -0,0 +1,79 @@ +#include +#include "db.h" +#include "util.h" + +const char * +get_db_path() +{ + return check_get_env("NEWSRAFT_DB_PATH"); +} + +bool +db_init() +{ + int result = sqlite3_open(get_db_path(), &db); + if (result != SQLITE_OK) { + fprintf(stderr, "Can't open database: %s", sqlite3_errmsg(db)); + sqlite3_close(db); + return false; + } + return true; +} + +void +db_clean() +{ + sqlite3_close(db); +} + +struct feed * +get_db_feeds() +{ + char *query; + size_t total_feeds = get_feed_count(); + if (total_feeds == 0) { + return NULL; + } + struct feed *feeds = calloc(sizeof(struct feed), total_feeds); + + query = "select feed_url,title from feeds;"; + int result = sqlite3_prepare_v2(db, query, -1, &statement, NULL); + + if (result == SQLITE_OK) { + for (size_t i = 0; sqlite3_step(statement) != SQLITE_DONE; i++) { + char *url = (char*)sqlite3_column_text(statement, 0); + char *title = (char*)sqlite3_column_text(statement, 1); + feeds[i] = create_feed(url, title); + } + } + +#ifdef DEBUG + for (size_t i = 0; i < total_feeds; i++) { + printf("%s, %s\n", feeds[i].title, feeds[i].url); + } +#endif + + sqlite3_finalize(statement); + return feeds; +} + +size_t +get_feed_count() +{ + char* query = "select count(*) from feeds;"; + int result = sqlite3_prepare_v2(db, query, -1, &statement, NULL); + int total_feeds = 0; + + if (result == SQLITE_OK) { + while(sqlite3_step(statement) != SQLITE_DONE) { + total_feeds = sqlite3_column_int(statement, 0); + printf("%d\n", total_feeds); + } + } + + sqlite3_finalize(statement); + return total_feeds; +} + +//size_t get_item_count() { +//} diff --git a/src/db.h b/src/db.h new file mode 100644 index 0000000..d332365 --- /dev/null +++ b/src/db.h @@ -0,0 +1,20 @@ +#ifndef _DB_H_ +#define _DB_H_ + +#include +#include +#include +#include "feed.h" + +static sqlite3 *db; +static sqlite3_stmt *statement; + +bool db_init(); +void db_clean(); + +struct feed *get_db_feeds(); +size_t get_feed_count(); +//size_t get_item_count(); + + +#endif diff --git a/src/feed.c b/src/feed.c new file mode 100644 index 0000000..4fa99af --- /dev/null +++ b/src/feed.c @@ -0,0 +1,21 @@ +#include +#include +#include "feed.h" + +struct feed create_feed(char *url, char* title) { + struct feed feed = { 0 }; + size_t size = strlen(url); + feed.url = calloc(sizeof(char), size); + strncpy(feed.url, url, size); + + size = strlen(title); + feed.title = calloc(sizeof(char), size); + strncpy(feed.title, title, size); + + return feed; +} + +void delete_feed(struct feed *feed) { + free(feed->url); + free(feed->title); +} diff --git a/src/feed.h b/src/feed.h new file mode 100644 index 0000000..c67d07a --- /dev/null +++ b/src/feed.h @@ -0,0 +1,13 @@ +#ifndef _FEED_H_ +#define _FEED_H_ + +struct feed { + char *url; + char *title; +}; + +struct feed create_feed(char *url, char* title); +void delete_feed(struct feed *feed); + +#endif + diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..1794a65 --- /dev/null +++ b/src/main.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include + +#include "curl.h" +#include "feed.h" +#include "db.h" + +#define _UTIL_DEF_ +#include "util.h" + +static sqlite3 *db; + +void init() { + if (!curl_init() || !db_init()) { + exit(1); + } +} + +void clean() { + curl_clean(); + db_clean(); +} + +int main(int argc, char **argv) { + + init(); + + //struct feed *remote_feeds = get_remote_feeds(); + struct feed *db_feeds = get_db_feeds(); + + for (size_t i = 0; i < get_feed_count(); i++) { + remote_add_feed(db_feeds[i]); + } + + free(db_feeds); + + //if (!remote_feeds) { + //exit(1); + //} + //free(remote_feeds); + + clean(); + return 0; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..4b3bed7 --- /dev/null +++ b/src/util.h @@ -0,0 +1,20 @@ +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include +#include + +const char* check_get_env(char* env); + +#ifdef _UTIL_DEF_ +const char* check_get_env(char* env) { + char *env_val = getenv(env); + if (!env_val) { + fprintf(stderr, "%s not set", env); + exit(1); + } + return env_val; +} +#endif + +#endif -- cgit v1.2.3