summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authornirav <nirav@teisuu.com>2019-03-21 16:34:24 +0530
committerDandelion <nirav@teisuu.com>2019-03-21 16:50:20 +0530
commit4b27c1a348d8de036dabd5525452f5b9ad08a32b (patch)
treef70c35351dc357d4297f985607fce9221ced96f0 /src
parentc608bcc3dfab2abe7b66c10f8556086b2d45b3a3 (diff)
downloadap_client-4b27c1a348d8de036dabd5525452f5b9ad08a32b.tar.gz
ap_client-4b27c1a348d8de036dabd5525452f5b9ad08a32b.zip
Use g_threads, add builder ui for timeline
Diffstat (limited to 'src')
-rw-r--r--src/auth.c347
-rw-r--r--src/auth.h7
-rw-r--r--src/config.c46
-rw-r--r--src/config.h8
-rw-r--r--src/http.c14
-rw-r--r--src/log.c4
-rw-r--r--src/login_window.c56
-rw-r--r--src/main.c3
-rw-r--r--src/register.c128
-rw-r--r--src/register.h8
-rw-r--r--src/string-util.c38
-rw-r--r--src/string-util.h1
-rw-r--r--src/timeline.c27
-rw-r--r--src/timeline_window.c81
14 files changed, 434 insertions, 334 deletions
diff --git a/src/auth.c b/src/auth.c
index 3a2ee17..c903e67 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -10,328 +10,137 @@
#include "config.h"
#include "log.h"
-#define CLIENT_NAME "ap_client"
-#define PROTOCOL_PREFIX "https://"
+#define LOGIN_URL "https://%s/oauth/token"
-static const char *app_register_url = "/api/v1/apps";
-static const 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_WARNING, "read_local_credentials",
- "access_token not found");
- return -1;
- }
- printf("token: %s\niu: %s\n", config->access_token, config->instance_url);
- return 0;
-}
+struct login_response {
+ char *access_token;
+ char *scope;
+};
-bool is_logged_in()
+static char *get_login_url(const char *domain)
{
- if (config->access_token)
- return true;
- return false;
-}
+ char *url;
+ size_t size;
-const char *get_access_token()
-{
- return (const char *)config->access_token;
-}
+ size = strlen(LOGIN_URL) + strlen(domain) - 1;
+ url = malloc(size);
+ if (!url) {
+ err(1, NULL);
+ return NULL;
+ }
-const char *get_instance_url()
-{
- return (const char *)config->instance_url;
+ sprintf(url, LOGIN_URL, domain);
+ return url;
}
-struct register_call_arg {
- char *url;
- char *domain;
- char *post_data;
- void (*callback)(bool);
-};
-
-static void *register_call(void *req_arg)
+static char *get_login_req(const char *email, const char *password)
{
- struct register_call_arg *arg;
- char *resp;
- json_t *root;
+ char *req;
+ json_t *json_root;
+ json_error_t error;
- arg = (struct register_call_arg *)req_arg;
- if (!arg || !(arg->url)) {
- log_msg(LOG_WARNING, "register_call", "invalid arguments");
- goto error;
+ json_root = json_pack_ex(&error, 1, "{s:s, s:s, s:s, s:s, s:s}",
+ "client_id", config->client_id, "client_secret",
+ config->client_secret, "grant_type", "password", "username", email,
+ "password", password);
+ if (!json_root) {
+ return NULL;
}
- resp = post_request(arg->url, arg->post_data);
- if (!resp) {
- log_msg(LOG_WARNING, "register_call", "failed to send http request");
- goto error;
- }
+ req = json_dumps(json_root, 0);
+ json_decref(json_root);
- if (!resp) {
- log_msg(LOG_WARNING, "register_call", "null response");
- goto error;
- }
+ return req;
+}
- root = json_loads(resp, 0, NULL);
- if (!root) {
- log_msg(LOG_WARNING, "register_call", "failed to parse json");
- goto error;
- }
+static struct login_response *get_login_resp(char *data)
+{
+ struct login_response *resp;
+ json_t *json_root;
+ json_t *access_token, *scope;
- if (!json_is_object(root)) {
- log_msg(LOG_WARNING, "register_call", "json root is not object");
- goto error;
+ json_root = json_loads(data, 0, NULL);
+ if (!json_root) {
+ return NULL;
}
- 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)) {
- log_msg(LOG_WARNING, "register_call",
- "invalid client_id or client_secret");
- goto error;
+ if (!json_is_object(json_root)) {
+ json_decref(json_root);
+ return NULL;
}
- 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_WARNING, "register_call",
- "invalid client_id or client_secret");
- goto error;
+ access_token = json_object_get(json_root, "access_token");
+ scope = json_object_get(json_root, "scope");
+ if (!json_is_string(access_token) || !json_is_string(scope)) {
+ json_decref(json_root);
+ return NULL;
}
- free(arg->url);
- if (arg->post_data)
- free(arg->post_data);
- free(arg);
- free(resp);
- json_decref(root);
- (*(arg->callback))(true);
- return NULL;
+ resp = calloc(1, sizeof(struct login_response));
+ resp->access_token = strdup(json_string_value(access_token));
+ resp->scope = strdup(json_string_value(scope));
-error:
- if (arg) {
- if (arg->url)
- free(arg->url);
- if (arg->post_data)
- free(arg->post_data);
- free(arg);
- }
- if (resp)
- free(resp);
- if (root)
- json_decref(root);
- (*(arg->callback))(false);
- return NULL;
+ json_decref(json_root);
+ return resp;
}
-int register_app(const char *instance, void (*callback)(bool success))
+int login(const char *email, const char *password)
{
- size_t size;
- char *instance_prefix;
- char *url, *req_data;
- struct register_call_arg *arg;
- json_t *root;
- json_error_t error;
- pthread_t t;
+ char *url, *req_data, *resp_data;
+ struct login_response *resp;
- if (!instance || strlen(instance) < 1 || !callback) {
- log_msg(LOG_WARNING, "register_app", "invalid argument");
+ if (!email || !*email || !password || !*password) {
+ log_msg(LOG_WARNING, "login", "invalid argument");
return -1;
}
- size = sizeof(PROTOCOL_PREFIX) + sizeof(instance) + 1;
- instance_prefix = malloc(size);
- if (!instance_prefix) {
- err(1, NULL);
+ if (!is_registered()) {
+ log_msg(LOG_WARNING, "login", "app not registred");
return -1;
}
- strlcpy(instance_prefix, PROTOCOL_PREFIX, size);
- strlcat(instance_prefix, instance, size);
-
- root = json_pack_ex(&error, 1, "{s:s, s:s, s:s}", "client_name",
- CLIENT_NAME, "redirect_uris", "urn:ietf:wg:oauth:2.0:oob", "scopes",
- "read write push");
- if (!root) {
- log_msg(LOG_WARNING, "register_app", "json pack error: line %d: %s",
- error.line, error.text);
+ url = get_login_url(config->instance_url);
+ if (!url) {
+ err(1, NULL);
return -1;
}
- req_data = json_dumps(root, 0);
- json_decref(root);
+ req_data = get_login_req(email, password);
if (!req_data) {
- log_msg(LOG_WARNING, "register_app", "failed to dump json");
+ free(url);
return -1;
}
- size = strlen(instance_prefix) + strlen(app_register_url) + 1;
- url = malloc(size);
- if (!url) {
- err(1, NULL);
+ resp_data = post_request(url, req_data);
+ free(url);
+ free(req_data);
+ if (!resp_data) {
+ log_msg(LOG_WARNING, "register_app", "login request failed");
return -1;
}
- strlcpy(url, instance_prefix, size);
- strlcat(url, app_register_url, size);
-
- arg = calloc(1, sizeof(struct register_call_arg));
- if (!arg) {
- err(1, NULL);
+ if (!resp_data) {
+ log_msg(LOG_WARNING, "register_app", "invalid response");
return -1;
}
- arg->url = url;
- arg->domain = instance_prefix;
- arg->post_data = req_data;
- arg->callback = callback;
-
- return pthread_create(&t, NULL, &register_call, arg);
-}
-
-struct login_call_arg {
- char *url;
- char *post_data;
- void (*callback)(bool);
-};
-
-static void *login_call(void *req_arg)
-{
- struct login_call_arg *arg = NULL;
- char *resp = NULL;
- json_t *root = NULL;
-
- arg = (struct login_call_arg *)req_arg;
- if (!arg || !(arg->url)) {
- log_msg(LOG_WARNING, "login_call", "invalid arguments");
- goto error;
- }
-
- resp = post_request(arg->url, arg->post_data);
- if (!resp) {
- log_msg(LOG_WARNING, "login_call", "failed to send http request");
- goto error;
- }
+ resp = get_login_resp(resp_data);
+ free(resp_data);
if (!resp) {
- log_msg(LOG_WARNING, "login_call", "null response");
- goto error;
- }
-
- root = json_loads(resp, 0, NULL);
- if (!root) {
- log_msg(LOG_WARNING, "login_call", "failed to parse json");
- goto error;
- }
-
- if (!json_is_object(root)) {
- log_msg(LOG_WARNING, "login_call", "json root is not object");
- goto error;
- }
-
- json_t *access_token_j = json_object_get(root, "access_token");
- json_t *scope_j = json_object_get(root, "scope");
- 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) {
- log_msg(LOG_WARNING, "login_call", "invalid access_token or scope");
- goto error;
+ log_msg(LOG_WARNING, "register_app", "invalid response");
+ return -1;
}
- config_set_access_token(json_string_value(access_token_j));
+ config_set_access_token(resp->access_token);
/* scope = strdup(json_string_value(scope_j)); */
if (config_save()) {
log_msg(LOG_WARNING, "login_call", "failed to save config");
- goto error;
}
- free(arg->url);
- if (arg->post_data)
- free(arg->post_data);
- free(arg);
+ free(resp->access_token);
+ free(resp->scope);
free(resp);
- json_decref(root);
- (*(arg->callback))(true);
-
- printf("access_token: %s", config->access_token);
- return NULL;
-
-error:
- if (arg) {
- if (arg->url)
- free(arg->url);
- if (arg->post_data)
- free(arg->post_data);
- free(arg);
- }
- if (resp)
- free(resp);
- if (root)
- json_decref(root);
- (*(arg->callback))(false);
- return NULL;
-}
-
-int login(
- const char *email, const char *password, void (*callback)(bool success))
-{
- json_t *root;
- json_error_t error;
- pthread_t t;
- size_t size;
- char *url, *req_data;
- struct login_call_arg *arg;
- if (!email || strlen(email) < 1 || !password || strlen(password) < 1) {
- log_msg(LOG_WARNING, "login", "invalid argument");
- return -1;
- }
-
- if (!(config->client_id) || !*(config->client_id) ||
- !(config->client_secret) || !*(config->client_secret) ||
- !(config->instance_url) || !*(config->instance_url)) {
- log_msg(LOG_WARNING, "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",
- config->client_id, "client_secret", config->client_secret,
- "grant_type", "password", "username", email, "password", password);
-
- if (!root) {
- log_msg(LOG_WARNING, "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) {
- log_msg(LOG_WARNING, "login", "failed to dump json");
- return -1;
- }
-
- size = strlen(config->instance_url) + strlen(login_url) + 1;
- url = malloc(size);
- if (!url) {
- err(1, NULL);
- return -1;
- }
- strlcpy(url, config->instance_url, size);
- strlcat(url, login_url, size);
-
- arg = calloc(1, sizeof(struct login_call_arg));
- if (!arg) {
- err(1, NULL);
- return -1;
- }
- arg->url = url;
- arg->post_data = req_data;
- arg->callback = callback;
-
- return pthread_create(&t, NULL, &login_call, arg);
+ return 0;
}
diff --git a/src/auth.h b/src/auth.h
index bc9c58b..9c3ee03 100644
--- a/src/auth.h
+++ b/src/auth.h
@@ -3,12 +3,7 @@
#include <stdbool.h>
-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));
+int login(const char *email, const char *password);
#endif
diff --git a/src/config.c b/src/config.c
index ca2d48e..211e953 100644
--- a/src/config.c
+++ b/src/config.c
@@ -18,6 +18,44 @@
struct config _config;
const struct config *config = (const struct config *)&_config;
+int read_local_credentials()
+{
+ if (!(config->access_token) || !*(config->access_token) ||
+ !(config->instance_url) || !*(config->instance_url)) {
+ log_msg(LOG_WARNING, "read_local_credentials",
+ "access_token not found");
+ return -1;
+ }
+ 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;
+}
+
+bool is_registered()
+{
+ if (!(_config.client_id) || !*(_config.client_id) ||
+ !(_config.client_secret) || !*(_config.client_secret) ||
+ !(_config.instance_url) || !*(_config.instance_url)) {
+ return false;
+ }
+ return true;
+}
+
char *get_config_path()
{
char *home = getenv("HOME");
@@ -38,7 +76,7 @@ void config_load()
char *path = get_config_path();
root = json_load_file(path, 0, &error);
if (!root) {
- log_msg(LOG_WARNING, "load_config", "json parse error: line %d: %s",
+ log_msg(LOG_WARNING, "config_load", "json parse error: line %d: %s",
error.line, error.text);
free(path);
return;
@@ -46,7 +84,7 @@ void config_load()
free(path);
if (!json_is_object(root)) {
- log_msg(LOG_WARNING, "load_config", "json root is not object");
+ log_msg(LOG_WARNING, "config_load", "json root is not object");
json_decref(root);
return;
}
@@ -96,14 +134,14 @@ int config_save()
if (stat(dir, &st)) {
if (mkdir(dir, S_IRWXU)) {
free(config_path);
- log_msg(LOG_WARNING, "load_config", "failed to create config dir");
+ log_msg(LOG_WARNING, "config_save", "failed to create config dir");
return -1;
}
}
free(config_path);
if (json_dump_file(root, get_config_path(), 0)) {
- log_msg(LOG_WARNING, "load_config", "unable to save json");
+ log_msg(LOG_WARNING, "config_save", "unable to save json");
json_decref(root);
return -1;
}
diff --git a/src/config.h b/src/config.h
index 3875a1b..2456c2b 100644
--- a/src/config.h
+++ b/src/config.h
@@ -1,6 +1,8 @@
#ifndef __CONFIG_H
#define __CONFIG_H
+#include <stdbool.h>
+
struct config {
char *instance_url;
char *client_id;
@@ -9,6 +11,12 @@ struct config {
};
extern const struct config *config;
+
+bool is_logged_in();
+const char* get_access_token();
+const char* get_instance_url();
+int read_local_credentials();
+bool is_registered();
void config_load();
int config_save();
void config_set_client_id(const char *cid);
diff --git a/src/http.c b/src/http.c
index 96a723d..84b62be 100644
--- a/src/http.c
+++ b/src/http.c
@@ -6,6 +6,7 @@
#include <curl/curl.h>
#include "string-util.h"
#include "auth.h"
+#include "config.h"
#include "log.h"
#define BUFFER_SIZE (256 * 1024)
@@ -13,7 +14,11 @@
int http_init()
{
- return curl_global_init(CURL_GLOBAL_ALL);
+ if (curl_global_init(CURL_GLOBAL_ALL)) {
+ log_msg(LOG_WARNING, "http_init", "failed to init curl");
+ return -1;
+ }
+ return 0;
}
void http_cleanup()
@@ -44,7 +49,6 @@ static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream)
char *get_request(const char *url)
{
-
CURL *curl = NULL;
CURLcode status;
struct curl_slist *headers = NULL;
@@ -61,6 +65,8 @@ char *get_request(const char *url)
struct write_result write_result = {.data = data, .pos = 0};
+ log_msg(LOG_INFO, "get_request", "loggedid: %d, token: %s", is_logged_in(), get_access_token());
+
if (is_logged_in()) {
const char *token = get_access_token();
size_t s = strlen(AUTH_HEADER_STR_PREFIX) + strlen(token) + 1;
@@ -76,7 +82,7 @@ char *get_request(const char *url)
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result);
status = curl_easy_perform(curl);
- if (status != 0) {
+ if (status) {
log_msg(LOG_WARNING, "get_request",
"unable to request data from %s: %s", url,
curl_easy_strerror(status));
@@ -145,7 +151,7 @@ char *post_request(const char *url, char *post_data)
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
status = curl_easy_perform(curl);
- if (status != 0) {
+ if (status) {
log_msg(LOG_WARNING, "post_request", "unable to request data from %s: %s",
url, curl_easy_strerror(status));
goto error;
diff --git a/src/log.c b/src/log.c
index 3c78caf..f1cb7d5 100644
--- a/src/log.c
+++ b/src/log.c
@@ -4,7 +4,7 @@
#include "log.h"
static const char *log_levels[] = {
- "info"
+ "info",
"warning",
"error",
"fatal",
@@ -18,7 +18,7 @@ void log_msg(enum log_level level, const char *namespace, const char *format, ..
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
- if (level == LOG_WARNING) {
+ if (level == LOG_ERROR) {
exit(EXIT_FAILURE);
} else if (level == LOG_FATAL) {
abort();
diff --git a/src/login_window.c b/src/login_window.c
index f1823b9..a060d6c 100644
--- a/src/login_window.c
+++ b/src/login_window.c
@@ -5,6 +5,7 @@
#include <stdbool.h>
#include <gtk-3.0/gtk/gtk.h>
#include "auth.h"
+#include "register.h"
#include "http.h"
#include "timeline.h"
#include "timeline_window.h"
@@ -17,54 +18,51 @@ static GtkWidget *instance_name_box, *email_box, *password_box;
static GtkWidget *submit_button;
static GtkWidget *spinner;
-static void window_removed(
- GtkApplication *application, GtkWindow *w, gpointer user_data)
+static gboolean login_completed(gpointer data)
{
- /* gtk_widget_destroy(GTK_WIDGET(w)); */
-}
-
-static void login_callback(bool success)
-{
- if (!success) {
+ int *val_ptr = data;
+ gtk_spinner_stop(GTK_SPINNER(spinner));
+ if (*val_ptr) {
log_msg(LOG_WARNING, "login_callback", "login failed");
- gtk_spinner_stop(GTK_SPINNER(spinner));
- return;
+ } else {
+ create_timeline_window(application, NULL);
}
- 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)); */
+
+ free(val_ptr);
+ return G_SOURCE_REMOVE;
}
-static void register_callback(bool success)
+static gpointer user_register(gpointer data)
{
- if (!success) {
- gtk_spinner_stop(GTK_SPINNER(spinner));
- log_msg(LOG_WARNING, "register_callback", "register failed");
- return;
- }
+ int *val_ptr;
+ const char *instance_name, *email, *password;
- const char *email, *password;
+ instance_name = gtk_entry_get_text(GTK_ENTRY(instance_name_box));
email = gtk_entry_get_text(GTK_ENTRY(email_box));
password = gtk_entry_get_text(GTK_ENTRY(password_box));
- if (login(email, password, &login_callback)) {
- gtk_spinner_stop(GTK_SPINNER(spinner));
- return;
+ val_ptr = malloc(sizeof(int));
+ *val_ptr = register_app(instance_name);
+ if (*val_ptr) {
+ log_msg(LOG_WARNING, "user_register", "registration failed");
+ }
+ *val_ptr = login(email, password);
+ if (*val_ptr) {
+ log_msg(LOG_WARNING, "user_register", "login failed");
}
+
+ gdk_threads_add_idle(login_completed, val_ptr);
+ return NULL;
}
static void submit_login_form()
{
gtk_spinner_start(GTK_SPINNER(spinner));
- const char *instance_name;
- instance_name = gtk_entry_get_text(GTK_ENTRY(instance_name_box));
- if (register_app(instance_name, &register_callback)) {
- gtk_spinner_stop(GTK_SPINNER(spinner));
- return;
- }
+ g_thread_new("register", user_register, NULL);
return;
}
@@ -104,7 +102,7 @@ void create_login_window(GtkApplication *app, gpointer user_data)
gtk_window_set_title(GTK_WINDOW(window), "ap_client");
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
- g_signal_connect(app, "window-removed", G_CALLBACK(window_removed), NULL);
+ /* g_signal_connect(app, "window-removed", G_CALLBACK(window_removed), NULL); */
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
gtk_widget_set_valign(GTK_WIDGET(box), GTK_ALIGN_CENTER);
diff --git a/src/main.c b/src/main.c
index c1c97f4..d95f547 100644
--- a/src/main.c
+++ b/src/main.c
@@ -23,8 +23,7 @@ static void startup(GtkApplication *app, gpointer user_data)
static void activate(GtkApplication *app, gpointer user_data)
{
if (read_local_credentials()) {
- /* create_login_window(app, user_data); */
- log_msg(LOG_WARNING, "activate", "failed to read config files");
+ create_login_window(app, user_data);
return;
}
create_timeline_window(app, NULL);
diff --git a/src/register.c b/src/register.c
new file mode 100644
index 0000000..4885ec5
--- /dev/null
+++ b/src/register.c
@@ -0,0 +1,128 @@
+#define _POSIX_C_SOURCE 200809L
+#include <err.h>
+#include <string.h>
+#include <stdbool.h>
+#include <jansson.h>
+#include "http.h"
+#include "config.h"
+#include "log.h"
+
+#define CLIENT_NAME "ap_client"
+#define REGISTER_URL "https://%s/api/v1/apps"
+
+struct register_response {
+ char *client_id;
+ char *client_secret;
+};
+
+static char *get_register_url(const char *domain)
+{
+ char *url;
+ size_t size;
+
+ size = strlen(REGISTER_URL) + strlen(domain) - 1;
+ url = malloc(size);
+ if (!url) {
+ err(1, NULL);
+ return NULL;
+ }
+
+ sprintf(url, REGISTER_URL, domain);
+ return url;
+}
+
+static char *get_register_req()
+{
+ char *req;
+ json_t *json_root;
+
+ json_root = json_pack_ex(NULL, 1, "{s:s, s:s, s:s}", "client_name",
+ CLIENT_NAME, "redirect_uris", "urn:ietf:wg:oauth:2.0:oob", "scopes",
+ "read write push");
+ if (!json_root) {
+ return NULL;
+ }
+
+ req = json_dumps(json_root, 0);
+ json_decref(json_root);
+
+ return req;
+}
+
+static struct register_response *get_register_resp(const char *data)
+{
+ struct register_response *resp;
+ json_t *json_root;
+ json_t *cid, *csec;
+
+ json_root = json_loads(data, 0, NULL);
+ if (!json_root) {
+ return NULL;
+ }
+
+ if (!json_is_object(json_root)) {
+ json_decref(json_root);
+ return NULL;
+ }
+
+ cid = json_object_get(json_root, "client_id");
+ csec = json_object_get(json_root, "client_secret");
+ if (!json_is_string(cid) || !json_is_string(csec)) {
+ json_decref(json_root);
+ return NULL;
+ }
+
+ resp = calloc(1, sizeof(struct register_response));
+ resp->client_id = strdup(json_string_value(cid));
+ resp->client_secret = strdup(json_string_value(csec));
+
+ json_decref(json_root);
+ return resp;
+}
+
+int register_app(const char *domain)
+{
+ char *url, *req_data, *resp_data;
+ struct register_response *resp;
+
+ if (!domain || !*domain) {
+ log_msg(LOG_WARNING, "register_app", "invalid argument");
+ return -1;
+ }
+
+ url = get_register_url(domain);
+ if (!url) {
+ return -1;
+ }
+
+ req_data = get_register_req();
+ if (!req_data) {
+ free(url);
+ return -1;
+ }
+
+ resp_data = post_request(url, req_data);
+ free(url);
+ free(req_data);
+ if (!resp_data) {
+ log_msg(LOG_WARNING, "register_app", "register request failed");
+ return -1;
+ }
+
+ resp = get_register_resp(resp_data);
+ free(resp_data);
+ if (!resp) {
+ log_msg(LOG_WARNING, "register_app", "invalid response");
+ return -1;
+ }
+
+ config_set_client_id(resp->client_id);
+ config_set_client_secret(resp->client_secret);
+ config_set_instance_url(domain);
+
+ free(resp->client_id);
+ free(resp->client_secret);
+ free(resp);
+
+ return 0;
+}
diff --git a/src/register.h b/src/register.h
new file mode 100644
index 0000000..2122d6b
--- /dev/null
+++ b/src/register.h
@@ -0,0 +1,8 @@
+#ifndef __REGISTER_H
+#define __REGISTER_H
+
+int register_app(const char *domain);
+
+#endif
+
+
diff --git a/src/string-util.c b/src/string-util.c
index e183288..d5a702b 100644
--- a/src/string-util.c
+++ b/src/string-util.c
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <string.h>
+#include <stdlib.h>
/*
* Copy src to string dst of size siz. At most siz-1 characters
@@ -83,3 +84,40 @@ size_t strlcat(char *dst, const char *src, size_t siz)
return (dlen + (s - src)); /* count does not include NUL */
}
+
+char *str_replace(const char *str, const char *old, const char *new)
+{
+ const char *ins;
+ char *result, *tmp;
+ size_t len_old, len_new, len_front, len_result;
+ int count;
+
+ if (!str || !old || !new)
+ return NULL;
+ len_old = strlen(old);
+ if (len_old == 0)
+ return NULL;
+ len_new = strlen(new);
+
+ ins = str;
+ for (count = 0; (tmp = strstr(ins, old)); ++count) {
+ ins = tmp + len_old;
+ }
+
+ len_result = strlen(str) + (len_new - len_old) * count + 1;
+ tmp = result = malloc(len_result);
+ if (!result)
+ return NULL;
+
+ while (count--) {
+ ins = strstr(str, old);
+ len_front = ins - str;
+ tmp = strncpy(tmp, str, len_front) + len_front;
+ strlcpy(tmp, new, len_result);
+ tmp += len_new;
+ str += len_front + len_old;
+ }
+ strlcpy(tmp, str, len_result);
+ return result;
+}
+
diff --git a/src/string-util.h b/src/string-util.h
index 5bf6f11..2625765 100644
--- a/src/string-util.h
+++ b/src/string-util.h
@@ -5,5 +5,6 @@
size_t strlcpy(char *dst, const char *src, size_t siz);
size_t strlcat(char *dst, const char *src, size_t siz);
+char *str_replace(const char *str, const char *old, const char *new);
#endif
diff --git a/src/timeline.c b/src/timeline.c
index 753f9f1..be1a4c4 100644
--- a/src/timeline.c
+++ b/src/timeline.c
@@ -5,11 +5,28 @@
#include <jansson.h>
#include "timeline.h"
#include "auth.h"
+#include "config.h"
#include "http.h"
#include "string-util.h"
#include "log.h"
-static char *timeline_url = "/api/v1/timelines/home";
+#define TIMELINE_URL "https://%s/api/v1/timelines/home"
+
+static char *get_timeline_url(const char *domain)
+{
+ char *url;
+ size_t size;
+
+ size = strlen(TIMELINE_URL) + strlen(domain) - 1;
+ url = malloc(size);
+ if (!url) {
+ err(1, NULL);
+ return NULL;
+ }
+
+ sprintf(url, TIMELINE_URL, domain);
+ return url;
+}
struct timeline *timeline_from_json(const char *json_data)
{
@@ -77,19 +94,15 @@ struct timeline *get_timeline(const char *max_id, const char *since_id, const ch
int limit)
{
char *url, *resp;
- size_t size;
struct timeline *t;
- size = strlen(get_instance_url()) + strlen(timeline_url) + 1;
- url = malloc(size);
+ url = get_timeline_url(config->instance_url);
if (!url) {
err(1, "get_timeline");
return NULL;
}
- strlcpy(url, get_instance_url(), size);
- strlcat(url, timeline_url, size);
-
+ printf("url: %s\n", url);
resp = get_request(url);
free(url);
if (!resp) {
diff --git a/src/timeline_window.c b/src/timeline_window.c
index 516f2d6..4b17824 100644
--- a/src/timeline_window.c
+++ b/src/timeline_window.c
@@ -8,19 +8,74 @@
#include "http.h"
#include "timeline.h"
#include "log.h"
+#include "string-util.h"
-static GtkWidget *window, *spinner, *list_box;
+static GtkWidget *window, *scrolled, *list_box;
+
+static gchar *html_to_pango(const char *content)
+{
+ char *str1, *str2;
+ gchar *result;
+ GRegex *regex = NULL;
+ GError *error = NULL;
+
+ if (!content) {
+ return NULL;
+ }
+
+ str1 = str_replace(content, "<p>", "");
+ if (!str1) {
+ log_msg(LOG_WARNING, "html_to_pango", "failed to parse html");
+ return NULL;
+ }
+ str2 = str_replace(str1, "</p>", "");
+ free(str1);
+ if (!str2) {
+ log_msg(LOG_WARNING, "html_to_pango", "failed to parse html");
+ return NULL;
+ }
+
+ regex = g_regex_new("(class|target|rel)=\"(.|\n)*?\"", G_REGEX_CASELESS, 0, &error);
+ if (!regex) {
+ log_msg(LOG_WARNING, "html_to_pango", error->message);
+ g_free(error);
+ return NULL;
+ }
+
+ result = g_regex_replace(regex, str2, -1, 0, "", 0, &error);
+ free(str2);
+ if (!result) {
+ log_msg(LOG_WARNING, "html_to_pango", error->message);
+ g_free(error);
+ return NULL;
+ }
+
+ return result;
+}
static gboolean timeline_loaded(gpointer data)
{
struct timeline *t = data;
- GtkWidget *label;
for (size_t i = 0; i < t->size; i++) {
- label = gtk_label_new(t->statuses[i]->content);
- gtk_widget_show(GTK_WIDGET(label));
- gtk_list_box_prepend(GTK_LIST_BOX(list_box), GTK_WIDGET(label));
+ GtkBuilder *post_builder;
+ GObject *post_box, *post_content_label;
+ char *content_markup;
+
+ content_markup = html_to_pango(t->statuses[i]->content);
+ if (!content_markup) {
+ continue;
+ }
+
+ post_builder = gtk_builder_new_from_file("data/post.ui");
+
+ post_box = gtk_builder_get_object(post_builder, "post_box");
+ post_content_label = gtk_builder_get_object(post_builder, "content_text");
+ gtk_label_set_markup(GTK_LABEL(post_content_label), content_markup);
+
+ gtk_list_box_prepend(GTK_LIST_BOX(list_box), GTK_WIDGET(post_box));
+ gtk_widget_show_all(GTK_WIDGET(post_box));
}
- gtk_spinner_stop(GTK_SPINNER(spinner));
+ /* gtk_spinner_stop(GTK_SPINNER(spinner)); */
timeline_free(t);
return G_SOURCE_REMOVE;
}
@@ -44,17 +99,21 @@ void create_timeline_window(GtkApplication *app, gpointer user_data)
gtk_window_set_title(GTK_WINDOW(window), "ap_client");
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
- gtk_window_set_destroy_with_parent(GTK_WINDOW(window), true);
+
+ scrolled = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
list_box = gtk_list_box_new();
gtk_widget_set_valign(GTK_WIDGET(list_box), GTK_ALIGN_CENTER);
gtk_widget_set_halign(GTK_WIDGET(list_box), GTK_ALIGN_CENTER);
- spinner = gtk_spinner_new();
- gtk_spinner_start(GTK_SPINNER(spinner));
- gtk_container_add(GTK_CONTAINER(list_box), spinner);
+ /* spinner = gtk_spinner_new(); */
+ /* gtk_spinner_start(GTK_SPINNER(spinner)); */
+ /* gtk_container_add(GTK_CONTAINER(list_box), spinner); */
- gtk_container_add(GTK_CONTAINER(window), list_box);
+ gtk_container_add(GTK_CONTAINER(window), scrolled);
+ gtk_container_add(GTK_CONTAINER(scrolled), list_box);
gtk_widget_show_all(window);
g_thread_new("load_timeline_thread", &load_timeline, NULL);