massive improvements all abound
This commit is contained in:
parent
9b4826f9cb
commit
b307906cf4
@ -57,4 +57,10 @@ bool dc_api_get_userinfo(dc_api_t api, dc_account_t login,
|
|||||||
bool dc_api_get_userguilds(dc_api_t api, dc_account_t login,
|
bool dc_api_get_userguilds(dc_api_t api, dc_account_t login,
|
||||||
GPtrArray **guilds);
|
GPtrArray **guilds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a list of friends of the login account "login". Returns a GPtrArray
|
||||||
|
* of dc_account_t which automatically cleans itself up.
|
||||||
|
*/
|
||||||
|
bool dc_api_get_friends(dc_api_t api, dc_account_t login, GPtrArray **friends);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -360,13 +360,40 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool dc_api_get_friends(dc_api_t api, dc_account_t login, GPtrArray **friends)
|
||||||
|
{
|
||||||
|
char *url = NULL;
|
||||||
|
json_t *reply = NULL;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
return_if_true(api == NULL, false);
|
||||||
|
return_if_true(login == NULL, false);
|
||||||
|
|
||||||
|
asprintf(&url, "users/%s/guilds", dc_account_id(login));
|
||||||
|
|
||||||
|
reply = dc_api_call_sync(api, "GET", dc_account_token(login), url, NULL);
|
||||||
|
goto_if_true(reply == NULL, cleanup);
|
||||||
|
|
||||||
|
dc_util_dump_json(reply);
|
||||||
|
ret = true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
json_decref(reply);
|
||||||
|
reply = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool dc_api_get_userguilds(dc_api_t api, dc_account_t login, GPtrArray **out)
|
bool dc_api_get_userguilds(dc_api_t api, dc_account_t login, GPtrArray **out)
|
||||||
{
|
{
|
||||||
char *url = NULL;
|
char *url = NULL;
|
||||||
json_t *reply = NULL, *c = NULL, *val = NULL;
|
json_t *reply = NULL, *c = NULL, *val = NULL;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
GPtrArray *guilds = g_ptr_array_new_with_free_func((GDestroyNotify)dc_unref);
|
GPtrArray *guilds = g_ptr_array_new_with_free_func(
|
||||||
|
(GDestroyNotify)dc_unref
|
||||||
|
);
|
||||||
|
|
||||||
return_if_true(api == NULL, false);
|
return_if_true(api == NULL, false);
|
||||||
return_if_true(login == NULL, false);
|
return_if_true(login == NULL, false);
|
||||||
|
@ -2,20 +2,25 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.0)
|
|||||||
|
|
||||||
PKG_CHECK_MODULES(NCURSES REQUIRED ncursesw)
|
PKG_CHECK_MODULES(NCURSES REQUIRED ncursesw)
|
||||||
PKG_CHECK_MODULES(PANEL REQUIRED panel)
|
PKG_CHECK_MODULES(PANEL REQUIRED panel)
|
||||||
PKG_CHECK_MODULES(EDIT REQUIRED libedit)
|
PKG_CHECK_MODULES(CONFUSE REQUIRED libconfuse)
|
||||||
|
|
||||||
SET(TARGET "ncdc")
|
SET(TARGET "ncdc")
|
||||||
|
|
||||||
SET(SOURCES
|
SET(SOURCES
|
||||||
"include/ncdc/cmds.h"
|
"include/ncdc/cmds.h"
|
||||||
|
"include/ncdc/config.h"
|
||||||
"include/ncdc/input.h"
|
"include/ncdc/input.h"
|
||||||
"include/ncdc/mainwindow.h"
|
"include/ncdc/mainwindow.h"
|
||||||
"include/ncdc/ncdc.h"
|
"include/ncdc/ncdc.h"
|
||||||
|
"include/ncdc/textview.h"
|
||||||
"src/cmds.c"
|
"src/cmds.c"
|
||||||
|
"src/config.c"
|
||||||
"src/emacs.c"
|
"src/emacs.c"
|
||||||
"src/input.c"
|
"src/input.c"
|
||||||
|
"src/login.c"
|
||||||
"src/mainwindow.c"
|
"src/mainwindow.c"
|
||||||
"src/ncdc.c"
|
"src/ncdc.c"
|
||||||
|
"src/textview.c"
|
||||||
"src/util.c"
|
"src/util.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,7 +33,7 @@ INCLUDE_DIRECTORIES(
|
|||||||
${GLIB2_INCLUDE_DIRS}
|
${GLIB2_INCLUDE_DIRS}
|
||||||
${NCURSES_INCLUDE_DIRS}
|
${NCURSES_INCLUDE_DIRS}
|
||||||
${PANEL_INCLUDE_DIRS}
|
${PANEL_INCLUDE_DIRS}
|
||||||
${EDIT_INCLUDE_DIRS}
|
${CONFUSE_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
ADD_EXECUTABLE(${TARGET} ${SOURCES})
|
ADD_EXECUTABLE(${TARGET} ${SOURCES})
|
||||||
@ -37,5 +42,5 @@ TARGET_LINK_LIBRARIES(${TARGET}
|
|||||||
${GLIB2_LIBRARIES}
|
${GLIB2_LIBRARIES}
|
||||||
${NCURSES_LIBRARIES}
|
${NCURSES_LIBRARIES}
|
||||||
${PANEL_LIBRARIES}
|
${PANEL_LIBRARIES}
|
||||||
${EDIT_LIBRARIES}
|
${CONFUSE_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include <ncdc/mainwindow.h>
|
#include <ncdc/mainwindow.h>
|
||||||
|
|
||||||
typedef bool (*ncdc_command_t)(ncdc_mainwindow_t n,
|
typedef bool (*ncdc_command_t)(ncdc_mainwindow_t n,
|
||||||
wchar_t const *s, size_t len);
|
size_t argc, wchar_t **argv);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
wchar_t const *name;
|
wchar_t const *name;
|
||||||
@ -14,6 +14,9 @@ typedef struct {
|
|||||||
|
|
||||||
extern ncdc_commands_t cmds[];
|
extern ncdc_commands_t cmds[];
|
||||||
|
|
||||||
bool ncdc_cmd_quit(ncdc_mainwindow_t n, wchar_t const *s, size_t len);
|
bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s);
|
||||||
|
|
||||||
|
bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, wchar_t **av);
|
||||||
|
bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
13
ncdc/include/ncdc/config.h
Normal file
13
ncdc/include/ncdc/config.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef NCDC_CONFIG_H
|
||||||
|
#define NCDC_CONFIG_H
|
||||||
|
|
||||||
|
#include <ncdc/ncdc.h>
|
||||||
|
|
||||||
|
struct ncdc_config_;
|
||||||
|
typedef struct ncdc_config_ *ncdc_config_t;
|
||||||
|
|
||||||
|
ncdc_config_t ncdc_config_new(void);
|
||||||
|
|
||||||
|
dc_account_t ncdc_config_account(ncdc_config_t c, char const *name);
|
||||||
|
|
||||||
|
#endif
|
@ -2,12 +2,18 @@
|
|||||||
#define NCDC_MAINWINDOW_H
|
#define NCDC_MAINWINDOW_H
|
||||||
|
|
||||||
#include <ncdc/ncdc.h>
|
#include <ncdc/ncdc.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
struct ncdc_mainwindow_;
|
struct ncdc_mainwindow_;
|
||||||
typedef struct ncdc_mainwindow_ *ncdc_mainwindow_t;
|
typedef struct ncdc_mainwindow_ *ncdc_mainwindow_t;
|
||||||
|
|
||||||
ncdc_mainwindow_t ncdc_mainwindow_new(void);
|
ncdc_mainwindow_t ncdc_mainwindow_new(void);
|
||||||
|
|
||||||
|
/* holy shit stains I am lazy
|
||||||
|
*/
|
||||||
|
#define LOG(n, ...) ncdc_mainwindow_log(n, __VA_ARGS__)
|
||||||
|
void ncdc_mainwindow_log(ncdc_mainwindow_t w, wchar_t const *fmt, ...);
|
||||||
|
|
||||||
void ncdc_mainwindow_refresh(ncdc_mainwindow_t n);
|
void ncdc_mainwindow_refresh(ncdc_mainwindow_t n);
|
||||||
void ncdc_mainwindow_input_ready(ncdc_mainwindow_t n);
|
void ncdc_mainwindow_input_ready(ncdc_mainwindow_t n);
|
||||||
|
|
||||||
|
@ -30,15 +30,32 @@
|
|||||||
#include <dc/refable.h>
|
#include <dc/refable.h>
|
||||||
#include <dc/api.h>
|
#include <dc/api.h>
|
||||||
#include <dc/loop.h>
|
#include <dc/loop.h>
|
||||||
|
#include <dc/account.h>
|
||||||
|
|
||||||
#define return_if_true(v,r) do { if (v) return r; } while(0)
|
#define return_if_true(v,r) do { if (v) return r; } while(0)
|
||||||
#define goto_if_true(v,l) do { if (v) goto l; } while(0)
|
#define goto_if_true(v,l) do { if (v) goto l; } while(0)
|
||||||
|
|
||||||
|
struct ncdc_account_ {
|
||||||
|
dc_account_t account;
|
||||||
|
GPtrArray *friends;
|
||||||
|
GPtrArray *guilds;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ncdc_account_ *ncdc_account_t;
|
||||||
|
|
||||||
|
extern GHashTable *accounts;
|
||||||
extern char *ncdc_private_dir;
|
extern char *ncdc_private_dir;
|
||||||
|
extern void *config;
|
||||||
|
|
||||||
int strwidth(char const *string);
|
int strwidth(char const *string);
|
||||||
char *read_char(FILE *stream);
|
char *read_char(FILE *stream);
|
||||||
|
|
||||||
|
char *w_convert(wchar_t const *w);
|
||||||
|
wchar_t* wcsndup(const wchar_t* string, size_t maxlen);
|
||||||
|
size_t w_strlenv(wchar_t **s);
|
||||||
|
void w_strfreev(wchar_t **s);
|
||||||
|
wchar_t **w_tokenise(wchar_t const *w);
|
||||||
|
wchar_t *w_next_tok(wchar_t const *w);
|
||||||
wchar_t const *w_next_word(wchar_t const *w, ssize_t len);
|
wchar_t const *w_next_word(wchar_t const *w, ssize_t len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
15
ncdc/include/ncdc/textview.h
Normal file
15
ncdc/include/ncdc/textview.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef NCDC_TEXTVIEW_H
|
||||||
|
#define NCDC_TEXTVIEW_H
|
||||||
|
|
||||||
|
#include <ncdc/ncdc.h>
|
||||||
|
|
||||||
|
struct ncdc_textview_;
|
||||||
|
typedef struct ncdc_textview_ *ncdc_textview_t;
|
||||||
|
|
||||||
|
ncdc_textview_t ncdc_textview_new(void);
|
||||||
|
|
||||||
|
void ncdc_textview_append(ncdc_textview_t v, wchar_t const *w);
|
||||||
|
wchar_t const *ncdc_textview_nthline(ncdc_textview_t v, size_t i);
|
||||||
|
void ncdc_textview_render(ncdc_textview_t v, WINDOW *win, int lines, int cols);
|
||||||
|
|
||||||
|
#endif
|
@ -1,11 +1,36 @@
|
|||||||
#include <ncdc/cmds.h>
|
#include <ncdc/cmds.h>
|
||||||
|
|
||||||
ncdc_commands_t cmds[] = {
|
ncdc_commands_t cmds[] = {
|
||||||
|
{ L"login", ncdc_cmd_login },
|
||||||
{ L"quit", ncdc_cmd_quit },
|
{ L"quit", ncdc_cmd_quit },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ncdc_cmd_quit(ncdc_mainwindow_t n, wchar_t const *s, size_t len)
|
bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s)
|
||||||
|
{
|
||||||
|
wchar_t **tokens = NULL;
|
||||||
|
size_t size = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
tokens = w_tokenise(s);
|
||||||
|
return_if_true(tokens == NULL, false);
|
||||||
|
|
||||||
|
size = w_strlenv(tokens);
|
||||||
|
|
||||||
|
for (i = 0; cmds[i].name != NULL; i++) {
|
||||||
|
if (wcscmp(cmds[i].name, tokens[0]) == 0) {
|
||||||
|
ret = cmds[i].handler(n, size, tokens);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w_strfreev(tokens);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
|
||||||
{
|
{
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
82
ncdc/src/config.c
Normal file
82
ncdc/src/config.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#include <ncdc/config.h>
|
||||||
|
#include <confuse.h>
|
||||||
|
|
||||||
|
static cfg_opt_t account_opts[] = {
|
||||||
|
CFG_STR("email", NULL, CFGF_NONE),
|
||||||
|
CFG_STR("password", NULL, CFGF_NONE),
|
||||||
|
CFG_END()
|
||||||
|
};
|
||||||
|
|
||||||
|
static cfg_opt_t opts[] = {
|
||||||
|
CFG_SEC("account", account_opts, CFGF_TITLE|CFGF_MULTI),
|
||||||
|
CFG_END()
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ncdc_config_
|
||||||
|
{
|
||||||
|
dc_refable_t ref;
|
||||||
|
|
||||||
|
char *configpath;
|
||||||
|
cfg_t *cfg;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ncdc_config_free(ncdc_config_t c)
|
||||||
|
{
|
||||||
|
return_if_true(c == NULL,);
|
||||||
|
|
||||||
|
cfg_free(c->cfg);
|
||||||
|
free(c->configpath);
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
ncdc_config_t ncdc_config_new(void)
|
||||||
|
{
|
||||||
|
ncdc_config_t c = calloc(1, sizeof(struct ncdc_config_));
|
||||||
|
return_if_true(c == NULL, NULL);
|
||||||
|
|
||||||
|
c->ref.cleanup = (dc_cleanup_t)ncdc_config_free;
|
||||||
|
|
||||||
|
c->cfg = cfg_init(opts, CFGF_NONE);
|
||||||
|
if (c->cfg == NULL) {
|
||||||
|
free(c);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
asprintf(&c->configpath, "%s/config", ncdc_private_dir);
|
||||||
|
if (cfg_parse(c->cfg, c->configpath) == CFG_PARSE_ERROR) {
|
||||||
|
free(c->configpath);
|
||||||
|
cfg_free(c->cfg);
|
||||||
|
free(c);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_account_t ncdc_config_account(ncdc_config_t c, char const *name)
|
||||||
|
{
|
||||||
|
cfg_t *cfg = NULL;
|
||||||
|
dc_account_t acc = NULL;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
return_if_true(c == NULL || name == NULL, NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < cfg_size(c->cfg, "account"); i++) {
|
||||||
|
cfg = cfg_getnsec(c->cfg, "account", i);
|
||||||
|
if (strcmp(cfg_title(cfg), name) == 0) {
|
||||||
|
/* entry has been found
|
||||||
|
*/
|
||||||
|
char const *email = cfg_getstr(cfg, "email");
|
||||||
|
char const *password = cfg_getstr(cfg, "password");
|
||||||
|
|
||||||
|
if (email == NULL || password == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
acc = dc_account_new2(email, password);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}
|
41
ncdc/src/login.c
Normal file
41
ncdc/src/login.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include <ncdc/cmds.h>
|
||||||
|
#include <ncdc/ncdc.h>
|
||||||
|
#include <ncdc/config.h>
|
||||||
|
|
||||||
|
bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
|
||||||
|
{
|
||||||
|
char *arg = NULL;
|
||||||
|
bool ret = false;
|
||||||
|
ncdc_account_t ptr = NULL;
|
||||||
|
dc_account_t acc = NULL;
|
||||||
|
|
||||||
|
goto_if_true(ac <= 1, cleanup);
|
||||||
|
|
||||||
|
arg = w_convert(av[1]);
|
||||||
|
goto_if_true(arg == NULL, cleanup);
|
||||||
|
|
||||||
|
if (g_hash_table_lookup(accounts, arg) != NULL) {
|
||||||
|
LOG(n, L"login: %ls: this account is already logged in", av[1]);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
acc = ncdc_config_account(config, arg);
|
||||||
|
if (acc == NULL) {
|
||||||
|
LOG(n, L"login: %ls: no such account in configuration", av[1]);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = calloc(1, sizeof(struct ncdc_account_));
|
||||||
|
goto_if_true(ptr == NULL, cleanup);
|
||||||
|
|
||||||
|
ptr->account = acc;
|
||||||
|
g_hash_table_insert(accounts, arg, ptr);
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
free(arg);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#include <ncdc/mainwindow.h>
|
#include <ncdc/mainwindow.h>
|
||||||
#include <ncdc/input.h>
|
#include <ncdc/input.h>
|
||||||
|
#include <ncdc/textview.h>
|
||||||
#include <ncdc/cmds.h>
|
#include <ncdc/cmds.h>
|
||||||
#include <ncdc/ncdc.h>
|
#include <ncdc/ncdc.h>
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ struct ncdc_mainwindow_
|
|||||||
WINDOW *sep2;
|
WINDOW *sep2;
|
||||||
|
|
||||||
ncdc_input_t in;
|
ncdc_input_t in;
|
||||||
|
ncdc_textview_t log;
|
||||||
|
|
||||||
int focus;
|
int focus;
|
||||||
};
|
};
|
||||||
@ -57,6 +59,7 @@ static void ncdc_mainwindow_free(ncdc_mainwindow_t n)
|
|||||||
delwin(n->sep2);
|
delwin(n->sep2);
|
||||||
|
|
||||||
dc_unref(n->in);
|
dc_unref(n->in);
|
||||||
|
dc_unref(n->log);
|
||||||
|
|
||||||
free(n);
|
free(n);
|
||||||
}
|
}
|
||||||
@ -71,6 +74,8 @@ ncdc_mainwindow_t ncdc_mainwindow_new(void)
|
|||||||
ptr->in = ncdc_input_new();
|
ptr->in = ncdc_input_new();
|
||||||
ncdc_input_set_callback(ptr->in, ncdc_mainwindow_callback, ptr);
|
ncdc_input_set_callback(ptr->in, ncdc_mainwindow_callback, ptr);
|
||||||
|
|
||||||
|
ptr->log = ncdc_textview_new();
|
||||||
|
|
||||||
ptr->guilds = newwin(5, 5, 1, 1);
|
ptr->guilds = newwin(5, 5, 1, 1);
|
||||||
ptr->chat = newwin(5, 5, 4, 4);
|
ptr->chat = newwin(5, 5, 4, 4);
|
||||||
|
|
||||||
@ -95,15 +100,11 @@ ncdc_mainwindow_callback(ncdc_input_t i, wchar_t const *s,
|
|||||||
ncdc_mainwindow_t mainwin = (ncdc_mainwindow_t)arg;
|
ncdc_mainwindow_t mainwin = (ncdc_mainwindow_t)arg;
|
||||||
|
|
||||||
if (s[0] == '/') {
|
if (s[0] == '/') {
|
||||||
size_t i = 0;
|
if (s[1] == '\0') {
|
||||||
wchar_t const *n = w_next_word(s, len);
|
return false;
|
||||||
|
|
||||||
for (; cmds[i].name != NULL; i++) {
|
|
||||||
if (wcsncmp(s+1, cmds[i].name, (n-s-1)) == 0) {
|
|
||||||
cmds[i].handler(mainwin, s, len);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ncdc_dispatch(mainwin, s+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -135,9 +136,9 @@ static void ncdc_mainwindow_resize(ncdc_mainwindow_t n)
|
|||||||
wnoutrefresh(n->sep1);
|
wnoutrefresh(n->sep1);
|
||||||
|
|
||||||
n->chat_h = LINES - n->input_h - 1;
|
n->chat_h = LINES - n->input_h - 1;
|
||||||
n->chat_w = COLS - n->guilds_w - 1;
|
n->chat_w = COLS - n->guilds_w - 2;
|
||||||
n->chat_y = 0;
|
n->chat_y = 0;
|
||||||
n->chat_x = n->guilds_w + 1;
|
n->chat_x = n->guilds_w + 2;
|
||||||
|
|
||||||
wresize(n->chat, n->chat_h, n->chat_w);
|
wresize(n->chat, n->chat_h, n->chat_w);
|
||||||
mvwin(n->chat, n->chat_y, n->chat_x);
|
mvwin(n->chat, n->chat_y, n->chat_x);
|
||||||
@ -194,6 +195,8 @@ void ncdc_mainwindow_input_ready(ncdc_mainwindow_t n)
|
|||||||
void ncdc_mainwindow_refresh(ncdc_mainwindow_t n)
|
void ncdc_mainwindow_refresh(ncdc_mainwindow_t n)
|
||||||
{
|
{
|
||||||
wnoutrefresh(n->guilds);
|
wnoutrefresh(n->guilds);
|
||||||
|
|
||||||
|
ncdc_textview_render(n->log, n->chat, n->chat_h, n->chat_w);
|
||||||
wnoutrefresh(n->chat);
|
wnoutrefresh(n->chat);
|
||||||
|
|
||||||
ncdc_input_draw(n->in, n->input);
|
ncdc_input_draw(n->in, n->input);
|
||||||
@ -205,6 +208,18 @@ void ncdc_mainwindow_refresh(ncdc_mainwindow_t n)
|
|||||||
wnoutrefresh(n->sep2);
|
wnoutrefresh(n->sep2);
|
||||||
|
|
||||||
ncdc_mainwindow_update_focus(n);
|
ncdc_mainwindow_update_focus(n);
|
||||||
|
}
|
||||||
doupdate();
|
|
||||||
|
void ncdc_mainwindow_log(ncdc_mainwindow_t w, wchar_t const *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list lst;
|
||||||
|
wchar_t buf[256] = {0};
|
||||||
|
|
||||||
|
return_if_true(w == NULL || fmt == NULL,);
|
||||||
|
|
||||||
|
va_start(lst, fmt);
|
||||||
|
vswprintf(buf, 255, fmt, lst);
|
||||||
|
va_end(lst);
|
||||||
|
|
||||||
|
ncdc_textview_append(w->log, buf);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <ncdc/ncdc.h>
|
#include <ncdc/ncdc.h>
|
||||||
#include <ncdc/mainwindow.h>
|
#include <ncdc/mainwindow.h>
|
||||||
|
#include <ncdc/config.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -16,14 +17,34 @@ ncdc_mainwindow_t mainwin = NULL;
|
|||||||
*/
|
*/
|
||||||
static bool done = false;
|
static bool done = false;
|
||||||
|
|
||||||
char *dc_private_dir = NULL;
|
/* all the accounts we have logged into
|
||||||
char *dc_config_file = NULL;
|
*/
|
||||||
|
GHashTable *accounts = NULL;
|
||||||
|
|
||||||
static GKeyFile *config = NULL;
|
char *ncdc_private_dir = NULL;
|
||||||
|
void *config = NULL;
|
||||||
|
|
||||||
dc_loop_t loop = NULL;
|
dc_loop_t loop = NULL;
|
||||||
dc_api_t api = NULL;
|
dc_api_t api = NULL;
|
||||||
|
|
||||||
|
static void ncdc_account_free(void *ptr)
|
||||||
|
{
|
||||||
|
ncdc_account_t a = (ncdc_account_t)ptr;
|
||||||
|
|
||||||
|
return_if_true(ptr == NULL,);
|
||||||
|
|
||||||
|
if (a->friends != NULL) {
|
||||||
|
g_ptr_array_unref(a->friends);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a->guilds != NULL) {
|
||||||
|
g_ptr_array_unref(a->guilds);
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_unref(a->account);
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
static void sighandler(int sig)
|
static void sighandler(int sig)
|
||||||
{
|
{
|
||||||
endwin();
|
endwin();
|
||||||
@ -42,8 +63,16 @@ static void cleanup(void)
|
|||||||
|
|
||||||
done = true;
|
done = true;
|
||||||
|
|
||||||
|
if (accounts != NULL) {
|
||||||
|
g_hash_table_unref(accounts);
|
||||||
|
accounts = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
dc_unref(api);
|
dc_unref(api);
|
||||||
dc_unref(loop);
|
dc_unref(loop);
|
||||||
|
|
||||||
|
dc_unref(config);
|
||||||
|
dc_unref(mainwin);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stdin_handler(int sock, short what, void *data)
|
static void stdin_handler(int sock, short what, void *data)
|
||||||
@ -78,31 +107,17 @@ static bool init_everything(void)
|
|||||||
|
|
||||||
dc_loop_add_api(loop, api);
|
dc_loop_add_api(loop, api);
|
||||||
|
|
||||||
config = g_key_file_new();
|
config = ncdc_config_new();
|
||||||
return_if_true(config == NULL, false);
|
return_if_true(config == NULL, false);
|
||||||
|
|
||||||
g_key_file_load_from_file(config, dc_config_file, 0, NULL);
|
accounts = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||||
|
g_free, ncdc_account_free
|
||||||
|
);
|
||||||
|
return_if_true(accounts == NULL, false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
dc_account_t account_from_config(void)
|
|
||||||
{
|
|
||||||
char const *email = NULL;
|
|
||||||
char const *password = NULL;
|
|
||||||
void *ptr = NULL;
|
|
||||||
|
|
||||||
email = g_key_file_get_string(config, "account", "email", NULL);
|
|
||||||
password = g_key_file_get_string(config, "account", "password", NULL);
|
|
||||||
|
|
||||||
return_if_true(email == NULL || password == NULL, NULL);
|
|
||||||
|
|
||||||
ptr = dc_account_new2(email, password);
|
|
||||||
dc_account_set_id(ptr, "@me");
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int ac, char **av)
|
int main(int ac, char **av)
|
||||||
{
|
{
|
||||||
bool done = false;
|
bool done = false;
|
||||||
@ -116,17 +131,15 @@ int main(int ac, char **av)
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
asprintf(&dc_private_dir, "%s/.ndc", getenv("HOME"));
|
asprintf(&ncdc_private_dir, "%s/.ncdc", getenv("HOME"));
|
||||||
if (mkdir(dc_private_dir, 0755) < 0) {
|
if (mkdir(ncdc_private_dir, 0755) < 0) {
|
||||||
if (errno != EEXIST) {
|
if (errno != EEXIST) {
|
||||||
fprintf(stderr, "failed to make %s: %s\n", dc_private_dir,
|
fprintf(stderr, "failed to make %s: %s\n", ncdc_private_dir,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
asprintf(&dc_config_file, "%s/config", dc_private_dir);
|
|
||||||
|
|
||||||
if (!init_everything()) {
|
if (!init_everything()) {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
82
ncdc/src/textview.c
Normal file
82
ncdc/src/textview.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#include <ncdc/textview.h>
|
||||||
|
#include <ncdc/ncdc.h>
|
||||||
|
|
||||||
|
struct ncdc_textview_
|
||||||
|
{
|
||||||
|
dc_refable_t ref;
|
||||||
|
GPtrArray *par;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ncdc_textview_free(ncdc_textview_t v)
|
||||||
|
{
|
||||||
|
return_if_true(v == NULL,);
|
||||||
|
|
||||||
|
g_ptr_array_unref(v->par);
|
||||||
|
free(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
ncdc_textview_t ncdc_textview_new(void)
|
||||||
|
{
|
||||||
|
ncdc_textview_t p = calloc(1, sizeof(struct ncdc_textview_));
|
||||||
|
return_if_true(p == NULL, NULL);
|
||||||
|
|
||||||
|
p->ref.cleanup = (dc_cleanup_t)ncdc_textview_free;
|
||||||
|
|
||||||
|
p->par = g_ptr_array_new_with_free_func(free);
|
||||||
|
if (p->par == NULL) {
|
||||||
|
free(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ncdc_textview_append(ncdc_textview_t v, wchar_t const *w)
|
||||||
|
{
|
||||||
|
return_if_true(v == NULL || w == NULL,);
|
||||||
|
|
||||||
|
wchar_t const *p = w;
|
||||||
|
wchar_t const *last = w;
|
||||||
|
|
||||||
|
while ((p = wcschr(p, '\n')) != NULL) {
|
||||||
|
wchar_t *dup = wcsndup(p, p - last);
|
||||||
|
g_ptr_array_add(v->par, dup);
|
||||||
|
last = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_add(v->par, wcsdup(last));
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t const *ncdc_textview_nthline(ncdc_textview_t v, size_t idx)
|
||||||
|
{
|
||||||
|
return_if_true(v == NULL, NULL);
|
||||||
|
return_if_true(idx >= v->par->len, NULL);
|
||||||
|
return g_ptr_array_index(v->par, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ncdc_textview_render(ncdc_textview_t v, WINDOW *win, int lines, int cols)
|
||||||
|
{
|
||||||
|
ssize_t i = 0, needed_lines = 0, atline = 0;
|
||||||
|
|
||||||
|
werase(win);
|
||||||
|
|
||||||
|
if (v->par->len == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = v->par->len-1; i >= 0; i--) {
|
||||||
|
wchar_t const *w = ncdc_textview_nthline(v, i);
|
||||||
|
size_t sz = wcslen(w);
|
||||||
|
|
||||||
|
needed_lines += (sz / cols);
|
||||||
|
if ((sz / cols) == 0) {
|
||||||
|
needed_lines += 1;
|
||||||
|
}
|
||||||
|
atline = (lines - needed_lines);
|
||||||
|
mvwaddwstr(win, atline, 0, ncdc_textview_nthline(v, i));
|
||||||
|
|
||||||
|
if (needed_lines >= lines) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
128
ncdc/src/util.c
128
ncdc/src/util.c
@ -14,40 +14,110 @@ wchar_t const *w_next_word(wchar_t const *w, ssize_t len)
|
|||||||
return w+i;
|
return w+i;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *read_char(FILE *stream)
|
wchar_t* wcsndup(const wchar_t* string, size_t maxlen)
|
||||||
{
|
{
|
||||||
uint8_t str[7] = {0};
|
size_t n = wcsnlen(string, maxlen) + 1;
|
||||||
int len = 0, i = 0;
|
wchar_t* r = calloc(n, sizeof(wchar_t));
|
||||||
|
return r == NULL ? NULL : wmemcpy(r, string, n);
|
||||||
|
}
|
||||||
|
|
||||||
/* check if we need more
|
size_t w_strlenv(wchar_t **s)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
for (; s[i] != NULL; i++)
|
||||||
|
;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void w_strfreev(wchar_t **s)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
return_if_true(s == NULL,);
|
||||||
|
|
||||||
|
for (; s[i] != NULL; i++) {
|
||||||
|
free(s[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t **w_tokenise(wchar_t const *w)
|
||||||
|
{
|
||||||
|
GPtrArray *array = g_ptr_array_new();
|
||||||
|
wchar_t const *item = w;
|
||||||
|
wchar_t *dup = NULL;
|
||||||
|
size_t len = 0, origlen = 0;
|
||||||
|
|
||||||
|
while ((dup = w_next_tok(item)) != NULL) {
|
||||||
|
len = origlen = wcslen(dup);
|
||||||
|
|
||||||
|
if (*dup == '"') {
|
||||||
|
memmove(dup, dup+1, sizeof(wchar_t)*(len-1));
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0 && dup[len-1] == '"') {
|
||||||
|
dup[len-1] = '\0';
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_add(array, dup);
|
||||||
|
item += origlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_add(array, NULL);
|
||||||
|
|
||||||
|
return (wchar_t**)g_ptr_array_free(array, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *w_convert(wchar_t const *w)
|
||||||
|
{
|
||||||
|
size_t sz = 0;
|
||||||
|
char *ptr = NULL;
|
||||||
|
|
||||||
|
sz = wcstombs(NULL, w, 0);
|
||||||
|
|
||||||
|
ptr = calloc(sz+1, sizeof(char));
|
||||||
|
return_if_true(ptr == NULL, NULL);
|
||||||
|
|
||||||
|
wcstombs(ptr, w, sz);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *w_next_tok(wchar_t const *w)
|
||||||
|
{
|
||||||
|
bool quotes = false;
|
||||||
|
wchar_t const *start = NULL;
|
||||||
|
|
||||||
|
/* skip first white spaces if there are any
|
||||||
*/
|
*/
|
||||||
str[0] = (uint8_t)fgetc(stream);
|
for (; *w != '\0' && iswspace(*w); w++)
|
||||||
len = g_utf8_skip[str[0]];
|
;
|
||||||
|
|
||||||
for (i = 1; i < len; i++) {
|
if (*w == '\0') {
|
||||||
str[i] = (uint8_t)fgetc(stream);
|
return NULL;
|
||||||
}
|
|
||||||
str[len] = '\0';
|
|
||||||
|
|
||||||
return strdup((char const *)str);
|
|
||||||
}
|
|
||||||
|
|
||||||
int strwidth(char const *string)
|
|
||||||
{
|
|
||||||
size_t needed = mbstowcs(NULL, string, 0) + 1;
|
|
||||||
wchar_t *wcstring = calloc(needed, sizeof(wchar_t));
|
|
||||||
size_t ret = 0;
|
|
||||||
|
|
||||||
return_if_true(wcstring == NULL, -1);
|
|
||||||
|
|
||||||
ret = mbstowcs(wcstring, string, needed);
|
|
||||||
if (ret == (size_t)-1) {
|
|
||||||
free(wcstring);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int width = wcswidth(wcstring, needed);
|
start = w;
|
||||||
free(wcstring);
|
quotes = (*w == '"');
|
||||||
|
|
||||||
return width;
|
do {
|
||||||
|
if (iswspace(*w) && !quotes) {
|
||||||
|
--w;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*w == '"' && *(w-1) != '\\' && quotes) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*w == '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++w;
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
return wcsndup(start, (w - start));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user