summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile69
-rw-r--r--data/avi.pngbin0 -> 997 bytes
-rw-r--r--data/login_window.ui178
-rw-r--r--data/post.ui245
-rw-r--r--src/account.c92
-rw-r--r--src/account.h4
-rw-r--r--src/config.c16
-rw-r--r--src/http.c2
-rw-r--r--src/login_window.c117
-rw-r--r--src/login_window.h2
-rw-r--r--src/main.c12
-rw-r--r--src/main_window.c (renamed from src/timeline_window.c)83
-rw-r--r--src/main_window.h9
-rw-r--r--src/status.c8
-rw-r--r--src/timeline.c1
-rw-r--r--src/timeline_window.h9
17 files changed, 591 insertions, 257 deletions
diff --git a/.gitignore b/.gitignore
index e7d5256..50fcf1a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
+*~
*.o
ap_client
diff --git a/Makefile b/Makefile
index 0134d5e..781f0aa 100644
--- a/Makefile
+++ b/Makefile
@@ -1,36 +1,34 @@
-CC=cc
-PKGCONFIG=$(shell which pkg-config)
-
-CFLAGS=-o2 -pipe
-CFLAGS+=-Wall -Wextra -Wno-unused-parameter -std=c99
-CFLAGS+=$(shell $(PKGCONFIG) --cflags gtk+-3.0 libcurl jansson) -lpthread
-LDFLAGS+=$(shell $(PKGCONFIG) --libs gtk+-3.0 libcurl jansson) -lpthread
+.POSIX:
+CC=c99
+CFLAGS=-Wall -Wextra -Wno-unused-parameter
+E_CGLAGS=$$(pkg-config --cflags gtk+-3.0 jansson libcurl) $(CFLAGS)
+LDFLAGS=
+E_LDFLAGS=$$(pkg-config --libs gtk+-3.0 jansson libcurl) $(LDFLAGS)
DESTDIR=
PREFIX=/usr/local
BINDIR=$(PREFIX)/bin
-OUTDIR=build
-OBJECTS=$(OUTDIR)/main.o \
- $(OUTDIR)/string-util.o \
- $(OUTDIR)/instance_info.o \
- $(OUTDIR)/http.o \
- $(OUTDIR)/status.o \
- $(OUTDIR)/timeline.o \
- $(OUTDIR)/auth.o \
- $(OUTDIR)/register.o \
- $(OUTDIR)/login_window.o \
- $(OUTDIR)/timeline_window.o \
- $(OUTDIR)/config.o \
- $(OUTDIR)/log.o
+OBJECTS=src/main.o \
+ src/string-util.o \
+ src/instance_info.o \
+ src/http.o \
+ src/status.o \
+ src/account.o \
+ src/timeline.o \
+ src/auth.o \
+ src/register.o \
+ src/login_window.o \
+ src/main_window.o \
+ src/config.o \
+ src/log.o
all: ap_client
ap_client: $(OBJECTS)
- $(CC) $(LDFLAGS) -o ap_client $(OBJECTS)
+ $(CC) $(E_LDFLAGS) -o ap_client $(OBJECTS)
-$(OUTDIR)/%.o: src/%.c src/*.h
- @mkdir -p $(OUTDIR)
- $(CC) $(CFLAGS) -c -o $@ $<
+.c.o:
+ $(CC) $(E_CGLAGS) -c -o $@ $<
install: ap_client
mkdir -p $(DESTDIR)$(BINDIR)
@@ -39,9 +37,28 @@ install: ap_client
clean:
rm -f ap_client
- rm -rf $(OUTDIR)
+ rm -rf src/*.o
uninstall:
rm -f $(DESTDIR)$(BINDIR)/ap_client
-.PHONY: all clean install uninstall
+src/account.o: src/account.c src/account.h src/log.h
+src/auth.o: src/auth.c src/string-util.h src/auth.h src/http.h \
+ src/config.h src/log.h
+src/config.o: src/config.c src/string-util.h src/config.h src/log.h
+src/http.o: src/http.c src/string-util.h src/auth.h src/config.h \
+ src/log.h
+src/instance_info.o: src/instance_info.c src/instance_info.h src/log.h
+src/log.o: src/log.c src/log.h
+src/login_window.o: src/login_window.c src/auth.h src/register.h \
+ src/http.h src/timeline.h src/status.h src/account.h src/main_window.h \
+ src/log.h
+src/main.o: src/main.c src/http.h src/config.h src/main_window.h
+src/main_window.o: src/main_window.c src/auth.h src/http.h src/timeline.h \
+ src/status.h src/account.h src/log.h src/config.h src/login_window.h \
+ src/string-util.h
+src/register.o: src/register.c src/http.h src/config.h src/log.h
+src/status.o: src/status.c src/status.h src/account.h src/log.h
+src/string-util.o: src/string-util.c
+src/timeline.o: src/timeline.c src/timeline.h src/status.h src/account.h \
+ src/auth.h src/config.h src/http.h src/string-util.h src/log.h
diff --git a/data/avi.png b/data/avi.png
new file mode 100644
index 0000000..3fc699c
--- /dev/null
+++ b/data/avi.png
Binary files differ
diff --git a/data/login_window.ui b/data/login_window.ui
new file mode 100644
index 0000000..9f409ff
--- /dev/null
+++ b/data/login_window.ui
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.4 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="login_dialog">
+ <property name="width_request">500</property>
+ <property name="height_request">400</property>
+ <property name="can_focus">False</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="login_button">
+ <property name="label" translatable="yes">Login</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="login_button_click" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="label" translatable="yes">Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="width_request">250</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="margin_left">4</property>
+ <property name="margin_right">4</property>
+ <property name="margin_top">4</property>
+ <property name="margin_bottom">4</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Instance Domain</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="instance_name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="primary_icon_name">applications-internet</property>
+ <property name="secondary_icon_tooltip_text" translatable="yes">Instance Domain</property>
+ <property name="placeholder_text" translatable="yes">example.com</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Email</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="email">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="primary_icon_name">mail-mark-read</property>
+ <property name="placeholder_text" translatable="yes">username@example.com</property>
+ <property name="input_purpose">email</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Password</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="password">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="invisible_char">●</property>
+ <property name="primary_icon_name">help-about</property>
+ <property name="placeholder_text" translatable="yes">1234</property>
+ <property name="input_purpose">password</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinner" id="spinner">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">4</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/data/post.ui b/data/post.ui
index da222d8..47f23ae 100644
--- a/data/post.ui
+++ b/data/post.ui
@@ -25,100 +25,49 @@ along with . If not, see <http://www.gnu.org/licenses/>.
<object class="GtkBox" id="post_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="margin_left">4</property>
- <property name="margin_right">4</property>
- <property name="margin_top">4</property>
- <property name="margin_bottom">4</property>
- <property name="spacing">8</property>
- <property name="baseline_position">top</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="valign">start</property>
- <property name="stock">gtk-select-color</property>
- <property name="icon_size">6</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
+ <property name="orientation">vertical</property>
+ <property name="spacing">10</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="valign">start</property>
- <property name="orientation">vertical</property>
+ <property name="margin_top">4</property>
+ <property name="margin_bottom">4</property>
<property name="spacing">8</property>
+ <property name="baseline_position">top</property>
<child>
- <object class="GtkBox">
+ <object class="GtkImage" id="avatar">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Display Name</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">@username</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
+ <property name="valign">start</property>
+ <property name="pixbuf">avi.png</property>
+ <property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
- <property name="fill">True</property>
+ <property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="content_text">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">A widget’s index in the overlay children list determines which order the children are drawn if they overlap. The first child is drawn at the bottom. It also affects the default focus chain order.</property>
- <property name="use_markup">True</property>
- <property name="wrap">True</property>
- <property name="wrap_mode">char</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="spacing">20</property>
+ <property name="valign">start</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">8</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="margin_right">10</property>
- <property name="spacing">5</property>
<child>
- <object class="GtkImage">
+ <object class="GtkLabel" id="display_name">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="icon_name">mail-reply-sender</property>
+ <property name="label" translatable="yes">Display Name</property>
+ <attributes>
+ <attribute name="size" value="12000"/>
+ </attributes>
</object>
<packing>
<property name="expand">False</property>
@@ -130,7 +79,8 @@ along with . If not, see <http://www.gnu.org/licenses/>.
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">4</property>
+ <property name="margin_left">4</property>
+ <property name="label" translatable="yes">@</property>
</object>
<packing>
<property name="expand">False</property>
@@ -138,6 +88,18 @@ along with . If not, see <http://www.gnu.org/licenses/>.
<property name="position">1</property>
</packing>
</child>
+ <child>
+ <object class="GtkLabel" id="username">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">username</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="expand">False</property>
@@ -146,36 +108,13 @@ along with . If not, see <http://www.gnu.org/licenses/>.
</packing>
</child>
<child>
- <object class="GtkBox">
+ <object class="GtkLabel" id="content_text">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="margin_right">10</property>
- <property name="spacing">5</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">media-playlist-repeat</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">4</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
+ <property name="label" translatable="yes">A widget’s index in the overlay children list determines which order the children are drawn if they overlap. The first child is drawn at the bottom. It also affects the default focus chain order.</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">char</property>
</object>
<packing>
<property name="expand">False</property>
@@ -187,13 +126,37 @@ along with . If not, see <http://www.gnu.org/licenses/>.
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="margin_right">10</property>
- <property name="spacing">5</property>
+ <property name="spacing">20</property>
<child>
- <object class="GtkImage">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="icon_name">emblem-favorite</property>
+ <property name="halign">start</property>
+ <property name="spacing">5</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">mail-reply-sender</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="replies_count">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="expand">False</property>
@@ -202,10 +165,35 @@ along with . If not, see <http://www.gnu.org/licenses/>.
</packing>
</child>
<child>
- <object class="GtkLabel">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">4</property>
+ <property name="halign">start</property>
+ <property name="spacing">5</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">media-playlist-repeat</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="reblogs_count">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="expand">False</property>
@@ -213,6 +201,42 @@ along with . If not, see <http://www.gnu.org/licenses/>.
<property name="position">1</property>
</packing>
</child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">5</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">help-about</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="favourites_count">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="expand">False</property>
@@ -224,13 +248,24 @@ along with . If not, see <http://www.gnu.org/licenses/>.
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">2</property>
+ <property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
diff --git a/src/account.c b/src/account.c
new file mode 100644
index 0000000..c407d56
--- /dev/null
+++ b/src/account.c
@@ -0,0 +1,92 @@
+#define _POSIX_C_SOURCE 200809L
+#include <err.h>
+#include <string.h>
+#include <jansson.h>
+#include "account.h"
+#include "log.h"
+
+struct account *account_from_json(const char *json_data)
+{
+ struct account *a;
+ json_t *root;
+ json_error_t error;
+
+ root = json_loads(json_data, 0, &error);
+ if (!root) {
+ log_msg(LOG_WARNING, "account_from_json", "json parse error: line %d: %s",
+ error.line, error.text);
+ return NULL;
+ }
+
+ a = account_from_json_t(root);
+ json_decref(root);
+ return a;
+}
+
+struct account *account_from_json_t(const json_t *root)
+{
+ struct account *a;
+ if (!root) {
+ log_msg(LOG_WARNING, "account_from_json_t", "json data is null");
+ return NULL;
+ }
+
+ if (!json_is_object(root)) {
+ log_msg(LOG_WARNING, "account_from_json_t", "json root is not object");
+ return NULL;
+ }
+
+ a = calloc(1, sizeof(struct account));
+ if (!a) {
+ err(1, "account_from_json_t");
+ return NULL;
+ }
+
+ json_t *id = json_object_get(root, "id");
+ if (json_is_string(id)) {
+ a->id = strdup(json_string_value(id));
+ }
+
+ json_t *username = json_object_get(root, "username");
+ if (json_is_string(username)) {
+ a->username = strdup(json_string_value(username));
+ }
+
+ json_t *acct = json_object_get(root, "acct");
+ if (json_is_string(acct)) {
+ a->acct = strdup(json_string_value(acct));
+ }
+
+ json_t *display_name = json_object_get(root, "display_name");
+ if (json_is_string(display_name)) {
+ a->display_name = strdup(json_string_value(display_name));
+ }
+
+ return a;
+}
+
+void account_free(struct account *a)
+{
+ if (a->id)
+ free(a->id);
+ if (a->username)
+ free(a->username);
+ if (a->acct)
+ free(a->acct);
+ if (a->display_name)
+ free(a->display_name);
+ if (a->note)
+ free(a->note);
+ if (a->url)
+ free(a->url);
+ if (a->avatar)
+ free(a->avatar);
+ if (a->avatar_static)
+ free(a->avatar_static);
+ if (a->header)
+ free(a->header);
+ if (a->header_static)
+ free(a->header_static);
+ free(a);
+}
+
diff --git a/src/account.h b/src/account.h
index 049c829..547f276 100644
--- a/src/account.h
+++ b/src/account.h
@@ -22,6 +22,8 @@ struct account {
bool bot;
};
-struct account *account_from_json(char *json_data);
+struct account *account_from_json(const char *json_data);
+struct account *account_from_json_t(const json_t *);
+void account_free(struct account *);
#endif
diff --git a/src/config.c b/src/config.c
index 211e953..f409700 100644
--- a/src/config.c
+++ b/src/config.c
@@ -18,22 +18,13 @@
struct config _config;
const struct config *config = (const struct config *)&_config;
-int read_local_credentials()
+bool is_logged_in()
{
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 false;
}
- return 0;
-}
-
-bool is_logged_in()
-{
- if (config->access_token)
- return true;
- return false;
+ return true;
}
const char *get_access_token()
@@ -162,7 +153,6 @@ void config_set_client_secret(const char *cs)
void config_set_instance_url(const char *iu)
{
- printf("updating url: %s", iu);
_config.instance_url = strdup(iu);
}
diff --git a/src/http.c b/src/http.c
index 84b62be..ddd0470 100644
--- a/src/http.c
+++ b/src/http.c
@@ -65,8 +65,6 @@ 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;
diff --git a/src/login_window.c b/src/login_window.c
index a060d6c..241ca9b 100644
--- a/src/login_window.c
+++ b/src/login_window.c
@@ -8,32 +8,28 @@
#include "register.h"
#include "http.h"
#include "timeline.h"
-#include "timeline_window.h"
+#include "main_window.h"
#include "log.h"
GtkApplication *application;
-static GtkWidget *window;
-static GtkWidget *box;
-static GtkWidget *instance_name_box, *email_box, *password_box;
-static GtkWidget *submit_button;
-static GtkWidget *spinner;
+GObject *login_dialog;
+GObject *instance_domain_entry, *email_entry, *password_entry;
+GObject *login_button, *cancel_button;
+GObject *spinner;
static gboolean login_completed(gpointer data)
{
int *val_ptr = data;
gtk_spinner_stop(GTK_SPINNER(spinner));
if (*val_ptr) {
+ free(val_ptr);
log_msg(LOG_WARNING, "login_callback", "login failed");
+ return G_SOURCE_REMOVE;
} else {
- create_timeline_window(application, NULL);
+ free(val_ptr);
+ gtk_widget_destroy(GTK_WIDGET(login_dialog));
+ return G_SOURCE_REMOVE;
}
-
- /* gtk_window_close(GTK_WINDOW(window)); */
- /* gtk_application_remove_window( */
- /* GTK_APPLICATION(application), GTK_WINDOW(window)); */
-
- free(val_ptr);
- return G_SOURCE_REMOVE;
}
static gpointer user_register(gpointer data)
@@ -41,9 +37,9 @@ static gpointer user_register(gpointer data)
int *val_ptr;
const char *instance_name, *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));
+ instance_name = gtk_entry_get_text(GTK_ENTRY(instance_domain_entry));
+ email = gtk_entry_get_text(GTK_ENTRY(email_entry));
+ password = gtk_entry_get_text(GTK_ENTRY(password_entry));
val_ptr = malloc(sizeof(int));
*val_ptr = register_app(instance_name);
@@ -68,15 +64,16 @@ static void submit_login_form()
static bool is_form_valid()
{
- if (strlen(gtk_entry_get_text(GTK_ENTRY(instance_name_box))) < 1 ||
- strlen(gtk_entry_get_text(GTK_ENTRY(email_box))) < 1 ||
- strlen(gtk_entry_get_text(GTK_ENTRY(password_box))) < 1)
+ if (strlen(gtk_entry_get_text(GTK_ENTRY(instance_domain_entry))) < 1 ||
+ strlen(gtk_entry_get_text(GTK_ENTRY(email_entry))) < 1 ||
+ strlen(gtk_entry_get_text(GTK_ENTRY(password_entry))) < 1)
return false;
return true;
}
-static void submit_button_clicked(GtkButton *button, gpointer user_data)
+static void login_button_click(GtkButton *button, gpointer user_data)
{
+ g_print("clicked\n");
if (is_form_valid())
submit_login_form();
}
@@ -87,67 +84,45 @@ static void form_on_activate(GtkEntry *entry, gpointer user_data)
submit_login_form();
}
-static void on_form_changed(GtkWidget *widget, gpointer data)
+static void login_form_changed(GtkWidget *widget, gpointer data)
{
if (is_form_valid())
- gtk_widget_set_sensitive(GTK_WIDGET(submit_button), true);
+ gtk_widget_set_sensitive(GTK_WIDGET(login_button), true);
else
- gtk_widget_set_sensitive(GTK_WIDGET(submit_button), false);
+ gtk_widget_set_sensitive(GTK_WIDGET(login_button), false);
}
-void create_login_window(GtkApplication *app, gpointer user_data)
+int create_login_dialog()
{
- application = app;
- window = gtk_application_window_new(app);
- 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); */
-
- box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
- gtk_widget_set_valign(GTK_WIDGET(box), GTK_ALIGN_CENTER);
- gtk_widget_set_halign(GTK_WIDGET(box), GTK_ALIGN_CENTER);
-
- instance_name_box = gtk_entry_new();
- gtk_entry_set_placeholder_text(
- GTK_ENTRY(instance_name_box), "Instance domain");
- g_signal_connect(GTK_ENTRY(instance_name_box), "activate",
- G_CALLBACK(form_on_activate), NULL);
- g_signal_connect(G_OBJECT(instance_name_box), "changed",
- G_CALLBACK(on_form_changed), NULL);
+ GtkBuilder *login_builder;
- email_box = gtk_entry_new();
- gtk_entry_set_placeholder_text(GTK_ENTRY(email_box), "Email");
- gtk_entry_set_input_purpose(GTK_ENTRY(email_box), GTK_INPUT_PURPOSE_EMAIL);
- g_signal_connect(GTK_ENTRY(email_box), "activate",
+ login_builder = gtk_builder_new_from_file("data/login_window.ui");
+ login_dialog = gtk_builder_get_object(login_builder, "login_dialog");
+
+ instance_domain_entry = gtk_builder_get_object(login_builder, "instance_name");
+ g_signal_connect(G_OBJECT(instance_domain_entry), "changed",
+ G_CALLBACK(login_form_changed), NULL);
+ g_signal_connect(GTK_ENTRY(instance_domain_entry), "activate",
G_CALLBACK(form_on_activate), NULL);
- g_signal_connect(
- G_OBJECT(email_box), "changed", G_CALLBACK(on_form_changed), NULL);
-
- password_box = gtk_entry_new();
- gtk_entry_set_placeholder_text(GTK_ENTRY(password_box), "Password");
- gtk_entry_set_input_purpose(
- GTK_ENTRY(password_box), GTK_INPUT_PURPOSE_PASSWORD);
- gtk_entry_set_visibility(GTK_ENTRY(password_box), false);
- g_signal_connect(GTK_ENTRY(password_box), "activate",
+
+ email_entry = gtk_builder_get_object(login_builder, "email");
+ g_signal_connect(G_OBJECT(email_entry), "changed",
+ G_CALLBACK(login_form_changed), NULL);
+ g_signal_connect(GTK_ENTRY(email_entry), "activate",
G_CALLBACK(form_on_activate), NULL);
- g_signal_connect(G_OBJECT(password_box), "changed",
- G_CALLBACK(on_form_changed), NULL);
- submit_button = gtk_button_new();
- g_signal_connect(GTK_BUTTON(submit_button), "clicked",
- G_CALLBACK(submit_button_clicked), G_OBJECT(window));
- gtk_button_set_label(GTK_BUTTON(submit_button), "Submit");
- gtk_widget_set_sensitive(GTK_WIDGET(submit_button), false);
+ password_entry = gtk_builder_get_object(login_builder, "password");
+ g_signal_connect(G_OBJECT(password_entry), "changed",
+ G_CALLBACK(login_form_changed), NULL);
+ g_signal_connect(GTK_ENTRY(password_entry), "activate",
+ G_CALLBACK(form_on_activate), NULL);
- spinner = gtk_spinner_new();
+ login_button = gtk_builder_get_object(login_builder, "login_button");
+ g_signal_connect(GTK_BUTTON(login_button), "clicked",
+ G_CALLBACK(login_button_click), NULL);
+ cancel_button = gtk_builder_get_object(login_builder, "cancel_button");
- gtk_container_add(GTK_CONTAINER(window), box);
- gtk_container_add(GTK_CONTAINER(box), instance_name_box);
- gtk_container_add(GTK_CONTAINER(box), email_box);
- gtk_container_add(GTK_CONTAINER(box), password_box);
- gtk_container_add(GTK_CONTAINER(box), submit_button);
- gtk_container_add(GTK_CONTAINER(box), spinner);
+ spinner = gtk_builder_get_object(login_builder, "spinner");
- gtk_widget_show_all(window);
+ return gtk_dialog_run(GTK_DIALOG(login_dialog));
}
diff --git a/src/login_window.h b/src/login_window.h
index cf879cc..b3d299d 100644
--- a/src/login_window.h
+++ b/src/login_window.h
@@ -1,7 +1,7 @@
#ifndef __LOGIN_WINDOW_H
#define __LOGIN_WINDOW_H
-void create_login_window(GtkApplication *app, gpointer user_data);
+int create_login_dialog();
#endif
diff --git a/src/main.c b/src/main.c
index d95f547..78968a3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,13 +4,9 @@
#include <stdlib.h>
#include <stdbool.h>
#include <gtk-3.0/gtk/gtk.h>
-#include "auth.h"
#include "http.h"
-#include "timeline.h"
-#include "login_window.h"
#include "config.h"
-#include "timeline_window.h"
-#include "log.h"
+#include "main_window.h"
static void startup(GtkApplication *app, gpointer user_data)
{
@@ -22,11 +18,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);
- return;
- }
- create_timeline_window(app, NULL);
+ create_main_window(app, NULL);
}
int main(int argc, char **argv)
diff --git a/src/timeline_window.c b/src/main_window.c
index 4b17824..048de51 100644
--- a/src/timeline_window.c
+++ b/src/main_window.c
@@ -8,49 +8,55 @@
#include "http.h"
#include "timeline.h"
#include "log.h"
+#include "config.h"
+#include "login_window.h"
#include "string-util.h"
static GtkWidget *window, *scrolled, *list_box;
static gchar *html_to_pango(const char *content)
{
- char *str1, *str2;
- gchar *result;
- GRegex *regex = NULL;
+ gchar *result1, *result2;
+ GRegex *regex_tag, *regex_attr;
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");
+ regex_tag = g_regex_new(
+ "(<p>|</p>|<br></br>|<br/>|<br />)", G_REGEX_CASELESS, 0, &error);
+ if (!regex_tag) {
+ log_msg(LOG_WARNING, "html_to_pango", error->message);
+ g_free(error);
return NULL;
}
- str2 = str_replace(str1, "</p>", "");
- free(str1);
- if (!str2) {
- log_msg(LOG_WARNING, "html_to_pango", "failed to parse html");
+
+ result1 = g_regex_replace(regex_tag, content, -1, 0, "", 0, &error);
+ if (!result1) {
+ log_msg(LOG_WARNING, "html_to_pango", error->message);
+ g_free(error);
return NULL;
}
- regex = g_regex_new("(class|target|rel)=\"(.|\n)*?\"", G_REGEX_CASELESS, 0, &error);
- if (!regex) {
+ regex_attr =
+ g_regex_new("(class|target|rel|data-user|data-tag)=\"(.|\n)*?\"",
+ G_REGEX_CASELESS, 0, &error);
+ if (!regex_attr) {
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) {
+ result2 = g_regex_replace(regex_attr, result1, -1, 0, "", 0, &error);
+ free(result1);
+ if (!result1) {
log_msg(LOG_WARNING, "html_to_pango", error->message);
g_free(error);
return NULL;
}
- return result;
+ return result2;
}
static gboolean timeline_loaded(gpointer data)
@@ -59,6 +65,10 @@ static gboolean timeline_loaded(gpointer data)
for (size_t i = 0; i < t->size; i++) {
GtkBuilder *post_builder;
GObject *post_box, *post_content_label;
+ GObject *display_name, *username;
+ GObject *replies_count, *reblogs_count, *favourites_count;
+ GObject *avatar;
+ GdkPixbuf *avatar_pixbuf;
char *content_markup;
content_markup = html_to_pango(t->statuses[i]->content);
@@ -69,9 +79,39 @@ static gboolean timeline_loaded(gpointer data)
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");
+ post_content_label =
+ gtk_builder_get_object(post_builder, "content_text");
gtk_label_set_markup(GTK_LABEL(post_content_label), content_markup);
+ avatar = gtk_builder_get_object(post_builder, "avatar");
+ avatar_pixbuf =
+ gdk_pixbuf_new_from_file_at_size("data/avi.png", 40, 40, NULL);
+ gtk_image_set_from_pixbuf(GTK_IMAGE(avatar), avatar_pixbuf);
+
+ display_name = gtk_builder_get_object(post_builder, "display_name");
+ gtk_label_set_text(
+ GTK_LABEL(display_name), t->statuses[i]->account->display_name);
+
+ username = gtk_builder_get_object(post_builder, "username");
+ gtk_label_set_text(
+ GTK_LABEL(username), t->statuses[i]->account->username);
+
+ replies_count = gtk_builder_get_object(post_builder, "replies_count");
+ gchar *repc = g_strdup_printf("%d", t->statuses[i]->replies_count);
+ gtk_label_set_text(GTK_LABEL(replies_count), repc);
+ g_free(repc);
+
+ reblogs_count = gtk_builder_get_object(post_builder, "reblogs_count");
+ gchar *rebc = g_strdup_printf("%d", t->statuses[i]->reblogs_count);
+ gtk_label_set_text(GTK_LABEL(reblogs_count), rebc);
+ g_free(rebc);
+
+ favourites_count =
+ gtk_builder_get_object(post_builder, "favourites_count");
+ gchar *fc = g_strdup_printf("%d", t->statuses[i]->favourites_count);
+ gtk_label_set_text(GTK_LABEL(favourites_count), fc);
+ g_free(fc);
+
gtk_list_box_prepend(GTK_LIST_BOX(list_box), GTK_WIDGET(post_box));
gtk_widget_show_all(GTK_WIDGET(post_box));
}
@@ -92,7 +132,7 @@ static gpointer load_timeline(gpointer data)
return NULL;
}
-void create_timeline_window(GtkApplication *app, gpointer user_data)
+void create_main_window(GtkApplication *app, gpointer user_data)
{
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_application(GTK_WINDOW(window), GTK_APPLICATION(app));
@@ -116,5 +156,12 @@ void create_timeline_window(GtkApplication *app, gpointer user_data)
gtk_container_add(GTK_CONTAINER(scrolled), list_box);
gtk_widget_show_all(window);
+ if (!is_logged_in()) {
+ create_login_dialog();
+ }
+ if (!is_logged_in()) {
+ log_msg(LOG_ERROR, "create_main_window",
+ "login is required to view timeline");
+ }
g_thread_new("load_timeline_thread", &load_timeline, NULL);
}
diff --git a/src/main_window.h b/src/main_window.h
new file mode 100644
index 0000000..3a2059e
--- /dev/null
+++ b/src/main_window.h
@@ -0,0 +1,9 @@
+#ifndef __MAIN_WINDOW_H
+#define __MAIN_WINDOW_H
+
+void create_main_window (GtkApplication *app, gpointer user_data);
+
+#endif
+
+
+
diff --git a/src/status.c b/src/status.c
index 69d1fa2..cfb3645 100644
--- a/src/status.c
+++ b/src/status.c
@@ -3,6 +3,7 @@
#include <string.h>
#include <jansson.h>
#include "status.h"
+#include "account.h"
#include "log.h"
struct status *status_from_json(const char *json_data)
@@ -57,6 +58,11 @@ struct status *status_from_json_t(const json_t *root)
s->url = strdup(json_string_value(url));
}
+ json_t *account = json_object_get(root, "account");
+ if (json_is_object(account)) {
+ s->account = account_from_json_t(account);
+ }
+
json_t *in_reply_to_id = json_object_get(root, "in_reply_to_id");
if (json_is_string(in_reply_to_id)) {
s->in_reply_to_id = strdup(json_string_value(in_reply_to_id));
@@ -100,6 +106,8 @@ void status_free(struct status *s)
free(s->uri);
if (s->url)
free(s->url);
+ if (s->account)
+ account_free(s->account);
if (s->in_reply_to_id)
free(s->in_reply_to_id);
if (s->in_reply_to_account_id)
diff --git a/src/timeline.c b/src/timeline.c
index be1a4c4..4cd9fe0 100644
--- a/src/timeline.c
+++ b/src/timeline.c
@@ -102,7 +102,6 @@ struct timeline *get_timeline(const char *max_id, const char *since_id, const ch
return NULL;
}
- printf("url: %s\n", url);
resp = get_request(url);
free(url);
if (!resp) {
diff --git a/src/timeline_window.h b/src/timeline_window.h
deleted file mode 100644
index 8aff454..0000000
--- a/src/timeline_window.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __TIMELINE_WINDOW_H
-#define __TIMELINE_WINDOW_H
-
-void create_timeline_window (GtkApplication *app, gpointer user_data);
-
-#endif
-
-
-