suddenly friend listing support

This commit is contained in:
2019-07-03 21:14:23 +02:00
parent b307906cf4
commit de6d02fd58
16 changed files with 400 additions and 79 deletions

View File

@@ -16,6 +16,7 @@ SET(SOURCES
"src/cmds.c"
"src/config.c"
"src/emacs.c"
"src/friends.c"
"src/input.c"
"src/login.c"
"src/mainwindow.c"

View File

@@ -14,9 +14,13 @@ typedef struct {
extern ncdc_commands_t cmds[];
bool ncdc_dispatch_init(void);
bool ncdc_dispatch_deinit(void);
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_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av);
bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av);
bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, wchar_t **av);
#endif

View File

@@ -44,12 +44,20 @@ struct ncdc_account_ {
typedef struct ncdc_account_ *ncdc_account_t;
extern GHashTable *accounts;
extern dc_account_t current_account;
extern dc_api_t api;
extern char *ncdc_private_dir;
extern void *config;
extern void *mainwindow;
void exit_main(void);
int strwidth(char const *string);
char *read_char(FILE *stream);
int aswprintf(wchar_t **buffer, wchar_t const *fmt, ...);
char *w_convert(wchar_t const *w);
wchar_t* wcsndup(const wchar_t* string, size_t maxlen);
size_t w_strlenv(wchar_t **s);

View File

@@ -1,36 +1,136 @@
#include <ncdc/cmds.h>
ncdc_commands_t cmds[] = {
{ L"friends", ncdc_cmd_friends },
{ L"login", ncdc_cmd_login },
{ L"quit", ncdc_cmd_quit },
{ NULL, NULL }
};
static GQueue *queue = NULL;
static pthread_t thr;
static pthread_mutex_t mtx;
static pthread_cond_t cnd;
typedef struct {
ncdc_commands_t *cmd;
size_t ac;
wchar_t **av;
ncdc_mainwindow_t mainwindow;
} queue_item;
static void *async_dispatcher(void *arg)
{
queue_item *item = NULL;
while (true) {
pthread_mutex_lock(&mtx);
pthread_cond_wait(&cnd, &mtx);
/* of course it is "get_length", and not "size" or
* "length", or something else. srsly.
*/
while (g_queue_get_length(queue) > 0) {
item = g_queue_pop_head(queue);
if (item == NULL) {
/* end of working orders
*/
pthread_mutex_unlock(&mtx);
printf("got exit\n");
return NULL;
} else {
/* call the handler
*/
item->cmd->handler(item->mainwindow, item->ac, item->av);
w_strfreev(item->av);
free(item);
}
}
pthread_mutex_unlock(&mtx);
}
return NULL;
}
bool ncdc_dispatch_init(void)
{
return_if_true(queue != NULL, true);
queue = g_queue_new();
return_if_true(queue == NULL, false);
pthread_mutex_init(&mtx, NULL);
pthread_cond_init(&cnd, NULL);
pthread_create(&thr, NULL, async_dispatcher, NULL);
return true;
}
bool ncdc_dispatch_deinit(void)
{
return_if_true(queue == NULL, true);
pthread_mutex_lock(&mtx);
g_queue_push_tail(queue, NULL);
pthread_cond_signal(&cnd);
pthread_mutex_unlock(&mtx);
pthread_join(thr, NULL);
pthread_mutex_destroy(&mtx);
pthread_cond_destroy(&cnd);
g_queue_free(queue);
queue = NULL;
return true;
}
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;
ncdc_commands_t *it = NULL;
queue_item *item = NULL;
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);
it = cmds+i;
break;
}
}
w_strfreev(tokens);
if (it == NULL) {
/* no such command
*/
LOG(n, L"error: no such command \"%ls\"", tokens[0]);
w_strfreev(tokens);
return false;
}
return ret;
item = calloc(1, sizeof(queue_item));
item->ac = w_strlenv(tokens);
item->av = tokens;
item->cmd = it;
item->mainwindow = n;
pthread_mutex_lock(&mtx);
g_queue_push_tail(queue, item);
pthread_cond_broadcast(&cnd);
pthread_mutex_unlock(&mtx);
return true;
}
bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
{
exit(0);
exit_main();
return true;
}

52
ncdc/src/friends.c Normal file
View File

@@ -0,0 +1,52 @@
#include <ncdc/cmds.h>
#include <ncdc/ncdc.h>
static bool
ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
{
bool ret = false;
size_t i = 0;
ret = dc_api_get_friends(api, current_account);
if (!ret) {
LOG(n, L"friends: list: failed to fetch your friends");
return false;
}
LOG(n, L"/FRIENDS list");
for (i = 0; i < dc_account_friends_size(current_account); i++) {
dc_account_t acc = dc_account_nthfriend(current_account, i);
LOG(n, L" %s", dc_account_full_username(acc));
}
LOG(n, L"End of /FRIENDS list");
return true;
}
bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
{
wchar_t *subcmd = NULL;
if (ac <= 1) {
return false;
}
if (current_account == NULL ||
!dc_account_has_token(current_account)) {
LOG(n, L"friends: not logged in");
return false;
}
subcmd = av[1];
--ac;
++av;
if (wcscmp(subcmd, L"list") == 0) {
return ncdc_cmd_friends_list(n, ac, av);
} else {
return false;
}
return true;
}

View File

@@ -6,7 +6,6 @@ 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);
@@ -14,23 +13,29 @@ bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
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);
acc = g_hash_table_lookup(accounts, arg);
if (acc == NULL) {
LOG(n, L"login: %ls: no such account in configuration", av[1]);
acc = ncdc_config_account(config, arg);
if (acc == NULL) {
LOG(n, L"login: %ls: no such account in configuration", av[1]);
goto cleanup;
}
g_hash_table_insert(accounts, arg, acc);
} else {
if (dc_account_has_token(acc)) {
LOG(n, L"login: %ls: this account is already logged in", av[1]);
goto cleanup;
}
}
if (!dc_api_authenticate(api, acc)) {
LOG(n, L"login: %ls: authentication failed; wrong password?", 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);
current_account = acc;
LOG(n, L"login: %ls: authentication successful", av[1]);
ret = true;
cleanup:

View File

@@ -1,6 +1,7 @@
#include <ncdc/ncdc.h>
#include <ncdc/mainwindow.h>
#include <ncdc/config.h>
#include <ncdc/cmds.h>
#include <stdio.h>
#include <unistd.h>
@@ -15,53 +16,41 @@ ncdc_mainwindow_t mainwin = NULL;
/* we loop in a different thread
*/
static bool done = false;
bool main_done = false;
static pthread_t event_thread;
static struct event_base *base = NULL;
/* all the accounts we have logged into
*/
GHashTable *accounts = NULL;
dc_account_t current_account = NULL;
char *ncdc_private_dir = NULL;
void *config = NULL;
dc_loop_t loop = NULL;
/* API handle we use for everything
*/
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)
{
endwin();
exit(3);
}
static void cleanup(void)
{
endwin();
main_done = true;
dc_loop_abort(loop);
pthread_join(event_thread, NULL);
if (stdin_ev != NULL) {
event_del(stdin_ev);
event_free(stdin_ev);
stdin_ev = NULL;
}
done = true;
event_base_loopbreak(base);
event_base_free(base);
base = NULL;
if (accounts != NULL) {
g_hash_table_unref(accounts);
@@ -75,6 +64,12 @@ static void cleanup(void)
dc_unref(mainwin);
}
static void sighandler(int sig)
{
cleanup();
exit(3);
}
static void stdin_handler(int sock, short what, void *data)
{
if ((what & EV_READ) == EV_READ) {
@@ -82,18 +77,38 @@ static void stdin_handler(int sock, short what, void *data)
}
}
static void *looper(void *arg)
{
while (!main_done) {
if (!dc_loop_once(loop)) {
break;
}
usleep(10 * 1000);
}
return NULL;
}
static bool init_everything(void)
{
int ret = 0;
evthread_use_pthreads();
setlocale(LC_CTYPE, "");
return_if_true(!ncdc_dispatch_init(), false);
base = event_base_new();
return_if_true(base == NULL, false);
loop = dc_loop_new();
return_if_true(loop == NULL, false);
/* add handle for STDIN, this info will then be fed to the UI
*/
stdin_ev = event_new(dc_loop_event_base(loop), 0 /* stdin */,
stdin_ev = event_new(base, 0 /* stdin */,
EV_READ|EV_PERSIST,
stdin_handler, NULL
);
@@ -111,18 +126,25 @@ static bool init_everything(void)
return_if_true(config == NULL, false);
accounts = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, ncdc_account_free
g_free, dc_unref
);
return_if_true(accounts == NULL, false);
ret = pthread_create(&event_thread, NULL, looper, NULL);
return_if_true(ret != 0, false);
return true;
}
void exit_main(void)
{
main_done = true;
event_base_loopbreak(base);
}
int main(int ac, char **av)
{
bool done = false;
atexit(cleanup);
int ret = 0;
signal(SIGINT, sighandler);
@@ -144,8 +166,6 @@ int main(int ac, char **av)
return 3;
}
done = false;
initscr();
noecho();
nonl();
@@ -165,17 +185,19 @@ int main(int ac, char **av)
return 3;
}
while (!done) {
while (!main_done) {
ncdc_mainwindow_refresh(mainwin);
doupdate();
if (!dc_loop_once(loop)) {
ret = event_base_loop(base, EVLOOP_ONCE|EVLOOP_NONBLOCK);
if (ret < 0) {
break;
}
usleep(10*1000);
}
dc_unref(mainwin);
endwin();
cleanup();
return 0;
}

View File

@@ -40,8 +40,10 @@ void ncdc_textview_append(ncdc_textview_t v, wchar_t const *w)
while ((p = wcschr(p, '\n')) != NULL) {
wchar_t *dup = wcsndup(p, p - last);
g_ptr_array_add(v->par, dup);
last = p;
if (dup != NULL) {
g_ptr_array_add(v->par, dup);
last = p;
}
}
g_ptr_array_add(v->par, wcsdup(last));

View File

@@ -14,6 +14,25 @@ wchar_t const *w_next_word(wchar_t const *w, ssize_t len)
return w+i;
}
int aswprintf(wchar_t **buffer, wchar_t const *fmt, ...)
{
size_t sz = 0;
FILE *f = NULL;
va_list lst;
f = open_wmemstream(buffer, &sz);
if (f == NULL) {
return -1;
}
va_start(lst, fmt);
vfwprintf(f, fmt, lst);
va_end(lst);
fclose(f);
return sz;
}
wchar_t* wcsndup(const wchar_t* string, size_t maxlen)
{
size_t n = wcsnlen(string, maxlen) + 1;