implement adding friends

This commit is contained in:
Florian Stinglmayr 2019-07-03 22:47:12 +02:00
parent 2e563b724a
commit efce6a6543
8 changed files with 231 additions and 68 deletions

View File

@ -8,8 +8,19 @@
struct dc_account_;
typedef struct dc_account_ *dc_account_t;
typedef enum {
FRIEND_STATE_NONE = 0,
/* accountt is a mutual friend
*/
FRIEND_STATE_FRIEND = 1,
/* pending account, the other side hasn't accepted yet
*/
FRIEND_STATE_PENDING = 4,
} dc_account_friend_states;
dc_account_t dc_account_new(void);
dc_account_t dc_account_new2(char const *email, char const *pass);
dc_account_t dc_account_from_fullid(char const *fullid);
void dc_account_set_email(dc_account_t a, char const *email);
char const *dc_account_email(dc_account_t a);
@ -37,5 +48,7 @@ bool dc_account_has_token(dc_account_t a);
void dc_account_set_friends(dc_account_t a, dc_account_t *ptr, size_t len);
dc_account_t dc_account_nthfriend(dc_account_t a, size_t i);
size_t dc_account_friends_size(dc_account_t a);
int dc_account_friend_state(dc_account_t a);
void dc_account_set_friend_state(dc_account_t a, int state);
#endif

View File

@ -65,4 +65,9 @@ bool dc_api_get_userguilds(dc_api_t api, dc_account_t login,
*/
bool dc_api_get_friends(dc_api_t api, dc_account_t login);
/**
* Add a given account as a friend to the friends list
*/
bool dc_api_add_friend(dc_api_t api, dc_account_t login, dc_account_t friend);
#endif

View File

@ -34,6 +34,9 @@ struct dc_account_
/* friends we have
*/
GPtrArray *friends;
/* our own friend state
*/
int friend_state;
};
static void dc_account_free(dc_account_t ptr)
@ -81,6 +84,38 @@ dc_account_t dc_account_new2(char const *email, char const *pass)
return ptr;
}
dc_account_t dc_account_from_fullid(char const *fullid)
{
return_if_true(fullid == NULL, NULL);
char *name = strdup(fullid), *discriminator = NULL;
dc_account_t acc = NULL;
return_if_true(name == NULL, NULL);
discriminator = strchr(name, '#');
if (discriminator == NULL || *discriminator == '\0') {
free(name);
return NULL;
}
*discriminator = '\0';
++discriminator;
acc = dc_account_new();
if (acc == NULL) {
free(name);
return NULL;
}
dc_account_set_username(acc, name);
dc_account_set_discriminator(acc, discriminator);
free(name);
return acc;
}
void dc_account_set_email(dc_account_t a, char const *email)
{
return_if_true(a == NULL,);
@ -219,3 +254,15 @@ size_t dc_account_friends_size(dc_account_t a)
return_if_true(a == NULL || a->friends == NULL, 0);
return a->friends->len;
}
int dc_account_friend_state(dc_account_t a)
{
return_if_true(a == NULL, 0);
return a->friend_state;
}
void dc_account_set_friend_state(dc_account_t a, int state)
{
return_if_true(a == NULL,);
a->friend_state = state;
}

View File

@ -349,6 +349,29 @@ error:
return NULL;
}
static json_t *dc_api_user_to_json(dc_account_t a)
{
json_t *j = NULL;
return_if_true(a == NULL, NULL);
return_if_true(dc_account_username(a) == NULL ||
dc_account_discriminator(a) == NULL,
NULL
);
j = json_object();
return_if_true(j == NULL, NULL);
json_object_set_new(j, "username",
json_string(dc_account_username(a))
);
json_object_set_new(j, "discriminator",
json_string(dc_account_discriminator(a))
);
return j;
}
bool dc_api_get_userinfo(dc_api_t api, dc_account_t login,
dc_account_t user)
{
@ -420,6 +443,15 @@ bool dc_api_get_friends(dc_api_t api, dc_account_t login)
if (a == NULL) {
continue;
}
/* read the type also known as "typ"
*/
val = json_object_get(c, "type");
if (val != NULL && json_is_integer(val)) {
int state = json_integer_value(val);
dc_account_set_friend_state(a, state);
}
g_ptr_array_add(f, a);
}
@ -440,6 +472,36 @@ cleanup:
return ret;
}
/**
* Add a given account as a friend to the friends list
*/
bool dc_api_add_friend(dc_api_t api, dc_account_t login, dc_account_t friend)
{
char const *url = "users/@me/relationships";
json_t *reply = NULL, *post = NULL;
bool ret = false;
return_if_true(api == NULL, false);
return_if_true(login == NULL, false);
post = dc_api_user_to_json(friend);
return_if_true(post == NULL, false);
reply = dc_api_call_sync(api, "POST", dc_account_token(login), url, post);
/* apparently if no data comes back, then the whole thing was a success
*/
goto_if_true(reply != NULL, cleanup);
ret = true;
cleanup:
json_decref(post);
json_decref(reply);
return ret;
}
bool dc_api_get_userguilds(dc_api_t api, dc_account_t login, GPtrArray **out)
{
char const *url = "users/@me/guilds";

View File

@ -1,9 +1,10 @@
#include <ncdc/cmds.h>
ncdc_commands_t cmds[] = {
{ L"friends", ncdc_cmd_friends },
{ L"login", ncdc_cmd_login },
{ L"quit", ncdc_cmd_quit },
{ L"/friend", ncdc_cmd_friends },
{ L"/friends", ncdc_cmd_friends },
{ L"/login", ncdc_cmd_login },
{ L"/quit", ncdc_cmd_quit },
{ NULL, NULL }
};
@ -36,7 +37,6 @@ static void *async_dispatcher(void *arg)
/* end of working orders
*/
pthread_mutex_unlock(&mtx);
printf("got exit\n");
return NULL;
} else {
/* call the handler
@ -92,15 +92,17 @@ bool ncdc_dispatch_deinit(void)
bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s)
{
wchar_t **tokens = NULL;
size_t i = 0;
size_t i = 0, tokenlen = 0;
ncdc_commands_t *it = NULL;
queue_item *item = NULL;
tokens = w_tokenise(s);
return_if_true(tokens == NULL, false);
tokenlen = wcslen(tokens[0]);
for (i = 0; cmds[i].name != NULL; i++) {
if (wcscmp(cmds[i].name, tokens[0]) == 0) {
if (wcsncmp(cmds[i].name, tokens[0], tokenlen) == 0) {
it = cmds+i;
break;
}

View File

@ -6,6 +6,7 @@ ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
{
bool ret = false;
size_t i = 0;
wchar_t c = ' ';
ret = dc_api_get_friends(api, current_account);
if (!ret) {
@ -16,27 +17,67 @@ ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
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));
switch (dc_account_friend_state(acc)) {
case FRIEND_STATE_PENDING: c = 'P'; break;
default: c = ' '; break;
}
LOG(n, L"%lc %s", c, 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)
static bool
ncdc_cmd_friends_add(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
{
wchar_t *subcmd = NULL;
char *name = NULL;
dc_account_t friend = NULL;
bool ret = false;
if (ac <= 1) {
return false;
}
name = w_convert(av[1]);
return_if_true(name == NULL, false);
friend = dc_account_from_fullid(name);
if (friend == NULL) {
LOG(n, L"friends: add: invalid username given, use the full ID");
goto cleanup;
}
if (!dc_api_add_friend(api, current_account, friend)) {
LOG(n, L"friends: add: failed to add friend, Vulkan would be sad");
goto cleanup;
}
LOG(n, L"friends: add: request for friendship sent");
ret = true;
cleanup:
dc_unref(friend);
free(name);
return ret;
}
bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
{
wchar_t *subcmd = NULL;
if (current_account == NULL ||
!dc_account_has_token(current_account)) {
LOG(n, L"friends: not logged in");
return false;
}
if (ac <= 1) {
return ncdc_cmd_friends_list(n, ac, av);
}
subcmd = av[1];
--ac;
@ -44,6 +85,8 @@ bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
if (wcscmp(subcmd, L"list") == 0) {
return ncdc_cmd_friends_list(n, ac, av);
} else if (wcscmp(subcmd, L"add") == 0) {
return ncdc_cmd_friends_add(n, ac, av);
} else {
return false;
}

View File

@ -99,12 +99,12 @@ ncdc_mainwindow_callback(ncdc_input_t i, wchar_t const *s,
{
ncdc_mainwindow_t mainwin = (ncdc_mainwindow_t)arg;
if (s[0] == '/') {
if (s != NULL && s[0] == '/') {
if (s[1] == '\0') {
return false;
}
return ncdc_dispatch(mainwin, s+1);
return ncdc_dispatch(mainwin, s);
}
return false;

View File

@ -33,11 +33,11 @@ int aswprintf(wchar_t **buffer, wchar_t const *fmt, ...)
return sz;
}
wchar_t* wcsndup(const wchar_t* string, size_t maxlen)
wchar_t* wcsndup(wchar_t const* string, size_t maxlen)
{
size_t n = wcsnlen(string, maxlen) + 1;
wchar_t* r = calloc(n, sizeof(wchar_t));
return r == NULL ? NULL : wmemcpy(r, string, n);
wchar_t* r = calloc(maxlen+1, sizeof(wchar_t));
return_if_true(r == NULL, NULL);
return wmemcpy(r, string, maxlen);
}
size_t w_strlenv(wchar_t **s)
@ -61,28 +61,56 @@ void w_strfreev(wchar_t **s)
free(s);
}
wchar_t **w_tokenise(wchar_t const *w)
wchar_t **w_tokenise(wchar_t const *str)
{
wchar_t const *p = NULL, *start_of_word = NULL;
wint_t c;
GPtrArray *array = g_ptr_array_new();
wchar_t const *item = w;
wchar_t *dup = NULL;
size_t len = 0, origlen = 0;
enum states { DULL, IN_WORD, IN_STRING } state = DULL;
while ((dup = w_next_tok(item)) != NULL) {
len = origlen = wcslen(dup);
for (p = str; *p != '\0'; p++) {
c = (wint_t) *p;
switch (state) {
case DULL:
{
if (iswspace(c)) {
continue;
}
if (c == '"') {
state = IN_STRING;
start_of_word = p + 1;
continue;
}
state = IN_WORD;
start_of_word = p;
} continue;
if (*dup == '"') {
memmove(dup, dup+1, sizeof(wchar_t)*(len-1));
--len;
case IN_STRING:
{
if (c == '"') {
size_t len = (p - 2 - start_of_word);
wchar_t *s = wcsndup(start_of_word, len);
g_ptr_array_add(array, s);
state = DULL;
}
} continue;
case IN_WORD:
{
if (iswspace(c)) {
size_t len = (p - start_of_word);
wchar_t *s = wcsndup(start_of_word, len);
g_ptr_array_add(array, s);
state = DULL;
}
} continue;
}
}
if (len > 0 && dup[len-1] == '"') {
dup[len-1] = '\0';
--len;
}
g_ptr_array_add(array, dup);
item += origlen;
if (state != DULL) {
size_t len = (p - start_of_word);
wchar_t *s = wcsndup(start_of_word, len);
g_ptr_array_add(array, s);
}
g_ptr_array_add(array, NULL);
@ -103,40 +131,3 @@ char *w_convert(wchar_t const *w)
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
*/
for (; *w != '\0' && iswspace(*w); w++)
;
if (*w == '\0') {
return NULL;
}
start = w;
quotes = (*w == '"');
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));
}