diff options
author | nirav <nirav@teisuu.com> | 2019-03-10 23:45:19 +0530 |
---|---|---|
committer | Dandelion <nirav@teisuu.com> | 2019-03-11 23:05:22 +0530 |
commit | 63e8c7f9d095fe0b1e0b44f950230c0e238f166d (patch) | |
tree | 01e0211f4fdede1eccda010fc944b3a0180a9632 | |
parent | 7e8ea36eb8106b4847af13a27a3e8f3177d25809 (diff) | |
download | ap_client-63e8c7f9d095fe0b1e0b44f950230c0e238f166d.tar.gz ap_client-63e8c7f9d095fe0b1e0b44f950230c0e238f166d.zip |
Add config and log
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | src/auth.c | 144 | ||||
-rw-r--r-- | src/auth.h | 11 | ||||
-rw-r--r-- | src/config.c | 146 | ||||
-rw-r--r-- | src/config.h | 20 | ||||
-rw-r--r-- | src/http.c | 138 | ||||
-rw-r--r-- | src/http.h | 2 | ||||
-rw-r--r-- | src/instance_info.c | 8 | ||||
-rw-r--r-- | src/log.c | 29 | ||||
-rw-r--r-- | src/log.h | 13 | ||||
-rw-r--r-- | src/login_window.c | 13 | ||||
-rw-r--r-- | src/main.c | 49 | ||||
-rw-r--r-- | src/option.c | 64 | ||||
-rw-r--r-- | src/option.h | 14 | ||||
-rw-r--r-- | src/status.c | 11 | ||||
-rw-r--r-- | src/timeline.c | 99 | ||||
-rw-r--r-- | src/timeline.h | 6 | ||||
-rw-r--r-- | src/timeline_window.c | 20 |
18 files changed, 460 insertions, 331 deletions
@@ -18,7 +18,9 @@ OBJECTS=$(OUTDIR)/main.o \ $(OUTDIR)/timeline.o \ $(OUTDIR)/auth.o \ $(OUTDIR)/login_window.o \ - $(OUTDIR)/timeline_window.o + $(OUTDIR)/timeline_window.o \ + $(OUTDIR)/config.o \ + $(OUTDIR)/log.o all: ap_client @@ -7,18 +7,43 @@ #include "string-util.h" #include "auth.h" #include "http.h" +#include "config.h" +#include "log.h" #define CLIENT_NAME "ap_client" #define PROTOCOL_PREFIX "https://" -char *instance_domain; -char *client_id; -char *client_secret; -char *access_token; -char *scope; +static const char *app_register_url = "/api/v1/apps"; +static const char *login_url = "/oauth/token"; -static char *app_register_url = "/api/v1/apps"; -static char *login_url = "/oauth/token"; +int read_local_credentials() +{ + if (!(config->access_token) || !*(config->access_token) || + !(config->instance_url) || !*(config->instance_url)) { + log_msg(LOG_ERROR, "read_local_credentials", + "access_token not found"); + return -1; + } + printf("token: %s\niu: %s\n", config->access_token, config->instance_url); + return 0; +} + +bool is_logged_in() +{ + if (config->access_token) + return true; + return false; +} + +const char *get_access_token() +{ + return (const char *)config->access_token; +} + +const char *get_instance_url() +{ + return (const char *)config->instance_url; +} struct register_call_arg { char *url; @@ -35,46 +60,46 @@ static void *register_call(void *req_arg) arg = (struct register_call_arg *)req_arg; if (!arg || !(arg->url)) { - fprintf(stderr, "register_call(): invalid arguments\n"); + log_msg(LOG_ERROR, "register_call", "invalid arguments"); goto error; } resp = post_request(arg->url, arg->post_data); if (!resp) { - fprintf(stderr, "register_call(): failed to send http request\n"); + log_msg(LOG_ERROR, "register_call", "failed to send http request"); goto error; } if (!resp) { - fprintf(stderr, "register_call(): null response\n"); + log_msg(LOG_ERROR, "register_call", "null response"); goto error; } root = json_loads(resp, 0, NULL); if (!root) { - fprintf(stderr, "register_call(): failed to parse json\n"); + log_msg(LOG_ERROR, "register_call", "failed to parse json"); goto error; } if (!json_is_object(root)) { - fprintf(stderr, "register_call(): json root is not object\n"); + log_msg(LOG_ERROR, "register_call", "json root is not object"); goto error; } json_t *cid = json_object_get(root, "client_id"); json_t *csec = json_object_get(root, "client_secret"); if (!json_is_string(cid) || !json_is_string(csec)) { - fprintf(stderr, - "register_call(): invalid client_id or client_secret\n"); + log_msg(LOG_ERROR, "register_call", + "invalid client_id or client_secret"); goto error; } - client_id = strdup(json_string_value(cid)); - client_secret = strdup(json_string_value(csec)); - instance_domain = arg->domain; - if (strlen(client_id) < 1 || strlen(client_secret) < 1) { - fprintf(stderr, - "register_call(): invalid client_id or client_secret\n"); + config_set_client_id(json_string_value(cid)); + config_set_client_secret(json_string_value(csec)); + config_set_instance_url(arg->domain); + if (!*(config->client_id) || !*(config->client_secret)) { + log_msg(LOG_ERROR, "register_call", + "invalid client_id or client_secret"); goto error; } @@ -114,14 +139,14 @@ int register_app(const char *instance, void (*callback)(bool success)) pthread_t t; if (!instance || strlen(instance) < 1 || !callback) { - fprintf(stderr, "register_app(): invalid argument\n"); + log_msg(LOG_ERROR, "register_app", "invalid argument"); return -1; } size = sizeof(PROTOCOL_PREFIX) + sizeof(instance) + 1; instance_prefix = malloc(size); if (!instance_prefix) { - err(1, "register_app(): malloc failed"); + err(1, NULL); return -1; } strlcpy(instance_prefix, PROTOCOL_PREFIX, size); @@ -132,7 +157,7 @@ int register_app(const char *instance, void (*callback)(bool success)) "read write push"); if (!root) { - fprintf(stderr, "register_app(): json pack error: line %d: %s\n", + log_msg(LOG_ERROR, "register_app", "json pack error: line %d: %s", error.line, error.text); return -1; } @@ -140,14 +165,14 @@ int register_app(const char *instance, void (*callback)(bool success)) req_data = json_dumps(root, 0); json_decref(root); if (!req_data) { - fprintf(stderr, "register_app(): failed to dump json\n"); + log_msg(LOG_ERROR, "register_app", "failed to dump json"); return -1; } size = strlen(instance_prefix) + strlen(app_register_url) + 1; url = malloc(size); if (!url) { - err(1, "register_app(): malloc failed"); + err(1, NULL); return -1; } @@ -156,7 +181,7 @@ int register_app(const char *instance, void (*callback)(bool success)) arg = calloc(1, sizeof(struct register_call_arg)); if (!arg) { - err(1, "register_app(): calloc failed"); + err(1, NULL); return -1; } arg->url = url; @@ -181,29 +206,29 @@ static void *login_call(void *req_arg) arg = (struct login_call_arg *)req_arg; if (!arg || !(arg->url)) { - fprintf(stderr, "login_call(): invalid arguments\n"); + log_msg(LOG_ERROR, "login_call", "invalid arguments"); goto error; } resp = post_request(arg->url, arg->post_data); if (!resp) { - fprintf(stderr, "login_call(): failed to send http request\n"); + log_msg(LOG_ERROR, "login_call", "failed to send http request"); goto error; } if (!resp) { - fprintf(stderr, "login_call(): null response\n"); + log_msg(LOG_ERROR, "login_call", "null response"); goto error; } root = json_loads(resp, 0, NULL); if (!root) { - fprintf(stderr, "login_call(): failed to parse json\n"); + log_msg(LOG_ERROR, "login_call", "failed to parse json"); goto error; } if (!json_is_object(root)) { - fprintf(stderr, "login_call(): json root is not object\n"); + log_msg(LOG_ERROR, "login_call", "json root is not object"); goto error; } @@ -212,12 +237,17 @@ static void *login_call(void *req_arg) if (!json_is_string(access_token_j) || !json_is_string(scope_j) || strlen(json_string_value(access_token_j)) < 1 || strlen(json_string_value(scope_j)) < 1) { - fprintf(stderr, "login_call(): invalid access_token or scope\n"); + log_msg(LOG_ERROR, "login_call", "invalid access_token or scope"); goto error; } - access_token = strdup(json_string_value(access_token_j)); - scope = strdup(json_string_value(scope_j)); + config_set_access_token(json_string_value(access_token_j)); + /* scope = strdup(json_string_value(scope_j)); */ + + if (config_save()) { + log_msg(LOG_ERROR, "login_call", "failed to save config"); + goto error; + } free(arg->url); if (arg->post_data) @@ -227,7 +257,7 @@ static void *login_call(void *req_arg) json_decref(root); (*(arg->callback))(true); - printf("access_token: %s\n", access_token); + printf("access_token: %s", config->access_token); return NULL; error: @@ -257,49 +287,46 @@ int login( struct login_call_arg *arg; if (!email || strlen(email) < 1 || !password || strlen(password) < 1) { - fprintf(stderr, "login(): invalid argument\n"); + log_msg(LOG_ERROR, "login", "invalid argument"); return -1; } - if (!client_id || strlen(client_id) < 1 || !client_secret || - strlen(client_secret) < 1 || !instance_domain || - strlen(instance_domain) < 1) { - fprintf(stderr, "login(): invalid client_id or client_secret\n"); - printf("cid: %s\n", client_id); - printf("csec: %s\n", client_secret); - printf("in: %s\n", instance_domain); + if (!(config->client_id) || !*(config->client_id) || + !(config->client_secret) || !*(config->client_secret) || + !(config->instance_url) || !*(config->instance_url)) { + log_msg(LOG_ERROR, "login", "invalid client_id or client_secret"); return -1; } root = json_pack_ex(&error, 1, "{s:s, s:s, s:s, s:s, s:s}", "client_id", - client_id, "client_secret", client_secret, "grant_type", "password", - "username", email, "password", password); + config->client_id, "client_secret", config->client_secret, + "grant_type", "password", "username", email, "password", password); if (!root) { - fprintf(stderr, "login(): json pack error: line %d: %s\n", error.line, - error.text); + log_msg(LOG_ERROR, "login", "json pack error: line %d: %s", + error.line, error.text); return -1; } req_data = json_dumps(root, 0); json_decref(root); if (!req_data) { - fprintf(stderr, "login(): failed to dump json\n"); + log_msg(LOG_ERROR, "login", "failed to dump json"); return -1; } - size = strlen(instance_domain) + strlen(login_url) + 1; + size = strlen(config->instance_url) + strlen(login_url) + 1; url = malloc(size); if (!url) { - err(1, "login(): malloc failed"); + err(1, NULL); return -1; } - strlcpy(url, instance_domain, size); + strlcpy(url, config->instance_url, size); strlcat(url, login_url, size); arg = calloc(1, sizeof(struct login_call_arg)); if (!arg) { - err(1, "login(): calloc failed"); + err(1, NULL); return -1; } arg->url = url; @@ -307,17 +334,4 @@ int login( arg->callback = callback; return pthread_create(&t, NULL, &login_call, arg); - return 0; -} - -void auth_cleanup() -{ - if (instance_domain) - free(instance_domain); - if (access_token) - free(access_token); - if (client_id) - free(client_id); - if (client_secret) - free(client_secret); } @@ -3,15 +3,12 @@ #include <stdbool.h> -extern char *instance_domain; -extern char *client_id; -extern char *client_secret; -extern char *access_token; -extern char *scope; - +bool is_logged_in(); +const char* get_access_token(); +const char* get_instance_url(); +int read_local_credentials(); int register_app(const char *instance, void (*callback) (bool success)); int login(const char *email, const char *password, void (*callback) (bool success)); -void auth_cleanup(); #endif diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..c4aecf0 --- /dev/null +++ b/src/config.c @@ -0,0 +1,146 @@ +#define _POSIX_C_SOURCE 200809L +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <limits.h> +#include <libgen.h> +#include <jansson.h> +#include "string-util.h" +#include "config.h" +#include "log.h" + +#define CONFIG_PATH_SUFFIX "/.config/ap_client/config" + +struct config _config; +const struct config *config = (const struct config *)&_config; + +char *get_config_path() +{ + char *home = getenv("HOME"); + if (!home || !*home) { + return NULL; + } + char config_path[PATH_MAX]; + strlcpy(config_path, home, sizeof(config_path)); + strlcat(config_path, CONFIG_PATH_SUFFIX, sizeof(config_path)); + return strdup(config_path); +} + +void config_load() +{ + json_t *root; + json_error_t error; + + char *path = get_config_path(); + root = json_load_file(path, 0, &error); + if (!root) { + log_msg(LOG_ERROR, "load_config", "json parse error: line %d: %s", + error.line, error.text); + free(path); + return; + } + free(path); + + if (!json_is_object(root)) { + log_msg(LOG_ERROR, "load_config", "json root is not object"); + json_decref(root); + return; + } + + json_t *instance_url = json_object_get(root, "instance_url"); + if (json_is_string(instance_url)) { + _config.instance_url = strdup(json_string_value(instance_url)); + } + + json_t *client_id = json_object_get(root, "client_id"); + if (json_is_string(client_id)) { + _config.client_id = strdup(json_string_value(client_id)); + } + + json_t *client_secret = json_object_get(root, "client_secret"); + if (json_is_string(client_secret)) { + _config.client_secret = strdup(json_string_value(client_secret)); + } + + json_t *access_token = json_object_get(root, "access_token"); + if (json_is_string(access_token)) { + _config.access_token = strdup(json_string_value(access_token)); + } + + json_decref(root); +} + +int config_save() +{ + json_t *root; + json_error_t error; + + root = json_pack_ex(&error, 1, "{s:s, s:s, s:s, s:s}", "instance_url", + _config.instance_url, "client_id", _config.client_id, + "client_secret", _config.client_secret, "access_token", + _config.access_token); + + if (!root) { + log_msg(LOG_ERROR, "register_app", "json pack error: line %d: %s", + error.line, error.text); + return -1; + } + + char *config_path = get_config_path(); + struct stat st; + char *dir = dirname(config_path); + if (stat(dir, &st)) { + if (mkdir(dir, S_IRWXU)) { + free(config_path); + log_msg(LOG_ERROR, "load_config", "failed to create config dir"); + return -1; + } + } + free(config_path); + + if (json_dump_file(root, get_config_path(), 0)) { + log_msg(LOG_ERROR, "load_config", "unable to save json"); + json_decref(root); + return -1; + } + + json_decref(root); + return 0; +} + +void config_set_client_id(const char *cid) +{ + _config.client_id = strdup(cid); +} + +void config_set_client_secret(const char *cs) +{ + _config.client_secret = strdup(cs); +} + +void config_set_instance_url(const char *iu) +{ + printf("updating url: %s", iu); + _config.instance_url = strdup(iu); +} + +void config_set_access_token(const char *a) +{ + _config.access_token = strdup(a); +} + +void config_cleanup() +{ + if (_config.client_id) + free(_config.client_id); + if (_config.client_secret) + free(_config.client_secret); + if (_config.instance_url) + free(_config.instance_url); + if (_config.access_token) + free(_config.access_token); +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..3875a1b --- /dev/null +++ b/src/config.h @@ -0,0 +1,20 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +struct config { + char *instance_url; + char *client_id; + char *client_secret; + char *access_token; +}; + +extern const struct config *config; +void config_load(); +int config_save(); +void config_set_client_id(const char *cid); +void config_set_client_secret(const char *cs); +void config_set_instance_url(const char *iu); +void config_set_access_token(const char *a); +void config_cleanup(); + +#endif @@ -6,6 +6,7 @@ #include <curl/curl.h> #include "string-util.h" #include "auth.h" +#include "log.h" #define BUFFER_SIZE (256 * 1024) #define AUTH_HEADER_STR_PREFIX "Authorization: Bearer " @@ -31,7 +32,7 @@ static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream) struct write_result *result = (struct write_result *)stream; if (result->pos + size * nmemb >= BUFFER_SIZE - 1) { - fprintf(stderr, "error: too small buffer\n"); + log_msg(LOG_ERROR, "write_response", "buffer too small"); return 0; } @@ -60,12 +61,12 @@ char *get_request(const char *url) struct write_result write_result = {.data = data, .pos = 0}; - if (access_token) { - char *auth_header_val = - malloc(strlen(AUTH_HEADER_STR_PREFIX) + strlen(access_token) + 1); - strlcpy(auth_header_val, AUTH_HEADER_STR_PREFIX, - sizeof(auth_header_val)); - strlcat(auth_header_val, access_token, sizeof(auth_header_val)); + if (is_logged_in()) { + const char *token = get_access_token(); + size_t s = strlen(AUTH_HEADER_STR_PREFIX) + strlen(token) + 1; + char *auth_header_val = malloc(s); + strlcpy(auth_header_val, AUTH_HEADER_STR_PREFIX, s); + strlcat(auth_header_val, token, s); headers = curl_slist_append(headers, auth_header_val); } @@ -76,14 +77,16 @@ char *get_request(const char *url) status = curl_easy_perform(curl); if (status != 0) { - fprintf(stderr, "get_request(): unable to request data from %s: %s\n", - url, curl_easy_strerror(status)); + log_msg(LOG_ERROR, "get_request", + "unable to request data from %s: %s", url, + curl_easy_strerror(status)); goto error; } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); if (code != 200) { - fprintf(stderr, "error: server responded with code %ld\n", code); + log_msg(LOG_ERROR, "get_request", "server responded with code %ld", + code); goto error; } @@ -121,12 +124,12 @@ char *post_request(const char *url, char *post_data) struct write_result write_result = {.data = data, .pos = 0}; - if (access_token) { - char *auth_header_val = - malloc(strlen(AUTH_HEADER_STR_PREFIX) + strlen(access_token) + 1); - strlcpy(auth_header_val, AUTH_HEADER_STR_PREFIX, - sizeof(auth_header_val)); - strlcat(auth_header_val, access_token, sizeof(auth_header_val)); + if (is_logged_in()) { + const char *token = get_access_token(); + size_t s = strlen(AUTH_HEADER_STR_PREFIX) + strlen(token) + 1; + char *auth_header_val = malloc(s); + strlcpy(auth_header_val, AUTH_HEADER_STR_PREFIX, s); + strlcat(auth_header_val, token, s); headers = curl_slist_append(headers, auth_header_val); } if (post_data) { @@ -138,18 +141,19 @@ char *post_request(const char *url, char *post_data) curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_response); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); + if (post_data) + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); status = curl_easy_perform(curl); if (status != 0) { - fprintf(stderr, "post_request(): unable to request data from %s: %s\n", + log_msg(LOG_ERROR, "post_request", "unable to request data from %s: %s", url, curl_easy_strerror(status)); goto error; } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); if (code != 200) { - fprintf(stderr, "error: server responded with code %ld\n", code); + log_msg(LOG_ERROR, "post_request", "server responded with code %ld", code); goto error; } @@ -168,99 +172,3 @@ error: curl_easy_cleanup(curl); return NULL; } - -struct post_request_arg { - char *url; - char *post_data; - void (*callback)(char *); -}; - -void *post_one_url(void *arg) -{ - - struct post_request_arg *req_args = (struct post_request_arg *)arg; - CURL *curl = NULL; - CURLcode status; - struct curl_slist *headers = NULL; - char *data = NULL; - long code; - - curl = curl_easy_init(); - if (!curl) - goto error; - - data = malloc(BUFFER_SIZE); - if (!data) - goto error; - - struct write_result write_result = {.data = data, .pos = 0}; - - if (access_token) { - char *auth_header_val = - malloc(strlen(AUTH_HEADER_STR_PREFIX) + strlen(access_token) + 1); - strlcpy(auth_header_val, AUTH_HEADER_STR_PREFIX, - sizeof(auth_header_val)); - strlcat(auth_header_val, access_token, sizeof(auth_header_val)); - headers = curl_slist_append(headers, auth_header_val); - } - if (req_args->post_data) { - char *content_type_header_val = "Content-Type: application/json"; - headers = curl_slist_append(headers, content_type_header_val); - } - - curl_easy_setopt(curl, CURLOPT_URL, req_args->url); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_response); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req_args->post_data); - - status = curl_easy_perform(curl); - if (status != 0) { - fprintf(stderr, "post_request(): unable to request data from %s: %s\n", - req_args->url, curl_easy_strerror(status)); - goto error; - } - - fprintf(stderr, "http method: POST, url: %s, res: %s\n", req_args->url, data); - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); - if (code != 200) { - fprintf(stderr, "post_request(): server responded with code %ld\n", code); - goto error; - } - - data[write_result.pos] = '\0'; - - curl_slist_free_all(headers); - curl_easy_cleanup(curl); - - (*(req_args->callback))(data); - return NULL; - -error: - if (data) - free(data); - if (headers) - curl_slist_free_all(headers); - if (curl) - curl_easy_cleanup(curl); - - (*(req_args->callback))(NULL); - return NULL; -} - -int http_post_async(char *url, char *post_data, void (*callback)(char *)) -{ - struct post_request_arg *arg; - pthread_t t; - - arg = calloc(1, sizeof(struct post_request_arg)); - if (!arg) { - err(1, "http_post_async(): calloc failed"); - return -1; - } - arg->url = url; - arg->post_data = post_data; - arg->callback = callback; - - return pthread_create(&t, NULL, post_one_url, arg); -} @@ -5,6 +5,6 @@ int http_init(); void http_cleanup(); char *get_request(const char *url); char *post_request(const char *url, char *data); -int http_post_async(char *url, char *post_data, void (*callback)(char *)); +/* int http_post_async(char *url, char *post_data, void (*callback)(char *)); */ #endif diff --git a/src/instance_info.c b/src/instance_info.c index 6dab351..7b9326e 100644 --- a/src/instance_info.c +++ b/src/instance_info.c @@ -2,6 +2,7 @@ #include <string.h> #include <jansson.h> #include "instance_info.h" +#include "log.h" struct instance_info *instance_info_from_json(char *json_data) { @@ -14,19 +15,20 @@ struct instance_info *instance_info_from_json(char *json_data) root = json_loads(json_data, 0, &error); if (!root) { - fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); + log_msg(LOG_ERROR, "instance_info_from_json", "error: on line %d: %s", + error.line, error.text); return NULL; } if (!json_is_object(root)) { - fprintf(stderr, "root is not object"); + log_msg(LOG_ERROR, "instance_info_from_json", "root is not object"); json_decref(root); return NULL; } json_t *title = json_object_get(root, "title"); if (!json_is_string(title)) { - fprintf(stderr, "title is not string"); + log_msg(LOG_ERROR, "instance_info_from_json", "title is not string"); return NULL; } info->title = strdup(json_string_value(title)); diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..52d7028 --- /dev/null +++ b/src/log.c @@ -0,0 +1,29 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include "log.h" + +static const char *log_levels[] = { + "info" + "warning", + "error", + "fatal", +}; + +void log_msg(enum log_level level, const char *namespace, const char *format, ...) { + va_list args; + va_start(args, format); + + fprintf(stderr, "%s: %s: ", log_levels[level], namespace); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + + if (level == LOG_ERROR) { + exit(EXIT_FAILURE); + } else if (level == LOG_FATAL) { + abort(); + } + + va_end(args); +} + diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..ecd3428 --- /dev/null +++ b/src/log.h @@ -0,0 +1,13 @@ +#ifndef __LOG_H +#define __LOG_H + +enum log_level { + LOG_INFO = 0, + LOG_WARNING, + LOG_ERROR, + LOG_FATAL +}; + +void log_msg(enum log_level level, const char *namespace, const char *format, ...); + +#endif diff --git a/src/login_window.c b/src/login_window.c index 32f88a0..8bf82c1 100644 --- a/src/login_window.c +++ b/src/login_window.c @@ -8,6 +8,7 @@ #include "http.h" #include "timeline.h" #include "timeline_window.h" +#include "log.h" GtkApplication *application; static GtkWidget *window; @@ -19,13 +20,13 @@ static GtkWidget *spinner; static void window_removed( GtkApplication *application, GtkWindow *w, gpointer user_data) { - gtk_widget_destroy(GTK_WIDGET(w)); + /* gtk_widget_destroy(GTK_WIDGET(w)); */ } static void login_callback(bool success) { if (!success) { - fprintf(stderr, "login_callback(): login failed\n"); + log_msg(LOG_ERROR, "login_callback", "login failed"); gtk_spinner_stop(GTK_SPINNER(spinner)); return; } @@ -33,16 +34,16 @@ static void login_callback(bool success) printf("login success\n"); gtk_spinner_stop(GTK_SPINNER(spinner)); create_timeline_window(application, NULL); - gtk_window_close(GTK_WINDOW(window)); - gtk_application_remove_window( - GTK_APPLICATION(application), GTK_WINDOW(window)); + /* gtk_window_close(GTK_WINDOW(window)); */ + /* gtk_application_remove_window( */ + /* GTK_APPLICATION(application), GTK_WINDOW(window)); */ } static void register_callback(bool success) { if (!success) { gtk_spinner_stop(GTK_SPINNER(spinner)); - fprintf(stderr, "register_callback(): register failed\n"); + log_msg(LOG_ERROR, "register_callback", "register failed"); return; } printf("register success\n"); @@ -8,23 +8,28 @@ #include "http.h" #include "timeline.h" #include "login_window.h" - +#include "config.h" +#include "timeline_window.h" +#include "log.h" static void activate(GtkApplication *app, gpointer user_data) { - create_login_window(app, user_data); + if (read_local_credentials()) { + create_login_window(app, user_data); + return; + } + create_timeline_window(app, NULL); } int main(int argc, char **argv) { - /* gtk_init(&argc, &argv); */ - /* create_main_window(); */ - /* gtk_main(); */ if (http_init()) { - fprintf(stderr, "main(): failed to load http library\n"); + log_msg(LOG_ERROR, "main", "failed to load http library"); return EXIT_FAILURE; } + config_load(); + GtkApplication *app; int status; @@ -34,37 +39,7 @@ int main(int argc, char **argv) g_object_unref(app); http_cleanup(); - auth_cleanup(); + config_cleanup(); return status; - - /* char *text; */ - /* struct timeline *t; */ - /* char *url = "https://mstdn.io/api/v1/timelines/home"; */ - /* char *token = */ - /* "580acfb412e927c2030fb5519f417b03ced1482c862d44376922cd81ee8a3655"; - */ - - /* text = request(url, token); */ - /* if (!text) { */ - /* fprintf(stderr, "main(): failed to get http response\n"); */ - /* return EXIT_FAILURE; */ - /* } */ - - /* t = timeline_from_json(text); */ - /* if (t == NULL) { */ - /* fprintf(stderr, "main(): failed to parse timeline\n"); */ - /* return EXIT_FAILURE; */ - /* } */ - - /* for (size_t i = 0; i < t->size; i++) { */ - /* printf("status id: %s\n", t->statuses[i]->id); */ - /* printf("content: %s\n", t->statuses[i]->content); */ - /* printf("reblog count: %d\n", t->statuses[i]->reblogs_count); */ - /* printf("fav count: %d\n", t->statuses[i]->favourites_count); */ - /* printf("\n"); */ - /* } */ - - /* free(text); */ - /* timeline_free(t); */ } diff --git a/src/option.c b/src/option.c deleted file mode 100644 index 011bd94..0000000 --- a/src/option.c +++ /dev/null @@ -1,64 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <unistd.h> -#include "option.h" - -static const char version[] = "qwe version 0.01"; -static const char usage[] = - "Usage: qwe [options...] <file>\n" - "\n" - " -i Hide info bar by default.\n" - " -f Use fullscreen mode by default.\n" - " -h Show help message and quit.\n" - " -v Show the version number and quit.\n"; - -void print_usage() -{ - printf("%s\n", usage); -} - -void print_version() -{ - printf("%s\n", version); -} - -struct option _options; -const struct option *options = (const struct option *)&_options; - -void parse_options(int argc, char **argv) -{ - // default options - _options.fullscreen = false; - _options.show_info = true; - - // override options from commandline parameters - int opt; - while ((opt = getopt(argc, argv, "hvif")) != -1) { - switch (opt) { - case '?': - print_usage(); - exit(EXIT_FAILURE); - case 'h': - print_usage(); - exit(EXIT_SUCCESS); - case 'v': - print_version(); - exit(EXIT_SUCCESS); - case 'i': - _options.show_info = false; - break; - case 'f': - _options.fullscreen = true; - break; - } - } - - if (optind >= argc) { - print_usage(); - exit(EXIT_FAILURE); - } - - _options.file_name = argv[optind]; -} diff --git a/src/option.h b/src/option.h deleted file mode 100644 index 33b8335..0000000 --- a/src/option.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __OPTION_H -#define __OPTION_H - -#include <stdbool.h> - -struct option { - char *file_name; - bool fullscreen; - bool show_info; -}; -extern const struct option *options; -void parse_options(int argc, char **argv); - -#endif diff --git a/src/status.c b/src/status.c index 36cd865..139c719 100644 --- a/src/status.c +++ b/src/status.c @@ -3,6 +3,7 @@ #include <string.h> #include <jansson.h> #include "status.h" +#include "log.h" struct status *status_from_json(char *json_data) { @@ -11,7 +12,7 @@ struct status *status_from_json(char *json_data) root = json_loads(json_data, 0, &error); if (!root) { - fprintf(stderr, "status_from_json(): json parse error: line %d: %s\n", + log_msg(LOG_ERROR, "status_from_json", "json parse error: line %d: %s", error.line, error.text); return NULL; } @@ -23,19 +24,19 @@ struct status *status_from_json_t(json_t *root) { struct status *s; if (!root) { - fprintf(stderr, "status_from_json_t(): json data is null\n"); + log_msg(LOG_ERROR, "status_from_json_t", "json data is null"); return NULL; } if (!json_is_object(root)) { - fprintf(stderr, "status_from_json_t(): json root is not object\n"); + log_msg(LOG_ERROR, "status_from_json_t", "json root is not object"); json_decref(root); return NULL; } s = calloc(1, sizeof(struct status)); if (!s) { - err(1, "status_from_json_t(): failed to allocate memory"); + err(1, NULL); json_decref(root); return NULL; } @@ -94,7 +95,7 @@ struct status *status_from_json_t(json_t *root) void status_free(struct status *s) { if (!s) { - fprintf(stderr, "status_free(): status not initializes"); + log_msg(LOG_ERROR, "status_free", "status not initializes"); return; } if (s->id) diff --git a/src/timeline.c b/src/timeline.c index 7b0a567..fbd123e 100644 --- a/src/timeline.c +++ b/src/timeline.c @@ -1,10 +1,17 @@ #define _POSIX_C_SOURCE 200809L #include <err.h> #include <string.h> +#include <pthread.h> #include <jansson.h> #include "timeline.h" +#include "auth.h" +#include "http.h" +#include "string-util.h" +#include "log.h" -struct timeline *timeline_from_json(char *json_data) +static char *timeline_url = "/api/v1/timelines/home"; + +struct timeline *timeline_from_json(const char *json_data) { json_t *root; json_error_t error; @@ -13,19 +20,19 @@ struct timeline *timeline_from_json(char *json_data) root = json_loads(json_data, 0, &error); if (!root) { - fprintf(stderr, "timeline_free(): json root it null\n"); + log_msg(LOG_ERROR, "timeline_free", "json root it null"); return NULL; } if (!json_is_array(root)) { - fprintf(stderr, "timeline_free(): timeline not initialized\n"); + log_msg(LOG_ERROR, "timeline_free", "timeline not initialized"); json_decref(root); return NULL; } t = calloc(1, sizeof(struct timeline)); if (!t) { - err(1, "timeline_from_json(): failed to allocate memory"); + err(1, NULL); json_decref(root); return NULL; } @@ -33,7 +40,7 @@ struct timeline *timeline_from_json(char *json_data) t->size = json_array_size(root); t->statuses = calloc(t->size, sizeof(struct status *)); if (!(t->statuses)) { - err(1, "timeline_from_json(): failed to allocate memory"); + err(1, NULL); json_decref(root); return NULL; } @@ -59,7 +66,7 @@ error: void timeline_free(struct timeline *t) { if (!t) { - fprintf(stderr, "timeline_free(): timeline not initialized\n"); + log_msg(LOG_ERROR, "timeline_free", "timeline not initialized"); return; } for (size_t i = 0; i < t->size; i++) { @@ -69,7 +76,83 @@ void timeline_free(struct timeline *t) free(t); } -int lod_timeline(const char *max_id, const char *since_id, const char *min_id, int limit) +struct load_timeline_call_arg { + char *url; + void (*callback)(bool, struct timeline *t); +}; + +static void *load_timeline_call(void *req_arg) +{ + struct load_timeline_call_arg *arg; + char *resp; + struct timeline *t; + + arg = (struct load_timeline_call_arg *)req_arg; + if (!(arg->url)) { + log_msg(LOG_ERROR, "load_timeline_call", "invalid arguments"); + goto error; + } + + resp = get_request(arg->url); + if (!resp) { + log_msg(LOG_ERROR, "load_timeline_call", "failed to send http request"); + goto error; + } + + if (!resp) { + log_msg(LOG_ERROR, "load_timeline_call", "null response"); + goto error; + } + + t = timeline_from_json(resp); + if (!t) { + log_msg(LOG_ERROR, "load_timeline_call", "null response"); + goto error; + } + + free(arg->url); + free(arg); + free(resp); + + (*(arg->callback))(true, t); + return NULL; + +error: + if (arg->url) + free(arg->url); + free(arg); + if (resp) + free(resp); + (*(arg->callback))(false, NULL); + return NULL; +} + +int get_timeline(const char *max_id, const char *since_id, const char *min_id, + int limit, void (*callback)(bool success, struct timeline *t)) { - return 0; + size_t size; + char *url; + struct load_timeline_call_arg *arg; + pthread_t t; + + size = strlen(get_instance_url()) + strlen(timeline_url) + 1; + url = malloc(size); + if (!url) { + err(1, NULL); + return -1; + } + + strlcpy(url, get_instance_url(), size); + strlcat(url, timeline_url, size); + + arg = calloc(1, sizeof(struct load_timeline_call_arg)); + if (!arg) { + err(1, NULL); + return -1; + } + + arg->url = url; + arg->callback = callback; + + return pthread_create(&t, NULL, &load_timeline_call, arg); } diff --git a/src/timeline.h b/src/timeline.h index f31f618..ea72e5c 100644 --- a/src/timeline.h +++ b/src/timeline.h @@ -8,9 +8,9 @@ struct timeline { size_t size; }; -struct timeline *timeline_from_json(char *); +struct timeline *timeline_from_json(const char *); void timeline_free(struct timeline *); -int lod_timeline(const char *max_id, const char *since_id, const char *min_id, - int limit); +int get_timeline(const char *max_id, const char *since_id, const char *min_id, + int limit, void (*callback)(bool success, struct timeline *t)); #endif diff --git a/src/timeline_window.c b/src/timeline_window.c index c09397a..10f2a84 100644 --- a/src/timeline_window.c +++ b/src/timeline_window.c @@ -7,13 +7,29 @@ #include "auth.h" #include "http.h" #include "timeline.h" +#include "log.h" static GtkWidget *window; static GtkWidget *box; static GtkWidget *label; -static void load_tieline() +static void timeline_callback(bool success, struct timeline *t) { + for (size_t i = 0; i < t->size; i++) { + printf("status id: %s\n", t->statuses[i]->id); + printf("content: %s\n", t->statuses[i]->content); + printf("reblog count: %d\n", t->statuses[i]->reblogs_count); + printf("fav count: %d\n", t->statuses[i]->favourites_count); + printf("\n"); + } +} + +static void load_timeline() +{ + if (get_timeline(NULL, NULL, NULL, 20, &timeline_callback)) { + log_msg(LOG_ERROR, "load_timeline", "failed"); + return; + } return; } @@ -34,5 +50,5 @@ void create_timeline_window(GtkApplication *app, gpointer user_data) gtk_container_add(GTK_CONTAINER(box), label); gtk_widget_show_all(window); - load_tieline(); + load_timeline(); } |