neocities.h

a C library for interacting with Neocities' API
git clone https://github.com/tanguyandreani/neocities.h
Log | Files | Refs | README | LICENSE

commit bf99ba966ef4246d3093f0301750022bf2c1f14c
parent f76f28422e428a8b4043f74981fc1540aa96c104
Author: Tanguy Andreani <dev@tanguy.space>
Date:   Fri, 22 Feb 2019 21:59:31 +0100

Added: batch commit

Diffstat:
M.gitignore | 6++++--
MMakefile | 4++--
Dexample.c | 92-------------------------------------------------------------------------------
Minfo.c | 4++--
Mlist.c | 4++--
Mneocities.h | 279++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mupload.c | 4+++-
7 files changed, 211 insertions(+), 182 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,3 +1,5 @@ apikey.h a.out -example- \ No newline at end of file +list +info +upload+ \ No newline at end of file diff --git a/Makefile b/Makefile @@ -14,4 +14,4 @@ upload: upload.c neocities.h dtparser.c dtparser.h $(CC) -o $(<:.c=) dtparser.c $< $(FLAGS) $(DEBUG) clean: - rm info list example- \ No newline at end of file + rm -f info list upload+ \ No newline at end of file diff --git a/example.c b/example.c @@ -1,92 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <curl/curl.h> -#include <json.h> - -#include "dtparser.h" - -#include "neocities.h" - -#define CURL_ERROR NEOCITIES_LLVL_ERR_CURL_GLOBAL_INIT -#define OK NEOCITIES_LLVL_OK - -int main(void) -{ - neocities_res res; - - int i, err; - - char date[33] = { 0 }; - - if (curl_global_init(CURL_GLOBAL_SSL) != 0) - return CURL_ERROR; - - if ((err = neocities_api_ex(APIKEY, LIST, "", &res)) != OK) - return err; - - puts("## Listing 5 files ##"); - - printf("success: %d\n", res.result); - - for (i = 0; i < 5; i++) { - rfc5322_date_create(res.data.list.files[i].updated_at, date, 32); - printf("path: %s\n last_update: %s\n is_dir: %d\n size: %d\n", - res.data.list.files[i].path, date, - res.data.list.files[i].is_directory, - res.data.list.files[i].size); - } - - neocities_destroy_list(&res); - - if ((err = neocities_api_ex(APIKEY, INFO, "", &res)) != OK) - return err; - - printf("## Site infos (%s) ##\n", res.data.info.sitename); - - printf("success: %d, views: %d, hits: %d, domain: %s\n", res.result, - res.data.info.views, res.data.info.hits, res.data.info.domain); - - puts("tags:"); - - i = 0; - while (res.data.info.tags[i] != NULL) { - printf("- %s\n", res.data.info.tags[i]); - i++; - } - - rfc5322_date_create(res.data.info.created_at, date, 32); - printf("created_at: %s\n", date); - - rfc5322_date_create(res.data.info.last_updated, date, 32); - printf("last_updated: %s\n", date); - - neocities_destroy_info(&res); - - puts("## Failing deliberately ##"); - - if ((err = neocities_api_ex(APIKEY, INFO, "donotexist", &res)) != OK) { - printf("result: %d, error_type: %d\n", res.result, - res.data.error.type); - neocities_destroy_error(&res); - } else { - neocities_destroy_info(&res); - } - - puts("## Uploading a file ##"); - - if ((err = neocities_api_ex(APIKEY, UPLOAD, "deps.txt", &res)) != OK) { - printf("result: %d, error_type: %d\n", res.result, - res.data.error.type); - - // not mandatory if res only used once - neocities_destroy_error(&res); - } else { - printf("result: %d\n", res.result); - } - - curl_global_cleanup(); - - return 0; -} diff --git a/info.c b/info.c @@ -30,7 +30,7 @@ int main(int argc, char *argv[]) return CURL_ERROR; if ((err = - neocities_api_ex(APIKEY, INFO, ((argc == 1) ? "" : argv[1]), + neocities_api_ex(APIKEY, info, ((argc == 1) ? "" : argv[1]), &res)) != OK) return err; @@ -67,7 +67,7 @@ int main(int argc, char *argv[]) printf("\"%s\"]\n", res.data.info.tags[i]); } - neocities_destroy_info(&res); + neocities_destroy(&res); curl_global_cleanup(); diff --git a/list.c b/list.c @@ -29,7 +29,7 @@ int main(int argc, char *argv[]) return CURL_ERROR; if ((err = - neocities_api_ex(APIKEY, LIST, (argc == 2) ? argv[1] : "", + neocities_api_ex(APIKEY, list, (argc == 2) ? argv[1] : "", &res)) != OK) return err; @@ -40,7 +40,7 @@ int main(int argc, char *argv[]) putchar('\n'); } - neocities_destroy_list(&res); + neocities_destroy(&res); curl_global_cleanup(); diff --git a/neocities.h b/neocities.h @@ -14,6 +14,14 @@ #define INFO BASEURL "info" #define KEY BASEURL "key" +enum neocities_action { + upload, + delete, + list, + info, + key +}; + enum neocities_low_level_error { NEOCITIES_LLVL_OK, NEOCITIES_LLVL_ERR_CURL_GLOBAL_INIT, @@ -34,7 +42,14 @@ enum neocities_low_level_error { NEOCITIES_LLVL_ERR_RECEIVED_UNSUPPORTED_JSON, NEOCITIES_LLVL_ERR_RECEIVED_INVALID_JSON, NEOCITIES_LLVL_ERR_NO_SUCCESS, - NEOCITIES_LLVL_ERR_MALLOC_FAIL + NEOCITIES_LLVL_ERR_MALLOC_FAIL, + NEOCITIES_LLVL_ERR_EXPECTED_STRING, + NEOCITIES_LLVL_ERR_EXPECTED_BOOL, + NEOCITIES_LLVL_ERR_EXPECTED_INT, + NEOCITIES_LLVL_ERR_EXPECTED_ARRAY, + NEOCITIES_LLVL_ERR_EXPECTED_STRING_OR_NULL, + NEOCITIES_LLVL_ERR_EXPECTED_OBJECT, + NEOCITIES_LLVL_ERR_RECEIVED_SOMETHING_ELSE }; /* Not prefixed for convenience */ @@ -43,12 +58,12 @@ enum neocities_api_level_error { UNSUPPORTED_ERROR }; -typedef struct Neocities_ { +typedef struct curl_buffer_ { char *buf; int size; int pos; -} Neocities; +} curl_buffer; struct neocities_info_ { char *sitename; /* default: NULL */ @@ -78,8 +93,16 @@ struct neocities_error_ { int type; }; +enum neocities_res_data { + NEOCITIES_NO_TYPE_YET, + NEOCITIES_INFO_STRUCT, + NEOCITIES_LIST_STRUCT, + NEOCITIES_ERROR_STRUCT +}; + typedef struct neocities_res_ { int result; + enum neocities_res_data type; union { struct neocities_list_ list; @@ -88,43 +111,36 @@ typedef struct neocities_res_ { } data; } neocities_res; -enum neocities_res_data { - NEOCITIES_NO_TYPE_YET, - NEOCITIES_INFO_STRUCT, - NEOCITIES_LIST_STRUCT, - NEOCITIES_ERROR_STRUCT -}; - -int neocities_init(Neocities * neocities, size_t size) +int curl_buffer_init(curl_buffer * curl_buf, size_t size) { - neocities->buf = malloc(sizeof(char) * size); + curl_buf->buf = malloc(sizeof(char) * size); - if (neocities->buf == NULL) + if (curl_buf->buf == NULL) return 1; - neocities->size = size; - neocities->pos = 0; + curl_buf->size = size; + curl_buf->pos = 0; return 0; } -void neocities_destroy(Neocities * neocities) +void curl_buffer_destroy(curl_buffer * curl_buf) { - free(neocities->buf); - neocities->buf = NULL; + free(curl_buf->buf); + curl_buf->buf = NULL; - neocities->size = 0; - neocities->pos = 0; + curl_buf->size = 0; + curl_buf->pos = 0; return; } -void neocities_dump(Neocities * neocities) +void curl_buffer_dump(curl_buffer * curl_buf) { int i = 0; - while (i < neocities->pos) { - fputc(neocities->buf[i], stderr); + while (i < curl_buf->pos) { + fputc(curl_buf->buf[i], stderr); i++; } @@ -132,26 +148,26 @@ void neocities_dump(Neocities * neocities) } size_t write_data(void *buffer, size_t size, size_t nmemb, - Neocities * neocities) + curl_buffer * curl_buf) { int i = 0; while (i < nmemb) { - if (neocities->pos >= neocities->size) { + if (curl_buf->pos >= curl_buf->size) { - neocities->size += nmemb; + curl_buf->size += nmemb; - neocities->buf = - realloc(neocities->buf, sizeof(char) * neocities->size); + curl_buf->buf = + realloc(curl_buf->buf, sizeof(char) * curl_buf->size); - if (neocities->buf == NULL) - return neocities->size; + if (curl_buf->buf == NULL) + return curl_buf->size; } - neocities->buf[neocities->pos] = *(char *) (buffer + i); + curl_buf->buf[curl_buf->pos] = *(char *) (buffer + i); - (neocities->pos)++; + (curl_buf->pos)++; i++; } @@ -159,11 +175,11 @@ size_t write_data(void *buffer, size_t size, size_t nmemb, } enum neocities_low_level_error neocities_api(const char *apikey, - const char *action, + enum neocities_action action, const char *params, json_object ** jobj) { - Neocities neocities; + curl_buffer curl_buf; struct curl_slist *headers = NULL; @@ -187,7 +203,7 @@ enum neocities_low_level_error neocities_api(const char *apikey, if (curl == NULL) return NEOCITIES_LLVL_ERR_CURL_EASY_INIT; - if (action != NULL && strcmp(action, UPLOAD) == 0) { + if (action == upload) { form = curl_mime_init(curl); @@ -227,26 +243,34 @@ enum neocities_low_level_error neocities_api(const char *apikey, if (curl_easy_setopt(curl, CURLOPT_MIMEPOST, form) != CURLE_OK) return NEOCITIES_LLVL_ERR_CURL_EASY_SETOPT; - if (curl_easy_setopt(curl, CURLOPT_URL, action) != CURLE_OK) + if (curl_easy_setopt(curl, CURLOPT_URL, UPLOAD) != CURLE_OK) return NEOCITIES_LLVL_ERR_CURL_EASY_SETOPT; - } else if (action != NULL && strcmp(action, DELETE) == 0) { + } else if (action == delete) { return NEOCITIES_LLVL_ERR_UNSUPPORTED_DELETE; - } else if (action != NULL - && (strcmp(action, INFO) == 0 || strcmp(action, LIST) == 0 - || strcmp(action, KEY) == 0)) { + } else if (action == info || action == list || action == key) { + + memset(&url_with_get_params[0], '\0', 500); - strcpy(&url_with_get_params[0], action); + if (action == key) { - if (strcmp(action, INFO) == 0 && strcmp(params, "") != 0) + strcpy(&url_with_get_params[0], KEY); - strcat(url_with_get_params, "?sitename="); + } else if (action == info) { - else if (strcmp(action, LIST) == 0 && strcmp(params, "") != 0) + strcpy(&url_with_get_params[0], INFO); + if (strcmp(params, "") != 0) + strcat(url_with_get_params, "?sitename="); - strcat(url_with_get_params, "?path="); + } else if (action == list) { + + strcpy(&url_with_get_params[0], LIST); + if (strcmp(params, "") != 0) + strcat(url_with_get_params, "?path="); + + } strcat(url_with_get_params, params); @@ -260,7 +284,7 @@ enum neocities_low_level_error neocities_api(const char *apikey, } - if (neocities_init(&neocities, 700) != 0) + if (curl_buffer_init(&curl_buf, 700) != 0) return NEOCITIES_LLVL_ERR_NEOCITIES_INIT; headers = curl_slist_append(headers, auth_bearer); @@ -276,7 +300,7 @@ enum neocities_low_level_error neocities_api(const char *apikey, return NEOCITIES_LLVL_ERR_CURL_EASY_SETOPT; if (curl_easy_setopt - (curl, CURLOPT_WRITEDATA, ((Neocities *) & neocities))) + (curl, CURLOPT_WRITEDATA, ((curl_buffer *) & curl_buf))) return NEOCITIES_LLVL_ERR_CURL_EASY_SETOPT; if (curl_easy_perform(curl) != CURLE_OK) @@ -287,10 +311,10 @@ enum neocities_low_level_error neocities_api(const char *apikey, curl_easy_cleanup(curl); *jobj = - json_tokener_parse_ex(tok, (char *) neocities.buf, neocities.pos); + json_tokener_parse_ex(tok, (char *) curl_buf.buf, curl_buf.pos); /* https://groups.google.com/forum/#!topic/json-c/CMvkXKXqtWs */ - if (tok->char_offset != neocities.pos) { + if (tok->char_offset != curl_buf.pos) { json_tokener_free(tok); return NEOCITIES_LLVL_ERR_RECEIVED_INVALID_JSON; } @@ -298,9 +322,9 @@ enum neocities_low_level_error neocities_api(const char *apikey, json_tokener_free(tok); #ifdef NEOCITIES_DEBUG - neocities_dump(&neocities); + curl_buffer_dump(&curl_buf); #endif - neocities_destroy(&neocities); + curl_buffer_destroy(&curl_buf); if (*jobj == NULL) return NEOCITIES_LLVL_ERR_JSON_TOKENER_PARSE; @@ -349,6 +373,28 @@ void neocities_destroy_error(neocities_res * res) return; } +void neocities_destroy(neocities_res * res) +{ + + switch (res->type) { + case NEOCITIES_NO_TYPE_YET: + break; + case NEOCITIES_INFO_STRUCT: + neocities_destroy_info(res); + break; + case NEOCITIES_LIST_STRUCT: + neocities_destroy_list(res); + break; + case NEOCITIES_ERROR_STRUCT: + neocities_destroy_error(res); + break; + } + + res->type = NEOCITIES_NO_TYPE_YET; + + return; +} + enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, neocities_res * res) @@ -364,25 +410,25 @@ enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, array_list *tmp_array = NULL; json_object *tmp_object = NULL; - enum neocities_res_data current_type = NEOCITIES_NO_TYPE_YET; + res->type = NEOCITIES_NO_TYPE_YET; json_object_object_foreachC(jobj, jobj_iter) { if (jobj_iter.key != NULL && strcmp(jobj_iter.key, "error_type") == 0) { + res->type = NEOCITIES_ERROR_STRUCT; + res->data.error.type = UNSUPPORTED_ERROR; + + if (json_object_get_type(jobj_iter.val) != json_type_string) + return NEOCITIES_LLVL_ERR_EXPECTED_STRING; + tmp_string = json_object_get_string(jobj_iter.val); if (tmp_string != NULL && strcmp(tmp_string, "site_not_found") == 0) - res->data.error.type = SITE_NOT_FOUND; - else - - res->data.error.type = UNSUPPORTED_ERROR; - - } else if (jobj_iter.key != NULL && strcmp(jobj_iter.key, "result") == 0) { @@ -391,26 +437,21 @@ enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, else seen_result = 1; - tmp_string = json_object_get_string(jobj_iter.val); + if (json_object_get_type(jobj_iter.val) != json_type_string) + return NEOCITIES_LLVL_ERR_EXPECTED_STRING; - if (tmp_string != NULL && strcmp - (json_object_get_string(jobj_iter.val), "success") != 0) { + tmp_string = json_object_get_string(jobj_iter.val); + if (tmp_string != NULL && strcmp(tmp_string, "success") != 0) res->result = -1; - - continue; - - } else { - + else res->result = 0; - } - } else if (jobj_iter.key != NULL && strcmp(jobj_iter.key, "info") == 0 - && current_type == NEOCITIES_NO_TYPE_YET) { + && res->type == NEOCITIES_NO_TYPE_YET) { - current_type = NEOCITIES_INFO_STRUCT; + res->type = NEOCITIES_INFO_STRUCT; res->data.info.sitename = NULL; res->data.info.views = -1; @@ -420,20 +461,35 @@ enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, res->data.info.domain = NULL; res->data.info.tags[0] = NULL; + if (json_object_get_type(jobj_iter.val) != json_type_object) + return NEOCITIES_LLVL_ERR_EXPECTED_OBJECT; + json_object_object_foreachC(jobj_iter.val, jobj_iter_info) { if (strcmp(jobj_iter_info.key, "views") == 0) { + if (json_object_get_type + (jobj_iter_info.val) != json_type_int) + return NEOCITIES_LLVL_ERR_EXPECTED_INT; + res->data.info.views = json_object_get_int(jobj_iter_info.val); } else if (strcmp(jobj_iter_info.key, "hits") == 0) { + if (json_object_get_type + (jobj_iter_info.val) != json_type_int) + return NEOCITIES_LLVL_ERR_EXPECTED_INT; + res->data.info.hits = json_object_get_int(jobj_iter_info.val); } else if (strcmp(jobj_iter_info.key, "sitename") == 0) { + if (json_object_get_type + (jobj_iter_info.val) != json_type_string) + return NEOCITIES_LLVL_ERR_EXPECTED_STRING; + res->data.info.sitename = strdup(json_object_get_string(jobj_iter_info.val)); @@ -442,6 +498,12 @@ enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, } else if (strcmp(jobj_iter_info.key, "domain") == 0) { + if (json_object_get_type + (jobj_iter_info.val) != json_type_string + && json_object_get_type(jobj_iter_info.val) != + json_type_null) + return NEOCITIES_LLVL_ERR_EXPECTED_STRING_OR_NULL; + tmp_string = json_object_get_string(jobj_iter_info.val); @@ -454,6 +516,10 @@ enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, } else if (strcmp(jobj_iter_info.key, "created_at") == 0) { + if (json_object_get_type + (jobj_iter_info.val) != json_type_string) + return NEOCITIES_LLVL_ERR_EXPECTED_STRING; + tmp_string = json_object_get_string (jobj_iter_info.val); @@ -462,6 +528,10 @@ enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, } else if (strcmp(jobj_iter_info.key, "last_updated") == 0) { + if (json_object_get_type + (jobj_iter_info.val) != json_type_string) + return NEOCITIES_LLVL_ERR_EXPECTED_STRING; + tmp_string = json_object_get_string (jobj_iter_info.val); @@ -470,12 +540,20 @@ enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, } else if (strcmp(jobj_iter_info.key, "tags") == 0) { + if (json_object_get_type + (jobj_iter_info.val) != json_type_array) + return NEOCITIES_LLVL_ERR_EXPECTED_ARRAY; + tmp_array = json_object_get_array(jobj_iter_info.val); i = 0; for (; i < tmp_array->length; i++) { + if (json_object_get_type + (((tmp_array->array)[i])) != json_type_string) + return NEOCITIES_LLVL_ERR_EXPECTED_STRING; + res->data.info.tags[i] = strdup(json_object_get_string ((tmp_array->array)[i])); @@ -491,15 +569,19 @@ enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, } - break; + //break; } else if (strcmp(jobj_iter.key, "files") == 0 - && current_type == NEOCITIES_NO_TYPE_YET) { + && res->type == NEOCITIES_NO_TYPE_YET) { - current_type = NEOCITIES_LIST_STRUCT; + res->type = NEOCITIES_LIST_STRUCT; res->data.list.files = NULL; res->data.list.length = 0; + + if (json_object_get_type(jobj_iter.val) != json_type_array) + return NEOCITIES_LLVL_ERR_EXPECTED_ARRAY; + res->data.list.length = json_object_array_length(jobj_iter.val); @@ -524,6 +606,10 @@ enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, if (strcmp(jobj_iter_list.key, "path") == 0) { + if (json_object_get_type + (jobj_iter_list.val) != json_type_string) + return NEOCITIES_LLVL_ERR_EXPECTED_STRING; + (res->data.list.files)[i].path = strdup(json_object_get_string (jobj_iter_list.val)); @@ -531,41 +617,56 @@ enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, if ((res->data.list.files)[i].path == NULL) return NEOCITIES_LLVL_ERR_MALLOC_FAIL; - } else if (strcmp(jobj_iter_list.key, "updated_at") == 0) { + if (json_object_get_type + (jobj_iter_list.val) != json_type_string) + return NEOCITIES_LLVL_ERR_EXPECTED_STRING; + tmp_string = json_object_get_string (jobj_iter_list.val); + if (tmp_string == NULL) + continue; + rfc5322_date_parse(tmp_string, strlen(tmp_string), &(res->data.list.files)[i]. updated_at, true); } else if (strcmp(jobj_iter_list.key, "size") == 0) { + if (json_object_get_type + (jobj_iter_list.val) != json_type_int) + return NEOCITIES_LLVL_ERR_EXPECTED_INT; + (res->data.list.files)[i].size = json_object_get_int(jobj_iter_list.val); } else if (strcmp(jobj_iter_list.key, "is_directory") == 0) { + if (json_object_get_type + (jobj_iter_list.val) != json_type_boolean) + return NEOCITIES_LLVL_ERR_EXPECTED_BOOL; + + /* TRUE is defined by libjson-c */ (res->data.list.files)[i].is_directory = (json_object_get_boolean(jobj_iter_list.val) == TRUE ? 1 : 0); - } else { + } - /* ignore ipfs thing */ + /*else { - continue; - } + return NEOCITIES_LLVL_ERR_UNSUPPORTED_JSON; + + } */ } } - break; } else { if (res->result == 0) // UPLOAD @@ -580,9 +681,22 @@ enum neocities_low_level_error neocities_json_to_struct(json_object * jobj, return NEOCITIES_LLVL_OK; } +enum neocities_res_data action_to_res_data_type(enum neocities_action + action) +{ + switch (action) { + case upload: + return NEOCITIES_NO_TYPE_YET; + case list: + return NEOCITIES_LIST_STRUCT; + case info: + return NEOCITIES_INFO_STRUCT; + } +} + enum neocities_low_level_error neocities_api_ex(const char *apikey, - const char *action, - const char *params, + enum neocities_action + action, const char *params, neocities_res * res) { int err; @@ -596,6 +710,9 @@ enum neocities_low_level_error neocities_api_ex(const char *apikey, err = neocities_json_to_struct(jobj, res); + if (res->type != action_to_res_data_type(action)) + return NEOCITIES_LLVL_ERR_RECEIVED_SOMETHING_ELSE; + json_object_put(jobj); return err; diff --git a/upload.c b/upload.c @@ -28,9 +28,11 @@ int main(int argc, char *argv[]) if (curl_global_init(CURL_GLOBAL_SSL) != 0) return CURL_ERROR; - if ((err = neocities_api_ex(APIKEY, UPLOAD, argv[1], &res)) != OK) + if ((err = neocities_api_ex(APIKEY, upload, argv[1], &res)) != OK) return err; + // neocities_destroy(&res); + curl_global_cleanup(); return 0;